본문 바로가기

네트워크/네트워크이론

[네트워크] 포트스캔의 이해와 구현

포트란?
사전적 의미 - 모뎀과 컴퓨터 사이에 데이털르 주고 받을 수 있는 통로
프로그래밍에 의해 만들어진 네트워크 프로그램이 외부와 통신을 위해 약속한 통로인 소프트웨어적인 측면
포트의 필요성
- 외부와 데이터를 교환하는 프로그램은 특정 포트를 이용하여 데이터를 교환한다.

포트 스캔이란?
포트를 조사하여 어떤 포트가 열려있고 닫혀있는지 조사하는 것
사용 목적
- 자신의 서버의 네트워크 서비스들을 점검하기 위해 사용
- 해커가 해킹을 하기 위해 정보 수집에서 타겟 서버의 정보를 수집하기 위해 사용

< 포트 스캔의 원리 >
http://www.hackerslab.org/images/tech/goodwarriors.wmv  <- 패킷 전달과정에 대한 이해
퍼트 활성화 여부 조사를 위해 타겟서버에 특정 포트에 대한 서비스를 요청하는 패킷을 보낸다.
일반적으로 포트가 열려 있을 떄와 닫혀 있을 떄의 응답 패킷이 다르므로 이 차이를 이용하여 포트 활성화 여부를
알 수 있다.

< IP Header의 구조 >


version - IP Header 형식 ( ex. IPv4, IPv6 )
header length - 데이터 영역을 제외한 순수 헤더의 길이, 만약 옵션이 사용 될 경우 4byte씩 채워짐
type of server - 우선순위, 지연시간, 처리능력, 신뢰성 등 바람직한 Qos를 표시
                총 8bit 중 4bit는 성정하여 사용하며, 마지막 bit의 값은 0으로 지정한다.
total length - IP Datagram의 길이를 byte로 표시한다. 최대 길이는 16bit이므로 '2의 16승 -1' 값인 65535byte이다.
identification - IP가 중복되지 않는 값으로 IP Header를 구별 할 수 있는 값
                이 값은 최대 65535까지 최대 증가하고, 이후 다시 처음으로 돌아와 다시 증가한다. IP단편화에 이용됨
flag - 단편화와 관련있는 플래그, [0, DF, MF]로 구성 [0/ 단편화를 하지 않는다/ 단편화를 한다]
fragment offset - MF가 되었을 때 그 위치 값 ( 분할 후 다시 재조립시의 상대적인 위치 값 )
time to live - 네트워크 상에서 얼마나 오래 동안 신호를 전송 할 수 있을 지를 결정하는 수치
               라우터를 지날 때마다 1씩 줄어들며, 값이 0이 되면 패킷은 버려진다.
protocoal - 수신할 상위 계층을 나타내기 위해 사용, 다중화의 지원을 위해 사용된다.
               한 IP 주소를 가진 컴퓨터에서 여러 가지 서비스를 동시에 하기 위해서 반드시 필요한 부분이다.
               TCP - 6번, UDP - 17번, ICMP - 1번
head checksum - IP Header에만 사용, 헤더를 구성하는 16개 비트, 각각 1의 보수를 더한다. 오류 검사를 위해 사용
source IP address, Destination IP address - 출발지와 목적지의 IP 주소 값

< TCP Header의 구조 >

source port - 패킷을 보내는 출발지 포트 번호
destinatio port - 패킷을 받는 목적지 포트 번호
sequence number - 처음 연결을 시도 할 때 시스템에서 임의로 생성
               이 값은 전송량을 내포하고 있으며, 수신자가 이 값을 이용하여 재조립을 한다.
acknowledge number - 상대편 호스트에서 받고자 하는 바이트의 번호를 정의
header length ( HLEN ) - TCP 헤더의 길이 값, 기본 값은 20이고 옵션이 사용될 경우 값의 크기는 변경된다.
reserved - 현재 사용되지 않으며, 예약되어 있는 비트
|U|A|P|R|S|F| - 6개의 서로 다른 제어 비트를 표시
    - URG(U) : 긴급 플래그 ( 데이터를 전송하는 중간에 [Ctrl + c]와 같은 행동을 했을 시 발생 플래그 )
    - ACK(A) : 수신 확인 플래그 ( 데이터가 제대로 전송되었다고 알려주는 플래그 )
    - PSH(P) : 푸시 플래그 ( 버퍼에 데이터가 차지 않아도 데이터 즉시 전송하겠다는 플래그 )
    - RST(R) : 리셋 플래그 ( 재설정을 요구하는 플래그, 이상한 패킷이 도착하면 잘못 전송하였다고 알려주는 플래그 )
    - SYN(S) : 동기화 플래그 ( 상대방에게 연결을 해도 되는지 제의하는 플래그 )
    - FIN(F) : 종료 플래그 ( 세션을 종료하고자 할 떄 사용하는 플래그 )
