all articles / 2026-10-28

8. Web Security Monitoring

Web Application Security Fundamentals

Core idea: The web became powerful by putting everything in the browser. That same reach makes web apps the most exposed front door into an organisation, and often stage one of a bigger attack.


1. How We Got Here: Desktop → Web

EraWhat dominatedWhy
1990sDesktop appsSlow, unreliable connectivity
2000sDynamic web apps (email, social, banking)Web tech matured
2010sCloud + SaaS (Software as a Service)Massive cloud adoption
TodayAlmost everything runs in a browser

The trade-off in one line: every benefit of the web is also an attacker benefit.

Benefit to usersMatching risk
Accessible from anywhereAttackable from anywhere
Faster updatesFaster-moving threat landscape
Better compatibilityLarger shared attack surface
Low resource use on the clientData and logic concentrated on the server

2. Who Carries the Risk

Web App OwnerWeb App User
App is online and must be defended 24/7Your data sits on someone else's server, possibly insecurely
Anyone, anywhere, can reach it at any timeA compromised browser exposes all your logged-in accounts
Hard to keep up with new threatsA breach can mean identity theft or financial loss
Legally and ethically responsible for user dataLeaked privacy can't be taken back

Why attackers love web apps: always on, publicly exposed, and wired directly to back-end databases and infrastructure → high impact for low effort.


3. Real-World Breaches (know these cold)

BreachYearRoot causeImpact
Equifax2017Unpatched Apache Struts vulnerability (CVE-2017-5638) in a web app~150M Americans' sensitive data; attackers reached internal databases
Capital One2019Misconfigured WAF (abused via SSRF) gave access to cloud infrastructure100M+ customers' personal & financial data

Lessons:

  • Equifax = a patching failure. The fix existed months before the breach.
  • Capital One = a configuration failure. The security tool itself became the entry point.
  • A defence is only as good as its maintenance and setup.

4. The Request–Response Cycle

