App-DubiousHTTP

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

  malicious

2017/06/09 0.034
- support custom payloads instead of EICAR, see --help for how to use
- fixed submission
- added more tests, see git log for details

2016/06/20 0.033
- If the firewall supports it use eicar.zip for tests because this might
  trigger different behavior (binary, ZIP instead of text). If this gets
  successfully blocked retry with eicar.txt though.
- download names are now generic instead of eicar.txt and novirus.txt so
  that one could not just block based on this name
- detect if firewall/AV matches eicar+junk or junk+eicar which is not
  allowed according to EICAR usage requirements
- mark some tests as COMMON_INVALID to show that these are invalid but still
  commonly used in practive. Issue a warning if harmless content of this
  type gets blocked.
- some small tests added as variations of existing. These should probably not
  cause any problems but are used to detect blocking of invalid responses
  which are nevertheless commonly seen in practice.

2016/04/20 0.032
- fixed debug function in Javascript which caused the final submission to fail

2016/04/20 0.031
- Each tests now has a fixed ID which will not change over the development of
  the program, i.e. if tests gets added, deleted.... This ID can also be used

bin/dubious_http.pl  view on Meta::CPAN


 4. Specify the payload in the URL, i.e.  http://ip:port/auto/all/virus.exe.
    In this simple form the custom virus.exe is considered malicious and the
    builtin novirus.txt will be used to check for overblocking.

    A more complex version would be:
    http://ip:port/auto/all/virus.zip|virus.exe|mynovirus.exe
    Assuming the virus.* contains the X-Virus header while mynovirus.exe does
    not it will first check with a fully correct and simple response if the
    firewall blocks virus.zip. If not it will retry with virus.exe and if this
    is not blocked too it will assume that the firewall is not able to block the
    virus at all. But if any of these will result in a block it will use it for
    all the further tests. Since mynovirus.exe does not contain the X-Virus
    header it will assumed to be innocent and used to check for overblocking
    instead of the builtin novirus.txt.


USAGE
    exit(1);
}

lib/App/DubiousHTTP/Tests.pm  view on Meta::CPAN

This bulk test tries to transfer the <a
href="http://www.eicar.org/86-0-Intended-use.html">EICAR test virus</a> from the
server to the client. This test virus is commonly used for basic tests of
antivirus and should be detected by every firewall which does deep
inspection to filter out malware. Since this virus itself is not malicious it is
safe to run this test.
</p><p>
But, the transfer is done with various kinds of uncommon or even invalid HTTP
responses to check if the inspection of the firewall can be bypassed this way.
The response from the server will then compared to the expected payload and
hopefully all transfers will be blocked either by the firewall or are considered
invalid by the browser.
</p><p>
The test uses XMLHttpRequests to issue the request and get the response. In most but
not all cases this shows the same behavior as other HTTP requests by the browser
(i.e. loading image, script,...). But to verify that an evasion is actually
possible with normal download one should use the provided link to actually test
the evasion.
</p>
<p id=test_virus class=runtest><a href="/auto/all/eicar">Run Test with <strong>EICAR test virus</strong> payload</a></p>

lib/App/DubiousHTTP/Tests.pm  view on Meta::CPAN

var expect64_harmless;
var file_harmless;
var expect64_bad;
var files_bad = null;
var skip_bad = 0;
var bad_name = null;
var accept = null;
var have_warn = {};

var evasions = 0;
var evasions_blocked = 0;
var overblocked = 0;
var maybe_overblocked = 0;
var browser_invalid = 0;

var rand = Math.random();

