Commits

Ethan Robish committed f04628f

Comments (0)

Files changed (9)

+<IfModule mod_rewrite.c>
+RewriteEngine On
+RewriteBase /labyrinth
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteRule . /labyrinth/index.php [L]
+</IfModule>
+WebLabyrinth - A simple tool that creates a maze of bogus web pages to 
+confuse web scanners. It's main goal is to delay and occupy malicious 
+scanners that scan websites in order for incident handlers to detected 
+and respond to them before damage is done.
+
+WebLabyrinth code Copyright (c) 2010, Ben Jackson and Mayhemic Labs -
+bbj@mayhemiclabs.com. All rights reserved.
+
+Dissociated Press functions based off of David Pascoe-Deslauriers' 
+<dpascoed@csiuo.com> dissociatedpress class. Copyright 2000-2009 
+David Pascoe-Deslauriers. All rights reserved.
+
+Original Dissociated Press code available at 
+http://www.csiuo.com/drupal/node/13
+
+PREREQUISITES
+
+* Apache
+* mod_rewrite
+* PHP
+* sqlite
+* PHP sqlite extension
+* PHP mail() support
+
+SETUP AND CONFIGURATION
+
+Configuration is broken up into two parts, setting up the web 
+application, and configuring the database. First, copy all the files in 
+a web accessible directory and edit the config.inc.php to reflect the 
+directory name. If you installed it as /labyrinth, it should be all set. 
+
+Next, you also need to create a .htaccess file in the same directory 
+as the installation. There is an example in EXAMPLE.htaccess, built 
+with theassumption that you have WebLabyrinth installed in a web path 
+called /labyrinth and the index.php file has not been renamed. The only two 
+variables in the .htaccess that should ever need to be changed is 
+RewriteBase which should be the web path that WebLabyrinth is installed
+in and RewriteRule which is the web path that the main index.php file
+is located. 
+
+Finally, you need to configure the database. This database should be
+installed in a non web accessible directory. The directory should both 
+readable and writeable by the Apache user. The SQL script to create the
+database is labyrinth.sql. The following commands do this on my (Debian) 
+system:
+
+ 	mkdir /opt/weblabyrinth/
+ 	cat labyrinth.sql | sqlite /opt/weblabyrinth/labyrinth.db
+	chown -R www-data:www-data /opt/weblabyrinth
+
+Once the database is created, edit the config.inc.php 'tracking_db'
+variable to point to your freshly created database.
+
+ALERTING
+
+One of the new features (as of the 0.3 branch) is the ability to generate 
+alerts if a crawler reaches a certain level. The two ways weblabyrinth can
+do this is by generating an e-mail or by generating text that an IDS system
+can trigger on. All of these options are controlled in the config.inc.php
+file. If you use snort, the following rule should generate an alert if the 
+word used by default is found.
+
+alert tcp any 80 -> any any (content:"honorificabilitudinitatibus"; msg: "WebLabyrinth alert keyword detected";)
+
+By default the system will generate an alert if the crawlers get three 
+levels deep within the labyrinth. The system will generate the alert maximum
+once an hour for an ongoing scan. 
+
+NOTE ABOUT APACHE
+
+Please note that you may need to reconfigure apache to allow .htaccess
+files to control configuration options. This is done in the apache site's
+configuration file (/etc/apache2/sites-available/<your site here>). Below 
+is an example from my installation on a Debian server:
+
+<Directory /var/www/labyrinth>
+	Options Indexes FollowSymLinks MultiViews
+	AllowOverride FileInfo Options
+	Order allow,deny
+	allow from all
+</Directory>
+
+The "AllowOverride FileInfo Options" is the important bit. Remember to 
+restart Apache when you're done. 
+Alice was beginning to get very tired of sitting by her sister on the
+bank, and of having nothing to do: once or twice she had peeped into the
+book her sister was reading, but it had no pictures or conversations in
+it, 'and what is the use of a book,' thought Alice 'without pictures or
+conversation?'
+
+So she was considering in her own mind (as well as she could, for the
+hot day made her feel very sleepy and stupid), whether the pleasure
+of making a daisy-chain would be worth the trouble of getting up and
+picking the daisies, when suddenly a White Rabbit with pink eyes ran
+close by her.
+
+There was nothing so VERY remarkable in that; nor did Alice think it so
+VERY much out of the way to hear the Rabbit say to itself, 'Oh dear!
+Oh dear! I shall be late!' (when she thought it over afterwards, it
+occurred to her that she ought to have wondered at this, but at the time
+it all seemed quite natural); but when the Rabbit actually TOOK A WATCH
+OUT OF ITS WAISTCOAT-POCKET, and looked at it, and then hurried on,
+Alice started to her feet, for it flashed across her mind that she had
+never before seen a rabbit with either a waistcoat-pocket, or a watch
+to take out of it, and burning with curiosity, she ran across the field
+after it, and fortunately was just in time to see it pop down a large
+rabbit-hole under the hedge.
+
+In another moment down went Alice after it, never once considering how
+in the world she was to get out again.
+
+The rabbit-hole went straight on like a tunnel for some way, and then
+dipped suddenly down, so suddenly that Alice had not a moment to think
+about stopping herself before she found herself falling down a very deep
+well.
+
+Either the well was very deep, or she fell very slowly, for she had
+plenty of time as she went down to look about her and to wonder what was
+going to happen next. First, she tried to look down and make out what
+she was coming to, but it was too dark to see anything; then she
+looked at the sides of the well, and noticed that they were filled with
+cupboards and book-shelves; here and there she saw maps and pictures
+hung upon pegs. She took down a jar from one of the shelves as
+she passed; it was labelled 'ORANGE MARMALADE', but to her great
+disappointment it was empty: she did not like to drop the jar for fear
+of killing somebody, so managed to put it into one of the cupboards as
+she fell past it.
+
+'Well!' thought Alice to herself, 'after such a fall as this, I shall
+think nothing of tumbling down stairs! How brave they'll all think me at
+home! Why, I wouldn't say anything about it, even if I fell off the top
+of the house!' (Which was very likely true.)
+
+Down, down, down. Would the fall NEVER come to an end! 'I wonder how
+many miles I've fallen by this time?' she said aloud. 'I must be getting
+somewhere near the centre of the earth. Let me see: that would be four
+thousand miles down, I think--' (for, you see, Alice had learnt several
+things of this sort in her lessons in the schoolroom, and though this
+was not a VERY good opportunity for showing off her knowledge, as there
+was no one to listen to her, still it was good practice to say it over)
+'--yes, that's about the right distance--but then I wonder what Latitude
+or Longitude I've got to?' (Alice had no idea what Latitude was, or
+Longitude either, but thought they were nice grand words to say.)
+
+Presently she began again. 'I wonder if I shall fall right THROUGH the
+earth! How funny it'll seem to come out among the people that walk with
+their heads downward! The Antipathies, I think--' (she was rather glad
+there WAS no one listening, this time, as it didn't sound at all the
+right word) '--but I shall have to ask them what the name of the country
+is, you know. Please, Ma'am, is this New Zealand or Australia?' (and
+she tried to curtsey as she spoke--fancy CURTSEYING as you're falling
+through the air! Do you think you could manage it?) 'And what an
+ignorant little girl she'll think me for asking! No, it'll never do to
+ask: perhaps I shall see it written up somewhere.'
+
+Down, down, down. There was nothing else to do, so Alice soon began
+talking again. 'Dinah'll miss me very much to-night, I should think!'
+(Dinah was the cat.) 'I hope they'll remember her saucer of milk at
+tea-time. Dinah my dear! I wish you were down here with me! There are no
+mice in the air, I'm afraid, but you might catch a bat, and that's very
+like a mouse, you know. But do cats eat bats, I wonder?' And here Alice
+began to get rather sleepy, and went on saying to herself, in a dreamy
+sort of way, 'Do cats eat bats? Do cats eat bats?' and sometimes, 'Do
+bats eat cats?' for, you see, as she couldn't answer either question,
+it didn't much matter which way she put it. She felt that she was dozing
+off, and had just begun to dream that she was walking hand in hand with
+Dinah, and saying to her very earnestly, 'Now, Dinah, tell me the truth:
+did you ever eat a bat?' when suddenly, thump! thump! down she came upon
+a heap of sticks and dry leaves, and the fall was over.
+
+Alice was not a bit hurt, and she jumped up on to her feet in a moment:
+she looked up, but it was all dark overhead; before her was another
+long passage, and the White Rabbit was still in sight, hurrying down it.
+There was not a moment to be lost: away went Alice like the wind, and
+was just in time to hear it say, as it turned a corner, 'Oh my ears
+and whiskers, how late it's getting!' She was close behind it when she
+turned the corner, but the Rabbit was no longer to be seen: she found
+herself in a long, low hall, which was lit up by a row of lamps hanging
+from the roof.
+
+There were doors all round the hall, but they were all locked; and when
+Alice had been all the way down one side and up the other, trying every
+door, she walked sadly down the middle, wondering how she was ever to
+get out again.
+
+Suddenly she came upon a little three-legged table, all made of solid
+glass; there was nothing on it except a tiny golden key, and Alice's
+first thought was that it might belong to one of the doors of the hall;
+but, alas! either the locks were too large, or the key was too small,
+but at any rate it would not open any of them. However, on the second
+time round, she came upon a low curtain she had not noticed before, and
+behind it was a little door about fifteen inches high: she tried the
+little golden key in the lock, and to her great delight it fitted!
+
+Alice opened the door and found that it led into a small passage, not
+much larger than a rat-hole: she knelt down and looked along the passage
+into the loveliest garden you ever saw. How she longed to get out of
+that dark hall, and wander about among those beds of bright flowers and
+those cool fountains, but she could not even get her head through the
+doorway; 'and even if my head would go through,' thought poor Alice, 'it
+would be of very little use without my shoulders. Oh, how I wish I could
+shut up like a telescope! I think I could, if I only know how to begin.'
+For, you see, so many out-of-the-way things had happened lately,
+that Alice had begun to think that very few things indeed were really
+impossible.
+
+There seemed to be no use in waiting by the little door, so she went
+back to the table, half hoping she might find another key on it, or at
+any rate a book of rules for shutting people up like telescopes: this
+time she found a little bottle on it, ('which certainly was not here
+before,' said Alice,) and round the neck of the bottle was a paper
+label, with the words 'DRINK ME' beautifully printed on it in large
+letters.
+
+It was all very well to say 'Drink me,' but the wise little Alice was
+not going to do THAT in a hurry. 'No, I'll look first,' she said, 'and
+see whether it's marked "poison" or not'; for she had read several nice
+little histories about children who had got burnt, and eaten up by wild
+beasts and other unpleasant things, all because they WOULD not remember
+the simple rules their friends had taught them: such as, that a red-hot
+poker will burn you if you hold it too long; and that if you cut your
+finger VERY deeply with a knife, it usually bleeds; and she had never
+forgotten that, if you drink much from a bottle marked 'poison,' it is
+almost certain to disagree with you, sooner or later.
+
+However, this bottle was NOT marked 'poison,' so Alice ventured to taste
+it, and finding it very nice, (it had, in fact, a sort of mixed flavour
+of cherry-tart, custard, pine-apple, roast turkey, toffee, and hot
+buttered toast,) she very soon finished it off.
+
+'What a curious feeling!' said Alice; 'I must be shutting up like a
+telescope.'
+
+And so it was indeed: she was now only ten inches high, and her face
+brightened up at the thought that she was now the right size for going
+through the little door into that lovely garden. First, however, she
+waited for a few minutes to see if she was going to shrink any further:
+she felt a little nervous about this; 'for it might end, you know,' said
+Alice to herself, 'in my going out altogether, like a candle. I wonder
+what I should be like then?' And she tried to fancy what the flame of a
+candle is like after the candle is blown out, for she could not remember
+ever having seen such a thing.
+
+After a while, finding that nothing more happened, she decided on going
+into the garden at once; but, alas for poor Alice! when she got to the
+door, she found she had forgotten the little golden key, and when she
+went back to the table for it, she found she could not possibly reach
+it: she could see it quite plainly through the glass, and she tried her
+best to climb up one of the legs of the table, but it was too slippery;
+and when she had tired herself out with trying, the poor little thing
+sat down and cried.
+
+'Come, there's no use in crying like that!' said Alice to herself,
+rather sharply; 'I advise you to leave off this minute!' She generally
+gave herself very good advice, (though she very seldom followed it),
+and sometimes she scolded herself so severely as to bring tears into
+her eyes; and once she remembered trying to box her own ears for having
+cheated herself in a game of croquet she was playing against herself,
+for this curious child was very fond of pretending to be two people.
+'But it's no use now,' thought poor Alice, 'to pretend to be two people!
+Why, there's hardly enough of me left to make ONE respectable person!'
+
+Soon her eye fell on a little glass box that was lying under the table:
+she opened it, and found in it a very small cake, on which the words
+'EAT ME' were beautifully marked in currants. 'Well, I'll eat it,' said
+Alice, 'and if it makes me grow larger, I can reach the key; and if it
+makes me grow smaller, I can creep under the door; so either way I'll
+get into the garden, and I don't care which happens!'
+
+She ate a little bit, and said anxiously to herself, 'Which way? Which
+way?', holding her hand on the top of her head to feel which way it was
+growing, and she was quite surprised to find that she remained the same
+size: to be sure, this generally happens when one eats cake, but Alice
+had got so much into the way of expecting nothing but out-of-the-way
+things to happen, that it seemed quite dull and stupid for life to go on
+in the common way.
+
+So she set to work, and very soon finished off the cake.
+<?php
+/**
+ * WebLabyrinth
+ *
+ * config.inc.php
+ *
+ * Configuration options for WebLabyrinth
+ *
+ * All code Copyright (c) 2010-2011, Ben Jackson and Mayhemic Labs - 
+ * bbj@mayhemiclabs.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the author nor the names of contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+
+	global $config;
+	$config = array(
+		//Web Path where WebLabyrinth is installed
+		'web_path' => '/labyrinth',
+
+		//Text file to generate text from
+		'corpus' => 'alice.txt',
+
+		//Database to track crawlers
+		'tracking_db' => '/opt/weblabyrinth/labyrinth.db',
+
+		'bogus_email' => array(
+			//Do we want to generate mailto: in addition to web links?
+			'enabled' => 'false',
+
+			//Domain to generate addresses to
+			'domain' => '',
+
+			//Probability (out of 100) of links generated to be e-mail
+			'probability' => 10,
+		),
+
+		//How many levels deep do we want to wait before we trigger an alert?
+		'alert_levels_deep' => 3,
+
+		//Do we want generate an alert if a host we have never logged before
+		//connects to the labyrinth for the first time?
+		'alert_on_new' => true,
+		
+		'alert_syslog' => array(
+			//Do we want to generate syslog alerts?
+			'enabled' => 'true'
+		),
+
+		'alert_email' => array(
+			//Do we want to generate email alerts?
+			'enabled' => 'true',
+
+			//e-mail to send alerts to
+			'address' => 'root@localhost'
+		),
+
+		'alert_ids' => array(
+			//Do we want to try to cause an IDS alert?
+			'enabled' => 'true',
+
+			//Text to trigger IDS alert
+			'text' => 'honorificabilitudinitatibus'
+		)
+	);
+?>

dissociated-press.inc.php

+<?php
+
+/**
+ * dissociated-press.inc.php
+ *
+ * Functions for creating random text for use within WebLabyrinth.
+ *
+ * Code based off of David Pascoe-Deslauriers' <dpascoed@csiuo.com> 
+ * dissociatedpress class. 
+ *
+ * @link       http://www.csiuo.com/drupal/node/13
+ *
+ * Copyright 2000-2009 David Pascoe-Deslauriers. All rights reserved.
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above 
+ * copyright notice, this list of conditions and the following 
+ * disclaimer in the documentation and/or other materials provided 
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY 
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR 
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Modifications Copyright (c) 2010, Ben Jackson and Mayhemic Labs - 
+ * bbj@mayhemiclabs.com. All rights reserved.
+ *
+ */
+ 
+ 
+class dissociatedpress {
+ 
+	function dissociate ($str, $url_dir, $randomstart = true, $groupsize = 4, $max = 128) {
+
+		if ($groupsize < 2) {
+			$groupsize = 2;
+		}
+			// Capitalize the first word
+		$capital = true;
+	 
+			//Remove from corpus, they just make the result confusing
+		$str = str_replace(array("(",")","[","]","{","}"), array(),$str);
+	 
+			//Break up tokens
+		$tokens = preg_split("/[ \r\n\t]/",$str);
+	 
+			//Clean up token array
+		for ($i = 0; $i < sizeof($tokens); $i++){
+			if ($tokens[$i] == ""){
+				unset($tokens[$i]);
+			}
+		}
+	 
+		$tokens = array_values($tokens);
+	 
+			//Init variables
+		$return = "";
+		$lastmatch = array();
+	 
+			// if we start at the beginning, start there
+		if (!$randomstart) {
+			for ($n = 0; $n < $groupsize; $n++){
+				array_push($lastmatch,$tokens[$n]);
+				$res = $this->cleanToken($tokens[$n],$capital);
+				$return .= $res[0];
+				$capital = $res[1];
+			}
+		}
+	 
+			//Loop until we have enough output
+		$i = 0;
+		while ($i < $max + 32){
+			// Try and end on a full sentence
+			if ($i > $max - 8 and $capital){
+				break;
+			}
+	 
+			//If the lastmatch group isn't good enough, start randomly
+			if (sizeof($lastmatch) < $groupsize){
+				$loc = rand(0,sizeof($tokens)-$groupsize);
+				$lastmatch = array();
+				for ($n = 0; $n < $groupsize; $n++){
+					array_push($lastmatch,$tokens[$loc+$n]);
+					$res = $this->cleanToken($tokens[$loc+$n],$capital);
+					$return .= $this->ProcessText($res[0],$url_dir);
+					$capital = $res[1];
+				}
+			} else {
+				$chains = $this->findChains($tokens, $lastmatch);
+				$lastmatch = array();
+	 
+				// If there aren't enough chains, start randomly next time (avoid getting caught in loops)
+				if (sizeof($chains) > 2) {
+					$loc = $chains[rand(0, sizeof($chains)-1)];
+					for ($n = 0; $n < $groupsize; $n++){
+						array_push($lastmatch,$tokens[$loc+$n]);
+						$res = $this->cleanToken($tokens[$loc+$n],$capital);
+						$return .= $this->ProcessText($res[0],$url_dir);
+						$capital = $res[1];
+					}
+				}
+			}
+			$i++;
+		}
+	 
+		return $return;
+	}
+	 
+	/**
+	 * Join the tokens with proper typography
+	 */
+	 
+	function cleanToken($token,$capital) {
+		if ($capital){
+			$token = ucfirst($token);
+			$capital = false;
+		}
+	 
+		if (substr($token,-1,1) == '.'){
+			$capital = true;
+			return array($token . "  ",$capital);
+		} else {
+			return array($token . " ",$capital);
+		}
+	}
+	 
+	/**
+	 * Naively find possible Markov Chains
+	 */
+	 
+	function findChains($haystack, $needle) {
+		$return = array();
+		for ($i = 0; $i < sizeof($haystack) - sizeof($needle); $i++){
+			if ($haystack[$i] == $needle[0]){
+				$matches = true;
+				for ($j = 1; $j < sizeof($needle); $j++){
+					if ($haystack[$i+$j] != $needle[$j]){
+						$matches = false;
+						break;
+					}
+				}
+				if ($matches == true){
+					array_push($return,$i+sizeof($needle));
+				}
+			}
+		}
+		return $return;
+	}
+
+	function ProcessText($text, $directory){
+
+		global $config;
+
+		$link = mt_rand(0,100);
+
+		if ($link < 10){
+			$text = trim($text);
+			$link = base64_encode(mt_rand(0,100000000));
+			$link = str_replace('=','',$link);
+
+			if ($config['bogus_email']['enabled']){
+				$email_link = mt_rand(0,100);
+				if ($email_link <= $config['bogus_email']['probability']){
+					return '<a href="mailto:' . $link . '@' . $config['bogus_email']['domain'] . '">' . $text . '</a> ';
+				}
+			}
+
+			return '<a href="' . $directory . '/' . $link . '">' . $text . '</a> ';
+		}else{
+			return "$text";
+		}
+	} 
+
+}
+
+?>
+<?php
+
+/**
+ * WebLabyrinth
+ *
+ * index.php
+ *
+ * Main web page that creates bogus links in order to entrap
+ * web scanners.
+ *
+ * All code Copyright (c) 2010-2011, Ben Jackson and Mayhemic Labs - 
+ * bbj@mayhemiclabs.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the author nor the names of contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+
+
+include_once('config.inc.php');
+include_once('labyrinth.inc.php');
+include_once('dissociated-press.inc.php');
+
+$labyrinth_handle = new Labyrinth($_SERVER['REMOTE_ADDR'],$_SERVER['HTTP_USER_AGENT']);
+
+// Obviously, a search engine spider hitting this will be like an unstoppable
+// force striking an immovable object. If the user agent appears to be a 
+// search engine return a 404 error and serenade them with some Tom Petty.
+
+if($labyrinth_handle->CheckForSearchEngines()){
+	header("HTTP/1.0 404 Not Found");
+	print "o/~ Whatever you're looking for... / Hey! Don't come around here no more... o/~";
+	exit;
+}
+
+// Randomly generate an error just to "Keep it real"
+// This was mainly done to fool w3af
+$labyrinth_handle->SpinTheWheelOfErrors();
+
+// If index.php is in the request URI, lob it off. Otherwise, lob off the trailing slash.
+if(preg_match("/index.php/",$_SERVER['REQUEST_URI'])){	
+	$directory = dirname($_SERVER['REQUEST_URI']);
+}else{
+	$directory = rtrim($_SERVER['REQUEST_URI'], "/");
+}
+
+
+// Alert
+$base_level = sizeof(explode('/',rtrim($config['web_path'],'/')));
+$uri_level = sizeof(explode('/',$directory)); 
+
+//Log the crawler to the database
+$labyrinth_handle->LogCrawler();
+
+if (($uri_level - $base_level) >= $config['alert_levels_deep']){
+	$labyrinth_handle->GenerateAlert("Crawler Ensnared!");
+}
+
+// Read the text into a variable for processing by the dissociated press class.
+$fh = fopen($config['corpus'], 'r');
+$corpus = fread($fh, filesize($config['corpus']));
+fclose($fh); 
+
+?>
+
+<link rel="stylesheet" type="text/css" href="<?php print $config['web_path']; ?>/labyrinth.css">
+<title><?php print basename($_SERVER['REQUEST_URI']); ?></title>
+<body>
+	<?php 
+		// Print the text with links
+		$dissociated_press = new dissociatedpress;
+		print $dissociated_press->dissociate($corpus, $directory);
+	?>
+</body>
+</html>
+body {
+    color: #2F2F2F;
+    font-size: small;
+    font-family: arial, verdana, tahoma, sans-serif;
+}
+h1 {
+    size: 130%;
+    border-bottom: 1px solid #888;
+}
+h2 {
+    size: 120%;
+    border-bottom: 1px solid #888;
+}
+h3 {
+    size: 110%;
+}
+h4 {
+    size: 107%;
+    border-bottom: 1px solid #888;
+}
+h5 {
+    size: 105%;
+}
+h6 {
+    size: 102%;
+}
+a {
+    color: #39F;
+    text-decoration: none;
+}
+a:hover {
+    color: #00F;
+    text-decoration: underline;
+}
+

labyrinth.inc.php

+<?php
+
+/**
+ * labyrinth.inc.php
+ *
+ * Functions for creating a web page with bogus links in order to entrap
+ * web scanners.
+ *
+ * All code Copyright (c) 2010-2011, Ben Jackson and Mayhemic Labs - 
+ * bbj@mayhemiclabs.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code mustu retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the author nor the names of contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+ 
+class Labyrinth {
+	
+	var $dbhandle;
+	var $crawler_info;
+	var $crawler_ip;
+	var $crawler_useragent;
+
+	public $new;
+
+	public function Labyrinth($ip,$useragent){
+		global $config;
+		mt_srand($this->MakeSeed());
+
+		$this->dbhandle = new SQLiteDatabase($config['tracking_db']);
+
+		$this->crawler_ip = sqlite_escape_string($ip);
+		$this->crawler_useragent = sqlite_escape_string($useragent);
+
+		$this->crawler_info = $this->dbhandle->query("SELECT crawler_ip FROM crawlers WHERE crawler_ip='" . $this->crawler_ip ."' AND crawler_useragent='" . $this->crawler_useragent . "'");
+	}
+
+	function CheckForSearchEngines(){
+		switch(true){
+			case preg_match("/Google/",$this->crawler_useragent):
+			case preg_match("/Yandex/",$this->crawler_useragent):
+			case preg_match("/Openfind/",$this->crawler_useragent):
+			case preg_match("/msnbot/",$this->crawler_useragent):
+			case preg_match("/bingbot/",$this->crawler_useragent):
+			case preg_match("/Slurp/",$this->crawler_useragent):
+			case preg_match("/Yahoo/",$this->crawler_useragent):
+			case preg_match("/Architext/",$this->crawler_useragent):
+				return true;
+				break;
+		}
+	}
+
+	function MakeSeed(){
+		list($usec, $sec) = explode(' ', microtime());
+		return (float) $sec + ((float) $usec * 123456);
+	}
+
+
+	function SpinTheWheelOfErrors(){
+		$error_chance = rand(0,100);
+
+		$error_string = false;
+
+		if ($error_chance == 16){
+			$error_string = "HTTP/1.1 404 Not Found";
+		}elseif ($error_chance == 23){
+			$error_string = "HTTP/1.1 403 Forbidden";
+		}elseif ($error_chance == 42){
+			#Included just for the WTF Factor
+			$error_string = "HTTP/1.1 402 Payment Required";
+		}
+
+		if ($error_string){
+			header($error_string);
+			exit;
+		}
+	}
+
+	function GenerateAlert($message="We got a live one!"){
+		global $config;
+
+		//Have we seen this crawler recently?		
+		$last_seen_query = $this->dbhandle->query("SELECT strftime('%s',datetime('now','localtime')) - strftime('%s',last_alert) FROM crawlers WHERE crawler_ip='" . $this->crawler_ip . "' AND crawler_useragent='" . $this->crawler_useragent . "'") or die(sqlite_error_string($this->dbhandle->lastError()));;
+		
+		$time = $last_seen_query->fetchSingle();
+
+		if (($time == 0) || ($time > 3600)){
+			if ($config['alert_ids']['enabled']){
+				print $config['alert_ids']['text'] . ' ';
+			}
+
+			if ($config['alert_email']['enabled']){
+				mail($config['alert_email']['address'], "WebLabyrinth Alert - " . $this->crawler_ip, "$message\n\nIP: "  . $this->crawler_ip . "\nUser Agent: " . $this->crawler_useragent);
+			}
+
+			if ($config['alert_syslog']['enabled']){
+				openlog("weblabyrinth", LOG_PID, LOG_LOCAL0);
+				syslog(LOG_WARNING, "ALERT, message=[$message], src_ip=[{$_SERVER['REMOTE_ADDR']}], user_agent=[{$_SERVER['HTTP_USER_AGENT']}]");
+				closelog();
+			}
+
+			$last_alert_query = $this->dbhandle->query("UPDATE crawlers SET last_alert=datetime('now','localtime') WHERE crawler_ip='" . $this->crawler_ip . "' AND crawler_useragent='" . $this->crawler_useragent . "'");
+		}
+	}
+
+	function LogCrawler(){
+		global $config;
+
+		if($this->crawler_info->numRows() > 0){
+			$this->dbhandle->query("UPDATE crawlers SET last_seen = datetime('now','localtime'), num_hits=num_hits+1 WHERE crawler_ip='" . $this->crawler_ip . "' AND crawler_useragent='" . $this->crawler_useragent . "'");
+		}else{
+			$crawler_rdns = gethostbyaddr($this->crawler_ip);
+			$this->dbhandle->query("INSERT INTO crawlers(crawler_ip, crawler_rdns, crawler_useragent, first_seen, last_seen, num_hits) VALUES('" . $this->crawler_ip . "', '$crawler_rdns', '" . $this->crawler_useragent . "', datetime('now','localtime'), datetime('now','localtime'), 1)");
+
+			$this->new = true;
+			if($config['alert_on_new']){
+				$this->GenerateAlert("New host logged!");
+			}
+
+		}
+	}
+}
+?>
+
+
+CREATE TABLE crawlers (crawler_ip TEXT, crawler_rdns TEXT, crawler_useragent TEXT, first_seen DATETIME, last_seen DATETIME, last_alert DATETIME, num_hits INTEGER);