Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upAuthenticode verification support for Windows (similar to the 'signature' table on macOS) #3716
Conversation
|
@alessandrogario has updated the pull request. View: changes |
|
@alessandrogario has updated the pull request. View: changes |
|
I'd recommend creating an |
|
@theopolis sure! I'm still writing the utilities I need, as I also want to be able to list signature information like signer name etc. Once it's done, I'll create the new table; how would you like it to work? Should it just list the running executables? |
Check out the |
|
@alessandrogario has updated the pull request. |
1 similar comment
|
@alessandrogario has updated the pull request. |
|
I have defined a 'signature' virtual table for Windows; it only sports two columns for now, but I plan on adding more. I'm using a more verbose field instead of the 'signed' boolean used in the macOS implementation. The following are the possible states:
EDIT: I should probably put this information in the summary! |
|
A couple of smaller nits and a question about the Otherwise super excited for this table to land! |
| case SignatureInformation::Result::Untrusted: { | ||
| row["result"] = "untrusted"; | ||
| break; | ||
| } |
muffins
Sep 29, 2017
Contributor
perhaps you could default to unknown or -1?
perhaps you could default to unknown or -1?
alessandrogario
Sep 29, 2017
Author
Contributor
Done!
Done!
| return row; | ||
| } | ||
|
|
||
| Status toUtf16String(std::wstring& output, const std::string& s) { |
muffins
Sep 29, 2017
Contributor
We have a stringToWstring function already implemented here that you could use, but this looks good -- any chance you could take a look at our implementation to see if it could stand some improvements? ;)
We have a stringToWstring function already implemented here that you could use, but this looks good -- any chance you could take a look at our implementation to see if it could stand some improvements? ;)
alessandrogario
Sep 29, 2017
Author
Contributor
They look similar! I am now using that one!
They look similar! I am now using that one!
| if (status.ok()) { | ||
| results.push_back(r); | ||
| } else { | ||
| LOG(ERROR) << status.getMessage(); |
muffins
Sep 29, 2017
Contributor
ERROR seems a bit intense for a failure to compute the signature of an executable, maybe this could be a WARNING instead? I think we try and reserve ERROR for something which would halt the daemon itself.
ERROR seems a bit intense for a failure to compute the signature of an executable, maybe this could be a WARNING instead? I think we try and reserve ERROR for something which would halt the daemon itself.
| ]) | ||
| implementation("signature@generateQueryResults") | ||
| examples([ | ||
| "select * from signature where path = 'C:\\Windows\\notepad.exe'", |
muffins
Sep 29, 2017
Contributor
Would you mind adding in an example that joins off of the process table just to show up the extra cool features? :D
Would you mind adding in an example that joins off of the process table just to show up the extra cool features? :D
alessandrogario
Sep 29, 2017
Author
Contributor
Done! I've added a simple example in the table specs, and also edited the PR summary to include a couple of more (that we can probably add to the docs once this is merged).
Done! I've added a simple example in the table specs, and also edited the PR summary to include a couple of more (that we can probably add to the docs once this is merged).
| Result result; | ||
| }; | ||
|
|
||
| Row& operator<<(Row& row, const SignatureInformation& signature_info) { |
muffins
Sep 29, 2017
Contributor
While this is pretty awesome how you're making use of the << on Rows, I'm honestly not sure how to feel about it as it seems dangerous to overload an operator on a data structure that gets used in so many places in this high of namespace - /CC @theopolis to potentially put my worries to rest, but are there potentially other (arguably less awesome) ways to achieve the same behavior?
While this is pretty awesome how you're making use of the << on Rows, I'm honestly not sure how to feel about it as it seems dangerous to overload an operator on a data structure that gets used in so many places in this high of namespace - /CC @theopolis to potentially put my worries to rest, but are there potentially other (arguably less awesome) ways to achieve the same behavior?
|
@alessandrogario has updated the pull request. View: changes |
|
@alessandrogario has updated the pull request. View: changes |
|
@alessandrogario has updated the pull request. View: changes |
|
@alessandrogario has updated the pull request. View: changes |
|
@alessandrogario has updated the pull request. View: changes |
|
@alessandrogario has updated the pull request. |
|
|
||
| namespace osquery { | ||
| // These are defined in osquery/core/windows/wmi.cpp | ||
| std::wstring stringToWstring(const std::string& src); |
theopolis
Oct 4, 2017
Member
Are these not in a header somewhere?
Are these not in a header somewhere?
| // clang-format on | ||
|
|
||
| #include <osquery/core.h> | ||
| #include <osquery/core/conversions.h> |
theopolis
Oct 4, 2017
Member
This should be in it's own include block (double new line separated) and included using the local search:
#include "osquery/core/conversions.h"
This should be in it's own include block (double new line separated) and included using the local search:
#include "osquery/core/conversions.h"
| return Status(0, "Ok"); | ||
| } | ||
|
|
||
| QueryData generateQueryResults(QueryContext& context) { |
theopolis
Oct 4, 2017
Member
Can you use a more specific symbol name here? genAuthenticode or something similar?
Can you use a more specific symbol name here? genAuthenticode or something similar?
Dismissing as my review is dated. Will review again after the changes requested by @theopolis are addressed.
|
@alessandrogario has updated the pull request. |
|
@alessandrogario has updated the pull request. View: changes |
| &certificate_context->pCertInfo->SerialNumber; | ||
|
|
||
| std::stringstream serial_number_string; | ||
| for (DWORD i = serial_number->cbData - 1; i < serial_number->cbData; i--) { |
theopolis
Oct 10, 2017
Member
Can you explain this loop?
Can you explain this loop?
alessandrogario
Oct 10, 2017
Author
Contributor
This is used to print the serial number backwards (as it is shown in the Authenticode dialog properties of Windows).
Since DWORD is unsigned, the loop uses the fact that according to the standard the value will wrap around once you decrement past zero.
This is used to print the serial number backwards (as it is shown in the Authenticode dialog properties of Windows).
Since DWORD is unsigned, the loop uses the fact that according to the standard the value will wrap around once you decrement past zero.
| return false; | ||
| } | ||
|
|
||
| std::string buffer; |
theopolis
Oct 10, 2017
Member
You can create the buffer with a requested container size in the ctor
You can create the buffer with a requested container size in the ctor
|
ok to test |
| Column("issuer_name", TEXT, "The certificate issuer name"), | ||
| Column("subject_name", TEXT, "The certificate subject name"), | ||
| Column("result", TEXT, "The signature check result") | ||
| ]) |
theopolis
Oct 12, 2017
Member
Can we morph fields from darwin or windows such that we can have a unified signature table?
schema([
Column("path", TEXT, "Must provide a path or directory", required=True),
Column("signed", INTEGER, "1 If the file is signed else 0"),
Column("identifier", TEXT, "The signing identifier sealed into the signature"),
Column("cdhash", TEXT, "SHA1 hash of the application Code Directory"),
Column("team_identifier", TEXT, "The team signing identifier sealed into the signature"),
Column("authority", TEXT, "Certificate Common Name"),
])
path cool!
original_program_name can this be called identifier on both?
serial_number, issuer_name, subject_name can be extended schema on Windows for now.
cdhash does this checksum have an authenticode equivalent?
result can stay on both, maybe on darwin we fill this in with "signed" or "unknown"
signed being a boolean should be included here, it should indicate if the binary is properly signed.
Can we morph fields from darwin or windows such that we can have a unified signature table?
schema([
Column("path", TEXT, "Must provide a path or directory", required=True),
Column("signed", INTEGER, "1 If the file is signed else 0"),
Column("identifier", TEXT, "The signing identifier sealed into the signature"),
Column("cdhash", TEXT, "SHA1 hash of the application Code Directory"),
Column("team_identifier", TEXT, "The team signing identifier sealed into the signature"),
Column("authority", TEXT, "Certificate Common Name"),
])
pathcool!original_program_namecan this be calledidentifieron both?serial_number,issuer_name,subject_namecan be extended schema on Windows for now.cdhashdoes this checksum have an authenticode equivalent?resultcan stay on both, maybe on darwin we fill this in with "signed" or "unknown"signedbeing a boolean should be included here, it should indicate if the binary is properly signed.
theopolis
Oct 12, 2017
Member
The reason that the build is breaking in the CI is because there are two specfiles named signature. This is not allowed.
The reason that the build is breaking in the CI is because there are two specfiles named signature. This is not allowed.
alessandrogario
Oct 12, 2017
Author
Contributor
original_program_name: I have renamed this to "identifier".
cdhash: There is something but to grab it you need to parse the PE header and locate the PKCS#7 structure that contains the hash. There is really no easy way to calculate it without a custom tool (and it's hard to use this value in a meaningful way) so I skipped it.
result: I'll add this column to the darwin schema, and set it to "signed" when "signed" is 1 and to "unknown" when it is 0.
signed: Should this value be 1 only when the signature is both valid and trusted?
What should I do with the remaining fields? Should both specfiles (darwin and Windows) contain the exact same columns?
original_program_name: I have renamed this to "identifier".
cdhash: There is something but to grab it you need to parse the PE header and locate the PKCS#7 structure that contains the hash. There is really no easy way to calculate it without a custom tool (and it's hard to use this value in a meaningful way) so I skipped it.
result: I'll add this column to the darwin schema, and set it to "signed" when "signed" is 1 and to "unknown" when it is 0.
signed: Should this value be 1 only when the signature is both valid and trusted?
What should I do with the remaining fields? Should both specfiles (darwin and Windows) contain the exact same columns?
theopolis
Oct 13, 2017
Member
Leave the fields blank if there are no meaningful compromises/merging options.
You can add "extended" schema like:
extended_schema(WINDOWS, [
Column("friendly_name", TEXT, "The friendly display name of the interface."),
])
The first option is the requirement. These columns will be set to HIDDEN on platforms that do not match. Such that a SELECT * does not return them.
Your options for evaluators right now are: WINDOWS, LINUX, POSIX, DARWIN, FREEBSD. They are small functions defined in gentable.py.
Leave the fields blank if there are no meaningful compromises/merging options.
You can add "extended" schema like:
extended_schema(WINDOWS, [
Column("friendly_name", TEXT, "The friendly display name of the interface."),
])
The first option is the requirement. These columns will be set to HIDDEN on platforms that do not match. Such that a SELECT * does not return them.
Your options for evaluators right now are: WINDOWS, LINUX, POSIX, DARWIN, FREEBSD. They are small functions defined in gentable.py.
|
@alessandrogario has updated the pull request. |
|
@alessandrogario has updated the pull request. |
|
LGTM, @muffins I'll let you have the final look and merge when you're ready. |
|
LGTM |
Goal
This PR aims to add Authenticode verification support to osquery in a similar way to the 'signature' virtual table that has been implemented for macOS.
Changes
I have defined a signature virtual table for Windows, containing the following columns: path, original_program_name (from the publisher), serial_number, issuer_name, subject_name, result.
The following are the possible values for the result column:
Examples
Verifying the authenticode signature for running executables
Listing unsigned/untrusted processes listening for connections