
/* http://www.anticode.com  for the latest exploits, tools and documents! */

/*========================================================
                 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    <stdio.h>
#include    <netinet/in.h>
#include    <sys/socket.h>
#include    <sys/time.h>

#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);
}