window size - 패킷의 송수신 시 네트워크 상황이나, 자신의 상황을 고려하여 받을 수 있는 최대 버퍼의 크기
checksum - 데이터의 무결성을 보장해주는 값, 무결성 검사 후 잘못되었다고 판단이 되면 재전송을 요구 함
option - 최대 40byte의 선택 정보가 가능하며, 수신지에서 추가 정보를 전달하기 위해 사용

< 포트 스캔의 종류 >


Open Scan
TCP Connect - TCP를 이용한 가장 기본적인 스캔
작동하리라고 예상되는 포트에 세션을 생성하기 위한 SYN패킷을 보낸다.
3-Way Handhaking에 의해 서로 다른 패킷을 받을 수 있다.
상대방의 시스템에 로그 기록이 남는다는 단점이 있다.


Reverce ident
- 해당 포트의 실행 권한과 UID를 알아내기 위해 정상적인 TCP 3-Way Handshake 이후 추가로
Reverse Ident Query를 한다.


Half Open
Syn Flag - Open Scan은 완선하게 세션이 성립한 것으로 포트의 활성화 여부를 확인하였지만, Half Open은
세션을 완성하지 않는다. Half Open은 ACK 패킷을 보냈을 경우 완전한 연결이 성립되어 로그가 남기 때문에
ACK를 보내지 않고 RST 패킷을 보내 로그 기록을 남기지 않는다.


IP ID Header TCP Scanning
- IP ID Header TCP Scanning은 Attacker와 Target말고도 중간의 dumb 호스트가 필요하다.
1. Attacker는 dumb에 연속적으로 Ping을 보낸다.
2. IP를 dumb의 IP로 spoof하여 Target에 SYN 패킷을 보낸다.
   - 열린 포트의 경우 Target은 dumb에게 SYN/ACK 패킷을 보내고, dumb는 Target에게 RST로 응답한다.
   - 닫힌 포트의 경우 Target은 dumb에게 RST/ACK 패킷을 보내고, dumb는 아무런 응답을 하지 않는다.
3. dumb는 Attacker에게 보내는 Ping으 ID 필드를 관찰한다.
   - 열린 포트의 경우 ID 필드가 증가한다.
   - 닫힌 포트의 경우 ID 필드가 계속 1이다.

Stealth
FIN - FIN ( Finish ) 플래그 값만 설정하여 패킷을 보내는 방법
NULL - 모든 플래그 값을 설정하지 않고 패킷을 보내는 방법
XMAS - ACK, FIN, RST, SYN, URG 플래그를 모두 설정하여 패킷을 보내는 방법
위의 방법들을 모두 스텔스 ( Stealth ) 스캔이라 한다.
Open Scan처럼 세션을 완전히 성립하지 않고 공격 대상 시스템의 포트의 활성화 여부를 알아내기 때문에
로그 기록이 남지 않는다

위의 패킷을 보냈을 때 상대방 컴퓨터의 포트가 열려 있다면 아무 응답이 없고 상대 컴퓨터의 포트가 닫혀
있는 경우 RST패킷이 돌아온다



ACK
- 초기의 SYN 패킷 대신 ACK 패킷을 전송
- 다수의 패킷 필터링 장치가 네트워크에서 연결이 성립된 Session을 허용한다는 점을 이용하여, IPS와 같은 보안
장비의 패킷 필터링 기능을 우회하여 내부 네트워크를 스캔 할 수 있는 기능


ICMP Scan
- ICMP는 패킷의 오류에 대한 정보를 가지고 있고 패킷을 제어하는 역활을 한다.
ICMP 스캔은 특정 포트에 대한 스캔이라기 보다는 서버가 자신과 연결 가능한 상태인지 알아 보는 방법이다.
대표적인 예로 ping을 사용하는 경우이다.
실제 ICMP Scan은 실제 포트 스캔이 아니다.
ICMP는 종점( EndPoint )인 포트를 사용하지 않고 대신에 시스템이 ICMP 메시지에 응답하는지 알아보기 위해 사용
일반적으로 시스템에 Ping을 하면 ICMP Echo Request 메시지를 발송한다. 그리고 ICMP Echo Request는 목적지
호스트로부터 ICMP Reply Reply를 받는다 만약 목적지 호스트가 ICMP Echo Request 메시지에 대해 응답하도록
구성한다면 ICMP Echo Reply가 반환되고, 전송하지 못한다면 Request Timed Out을 출력한다.


