package conf;

# This file is part of sqlsus
#
# Copyright (c) 2008-2011 Jérémy Ruffet (sativouf)
# http://sqlsus.sourceforge.net/
#
# Licensed under GPLv3+: GNU GPL version 3 or later
# See LICENSE file or http://www.gnu.org/licenses/gpl.html

use strict;
use warnings;

###############################
###  sqlsus default values  ###
###############################

our $url_start = "";
our $url_end = "";
our $post = 0; 
our $blind = 0;
our $blind_string = "";
our $blind_sleep = 2;
our $allow_override = 1;
our $user_agent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)";
our $debug = 0;
our $null_substitute = "~";
our $hex_encode_strings = 1;
our $processes = 10;
our $sleep_after_hit = 0;
our $max_url_length = 0;
our $max_inj_length = 0;
our $max_subqueries = 70;
our $convert_spaces = 0;
our $use_cookie_jar = 1;
our $cookie = "";
our $proxy = "";
our $cred_realm = "";
our $cred_user = "";
our $cred_password  = "";
our @http_error_codes = qw(408 500 501 502 503 504);
our $http_error_retries = 10;
our $max_returned_length = 65530;
our $datapath = "$ENV{'HOME'}/.sqlsus";
our $filespath = "files";
our $binary = 0;
our $max_select_cols = 50;
our @columns = qw();
our $union_select = "UNION ALL SELECT BINARY";
our $default_range = join (',', (9,10,32..126));
our @regex_rlike = (
	# num
	"^[0-9]+\$", join (',',(48..57)),
	# lower alpha
	"^[a-z_\. @]+\$", join (',',(32,46,64,95,97..122)),
	# lower hex
	"^[a-f0-9]+\$", join (',',(48..57,97..102)),
	# upper hex
	"^[A-F0-9]+\$", join (',',(48..57,65..70)),
	# upper alpha
	"^[A-Z_\. @]+\$", join (',',(32,46,64,65..90,95)),
	# mixed alpha
	"^[A-Za-z_\. @]+\$", join (',',(32,46,64,65..90,95,97..122)),
	# alnum
	"^[a-z0-9\._@]+\$", join (',',(46,48..57,64,95,97..122)),
	# datetime
	"^[0-9 [.hyphen-minus.]:]+\$", join (',',(32,45,48..57,58)),
	# mixed alnum + stuff
	"^[A-Za-z0-9\._@+/ [.hyphen-minus.][.apostrophe.][.quotation-mark.]%]+\$", join (',',(32,34,37,39,43,45,46,47,48..57,64,65..90,95,97..122))
);

our $blind_max_length = 4096;
our $document_root = "/var/www/";
our @upload_directories = ();
our $crawler_depth = 5;
our $uploader = "";
our $uploader_name = ".u.php";
our $backdoor = "";
our $backdoor_name = ".b.php";
our $brute_table_dict = "dict/tables";
our $brute_column_dict = "dict/columns";
our $brute_start_string = "aaa";
our $table_prefix = "";
our $uc_first = 1;
our $uc_all = 0;
our @brute_tables_dict = qw(
login logins
user users
group groups
perm permissions perms
admin admins administrators staff
customer customers
client clients
config configuration
member members
name names
password passwords
);
our @brute_columns_dict = qw(
id admin 
login name user username
email emailaddress mail e_mail
tel phone number telephone
address adress street
pw pwd pass password
);
our %tables = (
    user_privs      => 'information_schema.user_privileges',
    database_privs  => 'information_schema.schema_privileges',
    tables          => 'information_schema.tables',
    columns         => 'information_schema.columns'
    );
our %target_keys = (
    version	=> 'version()',
    user 	=> 'current_user',
    database	=> 'database()',
    );
our $top_row = 999999999;
our $hex_start = "";
our $hex_end = "";
our $hex_start_if_binary = "HEX(BINARY(";
our $hex_end_if_binary = "))"; 

# disabled until better implemented
our $show_estimated_time_in_progress_bar = 0;
our $show_hits_info_in_progress_bar = 0;


###############################
sub backwards_compatibility {
	# < 0.7
	if (not $conf::blind_string and $conf::string_to_match) {
		&msg::info("\$string_to_match is deprecated, please use \$blind_string instead");
		$conf::blind_string = $conf::string_to_match;
	}
}

