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

Fix bug with multiple signatures. #940

Merged
merged 14 commits into from
Feb 17, 2020
Merged

Conversation

wxsBSD
Copy link
Collaborator

@wxsBSD wxsBSD commented Aug 23, 2018

This fixes a bug with files that have multiple signatures. Turns out there are two ways to have multiple signatures.

  • Multiple WIN_CERTIFICATE structures. We currently support this.
  • A "hidden" nested signature inside the first signature. This patch fixes it so we properly handle this case.

The way it works is it makes the code which converts a PKCS7 structure into YARA module data into a function _parse_pkcs7() and then at the very end it checks if there is a "hidden" nested signature and recursively calls itself if one is found. That part of it is on line 1265, the rest of this diff is mostly just a copy/paste of the rest of the code into the recursive function.

I've tested this with the sample mentioned in #515 (d29e93c0fe4f108fa063e1a9692559a4278a0d51ab4feabbb231907dffaeb019) and it does properly parse both of them. I've also verified it by comparing it to what Windows says about the binary and it does indeed match.

Fixes #515.

@edeca
Copy link

edeca commented Aug 23, 2018

One thought - if you are calling _parse_pkcs7() recursively you might like to check the value of counter for something sane (e.g. 16) to prevent malicious binaries triggering resource exhaustion.

@wxsBSD
Copy link
Collaborator Author

wxsBSD commented Aug 23, 2018

I plan to implement a limit (16 seems reasonable) and may have uncovered a bug in it. I'll hunt it down and update this PR soon.

@wxsBSD
Copy link
Collaborator Author

wxsBSD commented Sep 4, 2018

I've uncovered a weird case here which I haven't had the time to fully understand, and may not be able to get to it this week. If anyone wants to take a look here's what I know. b605b216588fe454b76c51dbb407cc9e71f7b1932367d5557fcc296bd9f28d34 is a PE with 3 signatures (according to Windows). The three serial numbers are ‎30 63 b3 a7 40 c1 cd fd f8 bb 9e 6c 33 1a d7 de, ‎06 and ‎38 bf a6 1b 82 b8 0f 60 57 15 e4 8a a1 0d e1 53. This pull request is able to find the first two signatures but not the third one.

I'm hoping to get to this by the end of this week but if someone knows what is going on with this file I'd appreciate a pointer. :)

@plusvic
Copy link
Member

plusvic commented Dec 19, 2018

@wxsBSD is this PR ready to be merged?

@wxsBSD
Copy link
Collaborator Author

wxsBSD commented Dec 19, 2018

I’ve got some more work to do on this. Can you give me a couple of days, please? I’ll dedicate some time to it and hopefully have a better PR by Friday morning!

@plusvic
Copy link
Member

plusvic commented Dec 19, 2018

I’ve got some more work to do on this. Can you give me a couple of days, please? I’ll dedicate some time to it and hopefully have a better PR by Friday morning!

Sure, no hurries. I was just cleaning up the list of pending PRs a little bit.

@wxsBSD
Copy link
Collaborator Author

wxsBSD commented Dec 21, 2018

Sorry for the force push, but after spending too long fighting with openssl I'm not in the best of moods. ;)

This branch is ready to merge. It now parses the files with nested signatures better (tested on d29e93c0fe4f108fa063e1a9692559a4278a0d51ab4feabbb231907dffaeb019) and will stop parsing at 16 nested signatures. I also moved away from using the BIO interface in OpenSSL in favor of d2i_PKCS7 as it's less cumbersome to work with.

I spent entirely too long trying to get b605b216588fe454b76c51dbb407cc9e71f7b1932367d5557fcc296bd9f28d34 to parse correctly, and I'm giving up on it. As far as I can tell this is not a very common format and was only used by MSFT for a while, but I've been told they are moving away from it in favor of the multiple WIN_CERT format (see https://twitter.com/vathpela/status/1045389079473459200 for details). I'll give a rundown of the file in case anyone wants to pick up where I left off, but I'm not planning on fixing this problem because it's a pain and not likely to be problematic IMO.

The start of the WIN_CERT structure is at 0xe3000. The certificate contained in there has serial 30:63:b3:a7:40:c1:cd:fd:f8:bb:9e:6c:33:1a:d7:de and has a nested signature (OID 1.3.6.1.4.1.311.2.4.1). This diff allows parsing of the nested signature, which is actually an ASN1 sequence (basically a list?) of signatures. The sequence starts at 0xe48cc, with the first signature at 0xe48e0. This second signature has a serial of 06 and is parsed correctly with this patch. The problem I'm having is finding a way to parse the rest of the sequence. I can only ever get OpenSSL to recognize the first item in the sequence. The third signature (second in the sequence, the missing one I can't parse) starts at 0xe6000. According to Windows this should have a serial of ‎38:bf:a6:1b:82:b8:0f:60:57:15:e4:8a:a1:0d:e1:53. If anyone can figure out how to get that to parse I'd love to see how, but as I said above I'm frustrated enough with this and am not going to deal with it. :)

@wxsBSD
Copy link
Collaborator Author

wxsBSD commented Dec 21, 2018

Thank you to @recvfrom for showing me how to walk the X509 attributes! I'm able to now parse the 3rd signature from the file in question. This PR is now complete and brings YARA more in line with how MSFT is parsing authenticode signatures.