function add_warning(m,test) {
    var id = test['num'];
    div_warnings.innerHTML = div_warnings.innerHTML + "[" + id + "] " + m + ": <span class=desc>" + test['desc'] + "</span>" +
	"&nbsp;<a class=trylink target=_blank download='" + test['file'] + "' href=" + test['page'] + ">try</a>" +
	"&nbsp;<a class=srclink target=_blank href=/src" + test['page'] + ">src</a>" +
	"<br>";

lib/App/DubiousHTTP/Tests.pm  view on Meta::CPAN

    if (test['log_header'] && header != '') {
	// i.e. Via added or similar
	results = results + "H | " + test['page'] + " | " + base64_encode(header) + "\n";
    }

    add_debug( test['desc'] + ' - ' + status + ( (test['retry'] == 'harmless') ? ' - retry with harmless content':''), test);

    if (files_bad && test['bad'] && ! test['isbad']) {
	// retry with harmless data: perfectly good response should pass, bad might fail or not
	if (status == 'match') {
	    // bad request was blocked while innocent request passed
	    // in this case an evasion attempt was blocked by the firewall
	    evasions_blocked++;
	    results = results + "Z | " + test['retry4status'] + " | " + test['retry4page'] + " | " + test['desc'] + " | evasion blocked\n";
	} else {
	    // both bad and innocent request failed: might be due to browser or firewall
	    browser_invalid++;
	    if (test['valid'] == 2) { // no browser should fail on this!
		overblocked++;
		add_warning("Failed to load harmless and perfectly valid response",test);
		results = results + "X | " + status + " | " + test['page'] + " | " + test['desc'] + " | failed harmless but must succeed\n";
		results = results + "T | " + test['page'] + " | " + result64 + "\n";
		if (!have_warn['blocked_harmless']) {
		    have_warn['blocked_harmless'] = 1;
		    var div_urlblock = document.getElementById('urlblock');
		    div_urlblock.innerHTML += "<div>" 
			+ "The firewall blocked a harmless and perfectly valid response from the server, which did not contain any kind of evasion attempts.<br>"
			+ "It might be that the firewall blocked the access based on URL filtering and not based on the response at all. "
			+ "This means any results you get during this tests should be considered with great caution because they might not actually reflect "
			+ "the abilities of the firewall to detect malware."
			+ "</div>";
		    div_urlblock.style.display = 'block';
		}
	    } else if (test['valid']>0) {
		if (test['valid'] == 3) {
		    // firewall might have modified request 
		    maybe_overblocked++;
		    add_warning("Failed to load harmless and valid response, maybe the firewall blocked too much",test);
		    results = results + "X | " + status + " | " + test['page'] + " | " + test['desc'] + " | failed harmless but should succeed\n";
		} else if (test['valid'] == 99) {
		    maybe_overblocked++;
		    add_notice("Antivirus cheats by accepting substring for test virus signature",test);
		    results = results + "X | " + status + " | " + test['page'] + " | " + test['desc'] + " | failed harmless but must succeed\n";
		    results = results + "T | " + test['page'] + " | " + result64 + "\n";
		    if (0 && !have_warn['av_substr']) {
			have_warn['av_substr'] = 1;
			var div_urlblock = document.getElementById('urlblock');
			div_urlblock.innerHTML += "<div>" 
			    + "The firewall blocked the content because a substring of the content contained the test virus signature. "
			    + "This is contrary to the rules in which the EICAR test virus should be used, which allow at most some white space after the signature. "
			    + "This means any results you get during this tests should be considered with caution because they might not actually reflect "
			    + "the abilities of the firewall to detect malware."
			    + "</div>";
			div_urlblock.style.display = 'block';
		    }
		} else {
		    add_notice("Failed to load harmless and valid response, might be browser bug",test);
		    results = results + "X | " + status + " | " + test['page'] + " | " + test['desc'] + " | failed harmless\n";
		}
		results = results + "T | " + test['page'] + " | " + result64 + "\n";
	    } else if (test['valid'] == -3) {
		results = results + "B | " + status + " | " + test['page'] + " | " + test['desc'] + " | common invalid failed harmless\n";
		add_warning("Blocked response which is invalid but still commonly seen in real life",test);
	    } else {
		results = results + "B | " + status + " | " + test['page'] + " | " + test['desc'] + " | failed harmless\n";
	    }
	}
	return status;
    }


    if (test['isbad']) {
	// check for evasion

lib/App/DubiousHTTP/Tests.pm  view on Meta::CPAN

		div_nobad.style.display = 'block';
		results = results + "I | " + status + " | " + test['page'] + " | " + test['desc'] + " | no content filter\n";
		div_title.innerHTML = '<h1>Browser behavior test with XMLHTTPRequest</h1>';
	    } else {
		// possible evasion of content filter
		add_warning("Evasion possible",test);
		results = results + "E | " + status + " | " + test['page'] + " | " + test['desc'] + " | evasion\n";
		evasions++;
	    }
	} else {
	    // response blocked
	    if (test['expect_bad']) {
		// add answer to results, maybe we can get the type of firewall from the error message
		results = results + "T | " + test['page'] + " | " + result64 + "\n";
	    } else {
		// recheck with innocent
		test['retry'] = 'harmless';
	    }
	}

    } else {

lib/App/DubiousHTTP/Tests.pm  view on Meta::CPAN


	return;
    }


    div_process.style.display = 'none';
    add_debug("*DONE*");
    var submit_url;
    if (files_bad) {
	var div;
	if (evasions == 0 && overblocked == 0) {
	    results = results + "NO EVASIONS\n";
	    div = document.getElementById('noevade');
	    div.innerHTML = "<h1>Congratulations!<br>No evasions detected.</h1>"
		+ evasions_blocked + " evasions attempts were blocked by the firewall and "
		+ browser_invalid + " attempts failed because the browser considered the response invalid or because the firewall blocks (invalid) responses even if there is no malware payload."
		+ "Please note that these might be considered valid by other browsers and might lead to possible evasions, so better try with other browsers too."
		+ "For this reason I would recommend to check with at least Firefox, Chrome, Safari, Internet Explorer, Edge and Opera because they all behave differently."
		+ "<br><br>To get an overview which products behave that nicely "
		+ "it would be helpful if you provide us with information about the firewall product you use. "
		+ "Please add as much details as you know and like to offer, i.e. model, patch level, specific configurations. ";
	} else if (evasions == 0) {
	    results = results + "NO EVASIONS BUT OVERBLOCKING\n";
	    div = document.getElementById('overblock');
	    div.innerHTML = "<h1>Suspicious!<br>No evasions detected but it looks like overblocking.</h1>"
		+ evasions_blocked + " evasions attempts were blocked by the firewall but in at least "
		+ overblocked + " cases the firewall blocked perfectly valid and innocent responses."
		+ browser_invalid + " attempts failed because the browser considered the response invalid or because the firewall blocks (invalid) responses even if there is no malware payload."
		+ "Please note that these might be considered valid by other browsers and might lead to possible evasions, so better try with other browsers too."
		+ "For this reason I would recommend to check with at least Firefox, Chrome, Safari, Internet Explorer, Edge and Opera because they all behave differently."
		+ "<br><br>To get an overview which products behave that nicely "
		+ "it would be helpful if you provide us with information about the firewall product you use. "
		+ "Please add as much details as you know and like to offer, i.e. model, patch level, specific configurations. ";
	} else {
	    div = document.getElementById('evadable');
	    var msg = "<h1>Danger!<br>Possible evasions detected!</h1>"
		+ "The test detected that " + evasions + " evasion attempts were not blocked by the firewall.<br>"
		+ ((overblocked>0) ? "Additionally in " + overblocked + " cases the firewall blocked perfectly valid and innocent responses.<br>" : '' )
		+ evasions_blocked + " evasions attempts were blocked by the firewall and "
		+ browser_invalid + " attempts failed because the browser considered the response invalid or because the firewall blocks (invalid) responses even if there is no malware payload."
		+ "Please note that these might be considered valid by other browsers and might lead to possible evasions, so better try with other browsers too."
		+ "For this reason I would recommend to check with at least Firefox, Chrome, Safari, Internet Explorer, Edge and Opera because they all behave differently.<br>"
		+ "Since the test differs slightly from a manually triggered download it might be that some of the detected evasions are "
		+ "not usable in reality, so please make sure the evasion works by clicking the [TRY] link "
		+ "and comparing the downloaded file wth your expectation";
	    if (bad_name == 'EICAR') {
		msg += "In case of the EICAR test virus the file should be 68 byte and contain the string "
		    + "<p><span id=eicar>X5O!P%@AP" + "[4\PZX54(P^)" + "7CC)7}$EICAR-STAND" + "ARD-ANTIVI" + "RUS-TEST-FILE!$H+H*</span></p>";
	    }
	    msg += "To get an overview which products are affected by which evasions and to inform the maker of the product about the problems "
		+ "it would be helpful if you provide us with information about the firewall product you use. "
		+ "Please add as much details as you know and like to offer, i.e. model, patch level, specific configurations. ";
	    div.innerHTML = msg;
	}
	div.innerHTML += '<br><br><form enctype="multipart/form-data" method=POST action="/submit_details/' + reference + '/evasions=' + evasions + "/evasions_blocked=" + evasions_blocked + '">'
	    + '<textarea name=product cols=80 rows=4 placeholder="... please add product description here ..."></textarea>'
	    + '<br><input type=submit name=Send></form>';
	div.style.display = 'block';
	submit_url = '/submit_results/' + reference + '/evasions=' + evasions + "/evasions_blocked=" + evasions_blocked;
    } else {
	submit_url = '/submit_results/' + reference;
    }

    if (submit_url) {
	submit_result(submit_url,results);
	results = null;
    }
}

