-
Notifications
You must be signed in to change notification settings - Fork 13.8k
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
Always use module cache for searching #13998
Always use module cache for searching #13998
Conversation
@@ -57,7 +57,6 @@ class Module | |||
include Msf::Module::Options | |||
include Msf::Module::Privileged | |||
include Msf::Module::Ranking | |||
include Msf::Module::Search |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is dead, and was only being used by tests
# {"platform"=>[["android"], []]} will match modules targeting the android platform | ||
# {"platform"=>[[], ["android"]]} will exclude modules targeting the android platform | ||
# | ||
def self.parse_search_string(search_string) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the existing parse string functionality lifted from command_dispatcher/modules.rb
describe '#search_filter' do | ||
require 'spec_helper' | ||
|
||
RSpec.describe Msf::Modules::Metadata::Search do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've decided to port over the existing slow search tests and I've tried to keep as close to the original specification as I could, to ensure there was no unintentional regressions introduced. In a future PR I'll most likely expand/change these tests.
it "should reject a query containing '-#{query}'" do | ||
expect(subject.search_filter("-#{query}")).to be_truthy | ||
it "should reject an inverse query containing of '#{query}'" do | ||
expect(find(inverse_query_terms(query))).to be_empty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new search cache has stricter validation, this test was previously producing invalid query strings which aren't supported by the search mechanism such as:
-os:osx
For the scope of these tests, the new inverse_query_terms
just needs to support the translation to negating terms:
os:-osx
end | ||
|
||
unless opts.has_key?(:test_inverse) and not opts[:test_inverse] | ||
it "should accept a query containing '-#{query}'" do | ||
expect(subject.search_filter("-#{query}")).to be_truthy # what? why? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expect(subject.search_filter("-#{query}")).to be_truthy # what? why?
I've updated this to verify the exact module that's been returned, rather than using be_truthy
@@ -72,65 +107,63 @@ | |||
end | |||
|
|||
context 'on a module with the author "joev"' do | |||
let(:opts) { ({ 'Author' => ['joev'] }) } | |||
let(:opts) { ({ 'author' => ['joev'] }) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously these opts were used to hydrate a module, now they're hydrating the search cache - as a result I've had to update some of the keys.
# | ||
# Searches the module metadata using the passed hash of search params | ||
# | ||
def find(params, fields={}) | ||
raise ArgumentError if params.empty? || VALID_PARAMS.none? { |k| params.key?(k) } | ||
raise ArgumentError if params.any? && VALID_PARAMS.none? { |k| params.key?(k) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An empty search query will now result in all modules being returned, which aligns with the previous search functionality offered by framework's slow search / the old rpc search - #8606
The console never went down this path, as there's a guard clause in the dispatcher:
metasploit-framework/lib/msf/ui/console/command_dispatcher/modules.rb
Lines 411 to 418 in 2e887a8
if args.empty? | |
if @module_search_results.empty? | |
cmd_search_help | |
return false | |
end | |
cached = true | |
end |
So this feels like a safe/valid change to make 🤞
ad020b2
to
baa33df
Compare
# {"platform"=>[[], ["android"]]} will exclude modules targeting the android platform | ||
# | ||
def self.parse_search_string(search_string) | ||
search_string += ' ' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure why you're adding a space to the end of this only to split on spaces on the next line, it doesn't make a difference right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was copied from the original implementation, I noticed this problem on the RPC service, with the input:
author:egypt arch:x64
This parsing method gives the following result:
=> {"author"=>[["egypt arch:x64"], []]}
With the extra space appended, it gives the expected result of:
=> {"author"=>[["egypt"], []], "arch"=>[["x64"], []]}
I'll add a unit test to make sure this scenario is caught correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests added. The tests were red without this line:
Failure/Error: it { expect(described_class.parse_search_string("author:egypt arch:x64")).to eq({"author"=>[["egypt"], []], "arch"=>[["x64"], []]}) }
expected: {"arch"=>[["x64"], []], "author"=>[["egypt"], []]}
got: {"author"=>[["egypt arch:x64"], []]}
(compared using ==)
Diff:
@@ -1,3 +1,2 @@
-"arch" => [["x64"], []],
-"author" => [["egypt"], []],
+"author" => [["egypt arch:x64"], []],
And now it's green with the line added back in 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def parse_search_string(search_string) |
isn't this where you got the code from? unless I'm missing something no space is being added to the search term
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The addition of the space is from the slow search that I'm unifying:
metasploit-framework/lib/msf/core/module/search.rb
Lines 12 to 16 in 9bd98f9
def search_filter(search_string) | |
return false if not search_string | |
search_string += " " | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah gotcha, that one has a guard clause, does that need added in here too? or are we stopping nil being passed in from elsewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's technically possible to provide nil
via a message pack rpc call. I've updated this to handle nil, and added tests for an entirely empty string too. A nil search string will now result in empty search params, and thus return all modules.
341ca70
to
0491d34
Compare
0491d34
to
f8523cb
Compare
Release notesGreatly improved the performance of Metasploit Framework's |
This pull request updates the slow module search to use the module cache.
Verification
1 - Console search
Open the console, and ensure that normal search functionality works as expected:
2 - rpcd
Create an instance of msfrpcd in one tab:
In another create the client:
Ensure search works as expected, and aligns with the existing msfconsole search functionality:
3 - json web service
The existing webservice should not be impacted by this code change, but for a sanity check - run the service with:
Run some search queries: