/*
* FuzzerModel.java
*
* Created on 06 February 2005, 08:36
*/
package org.owasp.webscarab.plugin.fuzz;
import EDU.oswego.cs.dl.util.concurrent.Sync;
import java.net.MalformedURLException;
import org.owasp.webscarab.model.AbstractConversationModel;
import org.owasp.webscarab.model.ConversationModel;
import org.owasp.webscarab.model.FrameworkModel;
import org.owasp.webscarab.model.HttpUrl;
import org.owasp.webscarab.model.ConversationID;
import org.owasp.webscarab.model.NamedValue;
import org.owasp.webscarab.util.ReentrantReaderPreferenceReadWriteLock;
import org.owasp.webscarab.plugin.AbstractPluginModel;
import java.util.logging.Logger;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import javax.swing.event.EventListenerList;
/**
*
* @author rogan
*/
public class FuzzerModel extends AbstractPluginModel {
public final static String PROPERTY_FUZZMETHOD = "FuzzMethod";
public final static String PROPERTY_FUZZURL = "FuzzUrl";
public final static String PROPERTY_FUZZVERSION = "FuzzVersion";
public final static String PROPERTY_REQUESTINDEX = "RequestIndex";
public final static String PROPERTY_TOTALREQUESTS = "TotalRequests";
public final static String PROPERTY_BUSYFUZZING = "BusyFuzzing";
private FrameworkModel _model = null;
private Logger _logger = Logger.getLogger(getClass().getName());
private EventListenerList _listenerList = new EventListenerList();
private ReentrantReaderPreferenceReadWriteLock _rwl = new ReentrantReaderPreferenceReadWriteLock();
private FuzzConversationModel _conversationModel;
private String _fuzzMethod = "GET";
private String _fuzzUrl = "http://localhost:8080/test";
private String _fuzzVersion = "HTTP/1.0";
private List<NamedValue> _fuzzHeaders = new ArrayList<NamedValue>();
private List<Parameter> _fuzzParameters = new ArrayList<Parameter>();
private List<FuzzSource> _fuzzSources = new ArrayList<FuzzSource>();
private List<Integer> _parameterPriorities = new ArrayList<Integer>();
private int _maxPriority = 0;
private int _requestIndex = 0;
private int _totalRequests = 0;
private boolean _busyFuzzing = false;
/** Creates a new instance of FuzzerModel */
public FuzzerModel(FrameworkModel model) {
_model = model;
_conversationModel = new FuzzConversationModel(model);
}
public ConversationModel getTemplateConversationModel() {
return _model.getConversationModel();
}
public ConversationModel getConversationModel() {
return _conversationModel;
}
public void addConversation(ConversationID id) {
_conversationModel.addConversation(id);
}
public void setFuzzMethod(String method) {
Object old = _fuzzMethod;
_fuzzMethod = method;
if (old == null || _fuzzMethod != old)
_changeSupport.firePropertyChange(PROPERTY_FUZZMETHOD, old, _fuzzMethod);
resetFuzzer();
}
public String getFuzzMethod() {
return _fuzzMethod;
}
public void setFuzzUrl(String url) {
Object old = _fuzzUrl;
_fuzzUrl = url;
if (old == null || _fuzzUrl!= old)
_changeSupport.firePropertyChange(PROPERTY_FUZZURL, old, _fuzzUrl);
resetFuzzer();
}
public String getFuzzUrl() {
return _fuzzUrl;
}
public void setFuzzVersion(String version) {
Object old = _fuzzVersion;
_fuzzVersion = version;
if (old == null || _fuzzVersion != old)
_changeSupport.firePropertyChange(PROPERTY_FUZZVERSION, old, _fuzzVersion);
resetFuzzer();
}
public String getFuzzVersion() {
return _fuzzVersion;
}
public void setBusyFuzzing(boolean busy) {
boolean old = _busyFuzzing;
_busyFuzzing = busy;
if (_busyFuzzing!= old)
_changeSupport.firePropertyChange(PROPERTY_BUSYFUZZING, old, _busyFuzzing);
}
public boolean isBusyFuzzing() {
return _busyFuzzing;
}
public int getFuzzHeaderCount() {
return _fuzzHeaders.size();
}
public void addFuzzHeader(int index, NamedValue header) {
_fuzzHeaders.add(index, header);
fireFuzzHeaderAdded(index);
resetFuzzer();
}
public void setFuzzHeader(int index, NamedValue header) {
_fuzzHeaders.set(index, header);
fireFuzzHeaderChanged(index);
resetFuzzer();
}
public void removeFuzzHeader(int index) {
_fuzzHeaders.remove(index);
fireFuzzHeaderRemoved(index);
resetFuzzer();
}
public NamedValue getFuzzHeader(int position) {
return (NamedValue) _fuzzHeaders.get(position);
}
public int getFuzzParameterCount() {
return _fuzzParameters.size();
}
public void addFuzzParameter(int index, Parameter parameter, FuzzSource fuzzSource, int priority) {
_logger.info("Adding a parameter at index " + index);
_fuzzParameters.add(index, parameter);
_fuzzSources.add(index, fuzzSource);
_parameterPriorities.add(index, new Integer(priority));
fireFuzzParameterAdded(index);
resetFuzzer();
}
public void setFuzzParameter(int index, Parameter parameter, FuzzSource fuzzSource, int priority) {
_logger.info("Setting a parameter at index " + index + ", source is " + fuzzSource);
_fuzzParameters.set(index, parameter);
_fuzzSources.set(index, fuzzSource);
_parameterPriorities.set(index, new Integer(priority));
fireFuzzParameterChanged(index);
resetFuzzer();
}
public void removeFuzzParameter(int index) {
_logger.info("Removing parameter at index " + index);
_fuzzParameters.remove(index);
_fuzzSources.remove(index);
_parameterPriorities.remove(index);
fireFuzzParameterRemoved(index);
resetFuzzer();
}
public Parameter getFuzzParameter(int index) {
return (Parameter) _fuzzParameters.get(index);
}
public FuzzSource getParameterFuzzSource(int index) {
return _fuzzSources.get(index);
}
public int getFuzzParameterPriority(int index) {
Integer p = _parameterPriorities.get(index);
if (p == null)
return 0;
return p.intValue();
}
public Object getFuzzParameterValue(int index) {
FuzzSource fuzzSource = getParameterFuzzSource(index);
if (fuzzSource != null) {
return fuzzSource.current();
} else {
return ((Parameter)_fuzzParameters.get(index)).getValue();
}
}
public void resetFuzzer() {
Map<Integer, Integer> sizes = new HashMap<Integer, Integer>();
_maxPriority = 0;
int count = getFuzzParameterCount();
for (int i=0; i<count; i++) {
FuzzSource source = getParameterFuzzSource(i);
if (source != null) {
source.reset();
Integer priority = new Integer(getFuzzParameterPriority(i));
_maxPriority = Math.max(priority.intValue(), _maxPriority);
int size = source.size();
Integer s = sizes.get(priority);
if (s == null) {
sizes.put(priority, new Integer(size));
} else {
sizes.put(priority, new Integer(Math.min(s.intValue(),size)));
}
}
}
int totalsize = 1;
Iterator<Integer> it = sizes.values().iterator();
while (it.hasNext()) {
Integer size = it.next();
totalsize = totalsize * size.intValue();
}
setRequestIndex(0);
setTotalRequests(totalsize);
_conversationModel.clear();
}
public boolean incrementFuzzer() {
boolean success = false;
int count = getFuzzParameterCount();
for (int priority=0; priority<=_maxPriority; priority++) {
// make sure we can increment ALL the sources at the current priority
// set success = true if so
for (int param=0; param<count; param++) {
FuzzSource source = getParameterFuzzSource(param);
if (source == null) continue; // nothing to do for this param
int paramPriority = getFuzzParameterPriority(param);
if (paramPriority == priority) { // we need to increment this one
if (source.hasNext()) {
source.increment();
success = true;
} else {
success = false;
break;
}
}
}
if (success) {
setRequestIndex(getRequestIndex()+1);
return true;
} else {
// no success, reset all parameters <= current priority, we'll
// go around again, and increment the next priority level
for (int param=0; param<count; param++) {
FuzzSource source = getParameterFuzzSource(param);
if (source == null) continue; // nothing to do for this param
int paramPriority = getFuzzParameterPriority(param);
if (paramPriority <= priority) {
source.reset();
}
}
}
}
// we have gone through all the permutations, no more to do
setRequestIndex(getTotalRequests());
return false;
}
private void setRequestIndex(int index) {
int old = _requestIndex;
_requestIndex = index;
if (_requestIndex != old)
_changeSupport.firePropertyChange(PROPERTY_REQUESTINDEX, old, _requestIndex);
}
public int getRequestIndex() {
return _requestIndex;
}
private void setTotalRequests(int count) {
int old = _totalRequests;
_totalRequests = count;
if (_totalRequests != old)
_changeSupport.firePropertyChange(PROPERTY_TOTALREQUESTS, old, _totalRequests);
}
public int getTotalRequests() {
return _totalRequests;
}
public void addSignature(Signature signature) {
HttpUrl url = signature.getUrl();
_model.addUrlProperty(url, "SIGNATURE", signature.toString());
}
public int getSignatureCount(HttpUrl url) {
String[] signatures = _model.getUrlProperties(url, "SIGNATURE");
if (signatures == null) return 0;
return signatures.length;
}
public Signature getSignature(HttpUrl url, int index) {
String[] signatures = _model.getUrlProperties(url, "SIGNATURE");
if (signatures == null) return null;
try {
return new Signature(signatures[index]);
} catch (MalformedURLException mue) {
_logger.severe("Malformed URL reading a signature! " + mue.getMessage());
return null;
}
}
public void addChecksum(HttpUrl url, String checksum) {
_model.addUrlProperty(url, "CHECKSUM", checksum);
}
public int getChecksumCount(HttpUrl url) {
String[] checksums = _model.getUrlProperties(url, "CHECKSUM");
if (checksums == null) return 0;
return checksums.length;
}
public String getChecksum(HttpUrl url, int index) {
String[] checksums = _model.getUrlProperties(url, "CHECKSUM");
if (checksums == null) return null;
return checksums[index];
}
public void addModelListener(FuzzerListener listener) {
_listenerList.add(FuzzerListener.class, listener);
}
public void removeModelListener(FuzzerListener listener) {
_listenerList.remove(FuzzerListener.class, listener);
}
/**
* tells listeners that a header has been added
* @param url the url
*/
protected void fireFuzzHeaderAdded(int index) {
// Guaranteed to return a non-null array
Object[] listeners = _listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
FuzzerEvent evt = new FuzzerEvent(this, FuzzerEvent.FUZZHEADER_ADDED, index);
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==FuzzerListener.class) {
try {
((FuzzerListener)listeners[i+1]).fuzzHeaderAdded(evt);
} catch (Exception e) {
_logger.severe("Unhandled exception: " + e);
}
}
}
}
/**
* tells listeners that a header has been removed
* @param url the url
*/
protected void fireFuzzHeaderChanged(int index) {
// Guaranteed to return a non-null array
Object[] listeners = _listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
FuzzerEvent evt = new FuzzerEvent(this, FuzzerEvent.FUZZHEADER_CHANGED, index);
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==FuzzerListener.class) {
try {
((FuzzerListener)listeners[i+1]).fuzzHeaderChanged(evt);
} catch (Exception e) {
_logger.severe("Unhandled exception: " + e);
}
}
}
}
/**
* tells listeners that a header has been removed
* @param url the url
*/
protected void fireFuzzHeaderRemoved(int index) {
// Guaranteed to return a non-null array
Object[] listeners = _listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
FuzzerEvent evt = new FuzzerEvent(this, FuzzerEvent.FUZZHEADER_REMOVED, index);
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==FuzzerListener.class) {
try {
((FuzzerListener)listeners[i+1]).fuzzHeaderRemoved(evt);
} catch (Exception e) {
_logger.severe("Unhandled exception: " + e);
}
}
}
}
/**
* tells listeners that a parameter has been added
* @param url the url
*/
protected void fireFuzzParameterAdded(int index) {
// Guaranteed to return a non-null array
Object[] listeners = _listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
FuzzerEvent evt = new FuzzerEvent(this, FuzzerEvent.FUZZPARAMETER_ADDED, index);
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==FuzzerListener.class) {
try {
((FuzzerListener)listeners[i+1]).fuzzParameterAdded(evt);
} catch (Exception e) {
_logger.severe("Unhandled exception: " + e);
}
}
}
}
/**
* tells listeners that a parameter has been added
* @param url the url
*/
protected void fireFuzzParameterChanged(int index) {
// Guaranteed to return a non-null array
Object[] listeners = _listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
FuzzerEvent evt = new FuzzerEvent(this, FuzzerEvent.FUZZPARAMETER_CHANGED, index);
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==FuzzerListener.class) {
try {
((FuzzerListener)listeners[i+1]).fuzzParameterChanged(evt);
} catch (Exception e) {
_logger.severe("Unhandled exception: " + e);
}
}
}
}
/**
* tells listeners that a parameter has been added
* @param url the url
*/
protected void fireFuzzParameterRemoved(int index) {
// Guaranteed to return a non-null array
Object[] listeners = _listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
FuzzerEvent evt = new FuzzerEvent(this, FuzzerEvent.FUZZPARAMETER_REMOVED, index);
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==FuzzerListener.class) {
try {
((FuzzerListener)listeners[i+1]).fuzzParameterRemoved(evt);
} catch (Exception e) {
_logger.severe("Unhandled exception: " + e);
}
}
}
}
private class FuzzConversationModel extends AbstractConversationModel {
private List<ConversationID> _conversations = new ArrayList<ConversationID>();
public FuzzConversationModel(FrameworkModel model) {
super(model);
}
void addConversation(ConversationID id) {
try {
_rwl.writeLock().acquire();
int index = _conversations.size();
_conversations.add(id);
_rwl.readLock().acquire();
_rwl.writeLock().release();
fireConversationAdded(id, index);
_rwl.readLock().release();
} catch (InterruptedException ie) {
_logger.severe("Interrupted! " + ie);
}
}
void clear() {
try {
_rwl.writeLock().acquire();
_conversations.clear();
_rwl.readLock().acquire();
_rwl.writeLock().release();
fireConversationsChanged();
_rwl.readLock().release();
} catch (InterruptedException ie) {
_logger.severe("Interrupted! " + ie);
}
}
public ConversationID getConversationAt(int index) {
return (ConversationID) _conversations.get(index);
}
public int getIndexOfConversation(ConversationID id) {
return _conversations.indexOf(id);
}
public Sync readLock() {
return _rwl.readLock();
}
public int getConversationCount() {
return _conversations.size();
}
}
}