text
Browser ──request──▶ Web Server ──verifies access──▶ processes ──response──▶ Browser
  • Request: browser asks for something (e.g. https://website.thm/login).
  • Response: a webpage, image, or data (search results, account info).
  • This cycle is the foundation of the web, so it's also what attackers abuse.

Three ways attackers abuse the cycle:

  1. Overwhelm the server with requests → denial of service
  2. Bypass access controls → reach data they shouldn't
  3. Trick the server into running harmful commands → injection / code execution

5. The Three Components of a Web Service

Every web service (e.g. tryhackme.com) needs all three:

ComponentWhat it isExample
ApplicationCode, images, styles, icons; defines look and behaviourWeb app written in PHP
Web ServerHosts the app; listens for requests and returns responsesApache
Host MachineOperating system running the server and the appLinux VM / Windows

Flow: Browser → Internet → Web Server → Application, with the server and app both living on the Host Machine.

Think of it as layers: the app sits on the server, which sits on the host. Compromise a lower layer and everything above it falls too.

Common Web Servers

ServerKnown forTypical users
ApacheVery popular for simple sites and blogs, especially WordPressSmall/medium sites
NginxHigh-performance industry standardNetflix, Airbnb, GitHub
IIS (Internet Information Services)Microsoft's web serverEnterprise / Windows shops

Web servers sit in front of everything and handle all incoming traffic, which makes them a prime target.


6. Defences, Mapped to Each Component

Two kinds of security measures:

  • Visibility: see what's happening (e.g. logging)
  • Mitigation: actively stop or limit an attack (e.g. WAF)

Protecting the Application

ControlWhat it means
Secure codingAvoid insecure functions, handle errors properly, strip sensitive info from output
Input validation & sanitisationNever trust user input; stops injection attacks
Access controlRestrict actions based on user role

Protecting the Web Server

ControlWhat it means
LoggingRecord every request via access logs
WAFFilter and block malicious traffic by rules
CDNHide the server from direct exposure; often bundles a WAF

Protecting the Host Machine

ControlWhat it means
Least privilegeRun services as low-privilege users
System hardeningDisable unneeded services, close unused ports
AntivirusEndpoint protection against known malware

Applies to All Three

  • Strong authentication: lock down code repos, admin panels, and host access.
  • Patch management: keep dependencies, server software, and OS up to date. (Equifax is the cautionary tale.)

7. Logging (Access Logs)

Web servers can log every request. Each entry typically captures:

FieldWhy it matters
Client IP addressWho made the request
TimestampWhen; builds the attack timeline
Requested page/dataWhat they went after
Response statusDid it succeed? (200 vs 403 vs 500)
User agentWhat client/tool they used (browser vs sqlmap)

Purpose: detect malicious activity and trace attacker behaviour during investigations. Logging doesn't stop attacks; it lets you see and reconstruct them.


8. Content Delivery Network (CDN)

What: a network of edge servers around the world that cache and serve content from close to the user. The origin server (your real server) feeds them.

Primary purpose: speed (lower latency). Security bonus: acts as a buffer between users and the origin.

Security benefitHow
IP maskingHides the origin server's IP, so it's harder to target
DDoS protectionHuge capacity absorbs floods of traffic
Enforced HTTPSMost CDNs enforce TLS encryption by default
Integrated WAFCloudflare, Amazon CloudFront, Azure Front Door all bundle WAFs

⚠️ Caveat: IP masking only works if the origin IP never leaks (old DNS records, email headers, subdomains not behind the CDN). If an attacker finds it, they can bypass the CDN entirely.


9. Web Application Firewall (WAF)

What: inspects incoming HTTP traffic and blocks or logs harmful requests based on rules.

Analogy: a bouncer at a club. Every request is checked at the door; anyone who doesn't meet the standard is turned away.

Types of WAF

TypeWhere it sitsStrengths
Cloud-based (reverse proxy)In front of the web serverEasy to deploy, scales well
Host-basedSoftware on the web server itselfFine-grained control per application
Network-basedPhysical/virtual appliance at the network perimeterSuits enterprise environments

Detection Methods

MethodHow it worksExample it catches
Signature-basedMatches known attack patterns/payloadsUser-Agent sqlmap/1.8.1
Heuristic-basedJudges context and behaviour of the requestsearch?q=%3Cscript%20(1) (URL-encoded <script)
Anomaly / behaviouralFlags deviations from normal trafficOne IP spamming login attempts (brute force)
Location & IP reputationUses geolocation + threat intelRequest from outside your normal business region
  • Not an exhaustive list; owners can write custom rules.
  • Signatures catch the known; heuristics and anomaly detection target the unknown or disguised.
  • ⚠️ A WAF is a safety net, not a fix for insecure code. Attackers routinely craft payloads to evade rules, and a misconfigured WAF can itself be the hole (Capital One).

10. Antivirus (AV)

Common misconception: AV is blanket protection. Reality: it protects endpoints (desktops, laptops, servers) from known malicious files and programs.

  • Mostly signature-based: compares files against a database of known malware.
  • Web attacks usually hit the application layer, not the host, so AV is not your main web defence.
  • Where it helps in web security: catching malicious file uploads that land on the host:
    • Web shells (scripts giving attackers remote control via the browser)
    • Post-exploitation tools
    • Other malware
  • Weakness: new or obfuscated malware without a signature can slip past.

11. The Big Picture: Defence in Depth

No single control is enough. Each one covers a different failure:

If this fails……this still helps
Insecure code shipsWAF blocks common exploit payloads
WAF is bypassedInput validation and access control in the app
App is exploited, shell uploadedAV flags the web shell; least privilege limits damage
Something gets through anywayLogs let you detect it and trace what happened
Known vuln existsPatching removes it before anyone uses it

One-sentence takeaway: secure each layer (app, server, host), patch everything, log everything, and assume any single control will eventually fail.


Client-Side vs Server-Side Attacks, Detection & WAF Rules

Core idea: Where an attack runs decides whether you can see it.

  • Client-side attacks run in the victim's browser, which is mostly invisible to the SOC.
  • Server-side attacks hit your systems, so they leave evidence in logs and network traffic.

1. Client-Side vs Server-Side at a Glance

Client-SideServer-Side
TargetThe user: their behaviour, browser, deviceThe system: web server, app code, backend/database
Where it executesInside the user's browserOn the server
GoalHijack accounts, steal cookies/sessions, steal data from the deviceGain access, steal stored data, damage services
Weakness abusedBrowser bugs, tricking users into unsafe actionsFlawed logic, misconfigurations, poor input handling
SOC visibilityLow to noneHigh (logs + packets)
ExamplesXSS, CSRF, ClickjackingBrute force, SQLi, Command Injection

Why client-side risk is growing: sites keep adding third-party plugins and scripts. Each one is more code running in the user's browser, so the attack surface keeps widening.


2. Client-Side Attacks

The SOC's blind spot

  • SOC tools (server logs, packet captures) see what crosses the network to the server.
  • A client-side attack can run code, steal data, or alter the page entirely inside the browser, with no suspicious HTTP request reaching you.
  • Detection usually needs browser-side controls or endpoint monitoring (EDR on the user's machine).

The Big Three

AttackWhat happensExampleKey defence
Cross-Site Scripting (XSS)Attacker's script is injected into a trusted site and runs in visitors' browsers. Most common client-side attack.Unfiltered comment box accepts Hello <script>alert('You have been hacked');</script>; every visitor's browser runs it. Real attacks steal cookies/session data instead of popping alerts.Output encoding, input validation, Content-Security-Policy, HttpOnly cookies
Cross-Site Request Forgery (CSRF)Victim's browser is tricked into sending a request the user never intended, using their logged-in sessionMalicious page silently submits "change email" to your bank while you're logged inAnti-CSRF tokens, SameSite cookies
ClickjackingInvisible elements are layered over legitimate content, so the user clicks something other than what they seeTransparent "Delete account" button sits over a "Play video" buttonX-Frame-Options / CSP frame-ancestors (stop your site being framed)

XSS vs CSRF:

  • XSS = the attacker's code runs in your browser.
  • CSRF = the attacker's request is sent by your browser.

⚠️ Tutorial nuance: the "hidden window steals your cookies" story is simplified. The browser's same-origin policy stops a hidden cross-site frame from reading another site's cookies directly. In reality that outcome needs XSS on the target site, or clickjacking to make you perform the action yourself.


3. Server-Side Attacks

Setup: websites are full of input forms (login, search, order lookup). Mishandle input in just one and the backend database can be exposed.

Good news for defenders: every request is processed by the server, so it can be logged, and it crosses the network, so it can be captured. Server-side attacks leave a trail if you know where to look.

text
Attacker ──malicious requests──▶ [WAF] ──────────▶ [Web Server]
                                   │                    │
                         SOC sees network traffic   SOC sees server logs

The Big Three

AttackWhat happensReal caseKey defence
Brute forceRapid automated guessing of usernames/passwords from big credential listsT-Mobile, 2021: brute force led to PII of 50M+ customersRate limiting, account lockout, MFA, strong passwords
SQL Injection (SQLi)App builds SQL by string concatenation, so attacker input rewrites the query to read/change dataMOVEit, 2023: SQLi in file-transfer software hit 2,700+ orgs (US agencies, BBC, British Airways)Parameterised queries
Command InjectionUnchecked user input passed to the OS shell; attacker's commands run with the app's permissions—Never pass input to the shell; validate strictly; least privilege

Why SQLi works:

sql
-- App code:   SELECT * FROM users WHERE id = '<input>'
-- Input:      ' OR '1'='1
-- Result:     SELECT * FROM users WHERE id = '' OR '1'='1'
--             '1'='1' is always TRUE → every row returned

Parameterised queries treat input as data, never code, which kills this whole class of attack.

Why least privilege matters for command injection: injected commands inherit the app's permissions. An app running as root hands the attacker root.


4. Detecting Attacks in Access Logs

The six fields and what "suspicious" looks like

#FieldRed flag
1Client IPKnown-malicious IP, or outside expected geography
2Timestamp + requested pageOdd hours; many requests in seconds
3Status codeBursts of 404 (someone guessing paths)
4Response sizeMuch smaller or larger than normal (a big response may be a data dump)
5ReferrerDoesn't match normal site navigation
6User-AgentOutdated browsers or tool names: sqlmap, wpscan, gobuster, Hydra

No single field proves an attack. Each can be benign or malicious depending on context; it's the combination that tells the story.

Status codes worth knowing cold

CodeMeaningIn an attack
200 OKSuccessFuzzer found a real page / injection returned data
302 FoundRedirectAfter a login POST, often means login succeeded
401 UnauthorizedAuth failedFailed brute-force guess
404 Not FoundDoesn't existFuzzer guessing a path that isn't there

Worked example: one attacker, three stages (IP 10.10.10.100)

Stage 1 — Directory fuzzing (recon) · gobuster/1.9 · 05:45:26–28

  • Many GETs in ~2 seconds: /testdir, /backup, /private → 404
  • Hits: /catalog, /wordpress, /login.php → 200 ← attacker's target list

Stage 2 — Brute force · Hydra · 05:47:30

  • Repeated POST /login.php → 401, all size 4937
  • Final POST → 302, size 5036 (different) ← success
  • Then GET /account → 200 ← attacker is logged in

Stage 3 — SQL injection · sqlmap/1.7.2 · 05:48–05:49

  • GET /search?q=' OR '1'='1 → 200
  • GET /search?q=1' OR 'a'='a → 200
  • Payloads visible because they're in the GET query string

The pattern to recognise anywhere: recon → initial access → exploitation, from one IP, with tool-named User-Agents, in minutes.

Log limitations

  • Access logs show that a request happened, not what was inside it.
  • POST bodies are not logged: you see POST /login but never the username/password tried.
  • GET query strings may be logged, but some formats drop them.
  • What you get depends entirely on the server software and logging config.

5. Detecting Attacks in Network Traffic

Network traffic analysis = capturing and inspecting raw packets between client and server. It's more verbose than logs:

Logs showPacket captures add
Method, path, status, size, UAFull HTTP headers
POST bodies (submitted credentials, payloads)
Cookies
Uploaded/downloaded files
The server's response content (what the attacker actually got)

Big limit: encrypted protocols (HTTPS, SSH) hide payloads unless you have the decryption keys. This tutorial uses plain HTTP.

Wireshark essentials

  • Filter used: ip.dst == 10.10.20.200 && http.user_agent
    • ip.dst = destination IP · http.user_agent = only packets with a User-Agent
  • Follow HTTP Stream = see the full request + response of one conversation.

What packets revealed that logs couldn't

Packet 13 (brute-force success):

  • Body: log=admin&pwd=password123 → the attacker cracked the admin account with password123
  • Response: 302 Found → Location: /account
  • Server banner leaked: Apache/2.4.52 (Ubuntu) (free recon for attackers)

Stream 15 (SQLi):

  • Request: GET /search?q=' OR '1'='1 with User-Agent: sqlmap/1.7.2
  • Response 200 OK contained the whole users table (admin, Gordon Brown, Jane Lee, Bob Smith) → confirms the injection worked, not just that it was tried
  • MySQL protocol traffic can also be analysed in Wireshark to see the query and result directly

The key distinction:

  • Logs tell you an attack was attempted.
  • Packets tell you whether it succeeded and what was taken.

6. WAFs as Mitigation

So far: detection (logs, packets). WAFs are mitigation: they stop the request before it reaches the server.

  • Sits in front of the app as a gatekeeper.
  • Inspects full requests like Wireshark, but can decrypt TLS (when it terminates HTTPS, i.e. holds the site's certificate) and block before delivery.

Rule types

Rule typeWhat it doesExample
Block common attack patternsMatches known payloads/indicatorsBlock User-Agent containing sqlmap
Deny known malicious sourcesIP reputation, threat intel, geo-blockingBlock IPs from a current botnet campaign
Custom rulesTailored to your appOnly allow GET/POST to /login
Rate limitingCaps request frequencyMax 5 login attempts/min per IP (would have stopped Hydra)

Rule format

text
IF User-Agent contains "sqlmap"  THEN BLOCK
IF Client IP == 10.10.10.100     THEN BLOCK
IF User-Agent == "Hydra"         THEN BLOCK
IF Region != US or EU            THEN CHALLENGE

Modern WAFs block known bad User-Agents automatically; custom rules handle your app's specific threats without hurting normal traffic.

Three actions, not two

ActionWhen to use
ALLOWNormal traffic
BLOCKHigh-confidence malicious
CHALLENGE (e.g. CAPTCHA)Suspicious but might be a real user; proves human vs bot

CHALLENGE suits rules with a higher chance of false positives (e.g. geo rules). It matters because ~37% of global web traffic is malicious bots.

Threat intelligence built in

  • Prebuilt rule sets targeting the OWASP Top 10.
  • Auto-updating feeds of malicious IPs and User-Agents, covering APT groups and new CVEs.
  • Example: Cloudflare's curated IP lists (botnets, VPNs, anonymisers, malware sources).

⚠️ Know the weaknesses

  • User-Agent rules are trivially bypassed. The attacker sets any UA they like (sqlmap has a random-agent option). Treat UA blocking as noise reduction, not protection.
  • IP blocks are dodged by rotating IPs, proxies, or botnets.
  • Payload signatures can be evaded with encoding and obfuscation.
  • A WAF buys time; the real fix is in the code (parameterised queries, input handling) and the auth (MFA, strong passwords).

7. Mapping the Example Attack to Defences

StageDetected byStopped by WAF ruleReal fix
Fuzzing (gobuster)404 bursts, tool UA in logsRate limiting, UA blockDon't expose unneeded paths
Brute force (Hydra)Repeated POSTs, 401→302 in logs; creds in packetsRate limiting, UA block, IP blockMFA, strong passwords, lockout
SQLi (sqlmap)Payload in query string; data in response packetsSQLi signatures, UA blockParameterised queries

One-sentence takeaway: logs show that it happened, packets show what happened, WAFs try to stop it before it happens, and secure code makes it impossible.


Detecting Web Shells

Core idea: A web shell turns a web server into a remote command line that works through ordinary HTTP. To detect one, you look at the same event from several angles: web logs (how it got there and how it's used), host logs (what it actually did), the file system (where it lives), and network traffic (the payload itself). No single source is enough.


1. What a Web Shell Is

Definition: a malicious script uploaded to a web server that lets an attacker run commands remotely through the browser or simple HTTP requests.

It plays two roles in an attack:

RoleMeaning
Initial accessGets the attacker in, usually through a file upload vulnerability
PersistenceKeeps them in. Even if the original hole is patched, the shell file stays behind as a back door

Once in place, it drives the rest of the kill chain:

text
Reconnaissance → Privilege escalation → Lateral movement → Data exfiltration

Why SOC analysts care: web shells are one of the most common footholds attackers use, and everything after them in the attack depends on that foothold.


2. How Web Shells Get Deployed

The attacker needs one of these:

  1. A file upload vulnerability
  2. A misconfiguration (e.g. writable web directory, PUT method enabled)
  3. Prior access to the system (shell used for persistence)

Root cause of upload vulnerabilities: the app fails to validate the file's

  • type (is it really an image?)
  • extension (.php vs .jpg)
  • content (does it contain code?)
  • destination (does it land somewhere the server will execute it?)

Classic example: a pet-photo site meant for images accepts shell.php or mydog.aspx. The server stores it in a web-accessible folder, then executes it when requested, so the attacker has command execution.

The danger is not the upload itself; it's an uploaded file being stored where the server will run it.


3. Real-World Cases

GroupTargetWhat they did
Hafnium (Chinese state-linked APT) via ProxyLogon (2021)Microsoft Exchange serversDropped .aspx shells in \inetpub\wwwroot\aspnet_client\ and modified existing .aspx files in \FrontEnd\HttpProxy\owa\auth\. Then: command execution, recon, credential dumping, new user accounts for persistence, lateral movement, exfiltration, covering tracks
Conti ransomwareMicrosoft Exchange (similar flaw)Uploaded aspnetclient_log.aspx to the same \aspnet_client\ folder. Within minutes added a backup shell, then mapped computers, domain controllers, and domain admins

Lessons:

  • Attackers reuse known locations. If one group used a folder, check it.
  • Modifying a legitimate file is stealthier than adding a new one; you can't just look for unfamiliar names.
  • Backup shells are standard. Finding one shell doesn't mean you've found them all.
  • Speed: minutes from upload to network mapping. Detection has to be fast.

4. Anatomy of a Web Shell

Web shells don't need exploits once uploaded. They abuse legitimate language functions that run OS commands.

PHP execution functions to know: shell_exec(), exec(), system(), passthru() (also watch for eval(), assert(), base64_decode(); these often hide the payload)

A minimal PHP web shell

php
<?php
if(isset($_GET['cmd'])){          // 1. Is there a ?cmd= parameter?
    $cmd = $_GET['cmd'];          // 2. Store the attacker's command
    $output = shell_exec($cmd);   // 3. Run it on the OS
    echo "<pre>$output</pre>";    // 4. Send the result back
}
?>
<form method="GET">               <!-- 5. Simple UI -->
    <input name="cmd" type="text">          <!-- 6. Command box -->
    <input type="submit" value="Execute">
</form>

Using it: .../uploads/awebshell.php?cmd=whoami → page displays www-data (7. output)

What www-data tells you: commands run as the web server's user. The attacker's next move is usually privilege escalation, because www-data has limited rights. (This is why least privilege for services matters.)

Range of complexity: from one-liners driven through the URL to full GUIs with password protection and built-in file managers.


5. Evidence Source #1 — Web Server Logs

Web shells live on web servers, so the access logs are the natural first stop (Apache, Nginx).

Access log anatomy

text
192.168.0.1 - - [10/May/2025:13:00:00 +0000] "GET /index.html HTTP/1.1" 200 1024 "-" "Mozilla/5.0"
     │      │ │            │                          │                │    │    │       │
 Client IP  │ │        Timestamp                 Request line       Status Size Referrer User-Agent
            │ └ Authenticated user (usually "-" unless the server required login)
            └ Remote log name (legacy field, almost always "-")

Indicator 1: HTTP methods & request patterns

MethodNormal useAbuse
GETFetch a resourceRecon; talking to a shell
POSTSubmit dataUploading or talking to a shell
PUTUpload/replace a fileUploading a shell directly
DELETERemove a resourceCleanup (erasing tracks)
OPTIONSList supported methodsRecon (is PUT allowed?)
HEADLike GET, headers onlyChecking whether a file exists

Patterns:

  • Rapid repeated GETs → probing for an upload location
  • POST to an upload location after a burst of GETs → upload
  • Repeated GET/POST to the same odd file → using the shell

Worked example: full attack in the logs (IP 10.10.10.100)

Phase 1 — Hunting for an entry point (13:22:04, all in one second)

  • /upload.aspx, /uploads.php, /uploads.aspx, /uploads.asp, /uploads.jsp, /download* → 404
  • /uploads/ → 200 ← directory found
  • /upload_form.php → 200 ← form found
  • Note the attacker tries every server language (aspx, php, asp, jsp): they don't yet know what the server runs.

Phase 2 — Upload (13:23:09)

  • POST /upload_form.php → 200 ← shell uploaded

Phase 3 — Using the shell (13:23:45 → 13:25:53)

  • Repeated GET /uploads/webshell.php → 200
  • Response sizes: 192, 192, 471, 332, 3345, 563

🔑 The response sizes are the giveaway. A normal static file returns the same size every time. One file returning wildly different sizes means it's producing different output each time, i.e. running different commands. The 3345-byte response was probably a big listing (directory contents, /etc/passwd, process list).

Tell-tale signs in this sequence: same IP, same User-Agent, timestamps seconds apart, 404 storm → 200, then POST, then repeated hits on a file in an uploads folder.

Indicator 2: User-Agents & IPs

TypeExampleWhy suspicious
AlteredMozilla/4.0+(+Windows+NT+5.1) cut down to Mozilla/4.0Real browsers send long, detailed UAs
OutdatedMozilla/4.0 (compatible; MSIE 6.0)Internet Explorer 6, from 2001
Blacklisted / toolscurl/1.XX.X, wget/1.XX.XCommand-line tools, not people browsing
IPUnknown external address hitting an internal-only serverUnexpected source

⚠️ The IP rule only holds for internal apps. A public website sees outside IPs all day, so there "external" means nothing on its own; use threat-intel reputation instead.

Indicator 3: Query strings

Query string = the part of the URL after ? that assigns values to parameters: example.php?query=somequery

  • Keywords: cmd=, exec= → a command is being passed
  • Abnormally long strings
  • Encoded strings hiding the command:
    • ?query=whoami → Base64 → ?query=d2hvYW1p
    • Decode with CyberChef (handles Base64 and most other encodings/obfuscation)

Indicator 4: Missing referrer

  • Referrer = the page the user came from.
  • Shell access is usually direct (typed or scripted), so the referrer is -.
  • ⚠️ Weak on its own: privacy settings, bookmarks, and typed URLs also produce no referrer. Use it only alongside other indicators.

Putting it together: one suspicious line

text
10.10.x.x - - [10/May/2025:03:21:41 +0000] "POST /uploads/suspectfile.php?cmd=hostname HTTP/1.1" 200 1024 "-" "curl/7.81.0"
#Indicator
1Untrusted / known-malicious IP
203:21 — outside business hours
3POST with ?cmd= to a .php file in uploads
4No referrer (-)
5curl User-Agent, not a browser

Any one of these is weak. Five together is an incident.


6. Evidence Source #2 — Auditd (Host Logging)

Auditd = native Linux auditing system. You write rules defining what to record (e.g. "log any file written in /var/www/html/uploads" or "log when this program runs"), and matches go to audit.log.

Rules carry a key (a label) so you can search for them later.

bash
# Example rule (for context): watch the uploads folder for writes/attribute changes
auditctl -w /var/www/html/uploads -p wa -k web_shell

# Search for events tagged with that key
ausearch -k web_shell
time->Wed Jul 23 06:20:36 2025
"name = /uploads/webshell.php"      ← the file involved
"OGID = www-data"                   ← owned by the web server's group

Why correlate web logs with auditd

Web logs tell youAuditd tells you
A request arrived (POST to an upload form)A file was actually created/modified/executed
Which URL and IPWhich user/process did it

Key syscalls to link:

  • creat → a file was created (the upload landed)
  • execve → a program was executed (the shell ran a command)

A suspicious POST in the web log + a creat in auditd at the same second = confirmed upload. Then execve events from the web server user = confirmed command execution.

🔑 Strongest host-level signal: the web server process (apache2, nginx, php-fpm, w3wp.exe on IIS) spawning a shell or command-line tool (sh, bash, whoami, cmd.exe). Web servers serve pages; they have almost no legitimate reason to launch whoami.


7. Evidence Source #3 — SIEM

A SIEM (Security Information and Event Management) platform:

  • Centralises logs from many sources (web, auditd, network, endpoint) in one place
  • Lets you correlate across them, which is exactly what web shell detection requires
  • Supports targeted queries for web shell patterns
  • Makes searching and analysis faster than grepping individual servers

8. Evidence Source #4 — File System Analysis

The shell has to be stored somewhere. Find the file, find the shell.

Where to look

LocationNotes
/var/www/html/Apache default on most Linux distros
/usr/share/nginx/html/Nginx default on many setups
/uploads/, /images/, /admin/Common upload folders, found even with custom web roots
/tmpWorld-writable; abused if permissions are weak
\inetpub\wwwroot\IIS (Windows), as in the Exchange cases

⚠️ Blind spot: WordPress, Django and similar platforms keep page content in a database. Malicious code injected into posts, themes, or settings won't show up in file searches. Check the database too.

What looks suspicious

  • Executable extensions in places that should only hold data: .php, .jsp (also .asp, .aspx, .phtml)
  • Double extensions: image.jpg.php (looks like an image, runs as PHP)
  • Random or out-of-place names that don't match the app's naming
  • Recently modified legitimate files (the Hafnium technique)

Hunting commands

bash
# Find .php files whose status changed between two dates
find /var/www -type f -name "*.php" -newerct "2025-07-01" ! -newerct "2025-08-01"
# → /var/www/html/uploads/awebshell.php

# Find files containing eval( in WordPress content
grep -r "eval(" wp-content
# → /wp-content/uploads/awebshell2.php : eval(b64_dd($['cmd']));

Reading the find command:

  • -type f = files only
  • -name "*.php" = PHP files
  • -newerct "2025-07-01" = changed after 1 July
  • ! -newerct "2025-08-01" = not changed after 1 August
  • Together: a date window

Why -newerct (change time) rather than modification time: attackers can fake a file's modification time with touch to make it look old ("timestomping"). The change time (ctime) is set by the system and can't be set by normal tools, so it's harder to fake.

Why grep for eval(: eval runs a string as code, which is how obfuscated shells unpack themselves (often eval(base64_decode(...))). Legitimate code rarely needs it, especially in an uploads folder.


9. Evidence Source #5 — Network Traffic

Packets go beyond logs: you see the payload itself.

Indicators (logs + extra ones only packets/hosts reveal)

  • Unusual HTTP methods and request patterns
  • Suspicious User-Agents and IPs
  • Encoded payloads
  • Malicious code or commands in request bodies (invisible in access logs)
  • Unexpected protocols or ports (e.g. a reverse shell calling out)
  • Unexpected resource usage
  • Web server processes spawning command-line tools

Useful Wireshark filters

FilterUse
http.request.method == "POST"Find uploads and shell interaction (swap in any method)
http.request.uri contains ".php"Find requests to scripts, incl. suspicious/new files
http.user_agentList UAs; spot odd or outdated ones
ip.dst == 10.10.20.200 && http.user_agentCombine: traffic to one server, with UAs shown

Worked example: the upload in the packet (stream 12)

Same attack as the logs, now with the contents visible:

text
POST /upload_form.php HTTP/1.1                      ← form abused
User-Agent: Mozilla/5.0                              ← bare UA (altered/minimal)
Referer: http://10.10.20.200/
Content-Type: multipart/form-data; boundary=...      ← file upload
Content-Disposition: form-data; name="fileToUpload"; filename="webshell.php"   ← shell uploaded
Content-Type: application/x-php                      ← openly declared as PHP, and the form accepted it

<?php
if(isset($_REQUEST['cmd'])){
    echo "<pre>";
    $cmd = ($_REQUEST['cmd']);
    system($cmd);                                    ← executes the command
    echo "</pre>";
    die;
}
?>

HTTP/1.1 200 OK
Server: Apache/2.4.29 (Ubuntu)
The file webshell.php has been uploaded.             ← server confirms success

What this proves that logs couldn't:

  • The exact file name and full source code of the shell
  • That it uses system() and $_REQUEST (accepts the command via either GET or POST)
  • The server confirmed the upload
  • The form did no validation: a file declared as application/x-php was accepted on an "Upload Image" form

10. Evidence Map: Which Source Answers Which Question

QuestionWeb logsAuditdFile systemNetwork
Was the server probed?✅ 404 storm✅
Was a file uploaded?⚠️ POST seen, not content✅ creat✅ file exists✅ full file
What does the shell contain?✅✅
Is it being used?✅ repeated hits, varying sizes✅ execve✅
What commands ran?⚠️ only if in query string✅✅ (if not encrypted)
Which user/process?✅✅ owner

One-sentence takeaway: web logs show the pattern, auditd confirms the action, the file system finds the file, packets reveal the payload. Correlate them, ideally in a SIEM, and assume there's a backup shell you haven't found yet.


Denial-of-Service (DoS) Attacks on Web Applications

Core idea: DoS attacks don't steal anything; they attack availability. If real users can't log in, shop, or reach a service, the attack has succeeded, however small it was. At the application layer the cheapest attack is not the biggest flood but the most expensive request, repeated.


1. What DoS Is

Definition: overwhelming a website or app so that legitimate users can't use it.

What users experience: pages that load forever, timeouts, error pages, or endless CAPTCHA challenges (the defender's response showing through).

Success criterion: any attack, of any size, that stops the service working as intended.

Scope of this room: Layer 7 (application layer) of the OSI model, where websites and web apps live.

Network-layer DoS (L3/L4)Application-layer DoS (L7)
FloodsPackets/connections (SYN, UDP floods)HTTP requests
ExhaustsBandwidth, network gearCPU, memory, database, app threads
Volume neededHugeCan be small; each request is costly
Looks likeObvious junk trafficLegitimate-looking requests
Hard partAbsorbing the volumeTelling attackers from real users

2. Even One Request Can Be a DoS

Bicycle-parts shop example: a search form takes input, queries the database, returns results. If input isn't validated, an attacker can:

  1. Send malformed/unexpected input that makes the app hang or crash
  2. Flood the form with many requests
  3. Send one massive request the server chokes on

The vulnerability is the same as in earlier tutorials (trusting user input); the outcome is just availability instead of data theft.


3. DoS vs DDoS

DoSDDoS (Distributed)
SourceOne machine, one connectionA botnet: many compromised devices
CeilingLimited by the attacker's CPU, memory, bandwidthCombined capacity of thousands–millions of devices
Botnet members—PCs, IoT devices, even servers, infected with malware and controlled remotely
BlockingBlock one IPBlocking IPs is whack-a-mole

Bicycle shop again: handles steady daily traffic fine but wasn't built for millions of requests in minutes. The botnet swarms it; resources run out; site goes down.


4. Types of Application-Layer DoS

All can be run from one machine (DoS) or a botnet (DDoS).

AttackHow it worksWhy it hurts
SlowlorisOpens many connections and sends HTTP requests very slowly, never finishing themServer holds each connection open waiting; its connection pool fills up with almost no bandwidth used
HTTP floodHuge number of ordinary HTTP requestsRaw volume overwhelms the server
Cache bypassMakes requests the CDN can't answer from cacheEvery request hits the origin server (see §10)
Oversized queryLarge, resource-heavy requestsEach one burns lots of CPU/DB time
Login/form abuseFloods login or password-reset logicPassword hashing, DB lookups, and emails are expensive
Faulty input validation abuseInputs that trigger bad code pathsHangs, crashes, runaway processing

Slowloris vs HTTP flood, the key contrast:

  • Flood = too many requests.
  • Slowloris = too long requests. A trickle of traffic can take down a server that limits concurrent connections.

5. Why Attackers Do It

MotiveGoalExample
Financial lossCut the victim's revenueFlooding a store during holiday sales
ExtortionGet paid to stop ("ransom DDoS")Threatening a bank
HacktivismPolitical/social protestHitting government sites during elections
DistractionKeep defenders busyDDoS as cover while another attack runs
CompetitionHurt a rivalDDoS during a competitor's product launch
Denial of walletRun up the victim's cloud billRepeatedly pulling AWS S3 data, paying per request
Reputational damageDestroy customer trustGame servers crashing on launch day

Motives often combine, and the list isn't exhaustive.

⚠️ Distraction matters most to a SOC. When a DDoS hits, ask "what else is happening right now?" The flood may be cover for an intrusion.

Denial of wallet is the cloud-era twist: auto-scaling keeps you online but turns the attack into a bill.


6. Real-World Cases

YearVictimWhat happened
2015 (New Year's Eve)BBCSite offline for hours; timeouts and internal errors. New World Hacking claimed it was a "test" of its capabilities
2023MicrosoftLarge Layer 7 DDoS caused outages in Azure, OneDrive, Outlook. Anonymous Sudan claimed it, using HTTP floods and Slowloris

Lesson from Microsoft: even the biggest providers are vulnerable at Layer 7, and old techniques like Slowloris still work at scale.


7. Detection in Web Server Logs

Apache, Nginx, and IIS all log requests in a similar format, so the same indicators apply.

Indicators

IndicatorExampleMeaning
High request rate10.10.10.100 → 1000× GET /loginFlooding an expensive endpoint
Odd User-Agentscurl/7.6.88 hitting /index repeatedly; Python-urllib/3.xScripts, not browsers (attackers may also spoof old or random UAs)
Geographic anomaliesRequests from all over the worldReal users cluster in a few regions; botnets are global
Burst timestamps50 requests in 1 second → /searchHumans don't click that fast
Server errors (5xx)Spike of 503 Service UnavailableServer is maxed out (5xx range = 500–511)
Logic abuseGET /products?limit=999999One request forces a massive load

No single indicator is proof. A real DDoS shows up as layered signals: many IPs, many regions, same expensive endpoints, same (or deliberately varied) UAs. Keep a watchlist of these indicators.

Endpoints attackers target (the expensive ones)

EndpointWhy it's costly
/loginAuthentication: password checks, DB queries
/searchComplex database queries
/apiDynamic content; often critical to the whole app
/register, /signupDB writes + validation
/contact, /feedbackDB entries + email sending
/cart, /checkoutSessions, inventory checks, payment processing

Rule of thumb: static pages and images are cheap. Anything that queries a database, writes data, or sends email is a DoS target.

Worked log sample

Phase 1 — Normal traffic (10:01:02–09)

text
192.168.1.10 "GET /index.html"    200 4523 "Mozilla/5.0"
192.168.1.15 "GET /products.html" 200 6112 "Mozilla/5.0"
192.168.1.20 "GET /contact.html"  200 2987 "Mozilla/5.0"

Different IPs, different pages, a few seconds apart.

Phase 2 — Attack (from 10:01:10)

text
203.0.113.55 "GET /login.php" 200 245 "curl/7.68.0"   ×5 in the same second
...100 more lines

One IP, one expensive page, one tool UA, same second.

Phase 3 — Outage (10:01:20 onward)

text
192.168.1.30 "GET /index.html"    503 0 "Mozilla/5.0"
192.168.1.33 "GET /products.html" 503 0 "Mozilla/5.0"

🔑 Notice whose requests fail. The attacker's requests return 200; the real users get 503 with 0 bytes. The attack itself looks "successful" in the logs; the damage shows up in everyone else's entries. Look for the 503 spike, then work backwards to what started just before it.

Log limitations

  • A real attack means thousands of lines per second; raw logs become unreadable.
  • Slowloris can be nearly invisible in access logs: entries are usually written when a request finishes, and Slowloris requests never finish. Look for timeouts (408), connection counts, and error logs instead.
  • In a DDoS, per-IP counts look normal; each bot may send only a few requests.

8. Detection with a SIEM (Splunk)

SIEMs combine log sources and let you filter, sort, and chart by IP, User-Agent, or status code instead of scrolling raw files.

Query 1: requests per page over time

text
index="main" | timechart span=1min count by uri limit=5
  • timechart span=1min → count events per minute
  • count by uri → one line per page
  • limit=5 → top 5 pages, rest grouped as OTHER

Result (10 minutes, 1,025 events):

  • Normal: 1–6 requests/min across various pages
  • 2:41 AM: 1,000 requests to /login in one minute

⚠️ Read the axis. The y-axis is logarithmic (10 → 100 → 1,000 → 10,000). On that scale the spike looks only a bit taller than normal traffic. In reality it's roughly 170–1,000× higher.

Query 2: who sent it

text
index="main" | top useragent clientip
User-AgentIPCount%
curl/7.88.1203.0.113.55100097.6%
Firefox 128 (Linux)192.168.1.10141.4%
Chrome 139 (Windows)192.168.1.5111.1%

Conclusion: one IP, one command-line tool, ~98% of all traffic → a single-source DoS, not a DDoS. Blocking that IP would end it. A DDoS would show the opposite: many IPs, each with a small share.


9. Defences

Application level

Secure development / input validation

  • Librarian analogy: a librarian with rules ("titles under 50 characters") answers quickly. Without rules, one person's absurd request holds up the queue.
  • Limit input length, reject odd characters, cap values server-side (e.g. never honour limit=999999; enforce a maximum).

Challenges

TypeHow it worksTrade-off
CAPTCHAUser solves a puzzle (images, checkbox)Small step for humans, a wall for simple bots; annoys users
JavaScript challengeRuns silently in the browser to check it's a real browserInvisible to users; tools like curl can't run JS and fail. Sophisticated bots using real (headless) browsers can pass

Network & infrastructure level

CDN (Content Delivery Network)

  • Serves cached content from edge servers near users, so the origin handles only a fraction of requests.
  • Absorbs much of a DDoS on the origin's behalf.
  • Load-balances across servers and reroutes if one goes down.

Reading the Cloudflare dashboard (16 TB attack):

MetricValueMeaning
① Total bandwidth (30 days)16.07 TBSite normally sees a few hundred GB/month, so this is abnormal
② Cached bandwidth16.07 TBServed by the CDN edge
Uncached bandwidth3.75 GBWhat actually reached the origin
③ Spike4.55 TB in one day (only 1.09 GB uncached)The attack

🔑 The number that matters is uncached. Only ~0.02% of the attack traffic reached the origin server. Without the CDN, all 16 TB would have hit it.

CDN dashboards also give visibility: traffic broken down by country, volume, and source. In the example, Indonesia (~909M) and the Philippines (~249M) led traffic, which is a geographic anomaly if your customers aren't there.

WAF (Web Application Firewall)

  • Usually built into CDNs.
  • Allow / Challenge / Block, using known attack indicators and threat intel; custom rules for targeted threats.
  • Modern WAFs are strong against DoS because they know the common patterns.

Rate-limiting rule:

text
IF Path == /login.php AND Requests > 5 per Minute  →  BLOCK  (or CHALLENGE)

The offending IP is blocked for a time, or challenged to prove it's human.

⚠️ Per-IP rate limits fail against DDoS. 10,000 bots each sending 4 requests/min stay under a 5/min limit and still deliver 40,000 requests/min. Rate limiting beats single-source DoS; DDoS needs global thresholds, reputation data, and challenges.

Large-scale mitigation

Big providers absorb attacks with massive distributed networks plus filtering:

  • Google (2023): mitigated a DDoS peaking at 398 million requests per second.
  • Cloudflare: reported a record attack peaking at 11.5 Tbps, lasting only 35 seconds. (Records are broken often; treat any "largest ever" figure as already out of date.)

Lesson: attacks can be huge and very short. Mitigation has to be automatic; no human reacts in 35 seconds.


10. How Attackers Bypass Defences

TechniqueHowCounter
Cache busting/products is cached, but /products?a=abcd is "new", so the CDN forwards it to the originIgnore or normalise unknown query strings in the cache key; rate-limit uncached requests
Rotating User-AgentsEvades UA-based WAF rulesBehaviour-based detection, JS challenges
Spoofed referrersLooks like normal site navigationDon't trust referrer alone
Geographically diverse sourcesEvades geo-blocking and per-IP limitsReputation feeds, global rate limits, challenges

11. Big Picture

StageToolWhat it tells / does
SpotWeb logs503 spike, burst timestamps, odd UAs, expensive endpoints
UnderstandSIEMWhen it started, which page, which IPs/UAs, DoS or DDoS
AbsorbCDNKeeps the flood off the origin
FilterWAFBlocks, challenges, rate-limits
PreventSecure codeValidated, capped inputs so no single request is expensive

One-sentence takeaway: find the expensive endpoint, identify whether the traffic comes from one source or thousands, keep it off the origin with a CDN, filter it with a WAF, and make sure no single request can cost the server too much.