PATH TO PHP#!/usr/bin/php
<?php

/*
 * Appfinger - Application Fingerprinter 
 * Francesco `ascii` Ongaro (ascii@ush.it)
 * (C) 2008 www.ush.it
 * 
 * P0C from a discussion with ehmo and kuza55
 */

$config = array();
$config['target'] = 'http://www.example.com';

define('DATABASE_DIR', 'database/');
define('DEBUG', FALSE);

$definitions = glob(DATABASE_DIR.'*.xml');

$results = array();
foreach ($definitions as $definition) {
	echo 'Loading '.$definition.' ..'."\n";
	
	$definition_tree = xml_parse_into_assoc($definition);
	if (DEBUG) print_r($definition_tree);
	
	$score = 0;
	foreach ($definition_tree as $software) {
		$tests = count($software['tests']);
		echo "\t".'Starting fingerprint for '.$software['name'].' ('.$tests.' test/s) ..'."\n";

		$test_id = 0;
		$results_test = array();
		foreach ($software['tests'] as $test) {
			echo "\t\t".'Performing test ('.$test_id.'/'.$tests.') version('.$test['version'].') score('.$test['score'].') ..'."\n";
			
			$in = call_user_func_array(
				'callback_'.$test['in']['callback'],
				array_merge(array($config), $test['in']['args'])
			);
			
			if (DEBUG) print_r($in);
			
			$out = call_user_func_array(
				'callback_'.$test['out']['callback'],
				array_merge(array($config), array($in), $test['out']['args'])
			);
			
			if (DEBUG) print_r($out);
			
			$test_score = 0;
			if ($out)
				$test_score = $test['score'];
				
			$score += $test_score;
			
			$results_test[] = array(
				'version' => $test['version'],
				$test_score
			);
			
			$test_id++;
		}
	}
	echo "\t\t".'Application scored '.$score.' points ..'."\n";
	$results[$software['name']] = array(
		'score' => $score,
		$results_test
	);
}

if (DEBUG) print_r($results);
$results_file = 'results_'.time().'.srz';
file_put_contents($results_file, serialize($results));
echo 'Results serialized to '.$results_file.'. Bye!'."\n";

function callback_http_fetch($config, $url) {
	return @file_get_contents($config['target'].$url);
}

function callback_preg_match($config, $in, $match) {
	if (preg_match($match, $in))
		return TRUE;

	return FALSE;
}

function xml_parse_into_assoc($file) {
	$data = implode('', file($file));
	$p = xml_parser_create();
 
	xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, 0);
	xml_parser_set_option($p, XML_OPTION_SKIP_WHITE, 1);
 
	xml_parse_into_struct($p, $data, $vals, $index);
	xml_parser_free($p);

	$levels = array(null);
 
	foreach ($vals as $val) {
		if ($val['type'] == 'open' || $val['type'] == 'complete')
			if (!array_key_exists($val['level'], $levels))
				$levels[$val['level']] = array();
	 
		$prevLevel =& $levels[$val['level']-1];
		$parent = $prevLevel[sizeof($prevLevel)-1];
	 
		if ($val['type'] == 'open') {
			$val['children'] = array();
			array_push(&$levels[$val['level']], $val);
			continue;
		}
	 
		else if ($val['type'] == 'complete')
			$parent['children'][$val['tag']] = $val['value'];
	 
		else if ($val['type'] == 'close') {
			$pop = array_pop($levels[$val['level']]);
			$tag = $pop['tag'];
		 
			if ($parent) {
				if (!array_key_exists($tag, $parent['children']))
					$parent['children'][$tag] = $pop['children'];

				else if (is_array($parent['children'][$tag]))
					$parent['children'][$tag][] = $pop['children'];

			} else
				return(array($pop['tag'] => $pop['children']));
		}
	 
		$prevLevel[sizeof($prevLevel)-1] = $parent;
	}
}

?>

