<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rocky</title>
    <description>The latest articles on DEV Community by Rocky (@rockyyy).</description>
    <link>https://dev.to/rockyyy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4026445%2F94b46dbb-5b45-421a-be13-61cb9779ec88.jpg</url>
      <title>DEV Community: Rocky</title>
      <link>https://dev.to/rockyyy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rockyyy"/>
    <language>en</language>
    <item>
      <title>The Alert Isn't the Problem, Your Third Blank Triage Decision Tonight Is</title>
      <dc:creator>Rocky</dc:creator>
      <pubDate>Mon, 24 Aug 2026 14:41:06 +0000</pubDate>
      <link>https://dev.to/rockyyy/the-alert-isnt-the-problem-your-third-blank-triage-decision-tonight-is-4oae</link>
      <guid>https://dev.to/rockyyy/the-alert-isnt-the-problem-your-third-blank-triage-decision-tonight-is-4oae</guid>
      <description>&lt;p&gt;It's alert 34 of the shift. The last 30 were PowerShell execution alerts from the same finance laptop running a legitimate reporting macro, and you closed every one as a false positive within about four seconds. Alert 34 looks the same at a glance: PowerShell, encoded command, medium severity. You're already moving the cursor to close it when something makes you pause, maybe nothing, maybe the start of a ransomware deployment. This is the moment SOC analysts actually live in, and it is nothing like the clean "investigate the incident" scenario training decks show. It's a judgment call made under fatigue, with a queue behind it, and the two ways to get it wrong (miss a real one, or escalate everything and get ignored) are both career-relevant.&lt;/p&gt;

&lt;p&gt;The fix isn't "pay closer attention." Attention runs out. What actually holds up under a long queue is a repeatable decision process you run the same way on alert 3 and alert 34.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read what the rule is actually detecting before you judge the alert's title.&lt;/strong&gt; A severity label and a one-line summary tell you almost nothing. Open the actual detection logic: what command line pattern, what process lineage, what threshold triggered it. Half of triage mistakes come from reacting to the alert's name instead of the condition it fired on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Establish whether this is normal for this specific host and user, not "PowerShell in general."&lt;/strong&gt; A finance laptop running a signed, scheduled reporting macro that spawns PowerShell every morning at 9am is a different animal from a receptionist's machine spawning PowerShell for the first time ever, at 2am, with an encoded command tail. Same process, same alert rule, completely different baseline. Triage without checking the baseline is just triage by vibes with extra steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Follow the process lineage, not just the flagged process.&lt;/strong&gt; What actually spawned this? &lt;code&gt;winword.exe -&amp;gt; powershell.exe -&amp;gt; encoded command&lt;/code&gt; is a documented macro-malware pattern worth escalating. &lt;code&gt;explorer.exe -&amp;gt; powershell.exe&lt;/code&gt; from a user who opens PowerShell as part of their job is usually nothing. The command line and its parent are the real signal; the process name alone almost never is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make the call and write down why, every time, even when you're sure.&lt;/strong&gt; "Closed as FP: parent process matches known scheduled task, host baseline shows this daily" takes ten seconds and means the next analyst who sees the same pattern doesn't have to re-litigate it from zero. This is also how you catch yourself when your reasoning doesn't actually hold up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you escalate, scope the blast radius before you page anyone.&lt;/strong&gt; What else does this host talk to, what account is logged in, has this signature shown up anywhere else in the last 24 hours. Escalating with "this looks suspicious" gets deprioritized. Escalating with "this host, this account, these three other machines show the same pattern" gets acted on immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you close it, feed it back into the detection so it stops asking you the same question.&lt;/strong&gt; A false positive that fires the same way every week isn't a tuning backlog item, it's a debt against your own attention, and it is exactly what alert fatigue is made of. Turning a recurring FP into a suppression rule or a better detection condition is the difference between triage staying sustainable and triage slowly eating the rest of your shift.&lt;/p&gt;

&lt;p&gt;This progression, triage discipline into detection engineering, is exactly the arc Codelivly's &lt;a href="https://resources.codelivly.com/product/soc-analyst-the-complete-l1-l2-l3/" rel="noopener noreferrer"&gt;SOC Analyst Book Bundle: L1 + L2 + L3 Playbooks&lt;/a&gt; is built around, going from "how do I make this call correctly" to "how do I stop having to make it manually at all." If you want to run this exact decision process against a real alert queue first, the free &lt;a href="https://codelivly.com/learning-paths/soc-fundamentals" rel="noopener noreferrer"&gt;SOC Fundamentals learning path&lt;/a&gt; and the &lt;a href="https://codelivly.com/labs/soc-intro-workflow" rel="noopener noreferrer"&gt;SOC Intro Workflow lab&lt;/a&gt; put an actual triage queue in front of you before you spend anything.&lt;/p&gt;

</description>
      <category>soc</category>
      <category>blueteam</category>
      <category>infosec</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>You Ran the Deauth Attack Correctly. The Client Just Didn't Care.</title>
      <dc:creator>Rocky</dc:creator>
      <pubDate>Mon, 24 Aug 2026 14:39:57 +0000</pubDate>
      <link>https://dev.to/rockyyy/you-ran-the-deauth-attack-correctly-the-client-just-didnt-care-4ma8</link>
      <guid>https://dev.to/rockyyy/you-ran-the-deauth-attack-correctly-the-client-just-didnt-care-4ma8</guid>
      <description>&lt;p&gt;You're on-site for a wireless assessment. Evil twin AP is up, same SSID, same encryption type, signal stronger than the real access point. You fire the deauth frames at the target client, the same attack that's worked in every lab and every CTF you've practiced against. The tool reports success, frames sent, no errors. And the client just stays connected to the legitimate AP like nothing happened. No reconnection, no handshake capture, no drop in signal on their end at all. You check your syntax, you check your interface is in monitor mode, you check the target MAC address twice. Everything about your attack is correct. It still doesn't work, and the tool never tells you why.&lt;/p&gt;

&lt;p&gt;The answer isn't a misconfigured adapter. It's Protected Management Frames, 802.11w, and it's been quietly closing off the deauth attack you learned first for a few years now.&lt;/p&gt;

