/*======================================================== Simple Stealth Ver1.1 HalfOpen and Steath Port Scanner, and OS detection Developped by UNYUN Presented by The Shadow Penguin Security http://base.oc.to/skyscraper/byte/551 [動作確認] TURBO LINUX 3.0 ======================================================== */ #include #include #include #include #define SRC_PORT 10101 /* 応答を得るClient Port */ /*---------< TCPセッションフラグとその値 >--------------*/ #define TH_FIN 0x01 /* 最終フラグ */ #define TH_SYN 0x02 /* 同期用フラグ */ #define TH_RST 0x04 /* リセットフラグ */ #define TH_ACK 0x10 /* 肯定応答フラグ */ /*---------< IPヘッダ定義構造体 >-----------------------*/ struct iphdr{ u_int8_t ihl:4; /* IPヘッダ長 */ u_int8_t version:4; /* IPのバージョン */ u_int8_t tos; /* サービスタイプ */ u_int16_t tot_len; /* 全IP長フィールド */ u_int16_t id; /* データグラムID番号 */ u_int16_t frag_off; /* フラグメント領域 */ u_int8_t ttl; /* 生存時間 */ u_int8_t protocol; /* プロトコルフィールド */ u_int16_t check; /* ヘッダチェックサム値 */ u_int32_t saddr; /* 送信元アドレス */ u_int32_t daddr; /* 宛先アドレス */ }; /*---------< TCPヘッダ定義構造体 >----------------------*/ struct tcphdr{ u_int16_t th_sport; /* 送信元ポート */ u_int16_t th_dport; /* 宛先ポート */ u_int32_t th_seq; /* 送信元シーケンス番号 */ u_int32_t th_ack; /* 確認応答シーケンス番号 */ u_int8_t th_x2:4; /* 予約 */ u_int8_t th_off:4; /* TCPヘッダ長 */ u_int8_t th_flags; /* セッションフラグ */ u_int16_t th_win; /* 送信者ウインドウサイズ */ u_int16_t th_sum; /* ヘッダチェックサム値 */ u_int16_t th_urp; /* 緊急データポインタ */ }; /*---------< TCP疑似ヘッダ定義構造体 >------------------*/ struct pseudohdr { u_int32_t saddr; /* 送信元アドレス */ u_int32_t daddr; /* 宛先アドレス */ u_int8_t useless; /* 予約 */ u_int8_t protocol; /* プロトコル */ u_int16_t tcplength; /* TCP長 */ }; /*======================================================== チェックサムの計算 [Input] addr : チェックサム計算対象バッファ len : チェックサム計算対象バッファ長(byte) ======================================================== */ unsigned short in_cksum(u_short *addr, int len) { int sum=0; int nleft=len; u_short *w=addr; u_short answer=0; while (nleft > 1){ sum += *w++; nleft -= 2; } if (nleft == 1){ *(u_char *)(&answer) = *(u_char *)w ; sum += answer; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return(answer); } /*======================================================== 生パケットを送りつける [Input] socke : 生Socket target_addr : ターゲットサーバ属性 your_addr : 送信元クライアント属性 session_flags : TCPセッションフラグバイト sequence : シーケンス番号 [Output] 0 = 正常送信, 1 = エラー ======================================================== */ int send_packet(int socket, struct sockaddr_in *target_addr, struct sockaddr_in *your_addr, unsigned char session_flags,unsigned long sequence) { struct iphdr *ip_header; /* IPヘッダポインタ */ struct tcphdr *tcp_header; /* TCPヘッダポインタ */ struct pseudohdr *pseudo_header;/* TCP疑似ヘッダポインタ */ char send_buf[40]; /* 送信パケットバッファ */ int send_length; /* 送信パケット長 */ int sent_length; /* 送信したパケット長 */ /*-----< パケットバッファの初期化 >-------------------------*/ memset(send_buf,0,40); ip_header = (struct iphdr *)send_buf; tcp_header = (struct tcphdr *)(send_buf+sizeof(struct iphdr)); pseudo_header = (struct pseudohdr *)((char*)tcp_header-sizeof(struct pseudohdr)); /*-----< TCP疑似ヘッダの生成 >------------------------------*/ pseudo_header->saddr = your_addr->sin_addr.s_addr; pseudo_header->daddr = target_addr->sin_addr.s_addr; pseudo_header->protocol = IPPROTO_TCP; pseudo_header->tcplength = htons(sizeof(struct tcphdr)); tcp_header->th_sport = your_addr->sin_port; tcp_header->th_dport = target_addr->sin_port; tcp_header->th_off = 5; tcp_header->th_flags = session_flags; tcp_header->th_seq = htonl(sequence); tcp_header->th_ack = htonl(0); tcp_header->th_win = htons(512); tcp_header->th_sum = in_cksum((u_short *)pseudo_header,sizeof(struct pseudohdr)+sizeof(struct tcphdr)); /*-----< IPヘッダの生成 >-----------------------------------*/ memset(send_buf,0,sizeof(struct iphdr)); ip_header->saddr = your_addr->sin_addr.s_addr; ip_header->daddr = target_addr->sin_addr.s_addr; ip_header->version = 4; ip_header->ihl = 5; ip_header->ttl = 255; ip_header->id = rand()%0xffff; ip_header->protocol = IPPROTO_TCP; ip_header->tot_len = htons(sizeof(struct iphdr)+sizeof(struct tcphdr)); ip_header->check = in_cksum((u_short *)ip_header,sizeof(struct iphdr)); /*-----< パケットの送信 >-----------------------------------*/ send_length=sizeof(struct iphdr)+sizeof(struct tcphdr); sent_length=sendto(socket,send_buf,send_length,0, (struct sockaddr *)target_addr,sizeof(struct sockaddr)); if (send_length != sent_length) return -1; else return 0; } /*======================================================== プログラムエントリ & SCAN 実行 [Output] 0 = 正常送信, 1 = エラー ======================================================== */ int main(int argc, char *argv[]) { struct iphdr *ip_header; /* IPヘッダポインタ */ struct tcphdr *tcp_header; /* TCPヘッダ */ struct sockaddr_in target_info; /* ターゲット情報バッファ */ int target_info_len; /* ターゲット情報バッファ長 */ fd_set read_fd; /* Select用ビットマップ */ int scan_port; /* ターゲットSCANポート */ unsigned char scan_flag; /* SCANセッションフラグ */ char recvbuf[5000]; /* パケット受信バッファ */ struct sockaddr_in target_addr; /* ターゲットサーバ属性 */ struct sockaddr_in your_addr; /* 発信元クライアント属性 */ int raw_socket; /* 生ソケット */ int tcp_socket; /* TCP生ソケット */ int result=0; /* SCAN結果 */ int i; static struct{ /* OS検出用特徴パラメータ */ unsigned int WindowSize; /* Windowサイズ */ char OSname[30]; /* OS名 */ }OSfeatures[]={ /*-----< Checked OS >---------------------------------------*/ {0x9823,"Solaris 2"}, /* Sol7(Intel),2.6,2.5,2.4(Sparc) */ {0x0010,"SunOS 4"}, /* SunOS4.1 (Sparc) */ {0x00f0,"IRIX"}, /* IRIX 5.3(Indy),6.3(O2) */ {0x00c0,"IRIX6.2"}, /* IRIX 6.2(IMPACT) */ {0xe07f,"Linux"}, /* TurboLinux3.0 (Intel) */ {0x0040,"FreeBSD"}, /* FreeBSD 2.2.7 or NetBSD 1.3 */ {0x0080,"Digital"}, /* Digital 4.0 or HP-UX B1.10.20 */ {0x8021,"Windows"}, /* Windows 95/98/NT4 */ {0x5B45,"MacOS"}, /* MacOS 7.5.5 , 8.5 */ /*-----< Thanks! nmap-os-fingerprints >---------------------*/ {0x253f,"AIX 3"}, /* AIX 3 */ {0x433e,"AIX 4"}, /* AIX 4.1 */ {0xafff,"AIX 4"}, /* AIX 4.1 */ {0x253f,"AIX 4"}, /* AIX 4.1 */ {0x1720,"BSD/OS"}, /* BSDI BSD/OS 2.1, 3.0 */ {0x0020,"HP-UX"}, /* HP-UX 9 */ {0x2e40,"FreeBSD"}, /* FreeBSD 2.2.1 - 3.0 */ {0x3d40,"FreeBSD"}, /* FreeBSD 2.2.1 - 3.0 */ {0x5c80,"Digital"}, /* Digital UNIX OSF1 V 4.0,4.0B,4.0D */ {0x0008,"OS/2"}, /* IBM OS/2 V.3 */ {0x2aef,"IRIX5,6"}, /* IRIX 5.3 */ {0x00c0,"IRIX6.4,6.5"},/* IRIX6.4 or 6.5 */ {0x003c,"Linux2028"}, /* Linux 2.0.28 */ {0x007c,"Linux2030"}, /* Linux 2.0.30 */ {0xe07f,"Linux2033-"},/* Linux 2.0.33-36 */ {0x537f,"Linux21xx"}, /* Linux 2.1.122 - 2.1.130 */ {0x870f,"NeXT"}, /* NeXT Mach */ {0xff1f,"NetWare"}, /* Novell Netware 3.12 - 5.00 */ {0x2e40,"OpenBSD"}, /* OpenBSD 2.1-2.3 or WinNT5 Beta */ {0x2332,"Solaris 2"}, /* Solaris2.3-2.5 */ {0x9722,"Sol26-27"}, /* Solaris2.6-2.7 */ {0x1720,"Windows"}, /* Windows 95/98/NT4 */ {0x0000,""}}; /*-----< 使い方表示と引数処理 >---------------------------------*/ if (argc!=5){ printf("[usage] %s [YourIP] [TargetIP] [TargetPort] [mode]\n",argv[0]); printf(" (mode : 's'=SYN scan, 'f'=FIN scan, 'a'=ACK scan)\n"); return -1; } switch(argv[4][0]){ case 's' : scan_flag = TH_SYN; break; /* Half-Openスキャン */ case 'f' : scan_flag = TH_FIN; break; /* Stealthスキャン1 */ case 'a' : scan_flag = TH_ACK; break; /* Stealthスキャン2 */ default : printf("Invalid mode.\n"); return -1; } scan_port = atoi(argv[3]); /*-----< 各変数の初期化 >----------------------------------------*/ ip_header = (struct iphdr *)recvbuf; tcp_header = (struct tcphdr *)(recvbuf+sizeof(struct iphdr)); target_addr.sin_family = AF_INET; target_addr.sin_addr.s_addr = inet_addr(argv[2]); target_addr.sin_port = htons(scan_port); your_addr.sin_addr.s_addr = inet_addr(argv[1]); your_addr.sin_port = htons(SRC_PORT); /*-----< 生Socketの作成 >---------------------------------------*/ if ((tcp_socket=socket(AF_INET,SOCK_RAW,IPPROTO_TCP))==-1){ printf("TCP生ソケットの生成ができません\n"); return -1; } if ((raw_socket=socket(AF_INET,SOCK_RAW,IPPROTO_RAW))==-1){ printf("生ソケットの生成ができません\n"); return -1; } /*-----< ターゲットにパケットを投げて、応答を待つ >-------------*/ send_packet(raw_socket,&target_addr,&your_addr,scan_flag,100); FD_ZERO(&read_fd); FD_SET(tcp_socket,&read_fd); select(FD_SETSIZE,&read_fd,NULL,NULL,NULL); for (;;){ if (FD_ISSET(tcp_socket,&read_fd)){ /*-----< ターゲットからのパケットを受信 >---------------*/ target_info_len = sizeof(target_info); recvfrom(tcp_socket,recvbuf,5000,0, (struct sockaddr *)&target_info,&target_info_len); if (target_info.sin_addr.s_addr == target_addr.sin_addr.s_addr) if (ntohs(tcp_header->th_dport) == SRC_PORT && ntohs(tcp_header->th_sport) == scan_port){ /*-----< スキャン結果 >-------------------------*/ printf("\nReply from %s\n",argv[2]); if (tcp_header->th_flags & TH_RST) printf("RST\n"); if (tcp_header->th_flags & TH_ACK) printf("ACK\n"); if (tcp_header->th_flags & TH_SYN){ printf("SYN\n"); if (scan_flag & TH_SYN){ result=1; /*-----< OS判別結果 >------------------*/ for (i=0;;i++){ result=1; if (strlen(OSfeatures[i].OSname)==0) break; if (OSfeatures[i].WindowSize == tcp_header->th_win) printf("\nOS = %s\n",OSfeatures[i].OSname); } } } printf("\nTTL = %d\nTCP window size = %xH\n\n", ip_header->ttl,tcp_header->th_win); if (ip_header->ttl < 65 && tcp_header->th_win > 0 && scan_flag & TH_ACK) result=1; if (result==1) printf("Port %s : open\n\n",argv[3]); else printf("Port %s : close\n\n",argv[3]); if (!(tcp_header->th_flags & TH_RST)) send_packet(raw_socket,&target_addr,&your_addr, TH_RST, 101); break; } } } return(0); }