From bb6e11582fb71386d338cbe85272041f0f59e849 Mon Sep 17 00:00:00 2001 From: John Andersen Date: Wed, 6 Jan 2021 16:16:10 -0800 Subject: [PATCH] checkers: README: Add signature finding quickstart Signed-off-by: John Andersen --- cve_bin_tool/checkers/README.md | 108 ++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/cve_bin_tool/checkers/README.md b/cve_bin_tool/checkers/README.md index 1f66cf6146..a4c51e204a 100644 --- a/cve_bin_tool/checkers/README.md +++ b/cve_bin_tool/checkers/README.md @@ -144,6 +144,114 @@ You can find these by- $ strings (path of the binary) | grep -i (product_name) ``` +### Quickstart for finding patterns + +What often helps is trying to find an `.rpm` (or more than one) or a package +which contains the product you're looking for. + +Searching on https://pkgs.org is a good place to start. + +For this example we'll be using `libvorbis`: https://pkgs.org/search/?q=libvorbis + +In the below example we picked fedora 33's package for version 1.3.7 of +libvorbis. We can extract the `.rpm` file using a combintation of +[rpm2cpio and cpio](https://www.cyberciti.biz/tips/how-to-extract-an-rpm-package-without-installing-it.html) +or using [rpmfile](https://pypi.org/project/rpmfile/). Sometimes you'll have +packages which come in `.deb` or .`tar` files. + +- `.deb` files can be extracted with `ar x somefile.deb && tar xvf data.tar.xz` + +- `.tar` files can be extrated using `tar` + +```console +$ curl -sfL 'https://download-ib01.fedoraproject.org/pub/fedora/linux/releases/33/Everything/x86_64/os/Packages/l/libvorbis-1.3.7-2.fc33.x86_64.rpm' | rpmfile -xv - +/tmp/tmp.U3wkntEqtD/usr/lib/.build-id/02/980384bc359497f0121fc74974e465ba7e29aa +/tmp/tmp.U3wkntEqtD/usr/lib/.build-id/1c/ff0ed918467a6224a5108793bf779e61486151 +/tmp/tmp.U3wkntEqtD/usr/lib/.build-id/75/8407ea857c63ae42c4d9959ad252de6fb9bcca +/tmp/tmp.U3wkntEqtD/usr/lib64/libvorbis.so.0 +/tmp/tmp.U3wkntEqtD/usr/lib64/libvorbis.so.0.4.9 +/tmp/tmp.U3wkntEqtD/usr/lib64/libvorbisenc.so.2 +/tmp/tmp.U3wkntEqtD/usr/lib64/libvorbisenc.so.2.0.12 +/tmp/tmp.U3wkntEqtD/usr/lib64/libvorbisfile.so.3 +/tmp/tmp.U3wkntEqtD/usr/lib64/libvorbisfile.so.3.3.8 +/tmp/tmp.U3wkntEqtD/usr/share/doc/libvorbis/AUTHORS +/tmp/tmp.U3wkntEqtD/usr/share/licenses/libvorbis/COPYING +``` + +Then look for which files you downloaded are binaries or libraries. We can use +the `file` command combined with the `find` command for this. The `find` +command will list every file in the directory we proivde to it (`.` in this +case) and execute any program we want using that filename. In this case we want +to run the `file` command on each file we get from `find`. + +We want to filter the output using `grep` to show us only executables (programs +you run) and shared objects (libaries programs use) using +`-E 'executable,|shared object,'` which is a regex which says to show lines that +`find` output if they have either `executable,` or `shared object,` in them. + +The final `tee` command in combination with `sed` is creating a new file called +`executables.txt` which has all the filenames in it. It does this by only +writing what comes before the `:` to the file that was in the output of the +`grep` command which looked for executables. + +```console +$ find . -exec file {} \; | grep -E 'executable,|shared object,' | tee >(sed -e 's/:.*//g' > executables.txt) +./usr/lib64/libvorbisfile.so.3.3.8: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=1cff0ed918467a6224a5108793bf779e61486151, stripped +./usr/lib64/libvorbisenc.so.2.0.12: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=02980384bc359497f0121fc74974e465ba7e29aa, stripped +./usr/lib64/libvorbis.so.0.4.9: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=758407ea857c63ae42c4d9959ad252de6fb9bcca, stripped +``` + +You'll want to run strings on those binaries and do a case insensitive search +for the package name using `grep -i`. + +```console +$ strings $(cat executables.txt) | sort | uniq | grep -i libvorbis +3?Xiph.Org libVorbis 1.3.7 +libvorbisenc.so.2 +libvorbisenc.so.2.0.12-1.3.7-2.fc33.x86_64.debug +libvorbisfile.so.3 +libvorbisfile.so.3.3.8-1.3.7-2.fc33.x86_64.debug +libvorbis.so.0 +libvorbis.so.0.4.9-1.3.7-2.fc33.x86_64.debug +Xiph.Org libVorbis I 20200704 (Reducing Environment) +``` + +You also my want to look for the version number. In this case it's `1.3.7`. + +```console +$ strings $(cat executables.txt) | sort | uniq | grep -i 1.3.7 +3?Xiph.Org libVorbis 1.3.7 +libvorbisenc.so.2.0.12-1.3.7-2.fc33.x86_64.debug +libvorbisfile.so.3.3.8-1.3.7-2.fc33.x86_64.debug +libvorbis.so.0.4.9-1.3.7-2.fc33.x86_64.debug +``` + +In this case the most interesting line in the output of the above two commands +is `3?Xiph.Org libVorbis 1.3.7`. We can probably use this to create a regex for +`VERSION_PATTERS`. + +That regex would might like this: `3\?Xiph.Org libVorbis ([0-9]+\.[0-9]+\.[0-9]+)` + +> If you can't get a signature match using just regex you may end up needing to +> overwrite the +> [`get_version()`](https://github.com/intel/cve-bin-tool/blob/master/cve_bin_tool/checkers/__init__.py#L120-L132) +> method for the checker, but that should be a last resort if you can't find a +> regex that works for `VERSION_PATTERNS`. +> +> A note about this example: +> In the case of libvorbis the versions containing +> [CVEs](https://www.cvedetails.com/product/11738/Libvorbis-Libvorbis.html?vendor_id=6970) +> are 1.2.0 and below. The `.rpm` we used for this example was from version +> 1.3.7. While this was a nice example for how one might find a signature, it +> in the end is not all the work that is needed to create a checker for +> libvorbis. We need to make sure that any checker we develop has a +> `get_version()` function which works for versions of the software which have +> CVEs. If not overridden in a subclass the Checker base class implements a +> `get_version()` method which will use regex to determine the version (as +> described above). In the case of libvorbis a custom `get_version()` function +> is likely needed, this is because the signature we found is not in the 1.2.0 +> version, where the CVE is found. + ### Finding Vendor Product pairs Every checker class must contain the vendor and product name pair(s)