###############################
sub gen {
	my $filename = shift;
	my $tiny = shift;

	if (not $filename) {
		&help::usage("genconf");
		return 1;
	}

	if (-e "$filename") {
		return 0 if &functions::question("$filename already exists, overwrite ?", qw(y n)) eq "n";
	}

	if (not open CONF, ">$filename") {
		&msg::error("Could not open $filename for writing : $!");
		return 1;
	} else {
		my $hash_target_keys = "\n";
		for (keys %target_keys) { $hash_target_keys .= "\t$_ => '$target_keys{$_}',\n" }
		$hash_target_keys =~ s/,\n$/\n/;

		my $my_url_start = $url_start;
		$my_url_start =~ s/"/\\"/g;
		$my_url_start =~ s/ $//;
		
		my $my_url_end = $url_end;
		$my_url_end =~ s/"/\\"/g;
		$my_url_end =~ s/^ //;

		my $my_union_select = $union_select;
		$my_union_select =~ s/ $//;

		my $my_datapath = $datapath;
		if ($datapath eq $ENV{'HOME'}) { $my_datapath = "\$ENV{'HOME'}" };

	print CONF <<EOF;
# Configuration file generated by sqlsus $main::RELEASE
package conf; # do not remove this line
use strict;
use warnings;

#
# Note: only the values that differ from sqlsus defaults are mandatory, so you can have a configuration file with only a few lines in it
#
# All these values will be overriden by the variables you have set in sqlsus in a saved session, provided that \$allow_override == 1 (which is the default, see below)
# For example :
# - first run: you launch sqlsus with no cookie defined.
# before the second run, you configure a cookie in your configuration file
# - second run: the cookie is still empty, because the value has been overriden by the one saved
#
# In this case, you need to change the value of the cookie inside sqlsus using "set cookie <cookie>"
# You can always store you running configuration by using "genconf <filename>" inside sqlsus
#

###############################
########### GENERAL ###########

# Start of the url used for the injection
# In inband/union mode, it is generally a good idea to append "AND 0" so that the real query returns nothing
# Ex : our \$url_start = "http://localhost/script.php?id=1'";
our \$url_start = "$my_url_start";

# End of the url used for the injection
# When possible, it is generally a good idea to use "#" here, so that our queries won't be polluted by the original one
# Ex : our \$url_end = "#";
our \$url_end = "$my_url_end";

# Use POST instead of GET
our \$post = $post;

# Use blind injection ?
# set it to 1 for boolean-based blind injection
# set it to 2 for time-based blind injection (requires MySQL >= 5.0.12)
our \$blind = $blind;

# In boolean-based blind mode, string to be found in the HTML if the statement is true
our \$blind_string = "$blind_string";

# In time-based blind mode, how long in seconds (can be a float) to sleep() when the statement is true
# You must specify a value higher than the maximum delay to be expected in normal conditions
our \$blind_sleep = $blind_sleep;

# Allow the values specified in the configuration file to be overriden by the ones you have set in sqlsus (in a saved session)
our \$allow_override = $allow_override;

# User agent to use for HTTP queries
our \$user_agent = "$user_agent";

# Display "debug" messages
our \$debug = $debug;

# Char (not string) to display when something is null / not found
our \$null_substitute = "$null_substitute";

# Hex encode strings in the query ?
# ie: "sqlsus" will be sent as 0x73716c737573, thus escaping quotes filtering
our \$hex_encode_strings = $hex_encode_strings;

# Maximum running processes used to retrieve data (+main process +hits counter process)
our \$processes = $processes;

# Amount of seconds to sleep after each server hit. (can be a float)
# Note that it does not take the query / answer time in consideration, it's just a simple sleep() after a hit
our \$sleep_after_hit = $sleep_after_hit;

# -- maximum amount of data we can send at once --

# Typically, we are restricted either by the web server (URL size) or by the layer underneath (PHP / suhosin)
# Only one of the 2 variables can be set (non 0) at a time, and it will be the only one to be used by sqlsus
# If both are set to 0, using "start" or "autoconf max_sendable", sqlsus will find which restriction apply, and set the variable(s) accordingly

# Maximum amount of data we can send at once to the target (+ the size of the URL itself)
our \$max_url_length = $max_url_length;

# Maximum amount of data we can send through the injection point
our \$max_inj_length = $max_inj_length;

# ------------------------------------------------

# Max subqueries per query
# Note that setting a really big value here (ie: 900), as well as a high value for max_url_length (when using POST for example), may result in a potentially long computation time for the queries to be prepared
our \$max_subqueries = $max_subqueries;

# Convert spaces to /**/
our \$convert_spaces = $convert_spaces;

# Shall we consider cookies at all ?
our \$use_cookie_jar = $use_cookie_jar;

# Cookie to use, separate name=value pairs with ;
# This will only have an effect if \$use_cookie_jar = 1
our \$cookie = "$cookie";

# Proxy (HTTP / socks)
# Example for TOR proxying : our \$proxy = "socks://localhost:9050";
our \$proxy = "$proxy";

# Credentials
our \$cred_realm = "$cred_realm";
our \$cred_user = "$cred_user";
our \$cred_password  = "$cred_password";

# What HTTP error codes shall we retry on ?
our \@http_error_codes = qw(@http_error_codes);

# Maximum number of times to retry per thread/process on a HTTP error code
our \$http_error_retries = $http_error_retries;

# Variables to get in \%target when using "start"
our \%target_keys = ( $hash_target_keys );

###############################
############ DATA #############

# Maximum length before the data returned in the HTML is truncated
# Only used by "download" for the moment
our \$max_returned_length = $max_returned_length;

# Where to put the data (sessions, files, database(s) dump)
our \$datapath = "$my_datapath";

# Where to save downloaded files (via the "download" command)
# such files will be stored in ./\$datapath/SERVERNAME/\$filespath
our \$filespath = "$filespath";

# Binary mode (hex encode in mysql, and hex decode in sqlsus)
# This mode uses twice as much bandwith as in non binary mode
# binary mode is useful for :
# - in blind mode : retrieving non ASCII characters (UTF8 ?) or ones not listed in \$default_range (see below)
# - in general    : retrieving binary content
our \$binary = $binary;

###############################
######### INBAND MODE #########

# Maximum number of columns to be used in the UNION statement
# This is used at "start" (or "autoconf select_columns")
our \$max_select_cols = $max_select_cols;

# Columns usable for (inband) injection using union
# example :
# our \@columns = qw(0 0 1 0 1);
# 5 columns for union, 3rd and 5th can be used to see the result of the query
# The first "1" will be used as the injection spot
#
# Note that actual values will be used (0 or 1) (except the 1 replaced as the injection spot) in the UNION select query, which might not be what you want
# You can change the entries (but the "1" you want to use) to whatever value suits you
# Unless this variable is set, sqlsus will auto-detect the suitable number of columns to be used for injection
our \@columns = qw(@columns);

# How to union
our \$union_select = "$my_union_select";

###############################
######### BLIND MODE ##########

# ASCII chars to brute force if no regex matched
our \$default_range = join (',', (9,10,32..126));

# Regular expressions to test against each item retrieved on a blind injection
# and the corresponding ASCII values
# NOTE:
# - the values MUST be sorted
# - the regexs will be tried in order
our \@regex_rlike = (
	# num
	"^[0-9]+\\\$", join (',',(48..57)),
	# lower alpha
	"^[a-z_\. \@]+\\\$", join (',',(32,46,64,95,97..122)),
	# lower hex
	"^[a-f0-9]+\\\$", join (',',(48..57,97..102)),
	# upper hex
	"^[A-F0-9]+\\\$", join (',',(48..57,65..70)),
	# upper alpha
	"^[A-Z_\. \@]+\\\$", join (',',(32,46,64,65..90,95)),
	# mixed alpha
	"^[A-Za-z_\. \@]+\\\$", join (',',(32,46,64,65..90,95,97..122)),
	# alnum
	"^[a-z0-9\._\@]+\\\$", join (',',(46,48..57,64,95,97..122)),
	# datetime
	"^[0-9 [.hyphen-minus.]:]+\\\$", join (',',(32,45,48..57,58)),
	# mixed alnum + stuff
	"^[A-Za-z0-9\._\@+/ [.hyphen-minus.][.apostrophe.][.quotation-mark.]%]+\\\$", join (',',(32,34,37,39,43,45,46,47,48..57,64,65..90,95,97..122))
);

# Maximum length above which an item won't be bruteforced
# Set it high enough if you intend to download files
our \$blind_max_length = $blind_max_length;


###############################
########## TAKEOVER ###########

# Document root, on the web server, of the website we are injecting through
# This MUST be accurate for sqlsus to be able to upload its backdoor by automatically crawling for candidate directories
# Also, the web and mysql server must obviously be on the same box
our \$document_root = "$document_root";

# List of (relative to document root path) directories to try to upload backdoor to
# Leave empty for auto detection by crawling the web server
# ex : our \@upload_directories = ("/upload");
our \@upload_directories = (@upload_directories);

# Maximum depth to look at when crawling the web server for directories
our \$crawler_depth = $crawler_depth;

# URL of the uploader script, if already uploaded
our \$uploader = "$uploader";

# What remote filename to use when uploading the tiny uploader
our \$uploader_name = "$uploader_name";

# URL of the backdoor, if already uploaded
our \$backdoor = "$backdoor";

# What remote filename to use when uploading the backdoor
our \$backdoor_name = "$backdoor_name";


###############################
########### BRUTE #############

# Dynamic string to use for column/table names bruteforcing
# It will be "magically" (perl speaking) incremented and prefix with \$table_prefix when applicable
our \$brute_start_string = "$brute_start_string";

# String to begin the table/column name with
# ex : our \$start_string = "cms_";
our \$table_prefix = "$table_prefix";

# For each table name, also try an uppercase version for the first char only
our \$uc_first = $uc_first;

# For each table name, also try an uppercase version (for all chars)
our \$uc_all = $uc_all;

# Tables dictionnary
our \@brute_tables_dict = qw(@brute_tables_dict);

# Columns dictionnary
our \@brute_columns_dict = qw(@brute_columns_dict);
EOF
	}
	close CONF;
	&msg::info("Configuration successfully saved to $filename");
}

1

