All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zaproxy.zap.extension.spider.SpiderScan Maven / Gradle / Ivy

Go to download

The Zed Attack Proxy (ZAP) is an easy to use integrated penetration testing tool for finding vulnerabilities in web applications. It is designed to be used by people with a wide range of security experience and as such is ideal for developers and functional testers who are new to penetration testing. ZAP provides automated scanners as well as a set of tools that allow you to find security vulnerabilities manually.

There is a newer version: 2.15.0
Show newest version
/*
 * Zed Attack Proxy (ZAP) and its related class files.
 *
 * ZAP is an HTTP/HTTPS proxy for assessing web application security.
 *
 * Copyright 2014 The ZAP Development Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.zaproxy.zap.extension.spider;

import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.table.TableModel;
import org.apache.commons.httpclient.URI;
import org.parosproxy.paros.network.HttpMessage;
import org.parosproxy.paros.network.HttpRequestHeader;
import org.parosproxy.paros.network.HttpResponseHeader;
import org.parosproxy.paros.view.View;
import org.zaproxy.zap.model.GenericScanner2;
import org.zaproxy.zap.model.ScanEventPublisher;
import org.zaproxy.zap.model.ScanListenner;
import org.zaproxy.zap.model.ScanListenner2;
import org.zaproxy.zap.model.Target;
import org.zaproxy.zap.spider.SpiderListener;
import org.zaproxy.zap.spider.SpiderParam;
import org.zaproxy.zap.spider.SpiderTaskResult;
import org.zaproxy.zap.spider.filters.FetchFilter;
import org.zaproxy.zap.spider.filters.FetchFilter.FetchStatus;
import org.zaproxy.zap.spider.filters.ParseFilter;
import org.zaproxy.zap.spider.parser.SpiderParser;
import org.zaproxy.zap.users.User;

public class SpiderScan implements ScanListenner, SpiderListener, GenericScanner2 {

    private static enum State {
        NOT_STARTED,
        RUNNING,
        PAUSED,
        FINISHED
    };

    private static final EnumSet FETCH_STATUS_IN_SCOPE =
            EnumSet.of(FetchStatus.VALID, FetchStatus.SEED);

    private static final EnumSet FETCH_STATUS_OUT_OF_SCOPE =
            EnumSet.of(
                    FetchStatus.OUT_OF_SCOPE, FetchStatus.OUT_OF_CONTEXT, FetchStatus.USER_RULES);

    private final Lock lock;

    private int scanId;
    private Target target;
    private User user;

    private String displayName = "";

    /**
     * Counter for number of URIs, in and out of scope, found during the scan.
     *
     * 

The counter is incremented when a new URI is found. * * @see #foundURI(String, String, FetchStatus) * @see #getNumberOfURIsFound() */ private AtomicInteger numberOfURIsFound; private Set foundURIs; private List resourcesFound; private List resourcesIoErrors; private Set foundURIsOutOfScope; private SpiderThread spiderThread = null; private State state; private int progress; private ScanListenner2 listener = null; private volatile boolean cleared; /** * The table model of the messages sent. * *

Lazily initialised. * * @see #getMessagesTableModel() * @see #addMessageToMessagesTableModel(SpiderTaskResult) */ private SpiderMessagesTableModel messagesTableModel; /** * Constructs a {@code SpiderScan} with the given data. * * @param extension the extension to obtain configurations and notify the view * @param spiderParams the spider options * @param target the spider target * @param spiderURI the starting URI, may be {@code null}. * @param scanUser the user to be used in the scan, may be {@code null}. * @param scanId the ID of the scan * @deprecated (2.6.0) Use {@link #SpiderScan(ExtensionSpider, SpiderParam, Target, URI, User, * int, String)} instead. */ @Deprecated public SpiderScan( ExtensionSpider extension, SpiderParam spiderParams, Target target, URI spiderURI, User scanUser, int scanId) { this(extension, spiderParams, target, spiderURI, scanUser, scanId, "SpiderScan" + scanId); } /** * Constructs a {@code SpiderScan} with the given data. * * @param extension the extension to obtain configurations and notify the view * @param spiderParams the spider options * @param target the spider target * @param spiderURI the starting URI, may be {@code null}. * @param scanUser the user to be used in the scan, may be {@code null}. * @param scanId the ID of the scan * @param name the name that identifies the target * @since 2.6.0 */ public SpiderScan( ExtensionSpider extension, SpiderParam spiderParams, Target target, URI spiderURI, User scanUser, int scanId, String name) { lock = new ReentrantLock(); this.scanId = scanId; this.target = target; this.user = scanUser; setDisplayName(name); numberOfURIsFound = new AtomicInteger(); foundURIs = Collections.synchronizedSet(new HashSet()); resourcesFound = Collections.synchronizedList(new ArrayList()); resourcesIoErrors = Collections.synchronizedList(new ArrayList()); foundURIsOutOfScope = Collections.synchronizedSet(new HashSet()); state = State.NOT_STARTED; spiderThread = new SpiderThread(Integer.toString(scanId), extension, spiderParams, name, this); spiderThread.setStartURI(spiderURI); spiderThread.setStartNode(target.getStartNode()); spiderThread.setScanContext(target.getContext()); spiderThread.setScanAsUser(scanUser); spiderThread.setJustScanInScope(target.isInScopeOnly()); spiderThread.setScanChildren(target.isRecurse()); } /** * Returns the ID of the scan. * * @return the ID of the scan */ @Override public int getScanId() { return scanId; } /** * Returns the {@code String} representation of the scan state (not started, running, paused or * finished). * * @return the {@code String} representation of the scan state. */ public String getState() { lock.lock(); try { return state.toString(); } finally { lock.unlock(); } } /** * Returns the progress of the scan, an integer between 0 and 100. * * @return the progress of the scan. */ @Override public int getProgress() { return progress; } /** * Starts the scan. * *

The call to this method has no effect if the scan was already started. */ public void start() { lock.lock(); try { if (State.NOT_STARTED.equals(state)) { spiderThread.addSpiderListener(this); spiderThread.start(); state = State.RUNNING; SpiderEventPublisher.publishScanEvent( ScanEventPublisher.SCAN_STARTED_EVENT, this.scanId, this.target, user); } } finally { lock.unlock(); } } /** * Pauses the scan. * *

The call to this method has no effect if the scan is not running. */ @Override public void pauseScan() { lock.lock(); try { if (State.RUNNING.equals(state)) { spiderThread.pauseScan(); state = State.PAUSED; SpiderEventPublisher.publishScanEvent( ScanEventPublisher.SCAN_PAUSED_EVENT, this.scanId); } } finally { lock.unlock(); } } /** * Resumes the scan. * *

The call to this method has no effect if the scan is not paused. */ @Override public void resumeScan() { lock.lock(); try { if (State.PAUSED.equals(state)) { spiderThread.resumeScan(); state = State.RUNNING; SpiderEventPublisher.publishScanEvent( ScanEventPublisher.SCAN_RESUMED_EVENT, this.scanId); } } finally { lock.unlock(); } } /** * Stops the scan. * *

The call to this method has no effect if the scan was not yet started or has already * finished. */ @Override public void stopScan() { lock.lock(); try { if (!State.NOT_STARTED.equals(state) && !State.FINISHED.equals(state)) { spiderThread.stopScan(); state = State.FINISHED; SpiderEventPublisher.publishScanEvent( ScanEventPublisher.SCAN_STOPPED_EVENT, this.scanId); } } finally { lock.unlock(); } } /** * Returns the URLs found during the scan. * *

Note: Iterations must be {@code synchronized} on returned object. Failing * to do so might result in {@code ConcurrentModificationException}. * * @return the URLs found during the scan * @see ConcurrentModificationException */ public Set getResults() { return foundURIs; } /** * Returns the resources found during the scan. * *

Note: Iterations must be {@code synchronized} on returned object. Failing * to do so might result in {@code ConcurrentModificationException}. * * @return the resources found during the scan * @see ConcurrentModificationException */ public List getResourcesFound() { return resourcesFound; } /** * Returns the resources found during the scan that were not successfully obtained because of * I/O errors. * *

Note: Iterations must be {@code synchronized} on returned object. Failing * to do so might result in {@code ConcurrentModificationException}. * * @return the resources found during the scan that were not successfully obtained * @since 2.6.0 */ public List getResourcesIoErrors() { return resourcesIoErrors; } /** * Returns the URLs, out of scope, found during the scan. * *

Note: Iterations must be {@code synchronized} on returned object. Failing * to do so might result in {@code ConcurrentModificationException}. * * @return the URLs, out of scope, found during the scan * @see ConcurrentModificationException */ public Set getResultsOutOfScope() { return foundURIsOutOfScope; } @Override public void notifySpiderTaskResult(SpiderTaskResult spiderTaskResult) { HttpMessage msg = spiderTaskResult.getHttpMessage(); HttpRequestHeader requestHeader = msg.getRequestHeader(); HttpResponseHeader responseHeader = msg.getResponseHeader(); SpiderResource resource = new SpiderResource( msg.getHistoryRef() != null ? msg.getHistoryRef().getHistoryId() : -1, requestHeader.getMethod(), requestHeader.getURI().toString(), responseHeader.getStatusCode(), responseHeader.getReasonPhrase(), spiderTaskResult.isProcessed(), spiderTaskResult.getReasonNotProcessed()); if (msg.isResponseFromTargetHost()) { resourcesFound.add(resource); } else { resourcesIoErrors.add(resource); } if (View.isInitialised()) { addMessageToMessagesTableModel(spiderTaskResult); } } private void addMessageToMessagesTableModel(final SpiderTaskResult spiderTaskResult) { if (spiderTaskResult.getHttpMessage().getHistoryRef() == null) { return; } if (EventQueue.isDispatchThread() || cleared) { if (cleared) { return; } if (messagesTableModel == null) { messagesTableModel = new SpiderMessagesTableModel(); } messagesTableModel.addHistoryReference( spiderTaskResult.getHttpMessage().getHistoryRef(), spiderTaskResult.isProcessed(), spiderTaskResult.getReasonNotProcessed()); return; } EventQueue.invokeLater( new Runnable() { @Override public void run() { addMessageToMessagesTableModel(spiderTaskResult); } }); } @Override public void spiderComplete(boolean successful) { lock.lock(); try { state = State.FINISHED; SpiderEventPublisher.publishScanEvent( ScanEventPublisher.SCAN_COMPLETED_EVENT, this.scanId); } finally { lock.unlock(); } if (listener != null) { listener.scanFinshed(this.getScanId(), this.getDisplayName()); } } @Override public void spiderProgress(int percentageComplete, int numberCrawled, int numberToCrawl) { if (this.progress != percentageComplete) { this.progress = percentageComplete; SpiderEventPublisher.publishScanProgressEvent(scanId, percentageComplete); } if (listener != null) { listener.scanProgress(this.getScanId(), this.getDisplayName(), percentageComplete, 100); } } @Override public void foundURI(String uri, String method, FetchStatus status) { numberOfURIsFound.incrementAndGet(); if (FETCH_STATUS_IN_SCOPE.contains(status)) { foundURIs.add(uri); } else if (FETCH_STATUS_OUT_OF_SCOPE.contains(status)) { foundURIsOutOfScope.add(uri); } } @Override public void run() { // TODO Auto-generated method stub } @Override public void setScanId(int id) { this.scanId = id; } @Override public void setDisplayName(String name) { this.displayName = name; } @Override public String getDisplayName() { return this.displayName; } @Override public boolean isStopped() { return this.spiderThread.isStopped(); } @Override public int getMaximum() { return 100; } /** * Gets the number of URIs, in and out of scope, found during the scan. * * @return the number of URIs found during the scan * @since 2.4.3 */ public int getNumberOfURIsFound() { return numberOfURIsFound.get(); } public int getNumberOfNodesAdded() { return this.spiderThread.getNumberOfNodesAdded(); } @Override public boolean isPaused() { return this.spiderThread.isPaused(); } @Override public boolean isRunning() { return this.spiderThread.isRunning(); } @Override public void scanFinshed(String host) { this.spiderComplete(true); } @Override public void scanProgress(String host, int progress, int maximum) {} public TableModel getResultsTableModel() { return this.spiderThread.getResultsTableModel(); } public SpiderPanelTableModel getAddedNodesTableModel() { return this.spiderThread.getAddedNodesTableModel(); } /** * Gets the {@code TableModel} of the messages sent during the spidering process. * * @return a {@code TableModel} with the messages sent * @since 2.5.0 */ TableModel getMessagesTableModel() { if (messagesTableModel == null) { messagesTableModel = new SpiderMessagesTableModel(); } return messagesTableModel; } public void setListener(ScanListenner2 listener) { this.listener = listener; } public void setCustomSpiderParsers(List customSpiderParsers) { spiderThread.setCustomSpiderParsers(customSpiderParsers); } public void setCustomFetchFilters(List customFetchFilters) { spiderThread.setCustomFetchFilters(customFetchFilters); } public void setCustomParseFilters(List customParseFilters) { spiderThread.setCustomParseFilters(customParseFilters); } /** * Clears the table model of the HTTP messages sent. * * @since 2.5.0 * @see #getMessagesTableModel() */ void clear() { cleared = true; if (messagesTableModel != null) { messagesTableModel.clear(); messagesTableModel = null; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy