generated from kubernetes/kubernetes-template-project
-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
POC of CVE publication auto-generated artifacts
- Loading branch information
Showing
5 changed files
with
431 additions
and
0 deletions.
There are no files selected for viewing
283 changes: 283 additions & 0 deletions
283
sig-security-tooling/cve-announcement-recipe/cve_pub_artifact_gen.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
54 changes: 54 additions & 0 deletions
54
sig-security-tooling/cve-announcement-recipe/output/CVE-2023-5528/announcement.eml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
22 changes: 22 additions & 0 deletions
22
...security-tooling/cve-announcement-recipe/output/CVE-2023-5528/release-cve-publication.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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: [] |
Oops, something went wrong.