Misc
FTP bounce - 현재는 잘 사용되지 않지만 이 방법은 취약한 FTP서버에서는 Port 명령을 통해 다른 시스템의
포트에 대한 활성화 여부를 확인 할 수 있는데, 방화벽 내에 이런 취약한 FTP 서버가 있을 때 유용하게 사용될 수 있다.
하지만 현재에는 이런 취약점이 존재하는 FTP서버가 존재하지 않는다.

< 간단한 포트 스캔 구현 >
//TCP Connect Scan
//tcpscan.c
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char* argv[]) {
    int sockfd;
    struct sockaddr_in dest_addr;
    int port = 0;
    int ret = 0;
    for(port = 1; port <= 1024; port++) {
        sockfd = socket(PF_INET,SOCK_STREAM,0);
        memset((char*)&dest_addr,0,sizeof(dest_addr));
        dest_addr.sin_family = AF_INET;
        dest_addr.sin_port   = htons(port);
        dest_addr.sin_addr.s_addr = inet_addr(argv[1]);
        ret = connect(sockfd,(struct sockaddr*)&dest_addr,sizeof(dest_addr));
        if(ret != -1) {
            printf("%d Port Open\n",port);
        }
        else {
            //printf("%d Port Close\n",port);
        }
        close(sockfd);
    }
    printf("OK\n");
    return 0;
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
실행 화면 :
[wiseguyz@localhost tmp]$ gcc tcpscan.c -o tcpscan
[wiseguyz@localhost tmp]$ ./tcpscan 127.0.0.1
21 Port Open
22 Port Open
25 Port Open
80 Port Open
111 Port Open
631 Port Open
OK
[wiseguyz@localhost tmp]$
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
< Non-Blocking으로 수정된 TCP Connect Scan 예제 )
Non-Blocking 이란?
< http://blog.naver.com/PostView.nhn?blogId=sungil108&logNo=150083583015&categoryNo=37 >
//TCP Connect Scan
//tcpscan2.c
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
int pscan(struct hostent *he, int cport, int socktype);
int main(int argc, char* argv[]) {
    int cport;
    int start = 0;
    int end = 0;
    struct hostent *he;
    start = atoi(argv[2]);
    end = atoi(argv[3]);

    if( (he = gethostbyname(argv[1])) == NULL)
{
        printf("gethostbyname\n");
        exit(0);
    }

    if(argc !=4)
{
        printf("test [IP_Address] [start port] [end port]\n");
        return -1;
    }

    for(cport = start; cport <= end; cport++)

        pscan(he,cport,SOCK_STREAM);
        printf("OK\n");
    return 0;
}

int pscan(struct hostent *he,int cport, int socktype) {
    int sockfd;
    int flags, n, error;
    socklen_t len;
    fd_set rset,wset;
    struct timeval tval;
    struct sockaddr_in destaddr;
    sockfd = socket(AF_INET,socktype,0);

    destaddr.sin_family = AF_INET;

    destaddr.sin_addr = *((struct in_addr *)he->h_addr);
    destaddr.sin_port = htons(cport);
    bzero(&(destaddr.sin_zero),8);
    flags = fcntl(sockfd,F_GETFL,0);
    fcntl(sockfd,F_SETFL,flags | O_NONBLOCK);

   n=connect(sockfd,(struct sockaddr*)&destaddr,sizeof(struct sockaddr));
   FD_ZERO(&rset);
   FD_SET(sockfd,&rset);
   wset = rset;
   tval.tv_sec = 2;   //blcok time 2 second
   tval.tv_usec = 0;

   n = select(sockfd+1,&rset,&wset,NULL,&tval);
   if( n == 0 ) {
        close(sockfd);
        printf("%d Port TimeOut\n",cport);
        return -1;
   }
   if(FD_ISSET(sockfd,&rset) && FD_ISSET(sockfd,&wset)) {
    //  printf("%d Port Close\n",cport);
   }
   else {
        printf("%d Port Open\n",cport);
   }

   close(sockfd);
   return 0;
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
실행화면 :
[wiseguyz@localhost tmp]$ gcc tcpscan2.c -o tcpscan2
[wiseguyz@localhost tmp]$ ./tcpscan2 www.hackerschool.org 0 1000
21 Port Open
22 Port Open
23 Port Open
25 Port Open
53 Port Open
80 Port Open
111 Port Open
137 Port TimeOut
138 Port TimeOut
139 Port TimeOut
445 Port TimeOut
707 Port TimeOut
OK
[wiseguyz@localhost tmp]$
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

< 원문 : http://blog.naver.com/soma592/80043437934 >