|
| 1 | +#!/usr/local/bin/python |
| 2 | + |
| 3 | +## |
| 4 | +## Application Security Threat Attack Modeling (ASTAM) |
| 5 | +## |
| 6 | +## Copyright (C) 2017 Applied Visions - http://securedecisions.com |
| 7 | +## |
| 8 | +## Written by Aspect Security - http://aspectsecurity.com |
| 9 | +## |
| 10 | +## Licensed under the Apache License, Version 2.0 (the "License"); |
| 11 | +## you may not use this file except in compliance with the License. |
| 12 | +## You may obtain a copy of the License at |
| 13 | +## |
| 14 | +## http://www.apache.org/licenses/LICENSE-2.0 |
| 15 | +## |
| 16 | +## Unless required by applicable law or agreed to in writing, software |
| 17 | +## distributed under the License is distributed on an "AS IS" BASIS, |
| 18 | +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 19 | +## See the License for the specific language governing permissions and |
| 20 | +## limitations under the License. |
| 21 | +## |
| 22 | + |
| 23 | +""" |
| 24 | +CommandLineUtils.py |
| 25 | +
|
| 26 | +XssMap.py command line input utilities, including JSON config file parsing |
| 27 | +and traditional argument parsing |
| 28 | +""" |
| 29 | + |
| 30 | +import json |
| 31 | +import time |
| 32 | + |
| 33 | +def __print_command_line_usage(): |
| 34 | + """ |
| 35 | + (Private) Print XssMap.py command line usage |
| 36 | + """ |
| 37 | + |
| 38 | + print('usage : python XssMap.py myparams.json outputname.json') |
| 39 | + print(' inputs "json_version" (float, currently 1.00 supported),') |
| 40 | + print(' "request_type" (str), request_url" (str),') |
| 41 | + print(' "request_type" (str), "do_reflect" (bool),') |
| 42 | + print(' "do_xss" (bool),') |
| 43 | + print(' "headers" (list of objects with "name" and "value" fields),') |
| 44 | + print(' "cookies" (list of objects with "name" and "value" fields)') |
| 45 | + print('OR can use command line args for GET request targets only') |
| 46 | + print(' python XssMap.py url -x|r -c <cookies> -h <headers>') |
| 47 | + print(' url : target url, all arguments after this are optional...') |
| 48 | + print(' -t : put request type after, default is "GET", can also "POST"') |
| 49 | + print(' -b : put request body string after') |
| 50 | + print(' -x : only do xss scanning') |
| 51 | + print(' -r : only do reflection checking') |
| 52 | + print(' -h : put headers after, like header1=value1 header2=value2') |
| 53 | + print(' -c : put cookies after, like cookie1=value1 cookie2=value2') |
| 54 | + exit() |
| 55 | + |
| 56 | +def __parse_json_input(json_version, arg_array): |
| 57 | + """ |
| 58 | + (Private) Parses XssMap.py input / startup params from a JSON file. |
| 59 | +
|
| 60 | + Args: |
| 61 | + json_version (float) |
| 62 | + arg_array (list) |
| 63 | +
|
| 64 | + Returns: |
| 65 | + request_type (str) |
| 66 | + request_url (str) |
| 67 | + request_body (str) |
| 68 | + do_reflect (bool) |
| 69 | + do_xss (bool) |
| 70 | + headers (list) |
| 71 | + cookies (list) |
| 72 | + """ |
| 73 | + |
| 74 | + request_type = 'GET' |
| 75 | + request_url = None |
| 76 | + request_body = None |
| 77 | + do_reflect = True |
| 78 | + do_xss = True |
| 79 | + headers = [] |
| 80 | + cookies = [] |
| 81 | + |
| 82 | + with open(arg_array[1]) as json_data: |
| 83 | + |
| 84 | + d = json.load(json_data) |
| 85 | + |
| 86 | + if 'json_version' in d: |
| 87 | + if d['json_version'] != json_version: |
| 88 | + raise RuntimeError('Supported JSON version is ' + str(json_version)) |
| 89 | + |
| 90 | + if 'request_type' in d: |
| 91 | + request_type = d['request_type'] |
| 92 | + |
| 93 | + # This is the one param we really require |
| 94 | + if 'request_url' in d: |
| 95 | + request_url = d['request_url'] |
| 96 | + else: |
| 97 | + raise RuntimeError('Missing "request_url" param field in JSON config file.') |
| 98 | + |
| 99 | + if 'request_body' in d: |
| 100 | + request_body = d['request_body'] |
| 101 | + |
| 102 | + if 'do_reflect' in d: |
| 103 | + do_reflect = d['do_reflect'] |
| 104 | + |
| 105 | + if 'do_xss' in d: |
| 106 | + do_xss = d['do_xss'] |
| 107 | + |
| 108 | + if 'headers' in d: |
| 109 | + for header_dump in d['headers']: |
| 110 | + header_name = header_dump['name'] |
| 111 | + header_val = header_dump['value'] |
| 112 | + header = header_name, header_val |
| 113 | + headers.append(header) |
| 114 | + |
| 115 | + if 'cookies' in d: |
| 116 | + for cookie_dump in d['cookies']: |
| 117 | + cookie_name = cookie_dump['name'] |
| 118 | + cookie_val = cookie_dump['value'] |
| 119 | + cookie = cookie_name, cookie_val |
| 120 | + cookies.append(cookie) |
| 121 | + |
| 122 | + return request_type, request_url, request_body, do_reflect, do_xss, headers, cookies |
| 123 | + |
| 124 | +def __parse_cli_input(arg_array): |
| 125 | + """ |
| 126 | + (Private) Parses XssMap.py input / startup params from command line args. |
| 127 | +
|
| 128 | + Args: |
| 129 | + arg_array (list) |
| 130 | +
|
| 131 | + Returns: |
| 132 | + request_type (str) |
| 133 | + request_url (str) |
| 134 | + request_body (str) |
| 135 | + do_reflect (bool) |
| 136 | + do_xss (bool) |
| 137 | + headers (list) |
| 138 | + cookies (list) |
| 139 | + """ |
| 140 | + |
| 141 | + request_type = 'GET' |
| 142 | + request_url = None |
| 143 | + request_body = None |
| 144 | + do_reflect = True |
| 145 | + do_xss = True |
| 146 | + cookies = [] |
| 147 | + headers = [] |
| 148 | + |
| 149 | + idx = 1 |
| 150 | + while idx < len(arg_array): |
| 151 | + arg = arg_array[idx] |
| 152 | + if idx == 1: |
| 153 | + request_url = arg_array[1] |
| 154 | + idx = idx + 1 |
| 155 | + elif arg.lower() == '-v': |
| 156 | + # If we encounter verbose flag, ignore for now |
| 157 | + pass |
| 158 | + elif arg.lower() == '-r': |
| 159 | + do_xss = False |
| 160 | + idx = idx + 1 |
| 161 | + elif arg.lower() == '-x': |
| 162 | + do_reflect = False |
| 163 | + idx = idx + 1 |
| 164 | + elif arg.lower() == '-c': |
| 165 | + idx = idx + 1 |
| 166 | + while idx < len(arg_array) and '=' in arg_array[idx]: |
| 167 | + cookie_dump = arg_array[idx].split('=') |
| 168 | + cookies[cookie_dump[0]] = cookie_dump[1] |
| 169 | + idx = idx + 1 |
| 170 | + elif arg.lower() == '-h': |
| 171 | + idx = idx + 1 |
| 172 | + while idx < len(arg_array) and '=' in arg_array[idx]: |
| 173 | + header_dump = arg_array[idx].split('=') |
| 174 | + headers[header_dump[0]] = header_dump[1] |
| 175 | + idx = idx + 1 |
| 176 | + else: |
| 177 | + __print_command_line_usage() |
| 178 | + |
| 179 | + return request_type, request_url, request_body, do_reflect, do_xss, headers, cookies |
| 180 | + |
| 181 | +def handle_input(json_version, arg_array): |
| 182 | + """ |
| 183 | + General method that handles command line input to XssMap.py, interpreting |
| 184 | + either traditional arguments or a JSON input file as needed. |
| 185 | +
|
| 186 | + Args: |
| 187 | + json_version (float) |
| 188 | + arg_array (list) |
| 189 | +
|
| 190 | + Returns: |
| 191 | + request_type (str) |
| 192 | + request_url (str) |
| 193 | + request_body (str) |
| 194 | + do_reflect (bool) |
| 195 | + do_xss (bool) |
| 196 | + headers (list) |
| 197 | + cookies (list) |
| 198 | + output_filename (str) |
| 199 | + """ |
| 200 | + |
| 201 | + # TEMPORARY: delete verbose flag -v |
| 202 | + if len(arg_array) > 1 and arg_array[1].lower() == '-v': |
| 203 | + del arg_array[1] |
| 204 | + |
| 205 | + # sanity check on command line input |
| 206 | + if len(arg_array) > 1 and arg_array[1].lower() != '-h' and arg_array[1].lower() != '--help': |
| 207 | + |
| 208 | + interpreted_params = None |
| 209 | + output_filename = 'XssMap_Results_' + time.strftime('%Y%m%d-%H%M%S') + '.json' |
| 210 | + |
| 211 | + if len(arg_array) >= 2 and ('.json' in arg_array[1].lower()\ |
| 212 | + or '.conf' in arg_array[1].lower()): |
| 213 | + # parameters are coming in a .json file... this scenario calls for 3 |
| 214 | + # "arguments", where the first is XssMap.py, second is JSON input, |
| 215 | + # third is destination for JSON output file |
| 216 | + interpreted_params = __parse_json_input(json_version, arg_array) |
| 217 | + |
| 218 | + if len(arg_array) == 3 and ('.json' in arg_array[2].lower()\ |
| 219 | + or '.txt' in arg_array[2].lower()): |
| 220 | + output_filename = arg_array[2] |
| 221 | + else: |
| 222 | + # parameters were given on the command line |
| 223 | + interpreted_params = __parse_cli_input(arg_array) |
| 224 | + |
| 225 | + return interpreted_params + (output_filename,) |
| 226 | + |
| 227 | + else: |
| 228 | + # something went awry, print usage |
| 229 | + __print_command_line_usage() |
0 commit comments