Skip to content

Commit

Permalink
POC of CVE publication auto-generated artifacts
Browse files Browse the repository at this point in the history
  • Loading branch information
PushkarJ committed Feb 25, 2024
1 parent 8e8ea91 commit 6bee5b4
Show file tree
Hide file tree
Showing 5 changed files with 431 additions and 0 deletions.
283 changes: 283 additions & 0 deletions sig-security-tooling/cve-announcement-recipe/cve_pub_artifact_gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
package main

import (
"bufio"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
)

func main() {
const minVersions = 1

var cveID, title, component, vector, severity_score, severity, actor, action, detectIfVulnerable, mitigationSteps, fixImpact, platform, detectionMethods, githubIssueURL, reporter, fixTeam, releaseManagers, srcMember string
var vulnerableVersions, fixedVersions []string
scanner := bufio.NewScanner(os.Stdin)

// Get user input with validation
err := getUserInput(&cveID, scanner, "Enter CVE ID: ", "^CVE-[0-9]{4}-[0-9]{4,}$")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&title, scanner, "Title: ", ".+")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&component, scanner, "Impacted component (defaults to Kubernetes): ", "optional")
if err != nil {
fmt.Println(err)
return
}

if component == "" {
component = "Kubernetes"
}

err = getUserInput(&vector, scanner, "Enter CVSS vector: ", ".+")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&severity_score, scanner, "Enter severity score: ", ".+")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&severity, scanner, "Enter severity level (e.g., Critical, High, Medium, Low): ", "^(Critical|High|Medium|Low)$")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&detectIfVulnerable, scanner, "How to detect if you are vulnerable: ", ".+")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&actor, scanner, "Enter who can exploit the vulnerability (e.g., attacker, unauthorized user): ", ".+")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&action, scanner, "Describe what the actor can do if the vulnerability is exploited:", ".+")
if err != nil {
fmt.Println(err)
return
}

//Use better regex
err = getVersions(&vulnerableVersions, scanner, "Enter affected versions (x.y.z) separated by commas: ", minVersions, ".+")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&mitigationSteps, scanner, "Enter mitigation steps taken before upgrade (optional): ", "optional")
if err != nil {
fmt.Println(err)
return
}
if mitigationSteps == "" {
mitigationSteps = "There are no known mitigations"
} else {
mitigationSteps = "**ACTION REQUIRED:** The following steps must be taken to mitigate this vulnerability: ...\n_(If possible):_ Prior to upgrading, this vulnerability can be mitigated by ...\n" + mitigationSteps
}

err = getVersions(&fixedVersions, scanner, "Enter fixed versions (x.y.z) separated by commas: ", minVersions, ".+")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&fixImpact, scanner, "Enter any side effects of the fix (optional):", "optional")
if err != nil {
fmt.Println(err)
return
}
if fixImpact != "" {
fixImpact = "_(If fix has side effects)_ **Fix impact:** details of impact. \n" + fixImpact
}
err = getUserInput(&platform, scanner, "Which platform is impacted(defaults to all): ", "optional")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&detectionMethods, scanner, "Enter how to detect if the vulnerability is exploited: ", ".+")
if err != nil {
fmt.Println(err)
return
}
if detectionMethods != "" {
detectionMethods = "_How can exploitation of this vulnerability be detected?_\n" + detectionMethods
}

err = getUserInput(&githubIssueURL, scanner, "Enter link to the GitHub issue: ", ".+")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&reporter, scanner, "Enter who discovered the vulnerability:", ".+")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&fixTeam, scanner, "Enter who fixed the vulnerability (optional): ", ".+")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&releaseManagers, scanner, "Enter who coordinated the release (optional): ", "optional")
if err != nil {
fmt.Println(err)
return
}

err = getUserInput(&srcMember, scanner, "Enter your name (optional): ", "optional")
if err != nil {
fmt.Println(err)
return
}
// Ensure matching version counts
if len(vulnerableVersions) > len(fixedVersions) {
fmt.Println("\033[31mERROR: The number of affected and patched versions must match. Please correct and re-enter.\033[0m")
return
}

// Placeholder replacement using template file and string interpolation
placeholders := map[string]string{
"$CVE_NUMBER": cveID,
"$COMPONENT": component, // Replace with the actual component name
"$AFFECTED_VERSIONS": strings.Join(vulnerableVersions, ""),
"$TITLE": title,
"$FIXED_VERSIONS": strings.Join(fixedVersions, ""),
"$ACTOR": actor,
"$DO_SOMETHING": action,
"$DETECT_IF_VULNERABLE": detectIfVulnerable,
"$SEVERITY": strings.Title(severity), // Convert to title case
"$CVSS_VECTOR": vector,
"$SCORE": severity_score, // Replace with actual CVSS score if available
"$FIX_IMPACT": fixImpact,
"$PLATFORM": platform,
"$MITIGATION_METHODS": mitigationSteps,
"$EXPLOIT_DETECTION": detectionMethods,
"$GITHUBISSUEURL": githubIssueURL,
"$REPORTER": reporter,
"$FIXTEAM": fixTeam,
"$RELEASE_MANAGERS": releaseManagers,
"$PERSON": srcMember, // Replace with your name or appropriate contact
}
// Get filenames from the directory
filenames, err := ioutil.ReadDir("templates")
if err != nil {
fmt.Println("Error reading directory:", err)
return
}
// Iterate through the file infos and extract filenames
for _, file := range filenames {
if !file.IsDir() { // Only consider files, not directories
filename := file.Name()
err, outputFilename := replaceAndWriteFile(filename, placeholders, cveID)
if err != nil {
fmt.Errorf("Error while parsing %s when generating %s %v\n", filename, outputFilename, err)
} else {
fmt.Printf("Announcement generated and saved to %s\n", outputFilename)
}
}
}

}

func replaceAndWriteFile(filename string, placeholders map[string]string, cveID string) (error, string) {
// Specify the file to read

templatePath := filepath.Join("templates", filename)
// Read template content
content, err := ioutil.ReadFile(templatePath)
if err != nil {
return fmt.Errorf("Error reading template: %v", err), ""
}

// Replace placeholder occurrences with values
for placeholder, value := range placeholders {
content = []byte(strings.ReplaceAll(string(content), placeholder, value))
if string(content) == placeholder {
fmt.Printf("Warning: Placeholder '%s' not found in template.\n", placeholder)
}
}

// Generate output filename based on template name
outputFilename := removeMiddleAndJoin(filename)
// Create output directory with cveID
outputDir := filepath.Join("output", cveID)
err = os.MkdirAll(outputDir, 0755)
if err != nil {
return fmt.Errorf("Error creating output directory: %v", err), outputFilename
}

outputFilename = filepath.Join(outputDir, outputFilename)

// Write the content to the file
err = ioutil.WriteFile(outputFilename, content, 0644)
if err != nil {
return fmt.Errorf("Error writing content to file: %v", err), outputFilename
}

return nil, outputFilename
}

func removeMiddleAndJoin(filename string) string {
parts := strings.Split(filename, ".")
if len(parts) >= 3 {
return strings.Join(append(parts[:1], parts[2:]...), ".")
}
return filename // Return original filename if fewer than 3 parts
}

func getVersions(versions *[]string, scanner *bufio.Scanner, prompt string, minVersions int, validationRegex string) error {
fmt.Print(prompt)
scanner.Scan()
input := scanner.Text()

parsedVersions := strings.Split(input, ",")
if len(parsedVersions) < minVersions {
return fmt.Errorf("At least %d versions are required. Please enter comma-separated values and try again.", minVersions)
}

for _, version := range parsedVersions {
if !regexp.MustCompile(validationRegex).MatchString(version) {
return fmt.Errorf("Invalid version format. Please use x.y.z format for each version.")
}
}

*versions = parsedVersions
return nil
}

func getUserInput(value *string, scanner *bufio.Scanner, prompt string, validationRegex string) error {
fmt.Print(prompt)
scanner.Scan()
input := scanner.Text()
if validationRegex != "optional" {
if !regexp.MustCompile(validationRegex).MatchString(input) {
return fmt.Errorf("Invalid input format")
}
}

*value = input
return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
Hello Kubernetes Community,

A security issue was discovered in Kubernetes where a user that can create pods and persistent volumes on Windows nodes may be able to escalate to admin privileges on those nodes. Kubernetes clusters are only affected if they are using an in-tree storage plugin for Windows nodes..

This issue has been rated **High** (link to CVSS calculator https://www.first.org/cvss/calculator/3.1) (optional: 7.2), and assigned **CVE-2023-5528**

### Am I vulnerable?

Any kubernetes environment with Windows nodes is impacted. Run kubectl get nodes -l kubernetes.io/os=windows to see if any Windows nodes are in use.

#### Affected Versions

1.8.0

### How do I mitigate this vulnerability?

The provided patch fully mitigates the vulnerability.

Outside of applying the provided patch, there are no known mitigations to this vulnerability.

There are no known mitigations

#### Fixed Versions

1.28.4 1.27.8 1.26.11 1.25.16




Windows platform clusters are impacted.

_For core Kubernetes:_ https://kubernetes.io/docs/tasks/administer-cluster/cluster-upgrade/

### Detection


_How can exploitation of this vulnerability be detected?_
Kubernetes audit logs can be used to detect if this vulnerability is being exploited. Persistent Volume create events with local path fields containing special characters are a strong indication of exploitation.

If you find evidence that this vulnerability has been exploited, please contact [email protected]

#### Additional Details

See the GitHub issue for more details: https://github.com/kubernetes/kubernetes/issues/121879

#### Acknowledgements

This vulnerability was reported by Tomer Peled @tomerpeled92.

_(optional):_ The issue was fixed and coordinated by Fix team and Release managers.

Thank You,

Demo user on behalf of the Kubernetes Security Response Committee
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
pr: "<to be added by release managers"
datafields:
cve:
id: "CVE-2023-5528"
title: "Insufficient input sanitization in in-tree storage plugin leads to privilege escalation on Windows nodes "
description: |
A security issue was discovered in Kubernetes where "a user that can create pods and persistent volumes on Windows nodes " may be able to "escalate to admin privileges on those nodes. Kubernetes clusters are only affected if they are using an in-tree storage plugin for Windows nodes.".
**Affected Versions**:
- "Kubernetes" "1.8.0"
**Fixed Versions**:
- "Kubernetes" "1.28.4 1.27.8 1.26.11 1.25.16"
Reported by "Tomer Peled @tomerpeled92"
trackingissue: "https://github.com/kubernetes/kubernetes/issues/121879"
vector: "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H "
score: "7.2"
rating: "High"
linkedprs: []
Loading

0 comments on commit 6bee5b4

Please sign in to comment.