1 /* 2 * Zed Attack Proxy (ZAP) and its related class files. 3 * 4 * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 * 6 * Copyright 2011 The ZAP Development Team 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 package org.zaproxy.zap.extension.ascan; 21 22 import java.io.File; 23 import java.util.ArrayList; 24 import java.util.Arrays; 25 import java.util.Date; 26 import java.util.HashMap; 27 import java.util.List; 28 import java.util.Map; 29 import java.util.Map.Entry; 30 import java.util.regex.PatternSyntaxException; 31 import net.sf.json.JSON; 32 import net.sf.json.JSONException; 33 import net.sf.json.JSONObject; 34 import org.apache.commons.configuration.ConfigurationException; 35 import org.apache.commons.httpclient.URI; 36 import org.apache.commons.httpclient.URIException; 37 import org.apache.commons.lang.StringEscapeUtils; 38 import org.apache.commons.lang.StringUtils; 39 import org.apache.logging.log4j.LogManager; 40 import org.apache.logging.log4j.Logger; 41 import org.parosproxy.paros.Constant; 42 import org.parosproxy.paros.control.Control; 43 import org.parosproxy.paros.core.scanner.Category; 44 import org.parosproxy.paros.core.scanner.HostProcess; 45 import org.parosproxy.paros.core.scanner.NameValuePair; 46 import org.parosproxy.paros.core.scanner.Plugin; 47 import org.parosproxy.paros.core.scanner.Plugin.AlertThreshold; 48 import org.parosproxy.paros.core.scanner.ScannerParamFilter; 49 import org.parosproxy.paros.db.DatabaseException; 50 import org.parosproxy.paros.model.Model; 51 import org.parosproxy.paros.model.Session; 52 import org.parosproxy.paros.network.HttpRequestHeader; 53 import org.w3c.dom.Document; 54 import org.w3c.dom.Element; 55 import org.zaproxy.zap.extension.api.ApiAction; 56 import org.zaproxy.zap.extension.api.ApiException; 57 import org.zaproxy.zap.extension.api.ApiException.Type; 58 import org.zaproxy.zap.extension.api.ApiImplementor; 59 import org.zaproxy.zap.extension.api.ApiResponse; 60 import org.zaproxy.zap.extension.api.ApiResponseElement; 61 import org.zaproxy.zap.extension.api.ApiResponseList; 62 import org.zaproxy.zap.extension.api.ApiResponseSet; 63 import org.zaproxy.zap.extension.api.ApiView; 64 import org.zaproxy.zap.extension.users.ExtensionUserManagement; 65 import org.zaproxy.zap.model.Context; 66 import org.zaproxy.zap.model.SessionStructure; 67 import org.zaproxy.zap.model.StructuralNode; 68 import org.zaproxy.zap.model.Target; 69 import org.zaproxy.zap.users.User; 70 import org.zaproxy.zap.utils.ApiUtils; 71 import org.zaproxy.zap.utils.XMLStringUtil; 72 import org.zaproxy.zap.utils.ZapXmlConfiguration; 73 74 public class ActiveScanAPI extends ApiImplementor { 75 76 private static Logger log = LogManager.getLogger(ActiveScanAPI.class); 77 78 private static final String PREFIX = "ascan"; 79 private static final String ACTION_SCAN = "scan"; 80 private static final String ACTION_SCAN_AS_USER = "scanAsUser"; 81 private static final String ACTION_PAUSE_SCAN = "pause"; 82 private static final String ACTION_RESUME_SCAN = "resume"; 83 private static final String ACTION_STOP_SCAN = "stop"; 84 private static final String ACTION_PAUSE_ALL_SCANS = "pauseAllScans"; 85 private static final String ACTION_RESUME_ALL_SCANS = "resumeAllScans"; 86 private static final String ACTION_STOP_ALL_SCANS = "stopAllScans"; 87 private static final String ACTION_REMOVE_SCAN = "removeScan"; 88 private static final String ACTION_REMOVE_ALL_SCANS = "removeAllScans"; 89 90 private static final String ACTION_EXCLUDE_FROM_SCAN = "excludeFromScan"; 91 private static final String ACTION_CLEAR_EXCLUDED_FROM_SCAN = "clearExcludedFromScan"; 92 private static final String ACTION_ENABLE_ALL_SCANNERS = "enableAllScanners"; 93 private static final String ACTION_DISABLE_ALL_SCANNERS = "disableAllScanners"; 94 private static final String ACTION_ENABLE_SCANNERS = "enableScanners"; 95 private static final String ACTION_DISABLE_SCANNERS = "disableScanners"; 96 private static final String ACTION_SET_ENABLED_POLICIES = "setEnabledPolicies"; 97 private static final String ACTION_SET_POLICY_ATTACK_STRENGTH = "setPolicyAttackStrength"; 98 private static final String ACTION_SET_POLICY_ALERT_THRESHOLD = "setPolicyAlertThreshold"; 99 private static final String ACTION_SET_SCANNER_ATTACK_STRENGTH = "setScannerAttackStrength"; 100 private static final String ACTION_SET_SCANNER_ALERT_THRESHOLD = "setScannerAlertThreshold"; 101 private static final String ACTION_ADD_SCAN_POLICY = "addScanPolicy"; 102 private static final String ACTION_REMOVE_SCAN_POLICY = "removeScanPolicy"; 103 private static final String ACTION_UPDATE_SCAN_POLICY = "updateScanPolicy"; 104 private static final String ACTION_IMPORT_SCAN_POLICY = "importScanPolicy"; 105 106 private static final String ACTION_ADD_EXCLUDED_PARAM = "addExcludedParam"; 107 private static final String ACTION_MODIFY_EXCLUDED_PARAM = "modifyExcludedParam"; 108 private static final String ACTION_REMOVE_EXCLUDED_PARAM = "removeExcludedParam"; 109 110 private static final String ACTION_SKIP_SCANNER = "skipScanner"; 111 112 private static final String VIEW_STATUS = "status"; 113 private static final String VIEW_SCANS = "scans"; 114 private static final String VIEW_MESSAGES_IDS = "messagesIds"; 115 private static final String VIEW_ALERTS_IDS = "alertsIds"; 116 private static final String VIEW_EXCLUDED_FROM_SCAN = "excludedFromScan"; 117 private static final String VIEW_SCANNERS = "scanners"; 118 // TODO rename? Note any changes like this to the existing API must be clearly documented to 119 // users 120 private static final String VIEW_POLICIES = "policies"; 121 private static final String VIEW_SCAN_POLICY_NAMES = "scanPolicyNames"; 122 private static final String VIEW_ATTACK_MODE_QUEUE = "attackModeQueue"; 123 private static final String VIEW_SCAN_PROGRESS = "scanProgress"; 124 private static final String VIEW_EXCLUDED_PARAMS = "excludedParams"; 125 private static final String VIEW_OPTION_EXCLUDED_PARAM_LIST = "optionExcludedParamList"; 126 private static final String VIEW_EXCLUDED_PARAM_TYPES = "excludedParamTypes"; 127 128 private static final String PARAM_URL = "url"; 129 private static final String PARAM_CONTEXT_ID = "contextId"; 130 private static final String PARAM_USER_ID = "userId"; 131 private static final String PARAM_REGEX = "regex"; 132 private static final String PARAM_RECURSE = "recurse"; 133 private static final String PARAM_JUST_IN_SCOPE = "inScopeOnly"; 134 private static final String PARAM_IDS = "ids"; 135 private static final String PARAM_ID = "id"; 136 private static final String PARAM_ATTACK_STRENGTH = "attackStrength"; 137 private static final String PARAM_ALERT_THRESHOLD = "alertThreshold"; 138 private static final String PARAM_SCAN_POLICY_NAME = "scanPolicyName"; 139 private static final String PARAM_PATH = "path"; 140 // TODO rename to categoryId? Note any changes like this to the existing API must be clearly 141 // documented to users 142 private static final String PARAM_CATEGORY_ID = "policyId"; 143 private static final String PARAM_SCAN_ID = "scanId"; 144 private static final String PARAM_SCANNER_ID = "scannerId"; 145 private static final String PARAM_METHOD = "method"; 146 private static final String PARAM_POST_DATA = "postData"; 147 private static final String PARAM_IDX = "idx"; 148 private static final String PARAM_TYPE = "type"; 149 private static final String PARAM_NAME = "name"; 150 151 private ExtensionActiveScan controller = null; 152 ActiveScanAPI(ExtensionActiveScan controller)153 public ActiveScanAPI(ExtensionActiveScan controller) { 154 this.controller = controller; 155 this.addApiAction( 156 new ApiAction( 157 ACTION_SCAN, 158 null, 159 new String[] { 160 PARAM_URL, 161 PARAM_RECURSE, 162 PARAM_JUST_IN_SCOPE, 163 PARAM_SCAN_POLICY_NAME, 164 PARAM_METHOD, 165 PARAM_POST_DATA, 166 PARAM_CONTEXT_ID 167 })); 168 this.addApiAction( 169 new ApiAction( 170 ACTION_SCAN_AS_USER, 171 null, 172 new String[] { 173 PARAM_URL, 174 PARAM_CONTEXT_ID, 175 PARAM_USER_ID, 176 PARAM_RECURSE, 177 PARAM_SCAN_POLICY_NAME, 178 PARAM_METHOD, 179 PARAM_POST_DATA 180 })); 181 this.addApiAction(new ApiAction(ACTION_PAUSE_SCAN, new String[] {PARAM_SCAN_ID})); 182 this.addApiAction(new ApiAction(ACTION_RESUME_SCAN, new String[] {PARAM_SCAN_ID})); 183 this.addApiAction(new ApiAction(ACTION_STOP_SCAN, new String[] {PARAM_SCAN_ID})); 184 this.addApiAction(new ApiAction(ACTION_REMOVE_SCAN, new String[] {PARAM_SCAN_ID})); 185 this.addApiAction(new ApiAction(ACTION_PAUSE_ALL_SCANS)); 186 this.addApiAction(new ApiAction(ACTION_RESUME_ALL_SCANS)); 187 this.addApiAction(new ApiAction(ACTION_STOP_ALL_SCANS)); 188 this.addApiAction(new ApiAction(ACTION_REMOVE_ALL_SCANS)); 189 this.addApiAction(new ApiAction(ACTION_CLEAR_EXCLUDED_FROM_SCAN)); 190 this.addApiAction(new ApiAction(ACTION_EXCLUDE_FROM_SCAN, new String[] {PARAM_REGEX})); 191 this.addApiAction( 192 new ApiAction( 193 ACTION_ENABLE_ALL_SCANNERS, null, new String[] {PARAM_SCAN_POLICY_NAME})); 194 this.addApiAction( 195 new ApiAction( 196 ACTION_DISABLE_ALL_SCANNERS, null, new String[] {PARAM_SCAN_POLICY_NAME})); 197 this.addApiAction( 198 new ApiAction( 199 ACTION_ENABLE_SCANNERS, 200 new String[] {PARAM_IDS}, 201 new String[] {PARAM_SCAN_POLICY_NAME})); 202 this.addApiAction( 203 new ApiAction( 204 ACTION_DISABLE_SCANNERS, 205 new String[] {PARAM_IDS}, 206 new String[] {PARAM_SCAN_POLICY_NAME})); 207 this.addApiAction( 208 new ApiAction( 209 ACTION_SET_ENABLED_POLICIES, 210 new String[] {PARAM_IDS}, 211 new String[] {PARAM_SCAN_POLICY_NAME})); 212 this.addApiAction( 213 new ApiAction( 214 ACTION_SET_POLICY_ATTACK_STRENGTH, 215 new String[] {PARAM_ID, PARAM_ATTACK_STRENGTH}, 216 new String[] {PARAM_SCAN_POLICY_NAME})); 217 this.addApiAction( 218 new ApiAction( 219 ACTION_SET_POLICY_ALERT_THRESHOLD, 220 new String[] {PARAM_ID, PARAM_ALERT_THRESHOLD}, 221 new String[] {PARAM_SCAN_POLICY_NAME})); 222 this.addApiAction( 223 new ApiAction( 224 ACTION_SET_SCANNER_ATTACK_STRENGTH, 225 new String[] {PARAM_ID, PARAM_ATTACK_STRENGTH}, 226 new String[] {PARAM_SCAN_POLICY_NAME})); 227 this.addApiAction( 228 new ApiAction( 229 ACTION_SET_SCANNER_ALERT_THRESHOLD, 230 new String[] {PARAM_ID, PARAM_ALERT_THRESHOLD}, 231 new String[] {PARAM_SCAN_POLICY_NAME})); 232 this.addApiAction( 233 new ApiAction( 234 ACTION_ADD_SCAN_POLICY, 235 new String[] {PARAM_SCAN_POLICY_NAME}, 236 new String[] {PARAM_ALERT_THRESHOLD, PARAM_ATTACK_STRENGTH})); 237 this.addApiAction( 238 new ApiAction(ACTION_REMOVE_SCAN_POLICY, new String[] {PARAM_SCAN_POLICY_NAME})); 239 this.addApiAction( 240 new ApiAction( 241 ACTION_UPDATE_SCAN_POLICY, 242 new String[] {PARAM_SCAN_POLICY_NAME}, 243 new String[] {PARAM_ALERT_THRESHOLD, PARAM_ATTACK_STRENGTH})); 244 this.addApiAction(new ApiAction(ACTION_IMPORT_SCAN_POLICY, new String[] {PARAM_PATH})); 245 246 this.addApiAction( 247 new ApiAction( 248 ACTION_ADD_EXCLUDED_PARAM, 249 new String[] {PARAM_NAME}, 250 new String[] {PARAM_TYPE, PARAM_URL})); 251 this.addApiAction( 252 new ApiAction( 253 ACTION_MODIFY_EXCLUDED_PARAM, 254 new String[] {PARAM_IDX}, 255 new String[] {PARAM_NAME, PARAM_TYPE, PARAM_URL})); 256 this.addApiAction(new ApiAction(ACTION_REMOVE_EXCLUDED_PARAM, new String[] {PARAM_IDX})); 257 258 this.addApiAction( 259 new ApiAction(ACTION_SKIP_SCANNER, new String[] {PARAM_SCAN_ID, PARAM_SCANNER_ID})); 260 261 this.addApiView(new ApiView(VIEW_STATUS, null, new String[] {PARAM_SCAN_ID})); 262 this.addApiView(new ApiView(VIEW_SCAN_PROGRESS, null, new String[] {PARAM_SCAN_ID})); 263 this.addApiView(new ApiView(VIEW_MESSAGES_IDS, new String[] {PARAM_SCAN_ID})); 264 this.addApiView(new ApiView(VIEW_ALERTS_IDS, new String[] {PARAM_SCAN_ID})); 265 this.addApiView(new ApiView(VIEW_SCANS)); 266 this.addApiView(new ApiView(VIEW_SCAN_POLICY_NAMES)); 267 this.addApiView(new ApiView(VIEW_EXCLUDED_FROM_SCAN)); 268 this.addApiView( 269 new ApiView( 270 VIEW_SCANNERS, 271 null, 272 new String[] {PARAM_SCAN_POLICY_NAME, PARAM_CATEGORY_ID})); 273 this.addApiView( 274 new ApiView( 275 VIEW_POLICIES, 276 null, 277 new String[] {PARAM_SCAN_POLICY_NAME, PARAM_CATEGORY_ID})); 278 this.addApiView(new ApiView(VIEW_ATTACK_MODE_QUEUE)); 279 280 this.addApiView(new ApiView(VIEW_EXCLUDED_PARAMS)); 281 ApiView view = new ApiView(VIEW_OPTION_EXCLUDED_PARAM_LIST); 282 view.setDeprecated(true); 283 this.addApiView(view); 284 this.addApiView(new ApiView(VIEW_EXCLUDED_PARAM_TYPES)); 285 } 286 287 @Override getPrefix()288 public String getPrefix() { 289 return PREFIX; 290 } 291 292 @SuppressWarnings({"fallthrough"}) 293 @Override handleApiAction(String name, JSONObject params)294 public ApiResponse handleApiAction(String name, JSONObject params) throws ApiException { 295 log.debug("handleApiAction " + name + " " + params.toString()); 296 ScanPolicy policy; 297 int policyId; 298 299 User user = null; 300 Context context = null; 301 try { 302 switch (name) { 303 case ACTION_SCAN_AS_USER: 304 // These are not mandatory parameters on purpose, to keep the same order 305 // of the parameters while having PARAM_URL as (now) optional. 306 validateParamExists(params, PARAM_CONTEXT_ID); 307 validateParamExists(params, PARAM_USER_ID); 308 309 int userID = ApiUtils.getIntParam(params, PARAM_USER_ID); 310 ExtensionUserManagement usersExtension = 311 Control.getSingleton() 312 .getExtensionLoader() 313 .getExtension(ExtensionUserManagement.class); 314 if (usersExtension == null) { 315 throw new ApiException(Type.NO_IMPLEMENTOR, ExtensionUserManagement.NAME); 316 } 317 context = ApiUtils.getContextByParamId(params, PARAM_CONTEXT_ID); 318 user = 319 usersExtension 320 .getContextUserAuthManager(context.getId()) 321 .getUserById(userID); 322 if (user == null) { 323 throw new ApiException(Type.USER_NOT_FOUND, PARAM_USER_ID); 324 } 325 326 // Same behaviour but with addition of the user to scan 327 // $FALL-THROUGH$ 328 case ACTION_SCAN: 329 String url = ApiUtils.getOptionalStringParam(params, PARAM_URL); 330 331 if (context == null 332 && params.has(PARAM_CONTEXT_ID) 333 && !params.getString(PARAM_CONTEXT_ID).isEmpty()) { 334 context = ApiUtils.getContextByParamId(params, PARAM_CONTEXT_ID); 335 } 336 337 boolean scanJustInScope = 338 context != null 339 ? false 340 : this.getParam(params, PARAM_JUST_IN_SCOPE, false); 341 342 String policyName = null; 343 policy = null; 344 345 try { 346 policyName = params.getString(PARAM_SCAN_POLICY_NAME); 347 } catch (Exception e1) { 348 // Ignore 349 } 350 try { 351 if (policyName != null && policyName.length() > 0) { 352 // Not specified, use the default one 353 log.debug("handleApiAction scan policy =" + policyName); 354 policy = controller.getPolicyManager().getPolicy(policyName); 355 } 356 } catch (ConfigurationException e) { 357 throw new ApiException( 358 ApiException.Type.DOES_NOT_EXIST, PARAM_SCAN_POLICY_NAME); 359 } 360 String method = this.getParam(params, PARAM_METHOD, HttpRequestHeader.GET); 361 if (method.trim().length() == 0) { 362 method = HttpRequestHeader.GET; 363 } 364 if (!Arrays.asList(HttpRequestHeader.METHODS).contains(method)) { 365 throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_METHOD); 366 } 367 368 int scanId = 369 scanURL( 370 url, 371 user, 372 this.getParam(params, PARAM_RECURSE, true), 373 scanJustInScope, 374 method, 375 this.getParam(params, PARAM_POST_DATA, ""), 376 policy, 377 context); 378 379 return new ApiResponseElement(name, Integer.toString(scanId)); 380 381 case ACTION_PAUSE_SCAN: 382 getActiveScan(params).pauseScan(); 383 break; 384 case ACTION_RESUME_SCAN: 385 getActiveScan(params).resumeScan(); 386 break; 387 case ACTION_STOP_SCAN: 388 getActiveScan(params).stopScan(); 389 break; 390 case ACTION_REMOVE_SCAN: 391 ActiveScan activeScan = controller.removeScan(params.getInt(PARAM_SCAN_ID)); 392 if (activeScan == null) { 393 throw new ApiException(ApiException.Type.DOES_NOT_EXIST, PARAM_SCAN_ID); 394 } 395 break; 396 case ACTION_PAUSE_ALL_SCANS: 397 controller.pauseAllScans(); 398 break; 399 case ACTION_RESUME_ALL_SCANS: 400 controller.resumeAllScans(); 401 break; 402 case ACTION_STOP_ALL_SCANS: 403 controller.stopAllScans(); 404 break; 405 case ACTION_REMOVE_ALL_SCANS: 406 controller.removeAllScans(); 407 break; 408 case ACTION_CLEAR_EXCLUDED_FROM_SCAN: 409 try { 410 Session session = Model.getSingleton().getSession(); 411 session.setExcludeFromScanRegexs(new ArrayList<>()); 412 } catch (DatabaseException e) { 413 log.error(e.getMessage(), e); 414 throw new ApiException(ApiException.Type.INTERNAL_ERROR, e.getMessage()); 415 } 416 break; 417 case ACTION_EXCLUDE_FROM_SCAN: 418 String regex = params.getString(PARAM_REGEX); 419 try { 420 Session session = Model.getSingleton().getSession(); 421 session.addExcludeFromScanRegexs(regex); 422 } catch (DatabaseException e) { 423 log.error(e.getMessage(), e); 424 throw new ApiException(ApiException.Type.INTERNAL_ERROR, e.getMessage()); 425 } catch (PatternSyntaxException e) { 426 throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_REGEX); 427 } 428 break; 429 case ACTION_ENABLE_ALL_SCANNERS: 430 policy = getScanPolicyFromParams(params); 431 policy.getPluginFactory().setAllPluginEnabled(true); 432 policy.save(); 433 break; 434 case ACTION_DISABLE_ALL_SCANNERS: 435 policy = getScanPolicyFromParams(params); 436 policy.getPluginFactory().setAllPluginEnabled(false); 437 policy.save(); 438 break; 439 case ACTION_ENABLE_SCANNERS: 440 policy = getScanPolicyFromParams(params); 441 setScannersEnabled(policy, getParam(params, PARAM_IDS, "").split(","), true); 442 policy.save(); 443 break; 444 case ACTION_DISABLE_SCANNERS: 445 policy = getScanPolicyFromParams(params); 446 setScannersEnabled(policy, getParam(params, PARAM_IDS, "").split(","), false); 447 policy.save(); 448 break; 449 case ACTION_SET_ENABLED_POLICIES: 450 policy = getScanPolicyFromParams(params); 451 setEnabledPolicies(policy, getParam(params, PARAM_IDS, "").split(",")); 452 policy.save(); 453 break; 454 case ACTION_SET_POLICY_ATTACK_STRENGTH: 455 policyId = getPolicyIdFromParamId(params); 456 policy = getScanPolicyFromParams(params); 457 Plugin.AttackStrength attackStrength = getAttackStrengthFromParamAttack(params); 458 459 for (Plugin scanner : policy.getPluginFactory().getAllPlugin()) { 460 if (scanner.getCategory() == policyId) { 461 scanner.setAttackStrength(attackStrength); 462 } 463 } 464 policy.save(); 465 break; 466 case ACTION_SET_POLICY_ALERT_THRESHOLD: 467 policyId = getPolicyIdFromParamId(params); 468 policy = getScanPolicyFromParams(params); 469 Plugin.AlertThreshold alertThreshold1 = 470 getAlertThresholdFromParamAlertThreshold(params); 471 472 for (Plugin scanner : policy.getPluginFactory().getAllPlugin()) { 473 if (scanner.getCategory() == policyId) { 474 scanner.setAlertThreshold(alertThreshold1); 475 } 476 } 477 policy.save(); 478 break; 479 case ACTION_SET_SCANNER_ATTACK_STRENGTH: 480 policy = getScanPolicyFromParams(params); 481 Plugin scanner = getScannerFromParamId(policy, params); 482 scanner.setAttackStrength(getAttackStrengthFromParamAttack(params)); 483 policy.save(); 484 break; 485 case ACTION_SET_SCANNER_ALERT_THRESHOLD: 486 policy = getScanPolicyFromParams(params); 487 AlertThreshold alertThreshold2 = 488 getAlertThresholdFromParamAlertThreshold(params); 489 getScannerFromParamId(policy, params).setAlertThreshold(alertThreshold2); 490 policy.save(); 491 break; 492 case ACTION_ADD_SCAN_POLICY: 493 String newPolicyName = params.getString(PARAM_SCAN_POLICY_NAME); 494 if (controller.getPolicyManager().getAllPolicyNames().contains(newPolicyName)) { 495 throw new ApiException( 496 ApiException.Type.ALREADY_EXISTS, PARAM_SCAN_POLICY_NAME); 497 } 498 if (!controller.getPolicyManager().isLegalPolicyName(newPolicyName)) { 499 throw new ApiException( 500 ApiException.Type.ILLEGAL_PARAMETER, PARAM_SCAN_POLICY_NAME); 501 } 502 policy = controller.getPolicyManager().getTemplatePolicy(); 503 policy.setName(newPolicyName); 504 setAlertThreshold(policy, params); 505 setAttackStrength(policy, params); 506 controller.getPolicyManager().savePolicy(policy); 507 break; 508 case ACTION_REMOVE_SCAN_POLICY: 509 // Check it exists 510 policy = getScanPolicyFromParams(params); 511 if (controller.getPolicyManager().getAllPolicyNames().size() == 1) { 512 // Dont remove the last one 513 throw new ApiException( 514 ApiException.Type.ILLEGAL_PARAMETER, 515 "You are not allowed to remove the last scan policy"); 516 } 517 controller.getPolicyManager().deletePolicy(policy.getName()); 518 break; 519 case ACTION_UPDATE_SCAN_POLICY: 520 policy = getScanPolicyFromParams(params); 521 if (!isParamsChanged(policy, params)) { 522 break; 523 } 524 updateAlertThreshold(policy, params); 525 updateAttackStrength(policy, params); 526 controller.getPolicyManager().savePolicy(policy); 527 break; 528 case ACTION_IMPORT_SCAN_POLICY: 529 File file = new File(params.getString(PARAM_PATH)); 530 if (!file.exists()) { 531 throw new ApiException(ApiException.Type.DOES_NOT_EXIST, PARAM_PATH); 532 } 533 if (!file.isFile()) { 534 throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_PATH); 535 } 536 537 ScanPolicy scanPolicy; 538 try { 539 scanPolicy = new ScanPolicy(new ZapXmlConfiguration(file)); 540 } catch (IllegalArgumentException | ConfigurationException e) { 541 throw new ApiException( 542 ApiException.Type.BAD_EXTERNAL_DATA, file.toString(), e); 543 } 544 545 String scanPolicyName = scanPolicy.getName(); 546 if (scanPolicyName.isEmpty()) { 547 scanPolicyName = file.getName(); 548 } 549 if (controller 550 .getPolicyManager() 551 .getAllPolicyNames() 552 .contains(scanPolicyName)) { 553 throw new ApiException(ApiException.Type.ALREADY_EXISTS, scanPolicyName); 554 } 555 if (!controller.getPolicyManager().isLegalPolicyName(scanPolicyName)) { 556 throw new ApiException(ApiException.Type.BAD_EXTERNAL_DATA, scanPolicyName); 557 } 558 559 try { 560 controller.getPolicyManager().savePolicy(scanPolicy); 561 } catch (ConfigurationException e) { 562 throw new ApiException(ApiException.Type.INTERNAL_ERROR, e); 563 } 564 break; 565 case ACTION_ADD_EXCLUDED_PARAM: 566 int type = getParam(params, PARAM_TYPE, NameValuePair.TYPE_UNDEFINED); 567 if (!ScannerParamFilter.getTypes().containsKey(type)) { 568 throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_TYPE); 569 } 570 571 url = getParam(params, PARAM_URL, "*"); 572 if (url.isEmpty()) { 573 url = "*"; 574 } 575 576 ScannerParamFilter excludedParam = 577 new ScannerParamFilter(params.getString(PARAM_NAME), type, url); 578 579 List<ScannerParamFilter> excludedParams = 580 new ArrayList<>(controller.getScannerParam().getExcludedParamList()); 581 excludedParams.add(excludedParam); 582 controller.getScannerParam().setExcludedParamList(excludedParams); 583 break; 584 case ACTION_MODIFY_EXCLUDED_PARAM: 585 try { 586 int idx = params.getInt(PARAM_IDX); 587 if (idx < 0 588 || idx 589 >= controller 590 .getScannerParam() 591 .getExcludedParamList() 592 .size()) { 593 throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_IDX); 594 } 595 596 ScannerParamFilter oldExcludedParam = 597 controller.getScannerParam().getExcludedParamList().get(idx); 598 String epName = 599 getParam(params, PARAM_NAME, oldExcludedParam.getParamName()); 600 if (epName.isEmpty()) { 601 epName = oldExcludedParam.getParamName(); 602 } 603 604 type = getParam(params, PARAM_TYPE, oldExcludedParam.getType()); 605 if (!ScannerParamFilter.getTypes().containsKey(type)) { 606 throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_TYPE); 607 } 608 609 url = getParam(params, PARAM_URL, oldExcludedParam.getWildcardedUrl()); 610 if (url.isEmpty()) { 611 url = "*"; 612 } 613 614 ScannerParamFilter newExcludedParam = 615 new ScannerParamFilter(epName, type, url); 616 if (oldExcludedParam.equals(newExcludedParam)) { 617 break; 618 } 619 620 excludedParams = 621 new ArrayList<>( 622 controller.getScannerParam().getExcludedParamList()); 623 excludedParams.set(idx, newExcludedParam); 624 controller.getScannerParam().setExcludedParamList(excludedParams); 625 } catch (JSONException e) { 626 throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_IDX, e); 627 } 628 break; 629 case ACTION_REMOVE_EXCLUDED_PARAM: 630 try { 631 int idx = params.getInt(PARAM_IDX); 632 if (idx < 0 633 || idx 634 >= controller 635 .getScannerParam() 636 .getExcludedParamList() 637 .size()) { 638 throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_IDX); 639 } 640 641 excludedParams = 642 new ArrayList<>( 643 controller.getScannerParam().getExcludedParamList()); 644 excludedParams.remove(idx); 645 controller.getScannerParam().setExcludedParamList(excludedParams); 646 } catch (JSONException e) { 647 throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_IDX, e); 648 } 649 break; 650 case ACTION_SKIP_SCANNER: 651 int pluginId = getParam(params, PARAM_SCANNER_ID, -1); 652 if (pluginId == -1) { 653 throw new ApiException( 654 ApiException.Type.ILLEGAL_PARAMETER, PARAM_SCANNER_ID); 655 } 656 657 String reason = 658 Constant.messages.getString("ascan.progress.label.skipped.reason.user"); 659 getActiveScan(params) 660 .getHostProcesses() 661 .forEach(hp -> hp.pluginSkipped(pluginId, reason)); 662 break; 663 default: 664 throw new ApiException(ApiException.Type.BAD_ACTION); 665 } 666 } catch (ConfigurationException e) { 667 throw new ApiException(ApiException.Type.INTERNAL_ERROR, e.getMessage()); 668 } 669 return ApiResponseElement.OK; 670 } 671 setAlertThreshold(ScanPolicy policy, JSONObject params)672 private void setAlertThreshold(ScanPolicy policy, JSONObject params) throws ApiException { 673 if (isParamExists(params, PARAM_ALERT_THRESHOLD)) { 674 policy.setDefaultThreshold(getAlertThresholdFromParamAlertThreshold(params)); 675 } 676 } 677 setAttackStrength(ScanPolicy policy, JSONObject params)678 private void setAttackStrength(ScanPolicy policy, JSONObject params) throws ApiException { 679 if (isParamExists(params, PARAM_ATTACK_STRENGTH)) { 680 policy.setDefaultStrength(getAttackStrengthFromParamAttack(params)); 681 } 682 } 683 isParamsChanged(ScanPolicy policy, JSONObject params)684 private boolean isParamsChanged(ScanPolicy policy, JSONObject params) throws ApiException { 685 return isAlertThresholdChanged(policy, params) || isAttackStrengthChanged(policy, params); 686 } 687 isAlertThresholdChanged(ScanPolicy policy, JSONObject params)688 private boolean isAlertThresholdChanged(ScanPolicy policy, JSONObject params) 689 throws ApiException { 690 if (!isParamExists(params, PARAM_ALERT_THRESHOLD)) { 691 return false; 692 } 693 694 AlertThreshold updatedAlertThreshold = getAlertThresholdFromParamAlertThreshold(params); 695 AlertThreshold currentThreshold = policy.getDefaultThreshold(); 696 return !currentThreshold.equals(updatedAlertThreshold); 697 } 698 isAttackStrengthChanged(ScanPolicy policy, JSONObject params)699 private boolean isAttackStrengthChanged(ScanPolicy policy, JSONObject params) 700 throws ApiException { 701 if (!isParamExists(params, PARAM_ATTACK_STRENGTH)) { 702 return false; 703 } 704 705 Plugin.AttackStrength updatedAttackStrength = getAttackStrengthFromParamAttack(params); 706 Plugin.AttackStrength currentAttackStrength = policy.getDefaultStrength(); 707 return !currentAttackStrength.equals(updatedAttackStrength); 708 } 709 updateAlertThreshold(ScanPolicy policy, JSONObject params)710 private void updateAlertThreshold(ScanPolicy policy, JSONObject params) throws ApiException { 711 if (isAlertThresholdChanged(policy, params)) { 712 policy.setDefaultThreshold(getAlertThresholdFromParamAlertThreshold(params)); 713 } 714 } 715 updateAttackStrength(ScanPolicy policy, JSONObject params)716 private void updateAttackStrength(ScanPolicy policy, JSONObject params) throws ApiException { 717 if (isAttackStrengthChanged(policy, params)) { 718 policy.setDefaultStrength(getAttackStrengthFromParamAttack(params)); 719 } 720 } 721 isParamExists(JSONObject params, String key)722 private boolean isParamExists(JSONObject params, String key) { 723 return params.has(key) && StringUtils.isNotBlank(params.getString(key)); 724 } 725 getScanPolicyFromParams(JSONObject params)726 private ScanPolicy getScanPolicyFromParams(JSONObject params) throws ApiException { 727 String policyName = null; 728 try { 729 policyName = params.getString(PARAM_SCAN_POLICY_NAME); 730 } catch (Exception e1) { 731 // Ignore 732 } 733 if (policyName == null || policyName.length() == 0) { 734 // Not specified, use the default one 735 return controller.getPolicyManager().getDefaultScanPolicy(); 736 } 737 try { 738 return controller.getPolicyManager().getPolicy(policyName); 739 } catch (ConfigurationException e) { 740 throw new ApiException(ApiException.Type.DOES_NOT_EXIST, PARAM_SCAN_POLICY_NAME); 741 } 742 } 743 744 /** 745 * Returns a {@link ActiveScan} from the available active scans or the last active scan. If a 746 * scan ID ( {@link #PARAM_SCAN_ID}) is present in the given {@code params} it will be used to 747 * the get the {@code ActiveScan} from the available active scans, otherwise it's returned the 748 * last active scan. 749 * 750 * @param params the parameters of the API call 751 * @return the {@code ActiveScan} with the given scan ID or, if not present, the last active 752 * scan 753 * @throws ApiException if there's no scan with the given scan ID 754 */ getActiveScan(JSONObject params)755 private ActiveScan getActiveScan(JSONObject params) throws ApiException { 756 int id = getParam(params, PARAM_SCAN_ID, -1); 757 758 ActiveScan activeScan = null; 759 760 if (id == -1) { 761 activeScan = controller.getLastScan(); 762 } else { 763 activeScan = controller.getScan(id); 764 } 765 766 if (activeScan == null) { 767 throw new ApiException(ApiException.Type.DOES_NOT_EXIST, PARAM_SCAN_ID); 768 } 769 770 return activeScan; 771 } 772 setScannersEnabled(ScanPolicy policy, String[] ids, boolean enabled)773 private void setScannersEnabled(ScanPolicy policy, String[] ids, boolean enabled) 774 throws ConfigurationException, ApiException { 775 if (ids.length > 0) { 776 for (String id : ids) { 777 try { 778 Plugin scanner = 779 policy.getPluginFactory().getPlugin(Integer.valueOf(id.trim())); 780 if (scanner != null) { 781 scanner.setEnabled(enabled); 782 } 783 } catch (NumberFormatException e) { 784 log.warn("Failed to parse scanner ID: ", e); 785 } 786 } 787 } 788 } 789 setEnabledPolicies(ScanPolicy policy, String[] ids)790 private void setEnabledPolicies(ScanPolicy policy, String[] ids) { 791 policy.getPluginFactory().setAllPluginEnabled(false); 792 if (ids.length > 0) { 793 for (String id : ids) { 794 try { 795 int policyId = Integer.valueOf(id.trim()); 796 if (hasPolicyWithId(policyId)) { 797 for (Plugin scanner : policy.getPluginFactory().getAllPlugin()) { 798 if (scanner.getCategory() == policyId) { 799 scanner.setEnabled(true); 800 } 801 } 802 } 803 } catch (NumberFormatException e) { 804 log.warn("Failed to parse policy ID: ", e); 805 } 806 } 807 } 808 } 809 hasPolicyWithId(int policyId)810 private static boolean hasPolicyWithId(int policyId) { 811 return Arrays.asList(Category.getAllNames()).contains(Category.getName(policyId)); 812 } 813 getPolicyIdFromParamId(JSONObject params)814 private int getPolicyIdFromParamId(JSONObject params) throws ApiException { 815 final int id = getParam(params, PARAM_ID, -1); 816 if (id == -1) { 817 throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_ID); 818 } 819 if (!hasPolicyWithId(id)) { 820 throw new ApiException(ApiException.Type.DOES_NOT_EXIST, PARAM_ID); 821 } 822 return id; 823 } 824 getAttackStrengthFromParamAttack(JSONObject params)825 private Plugin.AttackStrength getAttackStrengthFromParamAttack(JSONObject params) 826 throws ApiException { 827 final String paramAttackStrength = 828 params.getString(PARAM_ATTACK_STRENGTH).trim().toUpperCase(); 829 try { 830 return Plugin.AttackStrength.valueOf(paramAttackStrength); 831 } catch (IllegalArgumentException e) { 832 throw new ApiException(ApiException.Type.DOES_NOT_EXIST, PARAM_ATTACK_STRENGTH); 833 } 834 } 835 getAlertThresholdFromParamAlertThreshold(JSONObject params)836 private Plugin.AlertThreshold getAlertThresholdFromParamAlertThreshold(JSONObject params) 837 throws ApiException { 838 final String paramAlertThreshold = 839 params.getString(PARAM_ALERT_THRESHOLD).trim().toUpperCase(); 840 try { 841 return Plugin.AlertThreshold.valueOf(paramAlertThreshold); 842 } catch (IllegalArgumentException e) { 843 throw new ApiException(ApiException.Type.DOES_NOT_EXIST, PARAM_ALERT_THRESHOLD); 844 } 845 } 846 getScannerFromParamId(ScanPolicy policy, JSONObject params)847 private Plugin getScannerFromParamId(ScanPolicy policy, JSONObject params) throws ApiException { 848 final int id = getParam(params, PARAM_ID, -1); 849 if (id == -1) { 850 throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_ID); 851 } 852 Plugin scanner = policy.getPluginFactory().getPlugin(id); 853 if (scanner == null) { 854 throw new ApiException(ApiException.Type.DOES_NOT_EXIST, PARAM_ID); 855 } 856 return scanner; 857 } 858 scanURL( String url, User user, boolean scanChildren, boolean scanJustInScope, String method, String postData, ScanPolicy policy, Context context)859 private int scanURL( 860 String url, 861 User user, 862 boolean scanChildren, 863 boolean scanJustInScope, 864 String method, 865 String postData, 866 ScanPolicy policy, 867 Context context) 868 throws ApiException { 869 870 boolean useUrl = true; 871 if (url == null || url.isEmpty()) { 872 if (context == null || !context.hasNodesInContextFromSiteTree()) { 873 throw new ApiException(Type.MISSING_PARAMETER, PARAM_URL); 874 } 875 useUrl = false; 876 } else if (context != null && !context.isInContext(url)) { 877 throw new ApiException(Type.URL_NOT_IN_CONTEXT, PARAM_URL); 878 } 879 880 StructuralNode node = null; 881 if (useUrl) { 882 URI startURI; 883 try { 884 if (scanChildren && url.endsWith("/")) { 885 // Always choose the non leaf node if scanChildren option selected 886 url = url.substring(0, url.length() - 1); 887 } 888 startURI = new URI(url, true); 889 } catch (URIException e) { 890 throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_URL, e); 891 } 892 String scheme = startURI.getScheme(); 893 if (scheme == null 894 || (!scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https"))) { 895 throw new ApiException( 896 ApiException.Type.ILLEGAL_PARAMETER, 897 PARAM_URL + " does not have a scheme."); 898 } 899 900 try { 901 Model model = Model.getSingleton(); 902 node = SessionStructure.find(model, startURI, method, postData); 903 if (node == null && "GET".equalsIgnoreCase(method)) { 904 // Check if there's a non-leaf node that matches the URI, to scan the subtree. 905 // (GET is the default method, but non-leaf nodes do not have any method.) 906 node = SessionStructure.find(model, startURI, null, postData); 907 } 908 } catch (Exception e) { 909 throw new ApiException(ApiException.Type.INTERNAL_ERROR, e); 910 } 911 912 if (node == null) { 913 throw new ApiException(ApiException.Type.URL_NOT_FOUND); 914 } 915 } 916 Target target; 917 if (useUrl) { 918 target = new Target(node); 919 target.setContext(context); 920 } else { 921 target = new Target(context); 922 } 923 target.setRecurse(scanChildren); 924 target.setInScopeOnly(scanJustInScope); 925 926 switch (Control.getSingleton().getMode()) { 927 case safe: 928 throw new ApiException(ApiException.Type.MODE_VIOLATION); 929 case protect: 930 if ((useUrl && !Model.getSingleton().getSession().isInScope(url)) 931 || (context != null && !context.isInScope())) { 932 throw new ApiException(ApiException.Type.MODE_VIOLATION); 933 } 934 // No problem 935 break; 936 case standard: 937 // No problem 938 break; 939 case attack: 940 // No problem 941 break; 942 } 943 944 Object[] objs = new Object[] {}; 945 if (policy != null) { 946 objs = new Object[] {policy}; 947 } 948 949 return controller.startScan(null, target, user, objs); 950 } 951 952 @Override handleApiView(String name, JSONObject params)953 public ApiResponse handleApiView(String name, JSONObject params) throws ApiException { 954 ApiResponse result; 955 ActiveScan activeScan = null; 956 ScanPolicy policy; 957 int categoryId; 958 959 switch (name) { 960 case VIEW_STATUS: 961 activeScan = getActiveScan(params); 962 int progress = 0; 963 if (activeScan.isStopped()) { 964 progress = 100; 965 } else { 966 progress = activeScan.getProgress(); 967 } 968 result = new ApiResponseElement(name, String.valueOf(progress)); 969 break; 970 case VIEW_SCANS: 971 ApiResponseList resultList = new ApiResponseList(name); 972 for (ActiveScan scan : controller.getAllScans()) { 973 Map<String, String> map = new HashMap<>(); 974 map.put("id", Integer.toString(scan.getScanId())); 975 map.put("progress", Integer.toString(scan.getProgress())); 976 map.put("state", scan.getState().name()); 977 map.put("reqCount", Integer.toString(scan.getTotalRequests())); 978 map.put("alertCount", Integer.toString(scan.getAlertsIds().size())); 979 map.put("newAlertCount", Integer.toString(scan.getTotalNewAlerts())); 980 resultList.addItem(new ApiResponseSet<>("scan", map)); 981 } 982 result = resultList; 983 break; 984 case VIEW_SCAN_PROGRESS: 985 resultList = new ApiResponseList(name); 986 activeScan = getActiveScan(params); 987 for (HostProcess hp : activeScan.getHostProcesses()) { 988 ApiResponseList hpList = new ApiResponseList("HostProcess"); 989 resultList.addItem(new ApiResponseElement("id", hp.getHostAndPort())); 990 991 for (Plugin plugin : hp.getCompleted()) { 992 long timeTaken = 993 plugin.getTimeFinished().getTime() 994 - plugin.getTimeStarted().getTime(); 995 int reqs = hp.getPluginRequestCount(plugin.getId()); 996 int alertCount = hp.getPluginStats(plugin.getId()).getAlertCount(); 997 hpList.addItem( 998 createPluginProgressEntry( 999 plugin, 1000 getStatus(hp, plugin, "Complete"), 1001 timeTaken, 1002 reqs, 1003 alertCount)); 1004 } 1005 1006 for (Plugin plugin : hp.getRunning()) { 1007 int pc = hp.getTestCurrentCount(plugin) * 100 / hp.getTestTotalCount(); 1008 // Make sure not return 100 (or more) if still running... 1009 // That might happen if more nodes are being scanned that the ones 1010 // enumerated at the beginning. 1011 if (pc >= 100) { 1012 pc = 99; 1013 } 1014 long timeTaken = new Date().getTime() - plugin.getTimeStarted().getTime(); 1015 int reqs = hp.getPluginRequestCount(plugin.getId()); 1016 int alertCount = hp.getPluginStats(plugin.getId()).getAlertCount(); 1017 hpList.addItem( 1018 createPluginProgressEntry( 1019 plugin, pc + "%", timeTaken, reqs, alertCount)); 1020 } 1021 1022 for (Plugin plugin : hp.getPending()) { 1023 hpList.addItem( 1024 createPluginProgressEntry( 1025 plugin, getStatus(hp, plugin, "Pending"), 0, 0, 0)); 1026 } 1027 resultList.addItem(hpList); 1028 } 1029 result = resultList; 1030 break; 1031 case VIEW_MESSAGES_IDS: 1032 resultList = new ApiResponseList(name); 1033 activeScan = getActiveScan(params); 1034 synchronized (activeScan.getMessagesIds()) { 1035 for (Integer id : activeScan.getMessagesIds()) { 1036 resultList.addItem(new ApiResponseElement("id", id.toString())); 1037 } 1038 } 1039 result = resultList; 1040 break; 1041 case VIEW_ALERTS_IDS: 1042 resultList = new ApiResponseList(name); 1043 activeScan = getActiveScan(params); 1044 synchronized (activeScan.getAlertsIds()) { 1045 for (Integer id : activeScan.getAlertsIds()) { 1046 resultList.addItem(new ApiResponseElement("id", id.toString())); 1047 } 1048 } 1049 result = resultList; 1050 break; 1051 case VIEW_EXCLUDED_FROM_SCAN: 1052 result = new ApiResponseList(name); 1053 Session session = Model.getSingleton().getSession(); 1054 List<String> regexs = session.getExcludeFromScanRegexs(); 1055 for (String regex : regexs) { 1056 ((ApiResponseList) result).addItem(new ApiResponseElement("regex", regex)); 1057 } 1058 break; 1059 case VIEW_SCANNERS: 1060 policy = getScanPolicyFromParams(params); 1061 List<Plugin> scanners = policy.getPluginFactory().getAllPlugin(); 1062 1063 categoryId = getParam(params, PARAM_CATEGORY_ID, -1); 1064 if (categoryId != -1 && !hasPolicyWithId(categoryId)) { 1065 throw new ApiException(ApiException.Type.DOES_NOT_EXIST, PARAM_CATEGORY_ID); 1066 } 1067 resultList = new ApiResponseList(name); 1068 for (Plugin scanner : scanners) { 1069 if (categoryId == -1 || categoryId == scanner.getCategory()) { 1070 resultList.addItem(new ScannerApiResponse(policy, scanner)); 1071 } 1072 } 1073 1074 result = resultList; 1075 break; 1076 case VIEW_POLICIES: 1077 policy = getScanPolicyFromParams(params); 1078 String[] policies = Category.getAllNames(); 1079 1080 resultList = new ApiResponseList(name); 1081 for (String pluginName : policies) { 1082 categoryId = Category.getCategory(pluginName); 1083 Plugin.AttackStrength attackStrength = 1084 getPolicyAttackStrength(policy, categoryId); 1085 Plugin.AlertThreshold alertThreshold = 1086 getPolicyAlertThreshold(policy, categoryId); 1087 Map<String, String> map = new HashMap<>(); 1088 map.put("id", String.valueOf(categoryId)); 1089 map.put("name", pluginName); 1090 map.put( 1091 "attackStrength", 1092 attackStrength == null ? "" : String.valueOf(attackStrength)); 1093 map.put( 1094 "alertThreshold", 1095 alertThreshold == null ? "" : String.valueOf(alertThreshold)); 1096 map.put("enabled", String.valueOf(isPolicyEnabled(policy, categoryId))); 1097 resultList.addItem(new ApiResponseSet<>("policy", map)); 1098 } 1099 1100 result = resultList; 1101 break; 1102 case VIEW_SCAN_POLICY_NAMES: 1103 resultList = new ApiResponseList(name); 1104 for (String policyName : controller.getPolicyManager().getAllPolicyNames()) { 1105 resultList.addItem(new ApiResponseElement("policy", policyName)); 1106 } 1107 result = resultList; 1108 break; 1109 case VIEW_ATTACK_MODE_QUEUE: 1110 result = 1111 new ApiResponseElement( 1112 name, String.valueOf(controller.getAttackModeStackSize())); 1113 break; 1114 case VIEW_OPTION_EXCLUDED_PARAM_LIST: 1115 case VIEW_EXCLUDED_PARAMS: 1116 resultList = new ApiResponseList(name); 1117 List<ScannerParamFilter> excludedParams = 1118 controller.getScannerParam().getExcludedParamList(); 1119 for (int i = 0; i < excludedParams.size(); i++) { 1120 resultList.addItem(new ExcludedParamApiResponse(excludedParams.get(i), i)); 1121 } 1122 result = resultList; 1123 break; 1124 case VIEW_EXCLUDED_PARAM_TYPES: 1125 resultList = new ApiResponseList(name); 1126 for (Entry<Integer, String> type : ScannerParamFilter.getTypes().entrySet()) { 1127 Map<String, String> typeData = new HashMap<>(); 1128 typeData.put("id", Integer.toString(type.getKey())); 1129 typeData.put("name", type.getValue()); 1130 resultList.addItem(new ApiResponseSet<>("type", typeData)); 1131 } 1132 result = resultList; 1133 break; 1134 default: 1135 throw new ApiException(ApiException.Type.BAD_VIEW); 1136 } 1137 return result; 1138 } 1139 createPluginProgressEntry( Plugin plugin, String status, long timeTaken, int requestCount, int alertCount)1140 private static ApiResponseList createPluginProgressEntry( 1141 Plugin plugin, String status, long timeTaken, int requestCount, int alertCount) { 1142 ApiResponseList pList = new ApiResponseList("Plugin"); 1143 pList.addItem(new ApiResponseElement("name", plugin.getName())); 1144 pList.addItem(new ApiResponseElement("id", Integer.toString(plugin.getId()))); 1145 pList.addItem(new ApiResponseElement("quality", plugin.getStatus().toString())); 1146 pList.addItem(new ApiResponseElement("status", status)); 1147 pList.addItem(new ApiResponseElement("timeInMs", Long.toString(timeTaken))); 1148 pList.addItem(new ApiResponseElement("reqCount", Integer.toString(requestCount))); 1149 pList.addItem(new ApiResponseElement("alertCount", Integer.toString(alertCount))); 1150 return pList; 1151 } 1152 isPolicyEnabled(ScanPolicy policy, int category)1153 private boolean isPolicyEnabled(ScanPolicy policy, int category) { 1154 for (Plugin scanner : policy.getPluginFactory().getAllPlugin()) { 1155 if (scanner.getCategory() == category && !scanner.isEnabled()) { 1156 return false; 1157 } 1158 } 1159 return true; 1160 } 1161 getPolicyAttackStrength(ScanPolicy policy, int categoryd)1162 private Plugin.AttackStrength getPolicyAttackStrength(ScanPolicy policy, int categoryd) { 1163 Plugin.AttackStrength attackStrength = null; 1164 for (Plugin scanner : policy.getPluginFactory().getAllPlugin()) { 1165 if (scanner.getCategory() == categoryd) { 1166 if (attackStrength == null) { 1167 attackStrength = scanner.getAttackStrength(true); 1168 } else if (!attackStrength.equals(scanner.getAttackStrength(true))) { 1169 // Not all the same 1170 return null; 1171 } 1172 } 1173 } 1174 return attackStrength; 1175 } 1176 getPolicyAlertThreshold(ScanPolicy policy, int categoryId)1177 private Plugin.AlertThreshold getPolicyAlertThreshold(ScanPolicy policy, int categoryId) { 1178 Plugin.AlertThreshold alertThreshold = null; 1179 for (Plugin scanner : policy.getPluginFactory().getAllPlugin()) { 1180 if (scanner.getCategory() == categoryId) { 1181 if (alertThreshold == null) { 1182 alertThreshold = scanner.getAlertThreshold(true); 1183 } else if (!alertThreshold.equals(scanner.getAlertThreshold(true))) { 1184 // Not all the same 1185 return null; 1186 } 1187 } 1188 } 1189 return alertThreshold; 1190 } 1191 getStatus(HostProcess hp, Plugin plugin, String defaultStatus)1192 private static String getStatus(HostProcess hp, Plugin plugin, String defaultStatus) { 1193 if (!hp.isSkipped(plugin)) { 1194 return defaultStatus; 1195 } 1196 1197 String skippedReason = hp.getSkippedReason(plugin); 1198 if (skippedReason == null) { 1199 return Constant.messages.getString("ascan.progress.label.skipped"); 1200 } 1201 return Constant.messages.getString("ascan.progress.label.skippedWithReason", skippedReason); 1202 } 1203 1204 private static class ExcludedParamApiResponse extends ApiResponse { 1205 1206 private final Map<String, String> excludedParamData; 1207 private final ApiResponseSet<String> type; 1208 private final Map<String, String> typeData; 1209 ExcludedParamApiResponse(ScannerParamFilter param, int idx)1210 public ExcludedParamApiResponse(ScannerParamFilter param, int idx) { 1211 super("excludedParam"); 1212 1213 excludedParamData = new HashMap<>(); 1214 excludedParamData.put("idx", Integer.toString(idx)); 1215 excludedParamData.put("parameter", param.getParamName()); 1216 excludedParamData.put("url", param.getWildcardedUrl()); 1217 1218 typeData = new HashMap<>(); 1219 typeData.put("id", Integer.toString(param.getType())); 1220 typeData.put("name", param.getTypeString()); 1221 type = new ApiResponseSet<>("type", typeData); 1222 } 1223 1224 @Override toXML(Document doc, Element parent)1225 public void toXML(Document doc, Element parent) { 1226 parent.setAttribute("type", "set"); 1227 for (Entry<String, String> val : excludedParamData.entrySet()) { 1228 Element el = doc.createElement(val.getKey()); 1229 el.appendChild(doc.createTextNode(XMLStringUtil.escapeControlChrs(val.getValue()))); 1230 parent.appendChild(el); 1231 } 1232 1233 Element el = doc.createElement(type.getName()); 1234 type.toXML(doc, el); 1235 parent.appendChild(el); 1236 } 1237 1238 @Override toJSON()1239 public JSON toJSON() { 1240 JSONObject jo = new JSONObject(); 1241 for (Entry<String, String> val : excludedParamData.entrySet()) { 1242 jo.put(val.getKey(), val.getValue()); 1243 } 1244 jo.put(type.getName(), type.toJSON()); 1245 return jo; 1246 } 1247 1248 @Override toHTML(StringBuilder sb)1249 public void toHTML(StringBuilder sb) { 1250 sb.append("<h2>" + this.getName() + "</h2>\n"); 1251 sb.append("<table border=\"1\">\n"); 1252 for (Entry<String, String> val : excludedParamData.entrySet()) { 1253 sb.append("<tr><td>\n"); 1254 sb.append(val.getKey()); 1255 sb.append("</td><td>\n"); 1256 sb.append(StringEscapeUtils.escapeHtml(val.getValue())); 1257 sb.append("</td></tr>\n"); 1258 } 1259 sb.append("<tr><td>\n"); 1260 sb.append(type.getName()); 1261 sb.append("</td><td>\n"); 1262 sb.append("<table border=\"1\">\n"); 1263 for (Entry<String, ?> val : typeData.entrySet()) { 1264 sb.append("<tr><td>\n"); 1265 sb.append(StringEscapeUtils.escapeHtml(val.getKey())); 1266 sb.append("</td><td>\n"); 1267 Object value = val.getValue(); 1268 if (value != null) { 1269 sb.append(StringEscapeUtils.escapeHtml(value.toString())); 1270 } 1271 sb.append("</td></tr>\n"); 1272 } 1273 sb.append("</table>\n"); 1274 sb.append("</td></tr>\n"); 1275 sb.append("</table>\n"); 1276 } 1277 1278 @Override toString(int indent)1279 public String toString(int indent) { 1280 StringBuilder sb = new StringBuilder(); 1281 for (int i = 0; i < indent; i++) { 1282 sb.append("\t"); 1283 } 1284 sb.append("ApiResponseSet "); 1285 sb.append(this.getName()); 1286 sb.append(" : [\n"); 1287 for (Entry<String, String> val : excludedParamData.entrySet()) { 1288 for (int i = 0; i < indent + 1; i++) { 1289 sb.append("\t"); 1290 } 1291 sb.append(val.getKey()); 1292 sb.append(" = "); 1293 sb.append(val.getValue()); 1294 sb.append("\n"); 1295 } 1296 sb.append(type.toString(indent + 1)); 1297 for (int i = 0; i < indent; i++) { 1298 sb.append("\t"); 1299 } 1300 sb.append("]\n"); 1301 return sb.toString(); 1302 } 1303 } 1304 1305 private class ScannerApiResponse extends ApiResponse { 1306 1307 final Map<String, String> scannerData; 1308 final ApiResponseList dependencies; 1309 ScannerApiResponse(ScanPolicy policy, Plugin scanner)1310 public ScannerApiResponse(ScanPolicy policy, Plugin scanner) { 1311 super("scanner"); 1312 1313 scannerData = new HashMap<>(); 1314 scannerData.put("id", String.valueOf(scanner.getId())); 1315 scannerData.put("name", scanner.getName()); 1316 scannerData.put("cweId", String.valueOf(scanner.getCweId())); 1317 scannerData.put("wascId", String.valueOf(scanner.getWascId())); 1318 scannerData.put("attackStrength", String.valueOf(scanner.getAttackStrength(true))); 1319 scannerData.put("alertThreshold", String.valueOf(scanner.getAlertThreshold(true))); 1320 scannerData.put("policyId", String.valueOf(scanner.getCategory())); 1321 scannerData.put("enabled", String.valueOf(scanner.isEnabled())); 1322 scannerData.put("quality", scanner.getStatus().toString()); 1323 1324 boolean allDepsAvailable = 1325 policy.getPluginFactory().hasAllDependenciesAvailable(scanner); 1326 scannerData.put("allDependenciesAvailable", Boolean.toString(allDepsAvailable)); 1327 1328 dependencies = new ApiResponseList("dependencies"); 1329 for (Plugin dependency : policy.getPluginFactory().getDependencies(scanner)) { 1330 dependencies.addItem( 1331 new ApiResponseElement("dependency", Integer.toString(dependency.getId()))); 1332 } 1333 } 1334 1335 @Override toXML(Document doc, Element parent)1336 public void toXML(Document doc, Element parent) { 1337 parent.setAttribute("type", "set"); 1338 for (Entry<String, String> val : scannerData.entrySet()) { 1339 Element el = doc.createElement(val.getKey()); 1340 el.appendChild(doc.createTextNode(XMLStringUtil.escapeControlChrs(val.getValue()))); 1341 parent.appendChild(el); 1342 } 1343 1344 Element el = doc.createElement(dependencies.getName()); 1345 dependencies.toXML(doc, el); 1346 parent.appendChild(el); 1347 } 1348 1349 @Override toJSON()1350 public JSON toJSON() { 1351 JSONObject jo = new JSONObject(); 1352 for (Entry<String, String> val : scannerData.entrySet()) { 1353 jo.put(val.getKey(), val.getValue()); 1354 } 1355 jo.put( 1356 dependencies.getName(), 1357 ((JSONObject) dependencies.toJSON()).getJSONArray(dependencies.getName())); 1358 return jo; 1359 } 1360 1361 @Override toHTML(StringBuilder sb)1362 public void toHTML(StringBuilder sb) { 1363 sb.append("<h2>" + this.getName() + "</h2>\n"); 1364 sb.append("<table border=\"1\">\n"); 1365 for (Entry<String, String> val : scannerData.entrySet()) { 1366 sb.append("<tr><td>\n"); 1367 sb.append(val.getKey()); 1368 sb.append("</td><td>\n"); 1369 sb.append(StringEscapeUtils.escapeHtml(val.getValue())); 1370 sb.append("</td></tr>\n"); 1371 } 1372 sb.append("<tr><td>\n"); 1373 sb.append(dependencies.getName()); 1374 sb.append("</td><td>\n"); 1375 sb.append("<table border=\"1\">\n"); 1376 for (ApiResponse resp : this.dependencies.getItems()) { 1377 sb.append("<tr><td>\n"); 1378 resp.toHTML(sb); 1379 sb.append("</td></tr>\n"); 1380 } 1381 sb.append("</table>\n"); 1382 sb.append("</td></tr>\n"); 1383 sb.append("</table>\n"); 1384 } 1385 1386 @Override toString(int indent)1387 public String toString(int indent) { 1388 StringBuilder sb = new StringBuilder(); 1389 for (int i = 0; i < indent; i++) { 1390 sb.append(" "); 1391 } 1392 sb.append("ScannerApiResponse "); 1393 sb.append(this.getName()); 1394 sb.append(" : [\n"); 1395 for (Entry<String, String> val : scannerData.entrySet()) { 1396 for (int i = 0; i < indent + 1; i++) { 1397 sb.append("\t"); 1398 } 1399 sb.append(val.getKey()); 1400 sb.append(" = "); 1401 sb.append(val.getValue()); 1402 sb.append("\n"); 1403 } 1404 dependencies.toString(indent + 1); 1405 for (int i = 0; i < indent; i++) { 1406 sb.append("\t"); 1407 } 1408 sb.append("]\n"); 1409 return sb.toString(); 1410 } 1411 } 1412 } 1413