Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add tests for ruby #168

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 40 additions & 33 deletions vulnerabilities/scraper/ruby.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,41 +37,48 @@ def get_patched_range(spec_list):
yield RangeSpecifier(spec)


def import_vulnerabilities():
vulnerability_package_dicts = []
for vulnerability in rubygem_advisories(RUBYSEC_DB_URL):
def load_vulnerability_package(vulnerability):
package_name = vulnerability.get(
'gem')

package_name = vulnerability.get(
'gem')
if not package_name:
return

if not package_name:
continue
if 'cve' in vulnerability:
vulnerability_id = 'CVE-{}'.format(vulnerability['cve'])
else:
return

if 'cve' in vulnerability:
vulnerability_id = 'CVE-{}'.format(vulnerability['cve'])
else:
continue
advisory_url = vulnerability.get('url')
patched_version_ranges = list(
get_patched_range(
vulnerability.get('patched_versions', [])))
all_versions = set(get_all_versions_of_package(package_name))
unaffected_versions = set()

if patched_version_ranges:
for version in all_versions:
for spec in patched_version_ranges:
if version in spec:
unaffected_versions.add(version)
break

affected_versions = all_versions - unaffected_versions

return {
'package_name': package_name,
'cve_id': vulnerability_id,
'fixed_versions': unaffected_versions,
'affected_versions': affected_versions,
'advisory': advisory_url
}


def import_vulnerabilities():
vulnerability_package_dicts = []
for vulnerability in rubygem_advisories(RUBYSEC_DB_URL):
package = load_vulnerability_package(vulnerability)
if package:
vulnerability_package_dicts.append(package)

advisory_url = vulnerability.get('url')
patched_version_ranges = list(
get_patched_range(
vulnerability.get('patched_versions', [])))
all_versions = set(get_all_versions_of_package(package_name))
unaffected_versions = set()

if patched_version_ranges:
for version in all_versions:
for spec in patched_version_ranges:
if version in spec:
unaffected_versions.add(version)
break

affected_versions = all_versions - unaffected_versions
vulnerability_package_dicts.append({
'package_name': package_name,
'cve_id': vulnerability_id,
'fixed_versions': unaffected_versions,
'affected_versions': affected_versions,
'advisory': advisory_url
})
return vulnerability_package_dicts
74 changes: 74 additions & 0 deletions vulnerabilities/tests/test_data/ruby.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
gem: actionpack
framework: rails
cve: 2016-0751
date: 2016-01-25
url: "https://groups.google.com/forum/#!topic/rubyonrails-security/9oLY_FCzvoc"

title: Possible Object Leak and Denial of Service attack in Action Pack

description: |
There is a possible object leak which can lead to a denial of service
vulnerability in Action Pack. This vulnerability has been
assigned the CVE identifier CVE-2016-0751.

Versions Affected: All.
Not affected: None.
Fixed Versions: 5.0.0.beta1.1, 4.2.5.1, 4.1.14.1, 3.2.22.1

Impact
------
A carefully crafted accept header can cause a global cache of mime types to
grow indefinitely which can lead to a possible denial of service attack in
Action Pack.

All users running an affected release should either upgrade or use one of the
workarounds immediately.

Releases
--------
The FIXED releases are available at the normal locations.

Workarounds
-----------
This attack can be mitigated by a proxy that only allows known mime types in
the Accept header.

Placing the following code in an initializer will also mitigate the issue:

```ruby
require 'action_dispatch/http/mime_type'

Mime.const_set :LOOKUP, Hash.new { |h,k|
Mime::Type.new(k) unless k.blank?
}
```

Patches
-------
To aid users who aren't able to upgrade immediately we have provided patches for
the two supported release series. They are in git-am format and consist of a
single changeset.

* 5-0-mime_types_leak.patch - Patch for 5.0 series
* 4-2-mime_types_leak.patch - Patch for 4.2 series
* 4-1-mime_types_leak.patch - Patch for 4.1 series
* 3-2-mime_types_leak.patch - Patch for 3.2 series

Please note that only the 4.1.x and 4.2.x series are supported at present. Users
of earlier unsupported releases are advised to upgrade as soon as possible as we
cannot guarantee the continued availability of security fixes for unsupported
releases.

Credits
-------
Aaron Patterson <3<3

cvss_v2: 5.0
cvss_v3: 7.5

patched_versions:
- ">= 5.0.0.beta1.1"
- "~> 4.2.5, >= 4.2.5.1"
- "~> 4.1.14, >= 4.1.14.1"
- "~> 3.2.22.1"
120 changes: 120 additions & 0 deletions vulnerabilities/tests/test_ruby.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Author: Islam ElHakmi (@EslamHiko)
# Copyright (c) 2017 nexB Inc. and others. All rights reserved.
# http://nexb.com and https://github.com/nexB/vulnerablecode/
# The VulnerableCode software is licensed under the Apache License version 2.0.
# Data generated with VulnerableCode require an acknowledgment.
#
# You may not use this software except in compliance with the License.
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
# derivative work, you must accompany this data with the following acknowledgment:
#
# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
# for any legal advice.
# VulnerableCode is a free software code scanning tool from nexB Inc. and others.
# Visit https://github.com/nexB/vulnerablecode/ for support and download.

