////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2009-2013 Denim Group, Ltd.
//
// The contents of this file are subject to the Mozilla Public 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.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is ThreadFix.
//
// The Initial Developer of the Original Code is Denim Group, Ltd.
// Portions created by Denim Group, Ltd. are Copyright (C)
// Denim Group, Ltd. All Rights Reserved.
//
// Contributor(s): Denim Group, Ltd.
//
////////////////////////////////////////////////////////////////////////
package com.denimgroup.threadfix.service.channel;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
import com.denimgroup.threadfix.data.dao.ChannelSeverityDao;
import com.denimgroup.threadfix.data.dao.ChannelTypeDao;
import com.denimgroup.threadfix.data.dao.ChannelVulnerabilityDao;
import com.denimgroup.threadfix.data.entities.ChannelType;
import com.denimgroup.threadfix.data.entities.Finding;
import com.denimgroup.threadfix.data.entities.Scan;
import com.denimgroup.threadfix.webapp.controller.ScanCheckResultBean;
/**
* Imports the results of a W3AF scan (xml output).
*
* The only information tags it currently handles are the "Interesting file" ones.
*
* @author mcollins
*/
public class W3afChannelImporter extends AbstractChannelImporter {
public static final String POTENTIALLY_INTERESTING_FILE = "Potentially interesting file";
/**
* Constructor with Spring dependencies injected.
*
* @param channelTypeDao
* @param channelVulnerabilityDao
* @param channelSeverityDao
* @param vulnerabilityMapLogDao
*/
@Autowired
public W3afChannelImporter(ChannelTypeDao channelTypeDao,
ChannelVulnerabilityDao channelVulnerabilityDao,
ChannelSeverityDao channelSeverityDao) {
this.channelVulnerabilityDao = channelVulnerabilityDao;
this.channelTypeDao = channelTypeDao;
this.channelSeverityDao = channelSeverityDao;
setChannelType(ChannelType.W3AF);
}
/*
* (non-Javadoc)
*
* @see
* com.denimgroup.threadfix.service.channel.ChannelImporter#parseInput()
*/
@Override
public Scan parseInput() {
try {
removeTagFromInputStream("httpresponse");
} catch (IOException e) {
e.printStackTrace();
}
return parseSAXInput(new W3afSAXParser());
}
/*
* This method takes the name of a tag as a parameter and then replaces the inputStream object
* with a new InputStream that does not include any of those tags.
*
* The start tag must start with the text <tagName and the end tag must be </tagName>.
*
* This method could be adapted to take out any of a list of tags and is fairly generic.
*
* @param tagName
* @throws IOException
*/
private void removeTagFromInputStream(String tagName) throws IOException {
if (inputStream == null)
return;
String startTag = "<" + tagName, endTag = "</" + tagName + ">";
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder contents = new StringBuilder();
String inputValue = reader.readLine();
boolean inResponseTag = false;
while (inputValue != null) {
if (inputValue.contains(startTag)) {
if (inputValue.contains(endTag)) {
inputValue = inputValue.substring(0,inputValue.indexOf(startTag)) +
inputValue.substring(inputValue.indexOf(endTag) + endTag.length());
} else {
inResponseTag = true;
inputValue = inputValue.substring(0,inputValue.indexOf(startTag));
contents.append(inputValue);
}
}
if (inResponseTag && inputValue.contains(endTag)) {
inResponseTag = false;
inputValue = inputValue.substring(inputValue.indexOf(endTag) + endTag.length());
}
if (!inResponseTag) {
contents.append(inputValue);
}
inputValue = reader.readLine();
}
closeInputStream(inputStream);
inputStream = new ByteArrayInputStream(contents.toString().getBytes("UTF-8"));
}
public class W3afSAXParser extends DefaultHandler {
public void add(Finding finding) {
if (finding != null) {
finding.setNativeId(getNativeId(finding));
finding.setIsStatic(false);
saxFindingList.add(finding);
}
}
////////////////////////////////////////////////////////////////////
// Event handlers.
////////////////////////////////////////////////////////////////////
public void startElement (String uri, String name, String qName, Attributes atts) {
if ("w3afrun".equals(qName))
date = getCalendarFromString("EEE MMM dd HH:mm:ss yyyy", atts.getValue("startstr"));
if ("vulnerability".equals(qName) && atts.getValue("url") != null &&
!atts.getValue("url").isEmpty()) {
String param = atts.getValue("var");
if ("None".equals(param))
param = null;
Finding finding = constructFinding(atts.getValue("url"),
param,
atts.getValue("name"),
atts.getValue("severity"));
add(finding);
}
if ("information".equals(qName) && POTENTIALLY_INTERESTING_FILE.equals(atts.getValue("name")) &&
atts.getValue("url") != null && !atts.getValue("url").isEmpty()) {
Finding finding = constructFinding(atts.getValue("url"),
null,
atts.getValue("name"),
"Info");
add(finding);
}
}
}
@Override
public ScanCheckResultBean checkFile() {
try {
removeTagFromInputStream("httpresponse");
} catch (IOException e) {
e.printStackTrace();
}
return testSAXInput(new W3afSAXValidator());
}
public class W3afSAXValidator extends DefaultHandler {
private boolean hasFindings = false, hasDate = false, correctFormat = false;
private void setTestStatus() {
if (!correctFormat)
testStatus = ScanImportStatus.WRONG_FORMAT_ERROR;
else if (hasDate)
testStatus = checkTestDate();
if (ScanImportStatus.SUCCESSFUL_SCAN == testStatus && !hasFindings)
testStatus = ScanImportStatus.EMPTY_SCAN_ERROR;
else if (testStatus == null)
testStatus = ScanImportStatus.SUCCESSFUL_SCAN;
}
////////////////////////////////////////////////////////////////////
// Event handlers.
////////////////////////////////////////////////////////////////////
public void endDocument() {
setTestStatus();
}
public void startElement (String uri, String name, String qName, Attributes atts) {
if ("vulnerability".equals(qName))
hasFindings = true;
if (!correctFormat && "w3afrun".equals(qName)) {
correctFormat = true;
testDate = getCalendarFromString("EEE MMM dd HH:mm:ss yyyy", atts.getValue("startstr"));
hasDate = testDate != null;
}
}
}
}