#! /usr/bin/env python """Strychnine implements anti-webscraping mechanisms to try to defer password guessing attacks against the server and to try to pollute spam databases. The simplest way of using it is to put in it your scripts or cgi-bin directory and then refer to it from your main page or some other common entry point. However, you can make it your error handler via this in apache's config files: ErrorDocument 404 /cgi-bin/strychnine.py Note that you might want to rename this file to something innocuous like "site.py", "main.py", or even rename the file to "site.asp", and use this: AddHandler cgi-script .cgi .py .asp ...in which case, you can place this file anywhere in your document tree. Original concept based upon wpoison.pl by Ronald F. Guilmette, please see: http://www.monkeys.com/wpoison/ """ __author__ = 'Chuck Swiger ' __copyright__ = 'Copyright (c) 2005 Charles Swiger' __version__ = '$Id: strychnine.py,v 1.2 2005/12/12 18:56:13 chuck Exp $' __license__ = 'This software is licenced under the same terms as Python. (See the PSF license at www.python.org/license.html).' import os,sys,string,time,random # useful for debugging #import cgi #import cgitb; cgitb.enable() #### # figure out the server name we were called by and the URI to ourselves. try: servername = os.environ['SERVER_NAME'] except KeyError: servername = 'localhost' try: URI = os.environ['REQUEST_URI'] except KeyError: URI = '/cgi-bin/strychnine.py' try: remote_addr = os.environ['REMOTE_ADDR'] except KeyError: remote_addr = '127.0.0.1' # generate randomized content per-IP which updates once per day... offset = time.localtime()[7] if (URI.find('?') > -1): offset += 100 * len(URI) rnd = random.Random(offset + int(string.join(remote_addr.split('.'), ''))) # top-level domain list including various international domains listed high # amoung the sources of spam. TLD = [ 'com', 'net', 'org', 'gov', 'edu', 'mil', 'us', 'jp', 'it', 'de', 'ca', 'fr', 'ch', 'tw', 'cn', 'kr', 'uk', 'br', 'ru', 'eu' ] # top-1000 most common english words, slightly modified # (its better to keep this inline with the program than open and read a file) wordlist = string.split('a able about above accept accord account across act actual add address admit adopt advance advantage adventure affair afford after again against age agent ago agree air all allow almost alone along already also although always among amount an ancient and animal another another answer any appear apply appoint arise arm army around arrive art article as ask association at attack attempt average away back bad ball bank bar base battle be bear beauty because become bed before begin behind being believe belong below beneath best better between beyond big bill bird bit black bless blood blow blue board boat boat body book born box boy branch bread break bridge bright bring broad brother build burn business but buy by call camp can canal capital captain car care carry case castle cause centre century certain chair chance change character charge chief child choose church circle city claim class clean clear close cloud club coal coast coin cold college colony color come comfort command committee common company compare complete concern condition connect consider contain content continue control corn corner cost cotton could council count country course court cover creature crop cross crowd crown cry current custom cut dance danger dare dark date daughter day dead deal dear debt decide declare deep defeat degree deliver demand department depend describe desert desire destroy detail determine develop die difference difficult direct discover disease distance distinguish district divide do dog dollar door double down draw dream dress drink drive drop dry due duty each ear early earth east easy eat edge edge effect effort egg either elect else empire employ end enemy english enjoy enough enter entire equal escape even evening event ever every evil example excellent except exchange exercise exist expect expense experience experiment explain express extend eye face fact factory fail fair faith fall familiar family famous fancy far farm fashion fast fate favor fear feed feel fellow few field fight figure fill find fine finger finish fire first fish fit fix flag floor flow fly follow for force foreign forest forget form former forth fortune free fresh friend from front full furnish future gain game garden gas gate gather general gentle get girl give glad glass glory go god gold good grain grave great green ground grow guard gun habit hall hand handle hang happen happy hard hardly have he head health hear heat heaven heavy help her here hide hide high hill his history hold home honest honour hope horse hot hour house how human I idea ideal if ill important impossible in inch include increase indeed independent influence instead intend interest into introduce iron it its join joy judge just keep kill kind king know lack lady lake land language large last late latter laugh law lay lead leaf learn least leave leg less let letter level liberty library lie life lift light like likely line limit lip listen literature little live local long look lord lose lost lot love low machine main make man manner manners manufacture many march mark market marry mass master material matter may me mean measure member memory mention merchant mere metal middle might mile milk mind mine mine minister minute miss mistake modern moment money month moon more moreover morning most mother motion motor mountain mouth much music must my name narrow nation native nature near necessary neck need neighbour neither never new next night no noble none nor north not note nothing notice now number object observe occasion ocean of off offer office often oil old once one only onto open operation opinion opportunity or or order ordinary organize other otherwise ought out of out over owe own page pain paint paper part particular party pass past pay peace people per perfect perhaps permanent permit person picture piece place plain plan plant play please poet point political poor popular population position possess possible post power practical practice prepare present preserve president press pretty prevent price print private problem produce product production profit programme progress promise proper property propose protect prove provide public pull purpose put quality quantity queen question quiet quite race raise rank rate rather reach read ready real realize really reason receive recent recognize record red reduce refuse regard regular relation religion remain remark remember rent repeat reply report represent republic reserve respect rest result return rich ride right ring rise river road rock roll room rough round royal ruin rule run rush safe sail sale salt same sand say scale scarce scene school science sea season seat second secret secretary see seem seize sell send sense separate serious serve set settle several shade shadow shake shall shape share she shine ship shoe shoot shore short should shout show side sign silence silver simple since sing single sir sister sit situation size skill sky slave sleep slight slow small smile snow so society soft soil soldier some son soon sort soul sound south space speak special speed spend spirit spite sport spot spread spring square stage stand standard star start state stay steel step stick still stock stone stop store storm story straight strange stream street stretch strike strong struggle study subject substance succeed such sudden suffer sugar suggest summer sun supply support suppose sure surface surprise surround sweet sword system table take talk taste tax teach tear tell temple tend term terrible test than that the theatre their them then there therefore these they thing think this though thought through throw thus till time title to today together ton too tooth top total touch toward town trade train travel tree trouble true trust try turn type uncle under understand union unite university unless until until up upon upper use usual valley value various very vessel victory view village virtue visit voice vote wage wait walk wall want war warn waste watch water wave way we wealth wear weather week welcome well west western what when where whether which while white who whose why wide wife wild will win wind window wine wing winter wise wish with within without woman wonder wood word work world worse worth wound write wrong year yes yet yield you young zap zeta') def make_title(): """Return a three-word string as the page title.""" return string.capwords(string.join(rnd.sample(wordlist,3))) def metatags(): """Return metatags for the page. Normally we should disable robots from following or indexing this content, but you can change this to returning randomized content beyond the first level of links (change 1 to 0).""" if 1 and URI.find('&') > -1: return """""" else: return """""" % \ rnd.choice(wordlist) # return """ #""" % \ #(100 * (2 + rnd.getrandbits(3))) def make_bodyline(): """Return a statement, possibly containing randomized colors.""" x = rnd.getrandbits(3) if x == 0: return '' elif x > 3: return '' % rnd.getrandbits(24) else: return '' % (rnd.getrandbits(24), rnd.getrandbits(24), rnd.getrandbits(24), rnd.getrandbits(24)) def make_nagline(): """Return a string indicating this is an anti-spam page.""" str = rnd.choice( ["Did you know that unfriendly people try to scrape websites for email addresses?", "Some people write worms and viruses which try to exploit URLs.", "Other unfriendly people try to log into machines that don't belong to them, using user accounts gleaned from websites.", "I'm sorry, Dave. This is not the page you are looking for.", "This is an automaticly generated page which does not contain useful information.", "Please do not send email to any of the addresses below.", "Bad spammer. No donut.", "If you are a web-spider, you should ignore this page.", "Not an ordinary day, nor an ordinary 404. Welcome to the Twilight Webzone." ]) # insert a random word as a comment to deter simple detection l = rnd.randint(0,len(str)) return str[:l] + '' + str[l:] def make_email(): """Creates random email addresses, some on the local machine, others point to randomly created 2nd-level domains.""" if rnd.random() > 0.5: name = chr(ord('a') + rnd.randint(0,25)) + rnd.choice(wordlist) else: name = rnd.choice(wordlist) if rnd.random() > 0.5: addr = "%s@%s" % (name, servername) else: addr = "%s@%s.%s" % (name, rnd.choice(wordlist), rnd.choice(TLD)) if rnd.random() > 0.5: name = string.capwords(name + ' ' + rnd.choice(wordlist)) else: name = string.capwords(rnd.choice(wordlist) + ' ' + name) if rnd.random() > 0.5: addr = name[0].lower() + addr return '%s <%s>' % (addr, name, addr) def make_link(): """Make a random relative or absolute link back to myself.""" str = string.join(rnd.sample(wordlist, 1 + rnd.getrandbits(2))) l = URI.find('?') if l > -1: arg = '&%s' % rnd.choice(wordlist) else: arg = '/%s?%s' % (rnd.choice(wordlist), rnd.choice(wordlist)) if rnd.random() > 0.5: return '%s' % (URI, arg, str) else: return '%s' % (servername, URI, arg, str) def make_sentence(): """Creates a sentence of 3-11 random words which ends with a period.""" s = string.capwords(rnd.choice(wordlist)) s += ' ' + string.join(rnd.sample(wordlist, 3 + rnd.getrandbits(3))) + '. ' return s def print_para(): """Print a paragraph of 1-9 sentences, followed by an HTML

.""" x = rnd.getrandbits(3) + 1 while (x > 0): x -= 1 print make_sentence() print '

' def print_body(): """This printers the rest of the page after the header & the nagline, which will consist of several random email addresses, followed by links which point back to the program itself.""" x = rnd.getrandbits(3) + 2 while (x > 0): x -= 1 if rnd.random() > 0.7: print make_email(), make_sentence(), '
' else: print make_email(), '
' print '

' print_para() x = rnd.getrandbits(3) + 2 while (x > 0): x -= 1 if rnd.random() > 0.7: print make_link(), make_sentence(), '
' else: print make_link(), '
' print '

' print_para() def main(): """This generates a page full of links and email addresses.""" print """Content-Type: text/html %s""" % make_title() print "%s" % metatags() print make_bodyline() print_para() print "

%s

" % make_nagline() sys.stdout.flush() time.sleep(2) print_body() print "" sys.stdout.flush() time.sleep(5) print "" if __name__ == '__main__': main()