nilp0inter / cpe

CPE: Common Platform Enumeration for Python
GNU Lesser General Public License v3.0
92 stars 30 forks source link

CPEs with just one (or very few?) (wfn) attributes will cause wrong 2.3 uris #28

Open TauPan opened 8 years ago

TauPan commented 8 years ago

We import a (non-official) dictionary from a corporate security advisory service provider, which contains some generic cpes that just have vendor, product or version set.

(No idea for what internal purpose they're being used at the vendor, but if we import them, they land in our (customers) database.)

I'll work on a PR for this today, but first I wanted to give you a description of the behaviour we see.

(with python 2 in current 1.2.0)

cpe_uri2_3_test.py:

#!/bin/env python
import cpe
import cpe.cpe2_3_uri
for uri in """
cpe:/a
cpe:/:vendor
cpe:/::product
cpe:/:::version
cpe:/::::update
cpe:/:::::edition
cpe:/:::::~edition~sw_edition~target_sw~target_hw~other
cpe:/:::::~~~~target_hw~
cpe:/::::::en
""".split():
    c = cpe.cpe2_3_uri.CPE2_3_URI(uri)
    print(("original uri: \"{uri}\":\n"
           "    as wfn: {wfn},\n"
           "    as uri_2_3: \"{uri2_3}\"\n").format(
               uri=uri,
               wfn=c.as_wfn(),
               uri2_3=c.as_uri_2_3()))

Outputs:

original uri: "cpe:/a":
    as wfn: wfn:[part="a"],
    as uri_2_3: "::::cpe:/a"

original uri: "cpe:/:vendor":
    as wfn: wfn:[part=ANY, vendor="vendor"],
    as uri_2_3: "cpe:/::::vendor"

original uri: "cpe:/::product":
    as wfn: wfn:[part=ANY, vendor=ANY, product="product"],
    as uri_2_3: "cpe:/::product"

original uri: "cpe:/:::version":
    as wfn: wfn:[part=ANY, vendor=ANY, product=ANY, version="version"],
    as uri_2_3: "cpe:/:::version"

original uri: "cpe:/::::update":
    as wfn: wfn:[part=ANY, vendor=ANY, product=ANY, version=ANY, update="update"],
    as uri_2_3: "cpe:/::::update"

original uri: "cpe:/:::::edition":
    as wfn: wfn:[edition="edition"],
    as uri_2_3: "::::cpe:/:edition"

original uri: "cpe:/:::::~edition~sw_edition~target_sw~target_hw~other":
    as wfn: wfn:[part=ANY, vendor=ANY, product=ANY, version=ANY, update=ANY, edition="edition", sw_edition="sw_edition", target_sw="target_sw", target_hw="target_hw", other="other"],
    as uri_2_3: "cpe:/:::::~edition~sw_edition~target_sw~target_hw~other"

original uri: "cpe:/:::::~~~~target_hw~":
    as wfn: wfn:[part=ANY, vendor=ANY, product=ANY, version=ANY, update=ANY, edition=ANY, sw_edition=ANY, target_sw=ANY, target_hw="target_hw", other=ANY],
    as uri_2_3: "cpe:/:::::~~~~target_hw~"

original uri: "cpe:/::::::en":
    as wfn: wfn:[part=ANY, vendor=ANY, product=ANY, version=ANY, update=ANY, edition=ANY, language="en"],
    as uri_2_3: "cpe:/::::::en"

I'll try to come up with testcases and PR later today (since I know your time is constrained and we'd like this to work soonish).

TauPan commented 8 years ago

(Also I'm not sure if the wfn for just the legacy edition is correct. I'm trying to make sense of NISTIR 7695 if the ANY values in the wfn string are required or not. You seem to assume they are required, at least they're consistently present in every other case.)

nilp0inter commented 7 years ago

Hi, sorry for the long delay, I'm not having much time lately for maintaining the package. I've merged #29 and uploaded version 1.2.1. I've seen the tests marked as xfail, but I don't know what should be the proper behavior here. Maybe @galindale can help here...

galindale commented 7 years ago

Hi,

I'm afraid the current implementation of the cpe library about WFN to URI conversion is wrong. In the second step of the section 6.1.3.1 called "Summary of algorithm", the standard specification (NISTIR-7695-CPE-Naming) says:

For URI components 1-5 and 7, decode the string and set the corresponding WFN attribute value. Decoding entails: converting sole "" to ANY, sole "-" to NA, adding quoting to embedded periods and hyphens, and decoding percent-encoded forms.

Therefore, the part, vendor, product, version, update and language components must always appear in the WFN although they are empty. The edition component WFN value depends on if its URI value is packed or not.

For example, the correct WFN of URI "cpe:/a" is:

wfn:[part="a", vendor=ANY, product=ANY, version=ANY, update=ANY, edition=ANY, language=ANY]

not:

wfn:[part="a"]

It's necessary to review the implementation of converter from URI to WFN with CPEs version 2.3.

For instance, I saw that in the line 383 of cpe2_3_uri module there is a wrong continue statement (the attribute is not set) instead of setting ANY value with "v.append(CPEComponent2_3_WFN.VALUE_ANY)".

In the case of binding a WFN to a URI some components can disappear if they have empty values. For example:

wfn:[part="a",vendor="microsoft",product="internet_explorer",version="8\.0\.6001",update="beta",edition=ANY]

binds to the following URI (edition part is missing because trailing colons are removed):

cpe:/a:microsoft:internet_explorer:8.0.6001:beta

I hope my explanation helps you @TauPan. Thank you very much for your pull request and your tests.

TauPan commented 7 years ago

Hm, interesting. Thanks @galindale for pointing out how the reference implementation works.

However I see in Section 5.2 (WFN Attributes): Each permitted attribute MAY be used at most once in a WFN. If an attribute is not used in a WFN, it is said to be unspecified, and its value SHALL default to the logical value ANY (cf. 5.3.1)

So it appears the current implementation conforms to that statement. I think it's a design choice if you want to conform to the reference implementation which is more strict (i.e. not omitting any attributes) or if you want to conform to the more lenient statement that omitting attributes in a wfn is permissible.