Move the nested signature checking out of the main certificate parsing loop. The
nested signatures are on the PKCS7 structure, not the certificate. Also, make
the loop better by not processing the same attribute over and over.

These were suggested by Andrew Williams.
If the nested signature is ever NULL, break early because it will always be
NULL. Also, tighten up the the checks for MAX_PE_CERTS. We aren't likely to ever
see a PE that hits the case where it has multiple certs in a single PKCS7 blob,
but it can't hurt to check in the loop too.
@plusvic plusvic added this to the v3.10 milestone Feb 22, 2019
@plusvic
Copy link
Member

plusvic commented May 2, 2019

@wxsBSD it looks like this is not compiling in Windows.

..\..\..\libyara\modules\pe.c(1128): error C2065: 'signer_info': undeclared identifier [C:\projects\yara\windows\vs2015\libyara\libyara.vcxproj]

Maybe the version of OpenSSL we are using in Windows doesn't have the PKCS7_SIGNER_INFO type.

@wxsBSD
Copy link
Collaborator Author

wxsBSD commented May 5, 2019

I’ll take a look tonight.

@wxsBSD
Copy link
Collaborator Author

wxsBSD commented May 6, 2019

I don't have a copy of VS 2017 handy to test on Windows, but I did manage to confirm the PKCS7_SIGNER_INFO structure is declared in the version of OpenSSL used by the Windows build. I did it by installing nuget on my OS X laptop and then fetching the OpenSSL source with nuget install YARA.OpenSSL.x64 -Version 1.1.0 -ConfigFile windows/vs2017/NuGet.Config and then checked and the PKCS7_SIGNER_INFO structure is declared in include/openssl/PKCS7.h. I'm not sure what is going on here...

Is it possible to get better build logs from appveyor? In particular can we get whatever the equivalent of "V=1 make" is on there? Maybe that will point us in a better direction for debugging?

@googlebot
Copy link

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here (e.g. I signed it!) and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

ℹ️ Googlers: Go here for more info.

@googlebot
Copy link

CLAs look good, thanks!

ℹ️ Googlers: Go here for more info.

@plusvic
Copy link
Member

plusvic commented Feb 17, 2020

It looks like this PR makes harder a future use of BoringSSL as a replacement of OpenSSL. BoringSSL doesn't implements any of the PKCS7 APIs and they don't plan to do it. So, we either forget about BoringSSL or keep this unfixed :(

@wxsBSD
Copy link
Collaborator Author

wxsBSD commented Feb 17, 2020

I’d rather see this fixed than switch to BoringSSL. I think accuracy in parsing is the more important thing here.

@recvfrom
Copy link

It'd be worth investigating how difficult it'd be to re-implement the functionality in this patch without using the PKCS7 functions... I'll aim to take a look sometime in the next few days unless someone beats me to it.

@plusvic
Copy link
Member

plusvic commented Feb 17, 2020

It'd be worth investigating how difficult it'd be to re-implement the functionality in this patch without using the PKCS7 functions... I'll aim to take a look sometime in the next few days unless someone beats me to it.

I don't think it's worth the effort, PKCS7 seems to be a very complicated format and parsing it is error-prone.

@plusvic
Copy link
Member

plusvic commented Feb 17, 2020

@wxsBSD I found out why the build is breaking in Appveyor. It turns out that wincrypt.h has the following macro definition which conflicts with the type defined by OpenSSL:

//+-------------------------------------------------------------------------
//  Predefined PKCS #7 data structures that can be encoded / decoded.
//--------------------------------------------------------------------------
#define PKCS7_SIGNER_INFO                   ((LPCSTR) 500)

Looking for the most elegant way for fixing this.

@plusvic
Copy link
Member

plusvic commented Feb 17, 2020

It looks like Wine had the same issue, they simply undefined those macros:
https://www.winehq.org/pipermail/wine-patches/2007-August/042510.html

@plusvic plusvic merged commit 264348b into VirusTotal:master Feb 17, 2020
@wxsBSD
Copy link
Collaborator Author

wxsBSD commented Feb 17, 2020

Ah, thanks for digging into this and merging it. As I’ve said before, I’m all for removing OpenSSL but I don’t want to sacrifice useful functionality or parsing accuracy.

@wxsBSD wxsBSD deleted the multi_signatures branch March 10, 2020 13:13
tarterp pushed a commit to mandiant/yara that referenced this pull request Mar 31, 2022
* Fix bug with multiple signatures.

* Don't use BIO interface, use d2i instead. Fix some other small bugs and don't recurse forever when parsing nested signatures.

* Walk the X509 attributes looking for nested signatures.

* Move variable declarations out of loop.

* Move nested signature checking out of the loop.

Move the nested signature checking out of the main certificate parsing loop. The
nested signatures are on the PKCS7 structure, not the certificate. Also, make
the loop better by not processing the same attribute over and over.

These were suggested by Andrew Williams.

* If the nested signature is NULL, break early.

If the nested signature is ever NULL, break early because it will always be
NULL. Also, tighten up the the checks for MAX_PE_CERTS. We aren't likely to ever
see a PE that hits the case where it has multiple certs in a single PKCS7 blob,
but it can't hurt to check in the loop too.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Parsing of multiple Authenticode signatures does not work
5 participants