import pytest
import os
from vulnerabilities.scraper.ruby import load_vulnerability_package
import saneyaml

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
TEST_DATA = os.path.join(BASE_DIR, 'test_data/')


@pytest.mark.webtest
def test_extract_data():
vulnerability = saneyaml.load(open(os.path.join(TEST_DATA, 'ruby.yml')))
package = load_vulnerability_package(vulnerability)
expected = {
'package_name': 'actionpack',
'cve_id': 'CVE-2016-0751',
'fixed_versions': {
'5.2.1.1', '5.0.4', '5.2.0.beta2', '4.2.8.rc1',
'3.2.22.3', '4.2.7', '5.1.7', '5.1.2.rc1', '3.2.22.5',
'4.2.11', '5.0.7.2', '4.1.14.1', '5.0.7', '5.0.3', '4.2.8',
'5.0.2', '4.2.6', '6.0.0.beta2', '5.0.0.rc1',
'5.2.4.1', '5.0.6.rc1', '4.2.10.rc1', '3.2.22.2', '5.2.3',
'4.2.10', '5.1.0.rc1', '6.0.1.rc1', '3.2.22',
'4.1.15.rc1', '5.2.0.beta1', '5.1.0.rc2', '5.0.2.rc1',
'5.1.0.beta1', '6.0.2.rc1', '3.2.22.4', '6.0.0.rc2',
'5.0.0.racecar1', '5.2.4.2', '5.0.1', '5.2.0.rc1', '6.0.0',
'5.0.1.rc1', '5.1.4', '4.2.5.1', '5.0.1.rc2',
'5.1.5.rc1', '5.0.5.rc1', '5.2.0', '5.0.7.1', '6.0.2.2',
'4.2.9', '5.0.0.beta1.1', '4.2.7.rc1', '5.1.0',
'5.2.2', '5.2.3.rc1', '5.1.3.rc3', '5.2.1.rc1', '4.2.9.rc2',
'5.1.3.rc2', '4.2.7.1', '5.0.0.1', '5.0.4.rc1',
'5.0.5', '6.0.2.1', '5.0.6', '5.1.3', '6.0.1', '5.1.5',
'5.0.0.rc2', '5.2.1', '4.1.16.rc1', '5.0.0', '6.0.0.beta1',
'5.2.4', '6.0.2', '5.1.2', '5.1.6.2', '5.1.1', '3.2.22.1',
'4.2.6.rc1', '4.1.15', '4.2.5.2', '5.2.0.rc2', '4.1.14.2',
'5.1.3.rc1', '5.1.7.rc1', '6.0.0.rc1', '4.2.11.1', '5.2.2.rc1',
'5.0.5.rc2', '5.2.4.rc1', '5.1.6.1', '4.1.16', '5.1.4.rc1',
'4.2.9.rc1', '6.0.2.rc2', '5.1.6', '5.2.2.1', '6.0.0.beta3'
},
'affected_versions': {
'4.1.0', '4.1.10.rc2', '2.0.5', '2.3.17', '3.2.12',
'4.2.5.rc1', '4.2.3', '3.2.13', '4.0.6.rc3',
'2.3.4', '1.13.4', '3.0.10.rc1', '4.1.11', '3.1.0',
'3.2.0', '4.0.1.rc3', '3.0.16', '3.0.2', '0.9.0', '3.2.13.rc1',
'3.1.7', '4.0.1.rc2', '4.0.6.rc1', '4.1.10.rc1', '2.1.1',
'3.2.14', '2.3.8.pre1', '1.13.2', '2.0.4', '3.1.0.beta1',
'3.1.2.rc2', '3.0.14', '3.2.8', '3.1.12', '1.3.1', '4.2.1.rc3',
'4.1.8', '3.0.15', '3.1.2.rc1', '4.0.1', '3.1.6',
'5.0.0.beta2', '2.1.0', '4.0.0.rc1', '4.0.7', '3.2.10',
'4.1.7.1', '4.1.2.rc3', '5.0.0.beta3', '3.2.15', '2.3.10',
'4.1.10.rc3', '4.1.1', '3.2.20', '4.2.5.rc2', '1.3.0',
'4.1.4', '3.0.5.rc1', '4.0.1.rc1', '4.1.0.rc1', '3.2.2.rc1',
'2.3.8', '4.1.0.beta1', '3.0.0.beta', '4.0.8', '2.0.1',
'1.5.1', '4.0.2', '4.1.3', '3.0.18', '1.10.2', '3.0.8.rc2',
'3.0.9.rc3', '1.8.0', '1.12.3', '4.0.10.rc1', '3.1.8',
'1.9.0', '4.2.4', '1.13.3', '4.1.2.rc1', '3.2.21', '4.0.11.1',
'3.0.0.beta4', '4.2.1.rc4', '4.1.12', '2.2.3', '4.2.3.rc1',
'3.0.5', '4.1.13', '2.3.9.pre', '3.0.6.rc2', '4.1.0.rc2',
'3.2.16', '3.2.3.rc1', '3.0.11', '0.9.5', '3.2.8.rc1', '3.2.3',
'4.0.12', '4.1.12.rc1', '3.1.1.rc3', '3.2.15.rc3', '3.0.6',
'4.1.0.beta2', '4.1.7', '4.2.0', '4.1.9', '3.2.9.rc2', '2.0.2',
'4.1.10', '4.0.1.rc4', '3.0.13', '4.1.2', '2.2.2', '4.2.4.rc1',
'3.0.9.rc1', '3.1.0.rc5', '4.1.5', '3.2.0.rc1', '4.0.0.beta1',
'3.0.8', '1.7.0', '3.0.9.rc4', '3.2.15.rc2', '4.2.0.rc3', '3.2.8.rc2',
'1.4.0', '2.3.16', '2.3.3', '3.1.5.rc1', '3.2.9', '1.0.0',
'4.2.0.beta4', '3.0.4', '3.0.7.rc1', '3.1.10', '1.10.1', '1.8.1', '2.3.11',
'3.1.0.rc4', '4.1.6', '5.0.0.beta1', '1.12.0', '1.12.4',
'2.3.6', '3.0.0.beta3', '3.2.17', '3.2.11', '4.1.14.rc2', '3.1.4.rc1', '4.1.14',
'3.0.3', '1.2.0', '4.0.4', '1.13.6', '1.9.1', '5.0.0.beta4',
'3.0.17', '3.0.19', '4.0.13.rc1', '2.3.18', '1.13.0', '2.3.7', '3.2.2',
'3.2.6', '4.0.10', '2.3.14', '4.0.13', '2.3.2', '3.0.9',
'3.1.5', '4.2.1.rc1', '4.2.0.rc1', '4.2.0.rc2', '3.1.11', '3.0.12', '3.2.14.rc2',
'3.0.0', '4.2.5', '3.0.13.rc1', '1.1.0', '4.1.10.rc4',
'3.2.18', '4.1.6.rc2', '3.0.6.rc1', '3.2.1', '3.0.9.rc5', '1.11.2', '4.0.6.rc2',
'3.0.10', '3.1.3', '4.0.6', '3.0.8.rc1', '3.1.2', '2.1.2',
'3.2.9.rc3', '3.2.4.rc1', '3.0.8.rc4', '3.0.4.rc1', '1.12.5', '3.0.1', '3.2.7.rc1',
'4.0.11', '3.0.12.rc1', '4.0.10.rc2', '3.1.1.rc2', '3.2.7',
'1.11.1', '2.3.15', '3.2.19', '3.1.9', '2.3.9', '4.1.9.rc1', '4.0.4.rc1',
'4.1.13.rc1', '4.2.1', '3.1.0.rc2', '1.12.1', '4.0.9',
'1.12.2', '3.1.0.rc1', '1.13.5', '1.6.0', '2.3.12', '4.2.1.rc2',
'4.0.0', '3.2.13.rc2', '3.0.0.beta2', '3.2.3.rc2', '3.2.4',
'3.2.14.rc1', '3.2.9.rc1', '4.0.0.rc2', '3.1.4', '3.0.20',
'1.11.0', '1.0.1', '3.2.5', '4.2.0.beta1', '3.0.7', '3.1.1',
'2.0.0', '4.2.0.beta3', '3.1.0.rc8', '4.0.3', '2.3.5',
'3.1.0.rc3', '3.1.1.rc1', '4.0.5', '1.5.0', '3.0.7.rc2',
'4.2.0.beta2', '1.13.1', '4.1.2.rc2', '3.0.0.rc2', '3.0.0.rc',
'3.1.0.rc6', '4.1.14.rc1', '4.2.2', '3.2.0.rc2', '4.1.6.rc1', '3.2.15.rc1'
},
'advisory': 'https://groups.google.com/forum/#!topic/rubyonrails-security/9oLY_FCzvoc'
}
assert expected['package_name'] == package['package_name']
assert expected['cve_id'] == package['cve_id']
assert expected['advisory'] == package['advisory']
# Check if expected affected version and fixed version is subset of what we get from online
assert set(expected['fixed_versions']) <= set(package['fixed_versions'])
assert set(expected['affected_versions']) <= set(
package['affected_versions'])