function submit_result(url,data) {
    xhr('POST', url, data, function(req) {
	var blocked = 1;
	try {
	    if (req.status != 200) {
		_log("bad status from submit: " + req.status);
	    } else if (req.getResponseHeader("X-ID") != url) {
	    	_log("bad response x-id:'" + req.getResponseHeader("X-ID") + "' expect:'" + url +"'");
	    } else {
		_log("submission ok");
		blocked = 0
	    }
	}
	catch(e) { _log(e); }

	// disable - to much false reports. Better use --fast-feedback
	if ( 0 && blocked) {
	    // POST might be blocked, try as lots of GET requests
	    var post = url + "\n" + data;
	    data = null;
	    var i = 0;
	    var submit_part;
	    submit_part = function(req,status) {
		if (!status) status = req.status;
		if (status != 200) {
		    _log("submitting part failed: " + status);
		    return;
		} else if (post == null) {

lib/App/DubiousHTTP/Tests/Common.pm  view on Meta::CPAN

    MUSTBE_VALID SHOULDBE_VALID VALID INVALID UNCOMMON_VALID UNCOMMON_INVALID COMMON_INVALID
    SETUP content html_escape url_encode garble_url ungarble_url bro_compress zlib_compress
    $NOGARBLE $CLIENTIP $TRACKHDR $FAST_FEEDBACK
);
use Scalar::Util 'blessed';

our $CLIENTIP = undef;
our $NOGARBLE = 0;
our $FAST_FEEDBACK = 0;
use constant {
    SHOULDBE_VALID => 3,  # simple chunked, gzip.. - note if blocked
    MUSTBE_VALID => 2,    # no browser should fail on this
    VALID => 1,
    INVALID => 0,
    UNCOMMON_VALID => -1,
    UNCOMMON_INVALID => -2,
    COMMON_INVALID => -3,
};

my $basedir = 'static/';
sub basedir { $basedir = pop }



( run in 0.473 second using v1.01-cache-2.11-cpan-49f99fa48dc )