diff --git a/docs/dynamic_task.md b/docs/dynamic_task.md index 6db9db4..88e0e56 100644 --- a/docs/dynamic_task.md +++ b/docs/dynamic_task.md @@ -38,11 +38,43 @@ Replace `report.json` and `mapping.json` with the paths to the relevant files. ## Built-In Tools The dynamic task support built-in mappings, that are shipped with Glue. Those mapping files aims to help others to use the mapping your created. -To use a built-in tools run Glue in the following format: + +### MobSF + +To parse MobSF report, use the following format: ``` ruby bin/glue -t Dynamic -T report.json --mapping-file mobsf ``` -This will look for a file with the name `mobsf.json` under this [folder](/lib/glue/mappings/). +where `report.json` is your report + +### Zaproxy +To parse Zaproxy report, you first need to generate it by using the API: +``` +curl --fail $PROXY_URL/OTHER/core/other/jsonreport/?formMethod=GET --output report.json +``` +Than, use [jq](https://stedolan.github.io/jq/) to flatten the report so Glue can parse it: +``` +jq '{ "@name" : .site."@name", + "alerts": + [.site.alerts[] as $in + | $in.instances[] as $h + | $in + | $h * $in + | { + "description": $in.desc, + "source": "URI: \($h.uri) Method: \($h.method)", + "detail": "\($in.name) \n Evidence: \($h.evidence) \n Solution: \($in.solution) \n Other info: \($in.otherinfo) \n Reference: \($in.reference)", + "severity": $in.riskdesc | split(" ") | .[0], + "fingerprint": "\($in.pluginid)_\($h.uri)_\($h.method)" + } + ] +} ' report.json > output.json +``` +Now use Glue to process the report: +``` +ruby bin/glue -t Dynamic -T report.json --mapping-file zaproxy +``` +You can modify the jq pattern to modify the fields in Glue's results. For example, you might want to remove `otherinfo`, or use something else for the fingerprint. ## Adding a new tool First, create the mapping file. After you have a working mapping file, open a PR and add it under `/lib/glue/mappings/`. diff --git a/lib/glue/mappings/snyk.json b/lib/glue/mappings/snyk.json new file mode 100644 index 0000000..ce3cde9 --- /dev/null +++ b/lib/glue/mappings/snyk.json @@ -0,0 +1,16 @@ +{ + "task_name": "Snyk", + "app_name": "path", + "mappings": [ + { + "key": "vulnerabilities", + "properties": { + "description": "title", + "detail": "description", + "source": "packageName", + "severity": "severity", + "fingerprint": "id" + } + } + ] +} \ No newline at end of file diff --git a/lib/glue/mappings/zaproxy.json b/lib/glue/mappings/zaproxy.json new file mode 100644 index 0000000..e73a9d0 --- /dev/null +++ b/lib/glue/mappings/zaproxy.json @@ -0,0 +1,16 @@ +{ + "task_name": "OWASP Zaproxy", + "app_name": "@name", + "mappings": [ + { + "key": "alerts", + "properties": { + "description": "description", + "detail": "detail", + "source": "source", + "severity": "severity", + "fingerprint": "fingerprint" + } + } + ] +} \ No newline at end of file diff --git a/lib/glue/tasks/base_task.rb b/lib/glue/tasks/base_task.rb index 9416034..51ca1dc 100644 --- a/lib/glue/tasks/base_task.rb +++ b/lib/glue/tasks/base_task.rb @@ -75,7 +75,7 @@ def severity sev return 1 if @severity_filter[:low].include?(sev.strip.chomp.downcase) return 2 if @severity_filter[:medium].include?(sev.strip.chomp.downcase) return 3 if @severity_filter[:high].include?(sev.strip.chomp.downcase) - puts "unsupperted severity found: " + sev + Glue.warn "unsupperted severity found: " + sev return 0 end diff --git a/spec/tasks/dynamic/dynamic_spec.rb b/spec/tasks/dynamic/dynamic_spec.rb index a3ad253..1913a70 100644 --- a/spec/tasks/dynamic/dynamic_spec.rb +++ b/spec/tasks/dynamic/dynamic_spec.rb @@ -131,4 +131,49 @@ def get_dynamic_task_buildin_mapping(report_path, mapping_name) expect(finding.task).to eq("MobSF") end end + + # The tests used the report after transformed with JQ, see the documentation for more details + context "zaproxy" do + let(:task) { get_dynamic_task_buildin_mapping "tools_samples/zaproxy.json", "zaproxy"} + subject(:task_findings) { task.findings } + before do + task.run + end + it "should produce one finding" do + should have(1).items + end + + it "should fill all the required fields" do + finding = subject[0] + expect(finding.severity).to eq(1) + expect(finding.description).to eq("
Base64 encoded data was disclosed by the application/web server
") + expect(finding.detail).to eq("Base64 Disclosure \n Evidence: DxyPP_YQ6qdWluCCz93Xs1CeJPvg \n Solution:Manually confirm that the Base64 data does not leak sensitive information, and that the data cannot be aggregated/used to exploit other vulnerabilities.
\n Other info:\\x000f\\x001c�?�\\x0010�V���Re\\x000c��9�7C\\x001b \\x0011Ű�\\x0004?a\tP�\\x0017���\u007f@]ۺ�\\x0005\\x0007��7\\x0006\\x000e���\\x0019�,�D[�n���_)��X�w��&^���3l����'�~h?��O\\x0011�H����΅\\x001c��ޕ�Bi|��>\\x0007\u007f:�-QY(\\x0016
��A|��9��E��%&\\x0011�]�j\\x001c!��o�\\x000e�\\x0014�L�\\x0000j:\\x0008V:��]L����փԫ�o$\\x0003����KՆn��5�T_P�ͭ�w����l$\\x000fU���+vq\\x001e\\x001b& P\n7+���u9�\\x001e��tN����+\\x0003�X�R$\\,��{5\t�O
\n Reference:https://www.owasp.org/index.php/Top_10_2013-A6-Sensitive_Data_Exposure
http://projects.webappsec.org/w/page/13246936/Information%20Leakage
") + expect(finding.source).to eq("URI: http://api:9999/ Method: POST") + expect(finding.fingerprint).to eq("10094_http://api:9999/_POST") + expect(finding.appname).to eq("http://api:9999") + expect(finding.task).to eq("OWASP Zaproxy") + end + end + + context "snyk" do + let(:task) { get_dynamic_task_buildin_mapping "tools_samples/snyk.json", "snyk"} + subject(:task_findings) { task.findings } + before do + task.run + end + it "should produce one finding" do + should have(2).items + end + + it "should fill all the required fields" do + finding = subject[0] + expect(finding.severity).to eq(2) + expect(finding.description).to eq("Denial of Service (DoS)") + expect(finding.detail).to eq("description") + expect(finding.source).to eq("Microsoft.AspNetCore.All") + expect(finding.fingerprint).to eq("SNYK-DOTNET-MICROSOFTASPNETCOREALL-60258") + expect(finding.appname).to eq("dummy/obj") + expect(finding.task).to eq("Snyk") + end + end end diff --git a/spec/tasks/dynamic/targets/tools_samples/snyk.json b/spec/tasks/dynamic/targets/tools_samples/snyk.json new file mode 100644 index 0000000..6a3f757 --- /dev/null +++ b/spec/tasks/dynamic/targets/tools_samples/snyk.json @@ -0,0 +1,121 @@ +{ + "ok": false, + "vulnerabilities": [ + { + "title": "Denial of Service (DoS)", + "credit": [ + "Unknown" + ], + "packageName": "Microsoft.AspNetCore.All", + "language": "dotnet", + "packageManager": "nuget", + "description": "description", + "identifiers": { + "CWE": [ + "CWE-400" + ], + "CVE": [] + }, + "semver": { + "unaffected": "", + "vulnerable": "[,2.0.9), [2.1.0, 2.1.2)" + }, + "patches": [], + "cvssScore": 6.5, + "severity": "medium", + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "disclosureTime": "2018-07-18T21:00:00.000Z", + "publicationTime": "2018-07-26T11:23:24.744Z", + "modificationTime": "2018-07-25T11:23:46.125Z", + "creationTime": "2018-07-25T11:23:46.125Z", + "id": "SNYK-DOTNET-MICROSOFTASPNETCOREALL-60258", + "from": [ + "Microsoft.AspNetCore.All@2.0.5" + ], + "upgradePath": [], + "version": "2.0.5", + "name": "Microsoft.AspNetCore.All", + "isUpgradable": false, + "isPatchable": false + }, + { + "title": "Privilege Escalation", + "credit": [ + "Unknown" + ], + "language": "dotnet", + "packageManager": "nuget", + "packageName": "Microsoft.AspNetCore.HttpOverrides", + "description": "description", + "semver": { + "vulnerable": "[,2.0.2)", + "unaffected": "" + }, + "identifiers": { + "CVE": [ + "CVE-2018-0787" + ], + "CWE": [ + "CWE-20" + ] + }, + "patches": [], + "cvssScore": 8.8, + "severity": "high", + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", + "modificationTime": "2017-01-25T13:19:47.018Z", + "creationTime": "2017-01-25T13:19:47.018Z", + "disclosureTime": "2017-01-25T13:19:47.018Z", + "publicationTime": "2018-05-02T14:33:27.159Z", + "id": "SNYK-DOTNET-MICROSOFTASPNETCOREHTTPOVERRIDES-60238", + "from": [ + "Microsoft.AspNetCore.All@2.0.5" + ], + "upgradePath": [], + "version": "2.0.1", + "name": "Microsoft.AspNetCore.HttpOverrides", + "isUpgradable": false, + "isPatchable": false + } + ], + "dependencyCount": 322, + "org": "soluto-tel-aviv", + "licensesPolicy": { + "severities": { + "MS-RL": "medium", + "EPL-1.0": "medium", + "GPL-2.0": "high", + "GPL-3.0": "high", + "MPL-1.1": "medium", + "MPL-2.0": "medium", + "AGPL-1.0": "high", + "AGPL-3.0": "high", + "CDDL-1.0": "medium", + "LGPL-2.0": "medium", + "LGPL-2.1": "medium", + "LGPL-3.0": "medium", + "CPOL-1.02": "high", + "LGPL-2.1+": "medium", + "LGPL-3.0+": "medium", + "SimPL-2.0": "high", + "Artistic-1.0": "medium", + "Artistic-2.0": "medium" + } + }, + "isPrivate": true, + "packageManager": "nuget", + "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.12.0\nignore: {}\npatch: {}\n", + "ignoreSettings": { + "adminOnly": false, + "reasonRequired": true, + "disregardFilesystemIgnores": false + }, + "summary": "88 vulnerable dependency paths", + "filesystemPolicy": false, + "filtered": { + "ignore": [], + "patch": [] + }, + "uniqueCount": 18, + "path": "dummy/obj" +} diff --git a/spec/tasks/dynamic/targets/tools_samples/zaproxy.json b/spec/tasks/dynamic/targets/tools_samples/zaproxy.json new file mode 100644 index 0000000..57a6516 --- /dev/null +++ b/spec/tasks/dynamic/targets/tools_samples/zaproxy.json @@ -0,0 +1,12 @@ +{ + "@name": "http://api:9999", + "alerts": [ + { + "description": "Base64 encoded data was disclosed by the application/web server
", + "source": "URI: http://api:9999/ Method: POST", + "detail": "Base64 Disclosure \n Evidence: DxyPP_YQ6qdWluCCz93Xs1CeJPvg \n Solution:Manually confirm that the Base64 data does not leak sensitive information, and that the data cannot be aggregated/used to exploit other vulnerabilities.
\n Other info:\\x000f\\x001c�?�\\x0010�V���Re\\x000c��9�7C\\x001b \\x0011Ű�\\x0004?a\tP�\\x0017���\u007f@]ۺ�\\x0005\\x0007��7\\x0006\\x000e���\\x0019�,�D[�n���_)��X�w��&^���3l����'�~h?��O\\x0011�H����΅\\x001c��ޕ�Bi|��>\\x0007\u007f:�-QY(\\x0016
��A|��9��E��%&\\x0011�]�j\\x001c!��o�\\x000e�\\x0014�L�\\x0000j:\\x0008V:��]L����փԫ�o$\\x0003����KՆn��5�T_P�ͭ�w����l$\\x000fU���+vq\\x001e\\x001b& P\n7+���u9�\\x001e��tN����+\\x0003�X�R$\\,��{5\t�O
\n Reference:https://www.owasp.org/index.php/Top_10_2013-A6-Sensitive_Data_Exposure
http://projects.webappsec.org/w/page/13246936/Information%20Leakage
", + "severity": "Informational", + "fingerprint": "10094_http://api:9999/_POST" + } + ] +}