Skip to content

Commit

Permalink
SSVC Implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
dylan-mulligan committed Oct 12, 2023
1 parent 345412d commit 9c261bb
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 11 deletions.
20 changes: 20 additions & 0 deletions nvip_data/mysql-database/newDB/db.init.xml
Original file line number Diff line number Diff line change
Expand Up @@ -930,5 +930,25 @@
</createTable>
</changeSet>

<changeSet id="createSSVCTable" author="dylan">
<createTable tableName="ssvc">
<column name="id" autoIncrement="true" type="SERIAL">
<constraints primaryKey="true" nullable="false" unique="true"/>
</column>
<column name="cve_id" type="VARCHAR(20)">
<constraints nullable="false"/>
</column>
<column name="automatable" type="TINYINT(1)">
<constraints nullable="false"/>
</column>
<column name="exploit_status" type="VARCHAR(50)">
<constraints nullable="false"/>
</column>
<column name="technical_impact" type="TINYINT(1)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>


</databaseChangeLog>
39 changes: 39 additions & 0 deletions reconciler/src/main/java/edu/rit/se/nvip/DatabaseHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ public class DatabaseHelper {
private static final String SELECT_MITRE_BY_DATE = "SELECT cve_id FROM mitredata WHERE last_modified >= DATE_SUB(NOW(), INTERVAL 2 MINUTE)";
private static final String INSERT_RUN_STATS = "INSERT INTO runhistory (run_date_time, total_cve_count, new_cve_count, updated_cve_count, not_in_nvd_count, not_in_mitre_count, not_in_both_count, avg_time_gap_nvd, avg_time_gap_mitre)" +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
private static final String EXPLOIT_EXISTS = "SELECT id FROM exploit WHERE cve_id = ?";
private static final String INSERT_SSVC = "INSERT INTO ssvc (cve_id, automatable, exploit_status, technical_impact) VALUES (?, ?, ?, ?)";

public static synchronized DatabaseHelper getInstance() {
if (databaseHelper == null) {
Expand Down Expand Up @@ -785,4 +787,41 @@ public Set<CompositeVulnerability> attachMitreVulns(Set<CompositeVulnerability>
return out;
}

public boolean exploitExists(String cveId) {
try (Connection conn = getConnection(); PreparedStatement pstmt = conn.prepareStatement(EXPLOIT_EXISTS)) {
pstmt.setString(1, cveId);
return pstmt.execute();
} catch (SQLException ex) {
logger.error("Error while fetching exploit data");
logger.error(ex);
return false;
}
}

public void insertSSVCSet(Set<CompositeVulnerability> vulns) {
try (Connection conn = getConnection(); PreparedStatement pstmt = conn.prepareStatement(INSERT_SSVC)) {
conn.setAutoCommit(false);
for (CompositeVulnerability vuln : vulns) {
// Get SSVC data
final SSVC ssvc = vuln.getSSVC();

// Skip vulns w/o data
if (!vuln.isRecharacterized() || ssvc == null) continue;

// Insert data into statement
pstmt.setString(1, vuln.getCveId());
pstmt.setBoolean(2, ssvc.isAutomatable());
pstmt.setString(3, ssvc.getExploitStatus());
pstmt.setBoolean(4, ssvc.getTechnicalImpact());

}
// Execute statement
pstmt.execute();
conn.commit();
} catch (SQLException ex) {
logger.error("Error while inserting vdo labels");
logger.error(ex);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public void main(Set<String> jobs) {

dbh.insertCvssBatch(recharacterized);
dbh.insertVdoBatch(recharacterized);
dbh.insertSSVCSet(recharacterized);
}
// PNE team no longer wants a finish message
//messenger.sendPNEFinishMessage();
Expand Down Expand Up @@ -144,7 +145,7 @@ public CveCharacterizer call() {
try {
String[] trainingDataInfo = {ReconcilerEnvVars.getTrainingDataDir(), ReconcilerEnvVars.getTrainingData()};
logger.info("Setting NVIP_CVE_CHARACTERIZATION_LIMIT to {}", ReconcilerEnvVars.getCharacterizationLimit());
return new CveCharacterizer(trainingDataInfo[0], trainingDataInfo[1], ReconcilerEnvVars.getCharacterizationApproach(), ReconcilerEnvVars.getCharacterizationMethod());
return new CveCharacterizer(trainingDataInfo[0], trainingDataInfo[1], ReconcilerEnvVars.getCharacterizationApproach(), ReconcilerEnvVars.getCharacterizationMethod(), dbh);
} catch (NullPointerException | NumberFormatException e) {
logger.warn("Could not fetch NVIP_CVE_CHARACTERIZATION_TRAINING_DATA or NVIP_CVE_CHARACTERIZATION_TRAINING_DATA_DIR from env vars");
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
* SOFTWARE.
*/

import com.fasterxml.jackson.databind.ObjectMapper;
import edu.rit.se.nvip.DatabaseHelper;
import edu.rit.se.nvip.automatedcvss.CvssScoreCalculator;
import edu.rit.se.nvip.automatedcvss.PartialCvssVectorGenerator;
import edu.rit.se.nvip.automatedcvss.preprocessor.CvePreProcessor;
Expand All @@ -37,8 +39,13 @@
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import sun.net.www.protocol.https.HttpsURLConnectionImpl;

import java.io.File;
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.file.Paths;
import java.util.*;

Expand All @@ -51,6 +58,8 @@
public class CveCharacterizer {
private Logger logger = LogManager.getLogger(CveCharacterizer.class.getSimpleName());
private final Map<VDONounGroup, AbstractCveClassifier> nounGroupToClassifier = new HashMap<>();
private final static ObjectMapper OM = new ObjectMapper();
private final DatabaseHelper dbh;

/**
* these two vars are used to derive the CVSS vector from VDO labels and then
Expand All @@ -74,10 +83,12 @@ public CveCharacterizer(CvePreProcessor cvePreProcessor,
CveClassifierFactory cveClassifierFactory,
CvssScoreCalculator cvssScoreCalculator,
PartialCvssVectorGenerator partialCvssVectorGenerator,
String trainingDataPath, String trainingDataFiles, String approach, String method) {
String trainingDataPath, String trainingDataFiles, String approach, String method,
DatabaseHelper dbh) {
this.cvssScoreCalculator = cvssScoreCalculator;
this.partialCvssVectorGenerator = partialCvssVectorGenerator;
this.cvePreProcessor = cvePreProcessor;
this.dbh = dbh;
try {

/**
Expand Down Expand Up @@ -133,8 +144,8 @@ public CveCharacterizer(CvePreProcessor cvePreProcessor,
*/

//removed boolean loadSerializedModels as well as exploitability package
public CveCharacterizer(String trainingDataPath, String trainingDataFiles, String approach, String method) {
this(new CvePreProcessor(true), new CveClassifierFactory(), new CvssScoreCalculator(), new PartialCvssVectorGenerator(), trainingDataPath, trainingDataFiles, approach, method);
public CveCharacterizer(String trainingDataPath, String trainingDataFiles, String approach, String method, DatabaseHelper dbh) {
this(new CvePreProcessor(true), new CveClassifierFactory(), new CvssScoreCalculator(), new PartialCvssVectorGenerator(), trainingDataPath, trainingDataFiles, approach, method, dbh);
}

/**
Expand Down Expand Up @@ -208,10 +219,8 @@ public void characterizeCveList(Set<CompositeVulnerability> cveSet, int limit) {
vuln.addCvssScore(score);
// logger.info("CVSS Score predicted for {}", vulnerability.getCveId());

// TODO: Route query to this object
// Get SSVC score
final SSVC ssvc = new SSVC(false, null, false);
// TODO: Attach object to vuln
// Get SSVC
vuln.setSSVC(characterizeCveForSSVC(vuln));

// log
if (totCharacterized % 100 == 0 && totCharacterized > 0) {
Expand All @@ -231,6 +240,39 @@ public void characterizeCveList(Set<CompositeVulnerability> cveSet, int limit) {
logger.info("{} CVEs did not have a good description, and {} CVEs had the same description (after reconciliation) and skipped!", countBadDescription, countNotChanged);
}

// Query SSVC AI models for scoring
private SSVC characterizeCveForSSVC(CompositeVulnerability vuln) {
try {
// Create parameter dict
final Map<String, String> params = new HashMap<>();
params.put("cveId", vuln.getCveId());
params.put("description", vuln.getDescription());
params.put("exploitStatus", dbh.exploitExists(vuln.getCveId()) ? "POC" : "NONE");

// Create url object
final URL url = new URL("ssvc" + getParamsString(params));

// // Setup connection and parameters
// final HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
// conn.setRequestMethod("GET");
// conn.setDoOutput(true);
// DataOutputStream out = new DataOutputStream(conn.getOutputStream());
// out.writeBytes(getParamsString(params));
// out.flush();
// out.close();

// Build object from request response
return OM.readValue(url, SSVC.class);

// // Extract values from response
//
// // Build SSVC object
// final SSVC ssvc = new SSVC(automatable, exploitExists, technicalImpact);
} catch (Exception e) {
return null;
}
}

/**
* get VDO labels and return a double array that includes the
* mean/minimum/maximum and standard deviation of the CVSS scores in NVD
Expand All @@ -247,4 +289,21 @@ private double getCvssScoreFromVdoLabels(Set<VDOLabel> predictionsForVuln) {
// return cvssScoreCalculator.getCvssScoreJython(cvssVec)[0]; // old way of doing it
return cvssScoreCalculator.lookupCvssScore(cvssVec); // should return same number as the old way but doesn't rely on python
}

private static String getParamsString(Map<String, String> params)
throws UnsupportedEncodingException {
StringBuilder result = new StringBuilder();

for (Map.Entry<String, String> entry : params.entrySet()) {
result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
result.append("=");
result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
result.append("&");
}

String resultString = result.toString();
return resultString.length() > 0
? resultString.substring(0, resultString.length() - 1)
: resultString;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public enum ReconciliationStatus {
// cvss scoring
private CvssScore cvssScore;

// ssvc scoring
private SSVC ssvc;

//list of related cwes
private final List<CWE> cweList = new ArrayList<>();
private ReconciliationStatus recStatus;
Expand Down Expand Up @@ -193,11 +196,15 @@ public CvssScore getCvssScoreInfo() {
return cvssScore;
}

public SSVC getSSVC() { return ssvc; }

public void addCvssScore(CvssScore cvss) {
this.cvssScore = cvss;
this.recharacterized = true;
}

public void setSSVC(SSVC ssvc) { this.ssvc = ssvc; }

public boolean isRecharacterized() {
return this.recharacterized;
}
Expand Down
4 changes: 4 additions & 0 deletions reconciler/src/main/java/edu/rit/se/nvip/model/SSVC.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ public SSVC(boolean automatable, EXPLOIT_STATUS exploitStatus, boolean technical
this.exploitStatus = exploitStatus;
this.technicalImpact = technicalImpact;
}

public boolean isAutomatable() { return automatable; }
public String getExploitStatus() { return exploitStatus.toString(); }
public boolean getTechnicalImpact() { return technicalImpact; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public static void main(String[] args){

String[] trainingDataInfo = {ReconcilerEnvVars.getTrainingDataDir(), ReconcilerEnvVars.getTrainingData()};
CveCharacterizer characterizer = new CveCharacterizer(trainingDataInfo[0], trainingDataInfo[1], ReconcilerEnvVars.getCharacterizationApproach(),
ReconcilerEnvVars.getCharacterizationMethod());
ReconcilerEnvVars.getCharacterizationMethod(), null); // TODO: Add/mock DBH


Set<CompositeVulnerability> cveSet = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public void testCveCharacterization() {
when(mockPartialCvssVectorGenerator.getCVssVector(anySet())).thenReturn(new String[8]);
//create characterizer with the mocks manually injected
CveCharacterizer cveCharacterizer = new CveCharacterizer(mockPreProcessor, mockCveClassifierFactory, mockCvssScoreCalculator, mockPartialCvssVectorGenerator,
trainingDataInfo[0], trainingDataInfo[1], "ML", "NB");
trainingDataInfo[0], trainingDataInfo[1], "ML", "NB", null); // TODO: Add/mock dbh



Expand Down

0 comments on commit 9c261bb

Please sign in to comment.