-
-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Makefile, readme and some more code for the Sarif plugin
- Loading branch information
Showing
3 changed files
with
249 additions
and
101 deletions.
There are no files selected for viewing
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,12 @@ | ||
all: | ||
r2 -i sarif.r2.js /bin/ls | ||
|
||
install user-install: | ||
mkdir -p $(shell r2 -H R2_USER_PLUGINS) | ||
cp -f sarif.r2.js $(shell r2 -H R2_USER_PLUGINS) | ||
|
||
uninstall user-uninstall: | ||
rm -f $(shell r2 -H R2_USER_PLUGINS)/sarif.r2.js | ||
|
||
indent: | ||
semistandard --fix sarif.r2.js |
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,24 @@ | ||
# SARIF for Radare2 | ||
|
||
Static Analysis Results Interchange Format (SARIF) Version 2.0 | ||
|
||
## Description | ||
|
||
This plugin for radare2 adds the `sarif` command to the r2 shell which allows to import and export SARIF documents (JSON files) into the current session, allowing the analyst to report and visualize the reported vulnerabilities in a binary using a standard file format. | ||
|
||
## Usage | ||
|
||
``` | ||
[0x00000000]> sarif? | ||
sarif [action] [arguments] | ||
sarif help - show this help message | ||
sarif import [file] - import sarif info from given file | ||
sarif export [file] - export sarif findings into given file or stdout | ||
sarif script - generate r2 script with loaded sarif info | ||
sarif reset - reset all loaded sarif reports | ||
[0x00000000]> | ||
``` | ||
|
||
## Links | ||
|
||
* https://docs.oasis-open.org/sarif/sarif/v2.0/sarif-v2.0.html |
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 |
---|---|---|
@@ -1,115 +1,227 @@ | ||
const sarifTemplate = { | ||
"$schema": "http://json.schemastore.org/sarif-2.1.0", | ||
"version": "2.1.0", | ||
"runs": [ | ||
$schema: 'http://json.schemastore.org/sarif-2.1.0', | ||
version: '2.1.0', | ||
runs: [ | ||
{ | ||
"tool": { | ||
"driver": { | ||
"name": "radare2", | ||
"semanticVersion": "1.0.0", | ||
"rules": [ | ||
tool: { | ||
driver: { | ||
name: 'radare2', | ||
semanticVersion: '1.0.0', | ||
rules: [ | ||
] | ||
} | ||
}, | ||
"results": [ | ||
results: [ | ||
] | ||
} | ||
] | ||
}; | ||
|
||
class R2Sarif { | ||
constructor() { | ||
this.doc = sarifTemplate; | ||
} | ||
addRule(id, description, helpUri) { | ||
if (this.doc.runs[0].tool.driver.rules.filter((x) => x.id === id).length !== 0) { | ||
return false; | ||
} | ||
const rule = { | ||
"id": id, | ||
"shortDescription": { | ||
"text": description | ||
}, | ||
"helpUri": helpUri | ||
} | ||
this.doc.runs[0].tool.driver.rules.push (rule); | ||
return true; | ||
} | ||
addRuleOverflow() { | ||
const ruleId = "VULN-OVERFLOW"; | ||
this.addRule(ruleId, "Potential Buffer overflow", | ||
"http://example.com/vulnerability/EXAMPLE-VULN-001"); | ||
return ruleId; | ||
} | ||
addResultOverflow(artifact, locations) { | ||
const ruleId = this.addRuleOverflow(); | ||
this.addResult (ruleId, "error", "Buffer overflow detected", artifact, locations); | ||
} | ||
addResult(ruleId, level, message, artifact, locations) { | ||
const sarifLocations = []; | ||
const result = { | ||
"ruleId": ruleId, | ||
"level": level, | ||
"message": { | ||
"text": message | ||
}, | ||
"locations": [] | ||
}; | ||
const locationTemplate = { | ||
"physicalLocation": { | ||
"artifactLocation": { | ||
"uri": "binary://" + artifact, | ||
"uriBaseId": "%SRCROOT%" | ||
}, | ||
"region": { | ||
"startByteOffset": locations, | ||
"byteLength": 128 | ||
} | ||
}, | ||
"properties": { | ||
"memoryAddress": "0x0040321A" | ||
} | ||
} | ||
for (let loc of locations) { | ||
const myLoc = locationTemplate; | ||
myLoc.physicalLocation.region = { | ||
startByteOffset: loc.pa, | ||
byteLength: loc.sz, | ||
} | ||
myLoc.properties = { | ||
memoryAddress: loc.va | ||
}; | ||
result.locations.push(myLoc); | ||
} | ||
this.doc.runs[0].results.push(result); | ||
} | ||
toString() { | ||
return JSON.stringify(this.doc); | ||
} | ||
toScript() { | ||
let script = ""; | ||
const results = this.doc.runs[0].results; | ||
let counter = 0; | ||
for (let res of results) { | ||
const text = res.message.text; | ||
for (let loc of res.locations) { | ||
console.log(JSON.stringify(res)); | ||
const address = loc.properties.memoryAddress; | ||
const size = loc.physicalLocation.region.byteLength; | ||
script += `CC ${text} @ ${address}\n`; | ||
script += `f bug.${counter} ${size} ${address}\n`; | ||
counter++; | ||
} | ||
} | ||
return script; | ||
} | ||
} | ||
constructor () { | ||
this.doc = sarifTemplate; | ||
} | ||
|
||
addRule (id, description, helpUri) { | ||
if (this.doc.runs[0].tool.driver.rules.filter((x) => x.id === id).length !== 0) { | ||
return false; | ||
} | ||
const rule = { | ||
id: id, | ||
shortDescription: { | ||
text: description | ||
}, | ||
helpUri: helpUri | ||
}; | ||
this.doc.runs[0].tool.driver.rules.push(rule); | ||
return true; | ||
} | ||
|
||
reset () { | ||
this.doc.runs[0].results = []; | ||
this.doc.runs[0].tool.driver.rules = []; | ||
} | ||
|
||
addRuleOverflow () { | ||
const ruleId = 'VULN-OVERFLOW'; | ||
this.addRule(ruleId, 'Potential Buffer Overflow', | ||
'http://example.com/vulnerability/EXAMPLE-VULN-001'); | ||
return ruleId; | ||
} | ||
|
||
addRuleWeakCrypto () { | ||
const ruleId = 'VULN-WEAKCRYPTO'; | ||
this.addRule(ruleId, 'Weak Crypto Usage', | ||
'http://example.com/vulnerability/EXAMPLE-VULN-002'); | ||
return ruleId; | ||
} | ||
|
||
addResultWeakCrypto (artifact, comment, locations) { | ||
const ruleId = this.addRuleWeakCrypto(); | ||
this.addResult(ruleId, 'error', comment, artifact, locations); | ||
} | ||
|
||
const s = new R2Sarif(); | ||
s.addResultOverflow('/bin/ls', [ | ||
{ va: 0x804804, pa: 0x804, sz: 32 } | ||
]); | ||
addResultOverflow (artifact, comment, locations) { | ||
const ruleId = this.addRuleOverflow(); | ||
this.addResult(ruleId, 'error', comment, artifact, locations); | ||
} | ||
|
||
console.log(s.toString()); | ||
console.log(s.toScript()); | ||
addResult (ruleId, level, message, artifact, locations) { | ||
const sarifLocations = []; | ||
const result = { | ||
ruleId: ruleId, | ||
level: level, | ||
message: { | ||
text: message | ||
}, | ||
locations: [] | ||
}; | ||
const locationTemplate = { | ||
physicalLocation: { | ||
artifactLocation: { | ||
uri: 'binary://' + artifact, | ||
uriBaseId: '%SRCROOT%' | ||
}, | ||
region: { | ||
startByteOffset: locations, | ||
byteLength: 128 | ||
} | ||
}, | ||
properties: { | ||
memoryAddress: '0x0040321A' | ||
} | ||
}; | ||
for (const loc of locations) { | ||
const myLoc = locationTemplate; | ||
myLoc.physicalLocation.region = { | ||
startByteOffset: loc.pa, | ||
byteLength: loc.sz | ||
}; | ||
myLoc.properties = { | ||
memoryAddress: loc.va | ||
}; | ||
result.locations.push(myLoc); | ||
} | ||
this.doc.runs[0].results.push(result); | ||
} | ||
|
||
toString () { | ||
return JSON.stringify(this.doc, null, 2) + '\n'; | ||
} | ||
|
||
toScript () { | ||
let script = '# r2sarif script\n'; | ||
const results = this.doc.runs[0].results; | ||
let counter = 0; | ||
for (const res of results) { | ||
const text = res.message.text; | ||
for (const loc of res.locations) { | ||
console.log(JSON.stringify(res)); | ||
const address = loc.properties.memoryAddress; | ||
const size = loc.physicalLocation.region.byteLength; | ||
script += `CC ${text} @ ${address}\n`; | ||
script += `f bug.${counter} ${size} ${address}\n`; | ||
counter++; | ||
} | ||
} | ||
return script; | ||
} | ||
} | ||
|
||
function sarifTest () { | ||
const s = new R2Sarif(); | ||
s.addResultOverflow('/bin/ls', 'buffer overflow detected', [ | ||
{ va: 0x804804, pa: 0x804, sz: 32 } | ||
]); | ||
console.log(s.toString()); | ||
console.log(s.toScript()); | ||
} | ||
|
||
function sarifRegisterPlugin () { | ||
const sarif = new R2Sarif(); | ||
function sarifCommand (args) { | ||
function sarifHelp () { | ||
console.log('sarif [action] [arguments]'); | ||
console.log('sarif help - show this help message'); | ||
console.log('sarif import [file] - import sarif info from given file'); | ||
console.log('sarif export [file] - export sarif findings into given file or stdout'); | ||
console.log('sarif script - generate r2 script with loaded sarif info'); | ||
console.log('sarif reset - reset all loaded sarif reports'); | ||
} | ||
function sarifImport (fileName) { | ||
console.log('Importing from ' + fileName); | ||
} | ||
function sarifExport (fileName) { | ||
console.log(fileName); | ||
if (fileName === '') { | ||
console.log(sarif.toString()); | ||
} else { | ||
console.log('Exporting to ' + fileName); | ||
} | ||
} | ||
function sarifScript (fileName) { | ||
console.log(sarif.toScript()); | ||
} | ||
function sarifAdd (args) { | ||
if (args === "") { | ||
console.log(""); | ||
} | ||
console.log(args); | ||
} | ||
let arg = args.substr('sarif'.length).trim(); | ||
const space = arg.indexOf(' '); | ||
let action = arg.trim(); | ||
if (space !== -1) { | ||
action = arg.substr(0, space); | ||
arg = arg.substr(space + 1); | ||
} else { | ||
arg = ''; | ||
} | ||
switch (action) { | ||
case '': | ||
case '?': | ||
case '-h': | ||
case 'help': | ||
sarifHelp(); | ||
break; | ||
case '-a': | ||
case 'add': | ||
sarifAdd(arg); | ||
break; | ||
case '-i': | ||
case 'import': | ||
sarifImport(arg); | ||
break; | ||
case '-e': | ||
case 'export': | ||
sarifExport(arg); | ||
break; | ||
case '*': | ||
case '-r': | ||
case 'r2': | ||
case 'script': | ||
sarifScript(arg); | ||
break; | ||
default: | ||
console.error('Unknown action'); | ||
break; | ||
} | ||
} | ||
r2.unload('core', 'sarif'); | ||
r2.plugin('core', function () { | ||
function coreCall (cmd) { | ||
if (cmd.startsWith('sarif')) { | ||
sarifCommand(cmd); | ||
return true; | ||
} | ||
return false; | ||
} | ||
return { | ||
name: 'sarif', | ||
license: 'MIT', | ||
desc: 'support importing and exporting sarif format', | ||
call: coreCall | ||
}; | ||
}); | ||
} | ||
sarifRegisterPlugin(); |