Vulnerability Analysis & CVE Research
By the end of this lesson you will be able to take the version list from enumeration, research each version for known weaknesses, separate real issues from false alarms, and rank what you found so the most dangerous problems are dealt with first.
Vulnerability analysis is the thinking phase between finding services and testing them. A careless tester sees "old version" and shouts "critical!". A careful tester checks which weakness applies, whether it is really present, and how much it matters.
The vocabulary
Think of a medicine recall in India. The drug regulator publishes a notice with a batch number, what is wrong, and how serious it is. Software has the same system:
| Term | Meaning | Example |
|---|---|---|
| Vulnerability | A weakness that could be used to cause harm | A backdoor in an FTP server |
| CVE | Common Vulnerabilities and Exposures: a unique ID for one publicly known vulnerability | CVE-2011-2523 |
| CWE | Common Weakness Enumeration: the type of mistake | CWE-89 is SQL injection |
| CVSS | Common Vulnerability Scoring System: a 0.0-10.0 severity score | 9.8 Critical |
| NVD | The US National Vulnerability Database, which adds scores and details to CVEs | nvd.nist.gov |
| KEV | CISA's Known Exploited Vulnerabilities catalogue: CVEs seen used in real attacks | A strong reason to fix first |
The CVE is the batch number, the CWE is the kind of defect, and CVSS is how serious the recall is. CVSS scoring is explained fully in CVSS Scoring & Reporting.
Step by step: research one service
Your enumeration found vsftpd 2.3.4 on 192.168.56.103:21. Here is the research process.
Step 1. Search NVD for the product and version. NVD also has a free public API. This query asks for one CVE record by ID:
curl -s "https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2011-2523" -o cve-2011-2523.jsonStep 2. Read the description. NVD's record says vsftpd 2.3.4 downloaded between 30 June and 3 July 2011 contains a backdoor which opens a shell on port 6200/tcp. Its CVSS v3.1 base score is 9.8 (Critical).
Notice two details. First, the problem is not in all copies of 2.3.4, only in copies downloaded in a short window when the official download was tampered with. Second, the CVE was published in 2019 although the incident happened in 2011. CVE years show when the ID was reserved, not always when the problem began.
Step 3. Check the vendor or distribution advisory. The vendor's own notice is the most reliable source for which versions are affected and fixed.
Step 4. Look for public exploit code, for research only. On Kali, searchsploit searches a local copy of Exploit-DB:
searchsploit vsftpd 2.3.4A match tells you a working exploit is public, which raises the urgency. Read it to understand the weakness. Never run downloaded exploit code you have not read, and never outside your lab and scope.
Step 5. Record the evidence you have so far: version source (banner and -sV), CVE ID, score, and whether exploitation is public.
The Metasploitable 2 candidates
Researching the services from Service Enumeration in NVD gives a list like this. The scores are NVD's; older CVEs have only a CVSS v2 score.
| Service | CVE | What it is | NVD score |
|---|---|---|---|
| vsftpd 2.3.4 | CVE-2011-2523 | Backdoor in tampered downloads, shell on port 6200 | 9.8 (v3.1) |
| UnrealIRCd 3.2.8.1 | CVE-2010-2075 | Trojan horse added to the source on some mirror sites | 7.5 (v2) |
| Samba 3.0.0 to 3.0.25rc3 | CVE-2007-2447 | Command execution when the "username map script" option is enabled | 6.0 (v2) |
Notice that Nmap reported Samba only as 3.X - 4.X. Before you claim CVE-2007-2447, you would need the exact version and the configuration. That is the difference between a candidate and a finding.
False positives and backported patches
A false positive is a reported vulnerability that is not really there. The most common cause is the backported patch. Linux distributions such as Ubuntu and Debian often fix a security bug without changing the main version number. They add a package revision instead.
For example, a banner like OpenSSH_8.9p1 Ubuntu-3ubuntu0.10 shows upstream version 8.9p1, but the 3ubuntu0.10 part means Ubuntu has applied fixes. A scanner that compares only 8.9p1 would wrongly flag many fixed CVEs. The right check is the distribution's security notice for that exact package version.
This script models the idea. It flags a version only when the advisory data says it is affected and no distribution fix applies:
advisories = {
("openssh", "8.9p1"): {"cve": "CVE-EXAMPLE-0001", "fixed_in_ubuntu": "1:8.9p1-3ubuntu0.4"},
}
def revision(pkg):
return tuple(int(n) for n in pkg.split("ubuntu")[-1].split("."))
def check(product, upstream, ubuntu_pkg):
adv = advisories.get((product, upstream))
if not adv:
return "no advisory found"
if ubuntu_pkg and revision(ubuntu_pkg) >= revision(adv["fixed_in_ubuntu"]):
return f"{adv['cve']}: patched by distribution (false positive)"
return f"{adv['cve']}: LIKELY VULNERABLE, confirm"
print(check("openssh", "8.9p1", "1:8.9p1-3ubuntu0.10"))
print(check("openssh", "8.9p1", "1:8.9p1-3ubuntu0.1"))
print(check("openssh", "9.6p1", "1:9.6p1-3ubuntu13.5"))CVE-EXAMPLE-0001: patched by distribution (false positive) CVE-EXAMPLE-0001: LIKELY VULNERABLE, confirm no advisory found
The advisory here is made-up sample data with a placeholder CVE ID, so you learn the logic without trusting invented facts. Real Debian and Ubuntu version comparison has more rules; tools like dpkg --compare-versions handle them properly.
Automated scanners and their limits
Vulnerability scanners such as Greenbone (OpenVAS) and Nessus automate this research across many hosts. They are useful and widely used. But they work mostly from versions and simple checks, so they produce false positives and miss logic flaws. Treat scanner output as a list of leads to verify, never as a finished report.
Nmap also has a vuln script category. Some scripts in it are intrusive, so use them only where your rules of engagement allow, and check each script's description first.
Prioritising findings
When you have several confirmed issues, decide what to fix first. Severity matters, but so does real-world exploitation: a CVE in the KEV catalogue is being used by attackers right now. This script ranks lab findings by known exploitation, public exploit availability, then score:
findings = [
{"host": "192.168.56.103", "issue": "Samba username map script", "cvss": 6.0, "public_exploit": True, "kev": False},
{"host": "192.168.56.103", "issue": "vsftpd 2.3.4 backdoor", "cvss": 9.8, "public_exploit": True, "kev": False},
{"host": "192.168.56.103", "issue": "Anonymous FTP enabled", "cvss": 5.3, "public_exploit": False, "kev": False},
{"host": "192.168.56.103", "issue": "UnrealIRCd backdoor", "cvss": 7.5, "public_exploit": True, "kev": False},
]
ranked = sorted(findings, key=lambda f: (f["kev"], f["public_exploit"], f["cvss"]), reverse=True)
for n, f in enumerate(ranked, start=1):
flag = "public exploit" if f["public_exploit"] else "no public exploit"
print(f"{n}. {f['issue']:<28} CVSS {f['cvss']:>4} {flag}")1. vsftpd 2.3.4 backdoor CVSS 9.8 public exploit 2. UnrealIRCd backdoor CVSS 7.5 public exploit 3. Samba username map script CVSS 6.0 public exploit 4. Anonymous FTP enabled CVSS 5.3 no public exploit
The kev values are set to False here as sample data. On real work, check each CVE against CISA's catalogue. The anonymous FTP score is our own example rating, not an NVD score.
Common mistakes
- Reporting candidates as findings. A matching version is a lead until you confirm it.
- Ignoring backports. Distribution packages are often patched despite old-looking version numbers.
- Copying scanner output into the report. Verify, remove false positives and explain impact in your own words.
- Running public exploits blindly. Read and understand code first, and run it only in your lab or an authorised scope.
Key points
- CVE identifies a known vulnerability, CWE the type of mistake, and CVSS its severity score.
- Research versions in NVD, vendor and distribution advisories; check KEV for real-world exploitation.
- A version match is a candidate; confirm the exact version and configuration before calling it a finding.
- Backported patches cause many false positives in version-based scanners.
- Prioritise by real-world exploitation, public exploits and severity, then business impact.
Exercise
Write a function that takes a list of (product, version) pairs from enumeration and a small advisory dictionary of product -> list of (affected_version, cve). Print each matching CVE as "candidate" and each product with no match as "no known advisory in our data".
Show solution
advisories = {
"vsftpd": [("2.3.4", "CVE-2011-2523")],
"UnrealIRCd": [("3.2.8.1", "CVE-2010-2075")],
}
services = [("vsftpd", "2.3.4"), ("OpenSSH", "4.7p1"), ("UnrealIRCd", "3.2.8.1")]
for product, version in services:
matches = [cve for affected, cve in advisories.get(product, []) if affected == version]
if matches:
for cve in matches:
print(f"{product} {version}: candidate {cve}")
else:
print(f"{product} {version}: no known advisory in our data")vsftpd and UnrealIRCd print as candidates; OpenSSH prints "no known advisory in our data". "Candidate" is the honest word until you confirm.
Quick Quiz
1. What does a CVE ID identify?
CVE gives each known vulnerability a unique ID; CWE is the weakness type and CVSS the score.
2. A scanner flags an old OpenSSH version on Ubuntu, but the package revision is newer than the fix in Ubuntu's notice. What is this most likely?
Distributions often patch without changing the upstream version number.
3. Why does inclusion in CISA's KEV catalogue raise priority?
KEV lists vulnerabilities with evidence of real-world exploitation.
4. What is the right use of searchsploit results?
Public exploits raise urgency; they are research material, not something to run blindly.
Learn Ethical Hacking with a mentor
Free lessons get you started. Our Ethical Hacking & Cyber Security training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