&lt;p&gt;Deauth and disassociation frames are management frames, not data frames, and for most of Wi-Fi's history management frames were sent completely unauthenticated. Anyone in range could forge one and the client's radio would honor it as if the real AP sent it, because there was no way to tell the difference. That's the entire mechanism behind the deauth attack: spoof the AP's address, tell the client "disconnect," and it does, because it has no way to verify the frame is a lie.&lt;/p&gt;

&lt;p&gt;PMF changes exactly that. It adds a cryptographic layer to management frames using keys derived during the original authentication handshake, so a forged deauth frame from an attacker who was never part of that handshake gets silently dropped by the client's radio. Not rejected with an error. Not logged anywhere you can see. Just ignored, as if you never sent it. WPA3 makes PMF mandatory. WPA2 has supported it as optional for years, and a growing number of networks, especially anything touched by a security-conscious IT team or a modern enterprise AP vendor, turn it on by default now.&lt;/p&gt;

&lt;p&gt;The mistake isn't running the attack wrong. It's not checking for PMF before you commit engagement hours to an attack that was never going to work against this specific network, and having no way to explain to a client afterward why the wireless assessment came back with nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check for PMF before you touch a deauth frame.&lt;/strong&gt; The beacon frames from the target AP advertise this in their RSN capabilities. &lt;code&gt;airodump-ng&lt;/code&gt; surfaces PMF status directly in newer versions, and tools like &lt;code&gt;wpa_supplicant&lt;/code&gt;'s scan output or a Wireshark capture of the beacon will show the MFPC (management frame protection capable) and MFPR (required) bits. Five minutes of passive recon here saves you from an entire engagement day of deauth frames that silently go nowhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If PMF is on, deauth is off the table, but the handshake usually still isn't.&lt;/strong&gt; You don't need to force a reconnection if you can capture the initial four-way handshake when a client joins normally, or target clients that are already configured to auto-connect to open or misconfigured networks regardless of what the "protected" network is doing. The attack surface shifts from forcing a disconnect to being patient and opportunistic instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The same lesson shows up on the wired side with ARP spoofing.&lt;/strong&gt; Dynamic ARP Inspection on a managed switch will drop ARP replies that don't match its DHCP snooping binding table, again silently, again with your tool reporting success while nothing actually reaches the target. The specific defense is different, wireless management frame protection versus switch-level ARP validation, but the trap is identical: a five-year-old tutorial assumes an undefended network, and modern environments increasingly aren't one.&lt;/p&gt;

&lt;p&gt;Codelivly's &lt;a href="https://resources.codelivly.com/product/practical-man-in-the-middle-attacks-in-computer-networks/" rel="noopener noreferrer"&gt;Practical Man-in-the-Middle Attacks book&lt;/a&gt; builds against this actual current threat model instead of the undefended-network assumption most MITM material still teaches from, covering where ARP spoofing, DNS spoofing, evil-twin Wi-Fi, and SSL interception still work and where they get quietly shut down. If you want to see PMF and evil-twin mechanics against something real first, the free &lt;a href="https://codelivly.com/learning-paths/wireless-social-engineering" rel="noopener noreferrer"&gt;Wireless &amp;amp; Social Engineering learning path&lt;/a&gt; and the &lt;a href="https://codelivly.com/rooms/aircrack-ng-suite-wireless-attacks" rel="noopener noreferrer"&gt;Aircrack-ng Suite &amp;amp; Wireless Attacks room&lt;/a&gt; put an actual target network in front of you before you spend anything.&lt;/p&gt;

</description>
      <category>wireless</category>
      <category>pentesting</category>
      <category>redteam</category>
      <category>infosec</category>
    </item>
    <item>
      <title>The Scanner Came Back Clean. The Discount Code Still Worked 40 Times.</title>
      <dc:creator>Rocky</dc:creator>
      <pubDate>Mon, 24 Aug 2026 08:01:08 +0000</pubDate>
      <link>https://dev.to/rockyyy/the-scanner-came-back-clean-the-discount-code-still-worked-40-times-p9g</link>
      <guid>https://dev.to/rockyyy/the-scanner-came-back-clean-the-discount-code-still-worked-40-times-p9g</guid>
      <description>&lt;p&gt;The automated scan on a checkout flow came back with nothing above low. No SQLi, no reflected XSS, no broken authentication, every OWASP Top 10 box quietly green. A junior pentester on the engagement was ready to write "no significant findings" and move to the next target, and honestly, most scanners would have agreed with them. Then someone on the team noticed the "apply discount code" endpoint didn't invalidate a single-use code until after the order confirmed, and asked the question a scanner never asks: what happens if you send this request twenty times before any of them finish?&lt;/p&gt;

&lt;p&gt;The answer was a single-use 50% code getting redeemed forty times in under a second, using nothing more exotic than sending the same request concurrently. No injection, no broken access control in the traditional sense, just a gap between "check if this code is valid" and "mark this code as used" wide enough to drive a cart full of orders through.&lt;/p&gt;

