Vulnerability Assessment and Exploitation Basics
"Finding a crack in the wall is one skill. Judging whether that crack will bring the wall down is another. Vulnerability assessment is the second skill — and it's the one that decides what actually gets fixed first."
From "Open Port" to "Actual Risk"
Chapter 5.4 gave you a list of open ports and service banners. That list, on its own, isn't a security finding — it's raw material. Vulnerability assessment is the process of turning that raw material into a judged, prioritized understanding of what's actually wrong: which discovered services or configurations are outdated, misconfigured, or vulnerable to a known weakness, and how serious each one is in context.
This is a distinct discipline from penetration testing (Chapter 5.8). Vulnerability assessment tends to be broad and largely automated — scan everything, match against known weaknesses, produce a report. Penetration testing is narrower and more manual — take a smaller set of findings and actually attempt to chain them into real, demonstrated impact.
The Vulnerability Assessment Lifecycle
- Discovery — enumerate assets and the software/versions running on them (Chapter 5.4's job).
- Identification — match what you found against known vulnerability databases: CVE (Common Vulnerabilities and Exposures) entries, vendor advisories, or vulnerability-scanner signature sets.
- Verification — confirm the match is real. Version banners can be wrong, backported patches can make an "old" version actually safe, and default assumptions produce false positives constantly.
- Scoring — rank severity so remediation effort goes where it matters most.
- Remediation and re-check — patch, reconfigure, or mitigate, then verify the fix actually closed the gap.
Skipping verification is the single most common mistake in this process — a scanner that reports "vulnerable" based on version string alone, without confirming the vulnerable code path is actually reachable, generates a flood of false positives that erodes trust in the whole assessment.
Reading a CVSS Score
The Common Vulnerability Scoring System (CVSS) is the standard way severity gets communicated, typically as a score from 0 to 10 built from metrics like:
- Attack vector — can it be exploited remotely over a network, or does it require local/physical access?
- Attack complexity — does exploitation require special conditions, or does it work reliably every time?
- Privileges required — does the attacker need any existing access, or none at all?
- Impact — what does successful exploitation actually get the attacker: read access, write access, full control?
A 9.8 "critical" remote, unauthenticated, high-impact vulnerability on an internet-facing service is a fire-drill; a 4.0 "medium" vulnerability that needs local access to a machine already fully controlled by the attacker is usually much lower on the list — context always matters more than the raw number.
Common Vulnerability Classes in Network Services
- Outdated software with known CVEs — the single most common finding in real assessments; patching promptly closes more doors than almost anything else on this list.
- Default or weak credentials — services deployed with vendor-default logins never changed.
- Misconfiguration — a service correctly patched but insecurely configured: an admin interface exposed to the internet, verbose error messages leaking internals, directory listing left enabled.
- Injection points — anywhere untrusted input reaches a command interpreter, SQL query, or deserializer without validation (Chapter 5.13 covers writing Go code that avoids this class entirely).
- Missing or broken transport security — services accepting plaintext connections, or TLS configured with an expired certificate or an obsolete protocol version.
What "Exploitation Basics" Means Here
Exploitation is the act of using a vulnerability to achieve an effect the system's designers didn't intend — reading data you shouldn't, running code you shouldn't, or crashing a service you shouldn't be able to crash. Understanding the concept is essential even if you never write an exploit yourself, because it's what lets you judge real severity instead of taking a scanner's word for it.
At a conceptual level, exploitation usually depends on one of a handful of patterns: the target trusts input it shouldn't (leading to injection or memory-corruption bugs), the target fails to check authorization on a sensitive action, or the target's cryptography is weak or misapplied. Recognizing which pattern is present is often more valuable than being able to write working exploit code for it — most working security engineers spend far more time preventing and assessing these patterns than crafting exploits from scratch.
Go in Action: A Toy Version-Risk Checker
A simplified illustration of what "identification" looks like in an assessment pipeline — matching a discovered service version against a small local list of known-risky versions:
package main
import "fmt"
// KnownIssue is a deliberately tiny stand-in for a real CVE feed.
type KnownIssue struct {
Service string
Version string
CVE string
Severity float64 // CVSS-style base score
}
var knownIssues = []KnownIssue{
{"vsftpd", "2.3.4", "CVE-2011-2523", 9.8},
{"openssh", "7.2", "CVE-2016-6210", 5.9},
}
// assess reports whether a discovered service+version matches a known issue.
// A real pipeline would query a live CVE database, not a hardcoded slice,
// and would still require manual verification before acting on a match.
func assess(service, version string) (KnownIssue, bool) {
for _, issue := range knownIssues {
if issue.Service == service && issue.Version == version {
return issue, true
}
}
return KnownIssue{}, false
}
func main() {
discovered := []struct{ Service, Version string }{
{"vsftpd", "2.3.4"},
{"nginx", "1.25.3"},
}
for _, d := range discovered {
if issue, found := assess(d.Service, d.Version); found {
fmt.Printf(
"MATCH: %s %s -> %s (severity %.1f)\n",
d.Service, d.Version, issue.CVE, issue.Severity,
)
continue
}
fmt.Printf("no known match for %s %s\n", d.Service, d.Version)
}
}
This is a toy, but the shape is exactly what real vulnerability scanners do at scale, against a constantly updated feed instead of two hardcoded entries — and every match they produce still deserves the same verification step before it's treated as fact.
Frequently Asked Questions
Is a critical CVSS score always an emergency? Not automatically — the score describes the vulnerability in isolation, not its blast radius in your specific environment. A 9.8 sitting on an internet-facing login page deserves a fire-drill; the same 9.8 on a service that's only reachable from an isolated lab network with no path to anything valuable is a much lower priority. Reading the score alongside exposure and business context is what separates real prioritization from just reacting to numbers.
If a scanner flags something, is it safe to assume it's real? No, and that's exactly why verification is its own step in the lifecycle above. Scanners often match on a version banner alone, and banners lie: a vendor can backport a security fix without bumping the version string, or a misconfigured banner can report the wrong software entirely. Treat every automated match as a hypothesis to confirm, not a finding to act on.
Can I run the toy version-risk checker against real servers I don't own? Only against systems you own or are explicitly authorized to test — a home lab, a CTF target, or a client covered by a signed engagement, the same boundary this whole part of the book holds to. The Go example here is a teaching illustration of how identification works structurally; a real assessment pipeline queries a live, constantly updated CVE feed and still requires the same manual verification before anyone treats a match as fact.
Why doesn't this chapter just show a working exploit? Because understanding why a vulnerability class is dangerous carries almost all of the professional value, while a working exploit against real software mostly just creates risk if it leaks. The pattern-recognition skill — spotting that a target trusts input it shouldn't, or skips an authorization check — is what you actually use day to day; writing exploit primitives is a narrow specialty best learned inside a controlled, authorized environment with purpose-built tooling.
Where This Leads
An assessed, prioritized list of findings is what feeds directly into a penetration test's exploitation phase (Chapter 5.8), and it's the artifact an incident responder wishes they'd had before an incident (Chapter 5.9). Assessment is unglamorous compared to exploitation, but it's the step that actually reduces risk at scale.