&lt;p&gt;This is the category automated scanning structurally cannot find, because a scanner tests requests one at a time. A race condition only exists in the space between two requests, and if you never send two requests at once, the vulnerability never has a chance to show itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Find the endpoints where it can happen.&lt;/strong&gt; Anywhere there's a check-then-act pattern is a candidate: redeem a coupon, apply a referral bonus, withdraw a balance, submit a vote, claim a limited inventory item. The tell is a read (is this still valid?) followed by a write (mark it used) as two separate steps instead of one atomic operation. Most business logic that touches money or scarcity is built exactly this way, because it's simpler to write and code review rarely questions it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Send the requests at the same instant, not just quickly.&lt;/strong&gt; A normal script firing requests in a loop still has network jitter between them, enough that the server processes most of them sequentially anyway and the race never triggers. Tools built for this (Burp's race condition tab, Turbo Intruder) send every request within the same TCP connection or the same packet, collapsing that window to as close to zero as HTTP allows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read the responses for overlap, not just success codes.&lt;/strong&gt; A 200 on all forty requests doesn't prove anything by itself, plenty of race conditions still return a clean success response on requests that shouldn't have gone through. Check the actual state afterward: how many times did the code apply, did the balance go negative, did the inventory count drop below zero. The proof is in the end state, not the response codes.&lt;/p&gt;

&lt;p&gt;None of this shows up in a report generated by a scanner running one request at a time, however thorough the coverage looks. It's the kind of finding that only surfaces when someone stops trusting a clean scan and starts asking what the application does under concurrency instead of in sequence.&lt;/p&gt;

&lt;p&gt;Codelivly's &lt;a href="https://resources.codelivly.com/product/web-application-hacking-l2/" rel="noopener noreferrer"&gt;Advanced Web Application Penetration Testing Book (L2)&lt;/a&gt; is built entirely around this gap, business logic and chained exploitation past what any scanner catches. The free &lt;a href="https://codelivly.com/labs/race-condition" rel="noopener noreferrer"&gt;Race Condition lab&lt;/a&gt; lets you fire this exact attack at a real vulnerable endpoint, and the &lt;a href="https://codelivly.com/ctf/challenges/nimbusops-killchain" rel="noopener noreferrer"&gt;NimbusOps Kill Chain CTF&lt;/a&gt; chains several logic flaws together the way a real engagement actually plays out.&lt;/p&gt;

</description>
      <category>appsec</category>
      <category>webdev</category>
      <category>security</category>
      <category>pentesting</category>
    </item>
    <item>
      <title>Nobody Assigned You This Hunt: Starting From an ATT&amp;CK Technique Instead of a Ticket</title>
      <dc:creator>Rocky</dc:creator>
      <pubDate>Mon, 24 Aug 2026 06:26:11 +0000</pubDate>
      <link>https://dev.to/rockyyy/nobody-assigned-you-this-hunt-starting-from-an-attck-technique-instead-of-a-ticket-41k3</link>
      <guid>https://dev.to/rockyyy/nobody-assigned-you-this-hunt-starting-from-an-attck-technique-instead-of-a-ticket-41k3</guid>
      <description>&lt;p&gt;There's no ticket. No EDR alert, no user complaint, no line in the SIEM dashboard telling you where to look. Your queue is empty and your manager just said "go hunt for a couple hours before the next incident." A new threat hunter freezes here more often than anywhere else in the job, because every other part of security work starts with something breaking. Hunting starts with nothing breaking yet, and that's the whole point of it.&lt;/p&gt;

&lt;p&gt;The instinct is to open a random tool and start poking at logs. That's triage without an incident, and it burns hours without producing anything repeatable. The actual discipline starts somewhere narrower: pick one ATT&amp;amp;CK technique your environment is realistically exposed to, and build the hunt around it on purpose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick a technique you can defend picking.&lt;/strong&gt; Not "let's hunt for malware," that's not a hypothesis, it's a mood. Pick something specific and justify it with what you actually know about your environment: if most of your fleet is Windows workstations with no application allowlisting, T1055 Process Injection is a reasonable bet, because an attacker with code execution has every reason to blend into a legitimate process instead of dropping something new and loud.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;State the hypothesis before you touch a query.&lt;/strong&gt; "If an attacker got execution on a workstation, they'd inject into a process like explorer.exe or a browser rather than run their own binary, because a new process name is exactly what gets flagged." Write that sentence down. It tells you what evidence would confirm the hunt, and just as important, what evidence means the hunt came up empty, which is a real result too, not a wasted afternoon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure out what telemetry actually tests it.&lt;/strong&gt; Process injection doesn't leave a new process behind, so a process list alone won't show it. You need remote thread creation events, image load anomalies, and memory regions with execute permissions that don't map back to a file on disk. If you don't have that telemetry, the honest answer is "we can't hunt for this yet," not a hunt that quietly can't succeed no matter how long you run it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sweep the fleet, not one box.&lt;/strong&gt; A hunt that checks a single host you already had a hunch about is triage wearing a hunting costume. The value of hunting is finding the host nobody flagged, which means running the query across everything, not confirming a suspicion you already walked in with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Turn what you find into a detection.&lt;/strong&gt; Whether the hunt finds something or comes back clean, the query you just wrote is worth more than one afternoon's answer. Convert it into a Sigma rule and it runs itself next month, on every host, without you remembering to do it again. That's the difference between a hunt and a permanent improvement to what your SOC catches on its own.&lt;/p&gt;

&lt;p&gt;Codelivly's &lt;a href="https://resources.codelivly.com/product/threat-hunter-hands-on-threat-hunting-blue-team-guide/" rel="noopener noreferrer"&gt;Hands-On Threat Hunting Book&lt;/a&gt; walks this exact loop across real ATT&amp;amp;CK techniques, building the Sigma rules alongside the hunts instead of treating them as a separate chapter at the end. If you want to run a hunt against a real intrusion first, the free &lt;a href="https://codelivly.com/labs/threat-hunting" rel="noopener noreferrer"&gt;Threat Hunting lab&lt;/a&gt; and &lt;a href="https://codelivly.com/labs/apt-intrusion" rel="noopener noreferrer"&gt;APT Intrusion lab&lt;/a&gt; put an actual compromised environment in front of you before you spend anything.&lt;/p&gt;

</description>
      <category>threathunting</category>
      <category>blueteam</category>
      <category>mitre</category>
      <category>infosec</category>
    </item>
    <item>
      <title>The Memory Dump Lands in Your Queue. Where Do You Actually Look First?</title>
      <dc:creator>Rocky</dc:creator>
      <pubDate>Mon, 24 Aug 2026 05:55:56 +0000</pubDate>
      <link>https://dev.to/rockyyy/the-memory-dump-lands-in-your-queue-where-do-you-actually-look-first-57n</link>
      <guid>https://dev.to/rockyyy/the-memory-dump-lands-in-your-queue-where-do-you-actually-look-first-57n</guid>
      <description>&lt;p&gt;A SOC escalates a host: unusual outbound traffic, an EDR alert that fired and then went quiet, and instead of a clean IOC someone hands you a memory image and says "figure out what ran." No process name, no known-bad hash yet, just a few gigabytes of RAM captured off a box nobody wants to reimage until they know what happened. This is the moment memory forensics actually matters, and it's also the moment a lot of people freeze, because there's no single command that says "here's the malware."&lt;/p&gt;

&lt;p&gt;There's an order that actually works, though, and it starts narrower than most people expect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Process trees before anything else&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A flat process list gives you names, but the tree is what actually matters, because malware families lie less about who spawned them than they lie about their own name. A process called svchost.exe sitting under explorer.exe as a parent instead of services.exe is a bigger tell than a slightly unusual filename. You're not looking for something with an obviously evil name, you're looking for a parent-child relationship that doesn't happen on a normal Windows box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then the injected-memory scan, for what the process list can't show you&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A process can look completely legitimate in a listing and still be hollowed out or carrying an injected DLL, because a listing only tells you a process exists, not what's actually living in its memory. Scanning for memory regions with execute permissions that don't map back to a file on disk is close to a direct signature for process injection and reflective DLL loading. This is usually where the actual payload shows up once the process tree points you at a candidate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network connections, because most of this exists to talk to something&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Almost nothing in this category sits quiet. Pulling network connections and listening ports out of the memory image catches ones a live netstat on the box would never see, because the malware already tore the socket down. Cross-reference the PID against whatever the process tree flagged, and an unexplained outbound connection to an IP that doesn't belong to anything on your asset list is usually the corroboration, not the discovery.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loaded modules, for the hijacked-not-injected cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not everything is injection. Sometimes it's a legitimate process that loaded a malicious DLL because of a search-order hijack or a planted file sitting somewhere earlier in the load path. Listing what's actually loaded per process and checking for anything loading from a user-writable directory instead of System32 is worth doing even when nothing upstream flagged it.&lt;/p&gt;

&lt;p&gt;None of this replaces a full investigation, timeline reconstruction and log correlation still matter. But this four-step pass, process tree, injected-memory scan, network connections, loaded modules, is what turns "here's a memory dump, good luck" into an actual starting point in under twenty minutes instead of an afternoon of undirected poking.&lt;/p&gt;

&lt;p&gt;Codelivly's &lt;a href="https://resources.codelivly.com/product/digital-forensics-playbook/" rel="noopener noreferrer"&gt;Digital Forensics Playbook&lt;/a&gt; walks through this exact triage workflow across a 259-page manual built around real investigations. If you want to run it hands-on first, the free &lt;a href="https://codelivly.com/labs/memory-forensics" rel="noopener noreferrer"&gt;Memory Forensics lab&lt;/a&gt; puts an actual dump in front of you before you spend anything.&lt;/p&gt;

</description>
      <category>forensics</category>
      <category>dfir</category>
      <category>blueteam</category>
      <category>infosec</category>
    </item>
    <item>
      <title>The Interview Question That Trips Up Junior Red Teamers: What Do You Check Before Mimikatz?</title>
      <dc:creator>Rocky</dc:creator>
      <pubDate>Mon, 24 Aug 2026 05:51:33 +0000</pubDate>
      <link>https://dev.to/rockyyy/the-interview-question-that-trips-up-junior-red-teamers-what-do-you-check-before-mimikatz-19g4</link>
      <guid>https://dev.to/rockyyy/the-interview-question-that-trips-up-junior-red-teamers-what-do-you-check-before-mimikatz-19g4</guid>
      <description>&lt;p&gt;An interview for a junior red team or pentest role, somewhere past the resume small talk: "You're dropped onto a Windows workstation on an internal network with valid low-privilege creds. Walk me through the first ten minutes." A lot of candidates answer with a tool. Mimikatz to dump credentials, Responder to poison LLMNR, BloodHound to map the domain. All real tools, all wrong as a first answer, because every one of them assumes you already know things you haven't checked yet: is this even a domain-joined box, where's the DC, is there a domain at all versus a flat workgroup network, and what "quiet" means on this particular network before you start being loud on it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confirm the domain before attacking it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;systeminfo&lt;/code&gt; and checking the domain environment variable tell you in seconds whether you're looking at Active Directory or a standalone workgroup, and that answer changes almost everything downstream. A DC lookup against the domain controller name, or a quick DNS query for the &lt;code&gt;_ldap._tcp&lt;/code&gt; SRV record, identifies the actual domain controller. Skipping this and assuming "internal network" means "Active Directory" is a surprisingly common beginner mistake, and it's the kind of gap an interviewer notices immediately, because it means you'd run domain-specific attacks against a target that isn't one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Passive before active, every time&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Checking the local ARP cache on the box you already have access to costs nothing and reveals what else is on the local segment without a single packet you didn't already have a legitimate reason to send. Reviewing DNS cache, checking existing SMB sessions, looking at what's already cached in memory, all of this is recon you get for free before you touch a tool that generates traffic a defender's SIEM will actually notice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anonymous and null sessions still matter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A null SMB session or unauthenticated LDAP bind against the DC, when it's still open, hands over domain user lists, password policy, and group membership without a single authentication attempt logged against a real account. It's less common on a hardened 2026 domain than it was five years ago, but checking costs nothing, and it's the difference between enumerating for free and enumerating in a way that shows up on someone's dashboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Only then does Responder or Mimikatz make sense&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Poisoning LLMNR/NBT-NS on a network you haven't mapped is loud and can catch traffic that has nothing to do with your actual objective, or worse, trip an alert before you've learned anything useful about the environment. Dumping credentials from a box before confirming what that box actually has access to burns your one shot at looking quiet, for information you might not even need yet. Both tools are legitimate and both belong in the workflow, just after the ten minutes of unglamorous enumeration, not instead of it.&lt;/p&gt;

&lt;p&gt;The honest interview answer isn't a tool name, it's a sequence: confirm the domain, do the recon that costs nothing, check what's open before you touch what makes noise. Codelivly's &lt;a href="https://resources.codelivly.com/product/red-team-operator-l1/" rel="noopener noreferrer"&gt;Red Team Book for Beginners&lt;/a&gt; builds this exact recon-before-action discipline into its labs, alongside privilege escalation and AD fundamentals. The free &lt;a href="https://codelivly.com/learning-paths/recon-enumeration-tools" rel="noopener noreferrer"&gt;Recon &amp;amp; Enumeration Tools learning path&lt;/a&gt; and &lt;a href="https://codelivly.com/rooms/active-directory-fundamentals" rel="noopener noreferrer"&gt;Active Directory Fundamentals room&lt;/a&gt; are a good place to drill the enumeration half before the exam or the interview.&lt;/p&gt;

</description>
      <category>redteam</category>
      <category>activedirectory</category>
      <category>pentesting</category>
      <category>infosec</category>
    </item>
    <item>
      <title>You Have a Shell as www-data. Now What?</title>
      <dc:creator>Rocky</dc:creator>
      <pubDate>Sun, 23 Aug 2026 18:19:56 +0000</pubDate>
      <link>https://dev.to/rockyyy/you-have-a-shell-as-www-data-now-what-1ef7</link>
      <guid>https://dev.to/rockyyy/you-have-a-shell-as-www-data-now-what-1ef7</guid>
      <description>&lt;p&gt;This is a scenario that comes up in interviews and in actual assessments often enough that it's worth having a real process for, instead of improvising it every time: you've landed a low-privilege shell, usually as &lt;code&gt;www-data&lt;/code&gt; or a similarly restricted service account, and you need root. &lt;code&gt;sudo -l&lt;/code&gt; comes back empty or asks for a password you don't have. What now?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start with SUID, because it's the cheapest check&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;find / -perm -4000 -type f 2&amp;gt;/dev/null&lt;/code&gt; lists every binary with the setuid bit set, meaning it runs as its owner (often root) regardless of who executes it. This takes seconds and costs nothing. Most boxes have a long, boring list of expected entries: &lt;code&gt;passwd&lt;/code&gt;, &lt;code&gt;sudo&lt;/code&gt;, &lt;code&gt;su&lt;/code&gt;, &lt;code&gt;mount&lt;/code&gt;. What you're looking for is anything unexpected in that list, or anything expected that shouldn't have SUID at that path.&lt;/p&gt;

&lt;p&gt;Once you have a candidate binary, check it against GTFOBins before trying to reason out an exploit yourself. GTFOBins catalogs the SUID abuse, sudo abuse, and file-read/write primitives for a huge list of standard Unix binaries. &lt;code&gt;find&lt;/code&gt;, &lt;code&gt;vim&lt;/code&gt;, &lt;code&gt;less&lt;/code&gt;, &lt;code&gt;cp&lt;/code&gt;, &lt;code&gt;tar&lt;/code&gt; and &lt;code&gt;python&lt;/code&gt; all have documented privilege escalation primitives when they carry SUID or an unrestricted sudo entry. Checking a name against that list before hand-deriving an exploit will save you real time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If sudo -l gave you anything, don't skip it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An empty &lt;code&gt;sudo -l&lt;/code&gt; is common, but a non-empty one is often solved territory. Any line that allows running a binary as root, even with a restricted argument, is worth cross-referencing against GTFOBins the same way. &lt;code&gt;(root) NOPASSWD: /usr/bin/find&lt;/code&gt; is a fully solved escalation, not a partial one. The mistake here is assuming a restricted sudo entry with one allowed binary is safe because it's "just one command" — several single commands are enough on their own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Capabilities are the modern equivalent of SUID&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;getcap -r / 2&amp;gt;/dev/null&lt;/code&gt; in 2026 finds what SUID enumeration used to catch alone. Linux capabilities let a binary hold a specific root-equivalent permission (&lt;code&gt;cap_setuid&lt;/code&gt;, &lt;code&gt;cap_dac_read_search&lt;/code&gt;) without the blunt all-or-nothing SUID bit, and a lot of hardening guides that tell you to "remove unnecessary SUID bits" don't mention checking capabilities at all, so this list is frequently longer than the SUID one on a box someone thought they'd locked down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cron jobs and writable service files&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cat /etc/crontab&lt;/code&gt;, then check anything it calls for a script or binary path you can write to. A cron job that runs as root but executes a script in a world-writable directory, or a systemd service file you have write access to that runs as root, both hand you the same outcome: write your payload where the privileged process will read it, wait for the next run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PATH hijacking, when a script calls a binary by name, not by full path&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a root-run script or cron job calls &lt;code&gt;mysql&lt;/code&gt; or &lt;code&gt;python&lt;/code&gt; without a full path, and your current directory or a writable directory is earlier in that process's &lt;code&gt;PATH&lt;/code&gt; than the real binary, you can plant your own binary with that name and get it executed as root. This is a narrower case but worth checking whenever you've already found something that runs as root without obviously being exploitable another way.&lt;/p&gt;

&lt;p&gt;The honest version of this: none of these steps are exotic, and that's the point. The overwhelming majority of real privilege escalation on Linux boxes is one of the five things above, checked in order, not a novel kernel exploit. Codelivly's &lt;a href="https://resources.codelivly.com/product/rootcraft-the-ultimate-linux-privilege-escalation-playbook-red-blue-edition/" rel="noopener noreferrer"&gt;Linux Privilege Escalation Playbook&lt;/a&gt; covers this enumeration workflow through container escape and hardening across 12 labs. The free &lt;a href="https://codelivly.com/learning-paths/privilege-escalation" rel="noopener noreferrer"&gt;Privilege Escalation learning path&lt;/a&gt; and the &lt;a href="https://codelivly.com/ctf/challenges/suid-treasure-hunt" rel="noopener noreferrer"&gt;SUID Treasure Hunt CTF&lt;/a&gt; are a good place to practice the SUID-enumeration step specifically before going deeper.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>linux</category>
      <category>pentesting</category>
      <category>infosec</category>
    </item>
    <item>
      <title>Your SQL Injection Test Isn't Done Until You've Ruled Out Blind</title>
      <dc:creator>Rocky</dc:creator>
      <pubDate>Sun, 23 Aug 2026 12:46:14 +0000</pubDate>
      <link>https://dev.to/rockyyy/your-sql-injection-test-isnt-done-until-youve-ruled-out-blind-59eg</link>
      <guid>https://dev.to/rockyyy/your-sql-injection-test-isnt-done-until-youve-ruled-out-blind-59eg</guid>
      <description>&lt;p&gt;You throw a single quote into a login field. The page reloads exactly the same as before: no stack trace, no ugly database error, no visible change at all. It's tempting to write "not injectable" in your notes and move on to the next parameter. That conclusion is wrong more often than people expect, because a visible error is only one class of SQL injection, and the two kinds that don't announce themselves, boolean-based blind and time-based blind, are exactly the ones a five-second test misses.&lt;/p&gt;

&lt;p&gt;Here's the methodology that actually rules them out instead of assuming them away.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start by testing a true/false pair, not a single payload&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A single &lt;code&gt;'&lt;/code&gt; tells you almost nothing. Send two requests instead: one where the injected condition is true (&lt;code&gt;' OR '1'='1&lt;/code&gt;) and one where it's false (&lt;code&gt;' OR '1'='2&lt;/code&gt;). If the app is vulnerable and the difference isn't a loud error, it will usually still be &lt;em&gt;some&lt;/em&gt; difference: a longer response, a different redirect, a login that succeeds versus one that doesn't, a slightly different word count in the page. That difference is your oracle. Without it, "no error" and "not vulnerable" are not the same statement, and treating them as the same is the actual mistake.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Boolean-based blind: read the page, not the error log&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once you have a working true/false oracle, you can extract data one bit at a time. Ask the database conditional questions through the query itself: is the first character of the admin password's hash greater than 'm'? Is the length of the current database name equal to 6? Each answer shows up as the same visible difference you found in the true/false test. It's slow, but it's completely mechanical, and it's the technique that gets dismissed as "well the page didn't error" more than any other.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time-based blind: when there's no visible difference at all&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some apps genuinely look identical no matter what you send. That's when you stop asking the database to show you something and start asking it to take its time: &lt;code&gt;AND IF(1=1, SLEEP(5), 0)&lt;/code&gt;. A true condition costs you five real seconds of response time; a false one comes back immediately. No content difference required, because the timing itself is the signal.&lt;/p&gt;

&lt;p&gt;The catch is confirming it's real and not noise. Run the false-condition version a few times as a baseline first, use a delay long enough that network jitter can't explain it (5 seconds, not 1), and always test both branches, true and false, before you trust the result. A single slow response proves nothing on its own; a consistent, reproducible gap between the two branches does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where SQLMap actually fits&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SQLMap isn't magic and it isn't cheating, it's automating exactly the oracle-testing loop above across every injection point and DBMS-specific payload variant, faster and more thoroughly than doing it by hand. That's also why understanding the manual methodology matters even when you plan to reach for it: its &lt;code&gt;--technique=B&lt;/code&gt; and &lt;code&gt;--technique=T&lt;/code&gt; flags map directly to boolean-based and time-based blind, rate limiting or a WAF can make it report "not injectable" on a target that actually is, and knowing the underlying oracle test is what lets you catch that and re-verify by hand instead of trusting a false negative.&lt;/p&gt;

&lt;p&gt;The gap between "no visible error" and "confirmed blind injection with a working extraction path" is exactly what Codelivly's &lt;a href="https://resources.codelivly.com/product/sql-injection-notes-professional-guide-by-codelivly/" rel="noopener noreferrer"&gt;SQL Injection Notes&lt;/a&gt; walks through payload by payload, boolean and time-based both, alongside the payloads that actually get past filtering. If you want to drill the oracle-building step by hand first, the &lt;a href="https://codelivly.com/labs/sqli-login-bypass" rel="noopener noreferrer"&gt;SQLi login bypass lab&lt;/a&gt; and the &lt;a href="https://codelivly.com/ctf/challenges/nimbuspay-sqli" rel="noopener noreferrer"&gt;NimbusPay SQLi CTF challenge&lt;/a&gt; are free and built around this exact test.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>sqlinjection</category>
      <category>appsec</category>
      <category>infosec</category>
    </item>
    <item>
      <title>The Clean Scanner Report Is Not the Same As a Clean App</title>
      <dc:creator>Rocky</dc:creator>
      <pubDate>Sun, 23 Aug 2026 08:25:25 +0000</pubDate>
      <link>https://dev.to/rockyyy/the-clean-scanner-report-is-not-the-same-as-a-clean-app-47il</link>
      <guid>https://dev.to/rockyyy/the-clean-scanner-report-is-not-the-same-as-a-clean-app-47il</guid>
      <description>&lt;p&gt;A pentester points Burp's automated scanner at a web app, lets it crawl and actively scan overnight, and wakes up to a report with a couple of low-severity missing-header findings and nothing else. "No critical findings" goes in the summary. A month later, someone else spends twenty minutes on the same app by hand and finds that any logged-in user can cancel any other user's order just by changing an ID in the request, broken access control, OWASP's own number one category. The scanner didn't catch it because it structurally can't: finding that bug requires two test accounts and knowing that order 4521 belongs to someone else, not a payload you can throw at a single endpoint.&lt;/p&gt;

&lt;p&gt;That gap is the actual lesson, not the specific bug. An automated scan is very good at the OWASP classes that reduce to "does this input produce a recognizable bad response": reflected errors, obvious injection, known-bad headers. It is close to useless at the classes that require understanding what the application's data model means: who owns what, what order operations are supposed to happen in, what a normal user is and isn't allowed to touch. Those are exactly the categories that show up in real breach reports and real bug bounty payouts, and they're the ones a "the scan came back clean" sign-off quietly skips.&lt;/p&gt;

&lt;p&gt;Here's how to actually work OWASP Top 10 with Burp instead of just running it against a target and calling that testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Burp to map the surface, not to scan it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Proxy everything through Burp first and build out the full site map: every endpoint, every parameter, every place an ID, a role, or a state value shows up. This step is manual reconnaissance, not automation, and it's what tells you where the interesting attack surface actually is before you touch a single payload.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test access control with two accounts, by hand, on every object endpoint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For every endpoint that takes an object identifier, register a second low-privilege account and replay the same request with the other account's session in Repeater. This is the single highest-yield manual step in the entire OWASP list, because it's the one category the automated scanner cannot approximate at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fuzz injection points yourself instead of trusting the active scan alone&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use Intruder or Repeater with your own payload list for SQL injection and command injection candidates rather than relying only on Burp's built-in active scan. The active scanner is tuned for speed across a whole site; a focused manual pass on the parameters that actually look interesting catches variants it's tuned to skip.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check XSS in the actual rendering context, not just the reflection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A payload reflecting in the response body doesn't tell you whether it executes. Confirm in the browser, and check stored XSS specifically: a comment field, a profile name, anything that gets rendered back to a different user later, since that's the sink an automated crawl often never revisits in the right context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treat the scanner as an assistant, not the test&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let it handle the mechanical, high-volume checks and spend your actual attention on the categories it can't reach: authorization logic, multi-step workflows, and anything where the "vulnerability" is really just a check that should exist and doesn't.&lt;/p&gt;

&lt;p&gt;This is the difference between a scan and an assessment, and it's exactly what Codelivly's &lt;a href="https://resources.codelivly.com/product/web-application-hacking-level-1/" rel="noopener noreferrer"&gt;Web Application Hacking Book for Beginners&lt;/a&gt; walks through: each OWASP Top 10 class worked manually with Burp Suite, not just described. The free &lt;a href="https://codelivly.com/labs/broken-access-control" rel="noopener noreferrer"&gt;broken access control&lt;/a&gt;, &lt;a href="https://codelivly.com/labs/reflected-xss" rel="noopener noreferrer"&gt;reflected XSS&lt;/a&gt;, &lt;a href="https://codelivly.com/labs/stored-xss" rel="noopener noreferrer"&gt;stored XSS&lt;/a&gt;, and &lt;a href="https://codelivly.com/labs/command-injection" rel="noopener noreferrer"&gt;command injection&lt;/a&gt; labs are the same categories to practice hands-on first.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>appsec</category>
      <category>burpsuite</category>
      <category>infosec</category>
    </item>
    <item>
      <title>Getting a Meterpreter Session Is Not the Deliverable</title>
      <dc:creator>Rocky</dc:creator>
      <pubDate>Sun, 23 Aug 2026 07:39:23 +0000</pubDate>
      <link>https://dev.to/rockyyy/getting-a-meterpreter-session-is-not-the-deliverable-2ec0</link>
      <guid>https://dev.to/rockyyy/getting-a-meterpreter-session-is-not-the-deliverable-2ec0</guid>
      <description>&lt;p&gt;The exploit lands. &lt;code&gt;msfconsole&lt;/code&gt; prints the line everyone wants to see, a Meterpreter session opens, and there's that small rush of "it worked." On a junior pentester's first few engagements, this is where the momentum quietly stops. The session gets a quick &lt;code&gt;sysinfo&lt;/code&gt;, a screenshot for the report, and the finding gets written up as "remote code execution achieved." Box checked, move to the next host.&lt;/p&gt;

&lt;p&gt;That's the exact point where the actual value of the assessment hasn't happened yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A shell answers one question. The client is paying for the next three.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Getting execution proves a vulnerability is exploitable. It does not prove what an attacker with that access could actually do to the client's environment, and "what could an attacker actually do" is the question a pentest report exists to answer. A finding that stops at "we got a shell" tells the client less than they're paying for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the session should actually get used for&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Confirm what you're really running as. &lt;code&gt;getuid&lt;/code&gt; and &lt;code&gt;sysinfo&lt;/code&gt; tell you whether this is a low-privilege service account or something with real reach, and that changes the severity of the finding more than the initial exploit does.&lt;/p&gt;

&lt;p&gt;Check whether the box is a dead end or a stepping stone. &lt;code&gt;route add&lt;/code&gt; through the session and a &lt;code&gt;portfwd&lt;/code&gt; rule can reach an internal-only segment that was never reachable from outside, which is often the actual headline finding: not "we got a shell," but "this one exposed host gave us a path to the internal network."&lt;/p&gt;

&lt;p&gt;Document it in a way the client's blue team can reproduce and verify, not a transcript of ad hoc console commands typed in the moment. A &lt;code&gt;.rc&lt;/code&gt; resource script that replays the exact sequence, and a payload built with &lt;code&gt;msfvenom&lt;/code&gt; rather than hand-assembled each time, turns "trust me, I did this" into something the client can re-run and confirm themselves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this is the actual skill gap&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;None of this is exotic. It's the difference between treating Metasploit as "the tool that gets me a shell" and treating it as the automation layer for everything that has to happen after the shell, in a way that produces evidence instead of a war story. That post-exploitation and automation workflow, pivoting, resource scripts, msfvenom for repeatable payloads, is exactly what Codelivly's &lt;a href="https://resources.codelivly.com/product/metasploit-mastery-the-ultimate-command-automation-handbook/" rel="noopener noreferrer"&gt;Metasploit Post Exploitation Handbook&lt;/a&gt; covers. If you want the reverse-shell and payload fundamentals first, the free &lt;a href="https://codelivly.com/learning-paths/exploitation-fundamentals" rel="noopener noreferrer"&gt;exploitation fundamentals path&lt;/a&gt; is a solid place to start before automating any of it.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>metasploit</category>
      <category>pentesting</category>
      <category>redteam</category>
    </item>
    <item>
      <title>Porting a Detection Rule to a New SIEM Isn't a Copy-Paste Job</title>
      <dc:creator>Rocky</dc:creator>
      <pubDate>Sat, 22 Aug 2026 20:46:40 +0000</pubDate>
      <link>https://dev.to/rockyyy/porting-a-detection-rule-to-a-new-siem-isnt-a-copy-paste-job-bpf</link>
      <guid>https://dev.to/rockyyy/porting-a-detection-rule-to-a-new-siem-isnt-a-copy-paste-job-bpf</guid>
      <description>&lt;p&gt;A detection engineer gets a routine-sounding ticket: the security team is standing up a second SIEM during a migration, and the rule that catches a suspicious child process spawned from a script host, the one that's caught two real incidents this year, needs to exist in both places until the cutover finishes. The original is written in Splunk SPL. The new platform speaks Sentinel KQL. The ticket says "port it over."&lt;/p&gt;

&lt;p&gt;The naive move is reading the SPL line by line and writing what looks like the same logic in KQL. It compiles, it runs, it even fires on the same test case someone hand-checks. Then a month later a real event that would have tripped the Splunk rule doesn't trip its Sentinel twin, and nobody notices for weeks because the rule looks done.&lt;/p&gt;

&lt;p&gt;This is the part that doesn't show up in a demo: the same detection logic behaves differently across SIEMs in ways that aren't visible until you go looking for them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why "the same rule" quietly isn't&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A few places translation breaks silently, not loudly:&lt;/p&gt;

&lt;p&gt;Field names never map one to one. &lt;code&gt;Image&lt;/code&gt; in Sysmon-derived data might be &lt;code&gt;process.executable&lt;/code&gt; somewhere else, and a rename that's off by one field means the condition never matches anything, not that it matches wrong things. That failure mode is worse: a rule that errors gets noticed, a rule that just never fires doesn't.&lt;/p&gt;

&lt;p&gt;Time window and aggregation semantics differ. "More than 5 failed logons" means something different depending on whether the platform's default bucket is a rolling window or a fixed one, and whether the count resets on a successful login. Two engines can both claim "same threshold" and alert at genuinely different rates.&lt;/p&gt;

&lt;p&gt;Case sensitivity and wildcard behavior aren't universal. A string match that's case-insensitive by default in one query language and case-sensitive in another will silently miss &lt;code&gt;powershell.exe&lt;/code&gt; vs &lt;code&gt;Powershell.exe&lt;/code&gt; depending on which system logged it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where Sigma actually helps, and where it doesn't&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the exact problem Sigma was built for: a generic, backend-agnostic detection format that gets converted into SPL, KQL, Elastic EQL and others through a shared translation layer instead of everyone hand-porting rules and drifting apart. Writing the detection logic once in Sigma and generating both backends from the same source cuts out a whole category of copy-paste drift.&lt;/p&gt;

&lt;p&gt;What Sigma doesn't do for you is verify the translation actually behaves the same on your data. The generic-to-specific conversion still runs into the field-mapping and semantics gaps above, because the converter doesn't know your schema quirks or your log source's exact field names. The rule that matters is: never trust a translated or ported detection until you've run it against a known-true-positive sample and confirmed it actually fires, in every backend it's supposed to run in, not just the one you tested by hand.&lt;/p&gt;

&lt;p&gt;That discipline, writing one rule and correctly proving it holds across SPL, KQL and EQL instead of assuming a port is a port, is what Codelivly's &lt;a href="https://resources.codelivly.com/product/soc-analyst-level-3/" rel="noopener noreferrer"&gt;Detection Engineering Book&lt;/a&gt; walks through end to end. If you want to practice the translation-and-verification loop hands-on first, the free &lt;a href="https://codelivly.com/labs/detection-engineering" rel="noopener noreferrer"&gt;detection engineering lab&lt;/a&gt; and &lt;a href="https://codelivly.com/labs/wazuh-rule-tuning" rel="noopener noreferrer"&gt;Wazuh rule tuning lab&lt;/a&gt; are built around exactly this.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>siem</category>
      <category>detectionengineering</category>
      <category>soc</category>
    </item>
    <item>
      <title>How to Actually Find IDOR and BOLA Bugs in an API</title>
      <dc:creator>Rocky</dc:creator>
      <pubDate>Sat, 22 Aug 2026 13:29:10 +0000</pubDate>
      <link>https://dev.to/rockyyy/how-to-actually-find-idor-and-bola-bugs-in-an-api-4db1</link>
      <guid>https://dev.to/rockyyy/how-to-actually-find-idor-and-bola-bugs-in-an-api-4db1</guid>
      <description>&lt;p&gt;Broken Object Level Authorization is the number one issue on the OWASP API Security Top 10, and it's also the bug most people test for wrong. They send one request, see their own data come back correctly, and move on. BOLA doesn't show up when you request your own object. It shows up when you request someone else's.&lt;/p&gt;

&lt;p&gt;Here's the methodology that actually surfaces it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Map every endpoint that takes an identifier&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before touching anything, walk the API and list every route that includes an object ID: &lt;code&gt;/api/orders/1042&lt;/code&gt;, &lt;code&gt;/api/users/318/invoices&lt;/code&gt;, &lt;code&gt;/api/messages/9981&lt;/code&gt;. Anything with a numeric ID, a UUID, or a slug in the path or body is a candidate. Don't skip the write endpoints (PUT, PATCH, DELETE) to focus only on GET — a BOLA on a PATCH that lets you edit someone else's order is a worse finding than one that just lets you read it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get two accounts, not one&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You cannot test authorization with a single account, because a single account can only prove authentication works. Register two low-privilege users, A and B. Log in as A, capture the ID of an object A owns, then replay that exact request with B's session token or cookie instead. If B gets A's data back, that's BOLA. If B can modify or delete it, that's worse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UUIDs are not a fix&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A lot of teams switch sequential integer IDs to UUIDs and consider the object-reference problem solved. It isn't. A UUID is unguessable, but that only matters if the ID is never exposed anywhere else. In practice IDs leak constantly: in another API response, in an invite link, in a webhook payload, in a support ticket URL. If the authorization check on the endpoint is still "does an object with this ID exist" instead of "does an object with this ID belong to the requesting user," the UUID just raises the cost of finding the ID, it doesn't fix the missing check.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test both directions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Horizontal BOLA is user A reaching user B's data at the same privilege level. Vertical is a regular user reaching an admin-only object or action. Test both, and test them at every parameter that references an object, including ones buried in the body or in query strings rather than the path, since those get missed by anyone only diffing the URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Watch for indirect BOLA through relationships&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The subtler version: endpoint A properly checks ownership, but endpoint B, which returns a nested object (a comment on an order, an attachment on a ticket), doesn't re-check ownership of the parent. You authenticated for the comment, not for the order it belongs to, and the API assumed that was enough. This is the class of bug that survives a first authorization pass because every individual endpoint looks correct in isolation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read the response, not just the status code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A 403 or 401 is the easy signal. The bug that gets missed is the 200 that returns a slightly different, sanitized version of someone else's object, a partial BOLA where fields you shouldn't see (an email, an internal note) are present but the object itself claims to be "not found" everywhere else. Diff full response bodies between accounts, not just status codes.&lt;/p&gt;

&lt;p&gt;This is the exact class of bug the OWASP API Top 10 puts first for a reason: it doesn't require finding an exploit chain, it requires noticing that a check that should exist doesn't. Codelivly's &lt;a href="https://resources.codelivly.com/product/hacking-your-first-apis/" rel="noopener noreferrer"&gt;API Hacking Book for Beginners&lt;/a&gt; walks through this methodology end to end against real API attack surfaces, alongside JWT and SSRF abuse. If you want to drill it hands-on first, the &lt;a href="https://codelivly.com/labs/idor" rel="noopener noreferrer"&gt;IDOR lab&lt;/a&gt; and the &lt;a href="https://codelivly.com/ctf/challenges/helphub-idor" rel="noopener noreferrer"&gt;HelpHub IDOR CTF challenge&lt;/a&gt; are free and built around exactly this two-account testing approach.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>api</category>
      <category>appsec</category>
      <category>infosec</category>
    </item>
  </channel>
</rss>
