오늘은
TCP 헤더를 이용한 공격 기법을 확인해 볼것이다.
TCP 공격기법으로는
1) TCP Scanning
2) TCP를 이용한 DDos 공격이 있다.

오늘은 TCP Scanning 기법을 확인 해 볼 것이다.

1) TCP Scanning
 - Flag ( SYN, FIN, RST, ACK, ... )
 - 열려있는 포트와 닫혀있는 포트의 응답이 다르다.
 - 3-way handshake를 이용한다.

- FULL-Scan
 : 3-way handshake과정을 모두 거친다.
 : 세션을 맺어보는 것이다.
 : 맺어지면 열려있는 것이고 연결이 안되면 닫혀있는 것이다.
 : TCP 연결 흔적이 남는다. 연결되었다는 기록이 남는다.



(FULL Scan 코드)





(포트가 열려있을 때 모습)




위 처럼 포트가 열려있으면 아무 반응이 없다.

하지만 포트가 닫혀있으면 연결이 안되므로



(135번 포트 스캔)




(오류 메세지)




연결 할 수 없다고 뜬다.

이 처럼 한번 TCP 연결을 해보면서 포트가 열려있는지 확인하는 것을
TCP 스캔이라고 한다.




(Half Scan 코드)




(포트가 열려있을 경우)




포트가 열려있을 경우 위 처럼 ACK SYN 패킷이 돌아온다.

닫혀있는 경우 RST 패킷이 돌아온다.




(닫혀있는 경우)




포트가 닫혀있는 경우는 위와 같이 RST 패킷이 돌아온다.
즉, 연결이 안된다.

- HALF-Scan( Stealth Scan )
 : 3-way handshake를 이용하지만 완벽하게 연결하지 않는다.
 SYN Scan( 열려있는 포트에 대한 스캐닝 기법 )
 (1) 서버에 동기화 요청 (SYN)
 (2) 서버에서는 SYN-ACK로 응답(Listening이라면)
     서버에서는 RST 패킷을 보낸다. (닫혀있다면)
 (3) ACK로 응답을 하지 않는다.

SYN-ACK 패킷이 오면 우리는 그에 따른 응답을 안해주고 연결을 여기서 끊어준다.
그렇기 때문에 Half Scan이라고 한다.

서버에 로그 흔적이 남지 않는다. (연결이 이루어지지 않았기 때문에)


 (닫혀있는 포트에 대한 스캐닝 기법)
 - FIN SCAN, NULL SCAN, X-MAS SCAN,...
 -> 이녀석들은 반대다.
 -> 닫혀있으면 반응하고, 열려있으면 반응을 안한다.
 => 이것이 표준이지만, 표준과 다른 경우도 많다.
 - X-MAS 는 모든 플래그를 세팅해둔다.


 - SYN-ACK 스캔 ( 호스트 스캔 )  (유용한 스캔) (포트와는 상관없다.)
 : ping보다 성능이 더 좋다. (방화벽에서 막지 못한다.)
 : 포트가 열려있는지 닫혀있는지 관계없이 호스트가 살아있다면 응답이온다.
 : 죽어있다면 응답이 오지 않는다.
 : 방화벽을 다 뚫을 수 있고 살아있는 시스템을 다 체크할 수 있는 좋은 스캔이다.
 : 해당 서버에 기록이 남지 않는다.




(SYN-ACK 스캔 모습)





오늘은 어제 작성했던 패킷을 덤프하는 프로그램작성을 완성시켰다.

TCP의 데이터까지 출력할 수 있게 만들었다.



(패킷 덤프 프로그램 코드)




(실행결과.(왼쪽-패킷내용, 오른쪽-TCP 통신프로그램))



이 때 Data를 보내는데 TCP에서 많은 패킷이 왔다갔다 한 것을 볼 수 있었다.

TCP헤더의 flag 필드를 보면 패킷의 용도를 확인 할 수 있다.

* TCP는 통신하기 앞서 동기화과정이 먼저 들어간다.


(SYN 패킷)


위 캡쳐한 패킷을 보면 Flag가 SYN으로 나와있다.
캡쳐한 패킷내용을 보면 IP주소 165가 client고  239가 server여서 server로 동기화 요청하였다.



(SYN-ACK 패킷)



그 다음으로 서버측에서 SYN-ACK 패킷을 보내오는 것을 확인할 수 있다.
ACK 패킷은 응답을 주는 것이다. 또 서버측도 내게 동기화를 맞춰야해서 SYN패킷을 보낸다.



(ACK 패킷)



마지막으로 클라이언트쪽에서 서버로 응답 ACK 패킷을 보내는 것을 확인할 수 있다.
여기서 데이터도 같이 보냈는데,
지금 상황에서는 데이터보내는 겸 같이 ACK 패킷을 전송한 것이다.
바로 이런식으로 보내는 것을 Piggyback이라고 한다.

바로 위에서 본 것이 3 Hand Shaking 과정을 본것이다.
3 Hand shaking은 데이터를 주고 받기 전에세션을 맺는 과정이다.

전에 확인했던 걸 생각해보면
TCP에는 상태라는 게 있었다. (Listen, Established...)
그래서 Listen 상태일 때 SYN패킷이 오면 응답을 해주고 쓰리핸드쉐이킹과정을 할 수 있다.
Listen 상태가 아니면 응답을 못해주게 된다. (이점이용하면 SYN Flooding 공격을 할 수 있다.)

3 Hand shaking이 진행됨에 따라 서버측의 상태변화
Listen -> Syn receive -> sysn sent -> established

* 세션을 끝낼때는 4 Hand 쉐이킹 과정이 있다.
  이건 나중에 확인해 보겠다.

* Syn 패킷에 들어있는 시퀀스 넘버를 ISN (Initial Sequence Number) 초기 시퀀스번호라고 한다.
-> 서버에게 나를 식별할 수 있는 번호를 보내준다. 서버와 클라이언트는 이 시퀀스 번호를 서로를 알아본다.
-> SYN 패킷의 목적은 이 ISN을 서버에 전달하는 목적이다.

3 Hand shaking 동작 내용.
1. 클라이언트는 SYN 패킷에 ISN을 넣어서 보낸다.
2. 서버도 SYN-ACK 패킷으로 응답을 한다. 이 때 서버의 ISN을 생성해서 클라이언트에 보내면서 응답을 한다.
(서버의 ACK 필드에는 클라이언트의 시퀀스넘버에 1을 더한 값이 들어간다.)
그래서 이 시퀀스 넘버가 틀어지지 않는 이상 이 연결은 유효하다.
3. 클라이언트는 ACK 패킷을 전송한다.


* 세션 하이재킹 -> 남이 로그인한 세션이 인증된 패킷 시퀀스 넘버를 예측해서 그 값을 데이터로 만들어서 보내면 서버에 로그인할수있다.

-> 시퀀스 넘버는 서로 주고받는 크기만큼 늘어난다.
* ACK -> 잘 받았다는 응답이다.
만약 이 패킷을 못받으면 잘 안간줄 간주하고 다시 보낸다.
이게 TCP가 가지고있는 에러정정(Error Control)이다.

이걸 응용하여 다음 ACK응답으로 올 번호를 예상하여 출력해보았다.



(추가한 코드)


(예상 다음 ACK 번호와 일치)



확인해보면 다음 받을 ACK 번호랑 예측한 값과 같음을 확인할 수 있다.

* IP에 관해 이야기를 시작하겠다.

Layer 3
 - IP - 경로 설정
       - 네트워크 상에서 호스트를 식별하는 식별자(IP주소)로도 사용한다.
       - 라우팅 프로토콜이 들어간다.
 -> ( 라우팅 프로토콜을 이용하여 취약점을 공략해 공격할 수 있다.)

 PDU : Packet (IP 패킷)
 - 라우팅 장비가 IP주소를 보고 어디로 보낼지 결정한다.

IP address
 -> IANA에서 IP주소 관리, 할당, 표준 제정등을 한다.
     - IPv4, IPv6

- 주소의 분류 (체계적으로 관리하기 위해서)
: IPv4의 주소 체계이다.
 - 4자리 자연수를 '.' 으로 구분해서 표기한다.
 - 1자리 수는 0~255까지 표현이 가능하다.
    전체 사용가능한 ip주소 범위 -> 0.0.0.0 ~ 255.255.255.255
   -> 실제 사용 불가능한 주소가 있다.
   ex)  0.0.0.0    ( 모든 ip를 의미한다. ) 
        255.255.255.255  (브로트캐스팅 주소)
: A class, B class, C class, D class, E class

IP 주소 클래스

A Class
 -> 앞에 한자리가 구역을 나타낸다. 이것을 network id라고 표현한다.
 -> 나머지 세자리는 host id이다.
 -> 네트워크 id : 첫번째 자리
 -> host id : 나머지 세 자리. (host를 구별하기위해 사용)
 -> 맨 앞 1비트가 0으로 공통이다.
ex) 1.xxx.xxx.xxx
    10.xxx.xxx.xxx
-> 2진수로 표현하면 0000 0000.hhhh hhhh.hhhh hhhh.hhhh hhhh
-> 맨 앞비트가 0이어야한다. 즉, 0000 0000 ~ 0111 1111 까지 표현 가능하다.
 -> 10진수로 따지면 1.h.h.h(10) ~ 126.h.h.h 까지 가능한 A클래스 주소 범위다. (0도 안된다.) (127도 가상ip주소이므로 사용못한다.)
 -> 또 10.h.h.h 도 사용하지 못한다. -> 사설 IP주소이다.
 -> 127로 시작하는건 loop back 주소로 자기자신을 표현하는 IP주소이다.
 ex) 1.0.0.0 ~ 1.255.255.255 ( 1.h.h.h 주소를 가지고 있다면, 이만큼 쓸수 있는 것이다.)
  -> 1.0.0.0 (x)
  -> 1.255.255.255  (x)  
  -> 이 두개는 사용하지 못한다. 이유는 1.0.0.0 은 1.h.h.h를 대표하는 IP주소이고
      1.255.255.255는 1.h.h.h 네트워크에 있는 전체에 보내는 브로드캐스트주소이다.
      실제 사용 가능한 주소는 1.0.0.1 ~ 1.255.255.254 이다.






저번주까지 UDP 패킷분석, 그리고 IP 패킷을 분석하였다.

오늘은 TCP 패킷을 분석해보았다.

TCP는 UDP와 달리 조금 까다로운 부분이 많았다.

포함관계를 다시 정리하자면

IP 패킷안에 TCP 혹은 UDP가 들어가는 것이다.

저번주 까지 했던 패킷을 덤프받는 프로그램에서
이제 IP헤더를 분석할 수 있었고
그에 따라
소스 IP주소와 목적지 IP주소를 파악할 수 있었으므로

조금 더 정교한 필터링을 할 수 있게 되었다.



(조건 문에 IP주소로 필터링 하는 코드)


또, IP 헤더에서 Protocol 타입을 알아낼 수 있으므로
TCP, UDP, ICMP를 구분하기로 했다.



(Protocol 필드로 구분하는 모습)


위 코드를 보면 이제 TCP 헤더를 분석해볼 것이므로
처음에 list를 이용해 16진수로 표현해보았다.




(오른쪽화면은 저번주에 만들었던 TCP 메세지전송 프로그램.)


위 화면을 보면 TCP 데이터가 나오는 것을 확인 할 수 있다.

UDP와 다른점은 UDP는 메세지 하나 보내면 끝이었는데
TCP는 그 전에 많은 패킷들이 왔다 갔다 한다.
자세한 특징은 다음에 더 알아보겠다.
우선,
TCP 패킷의 헤더를 분석하는 것이 먼저다.

우리가 덤프받은 TCP 패킷의 헤더
['0xc3', '0x29', '0xea', '0x60', '0x2a', '0x4', '0x15',
'0x1a', '0x0', '0x0', '0x0', '0x0', '0x80', '0x2', '0x20', '0x0',
 '0xd9', '0x88', '0x0', '0x0', '0x2', '0x4', '0x5', '0xb4', '0x1', '0x3',
'0x3', '0x2', '0x1', '0x1', '0x4', '0x2']

내용은 이렇다.
1. 출발지 포트번호(2바이트) : '0xc3', '0x29' = 0xc329 = 49961
2. 도착지 포트번호(2바이트) : '0xea', '0x60' = 0xea60 = 60000
3.  Sequence Number(4바이트) : '0x2a', '0x4', '0x15', '0x1a'
- 운영체제에 의하여 랜덤하게 시작된다. Session을 표현하는 고유값이다.
4. Acknowledge Number(4바이트) : '0x0', '0x0', '0x0', '0x0'
*'0x80' -> 8과 0으로 본다.
5. TCP 헤더의 길이 (4비트) -> 8 (x4) = 32바이트
6.  예약된 영역 : 0 (사용하지 않는 필드이다.)
7. Flag : '0x2' = 2 (여기서는 SYN패킷, 동기화요청)
Flag 종류
1 : FIN
2: SYN
4: RST(reset)
8: PSH(push)
16: ACK(응답)
32: URG(urgent) 
(만약 동시에 설정된다면, 예를들어 SYN과 ACK가 같이 설정되면 두개의 합이된다.)
(ex. SYN-ACK 은 18번이 된다.)

8. window size (2바이트) : '0x20', '0x0'
9. TCP의 Checksum(2바이트) : '0xd9', '0x88'
10. Urgent Pointer(2바이트) : '0x0', '0x0'
---- 여기까지 딱 20바이트다.-----------------

그 이후로 옵션이 더 붙어서 패킷이 보내질 수도 있다.

자. 그러면 이제 이 내용을 바탕으로 헤더내용을
분석하여 출력해보겠다.


(TCP 패킷 분석코드)


(TCP 헤더 분석 내용)



여기서
Header 길이를 표현하려면 아까 한 바이트를 4비트로 나누어야한다.
이제 그 작업을 시작하겠다.

0x45를 4와 5로 분리하는 것이다.
먼저 0x45를 2진수로 변환한다. (bin()함수 사용)

그 후 슬라이스로 4개씩 자르고 int로 형변환 해준다.
아래와 같다.


(분리된 모습)



이걸 이용해
IP 헤더의 버젼과 헤더길이를 나누고
TCP의 길이를 구하겠다.

또 IP헤더에서 헤더길이를 정확하게 구할 수 있고 그러면
UDP,TCP 패킷이 어디서부터 시작하는지 또한 정확하게 표현할 수 있다.

(지금까지는 그냥 IP헤더가 20바이트라고 가정하고 했었다.)




(헤더 길이를 분리하는 코드)



(UDP의 시작 슬라이스와 TCP 헤더 길이, 또 flag를 표현해 수정해주었다.)



flag를 dictionary로 정의하여 키값을 대입하면 그에 대응하는 값이 출력된다.



(결과 화면)



지금 까지 TCP패킷을 분석해보았고

IP헤더도 더 정밀하게 분석하였다.

내일은 현재 진행중인 패킷 분석 프로그램을 조금 더 수정하고
본격적으로 패킷을 확인하고 변조해 보겠다.









어제 하던 통신프로그램을 보완해서

그럴싸한 통신을 하는 프로그램으로 업그레이드 했다.



(while 문을 이용해 메세지를 종료할 때 까지 통신하는 코드)


(메세지를 주고받는 모습)


(맨 아래줄에 보면 외부 IP주소와 포트번호가 나와있다.)



위 화면에서 외부주소 맨 아래를 보면 상대 IP주소와 포트번호가 나와있다.

코드에 적힌 대로 IP주소와 포트번호로 연결된것을 확인할 수 있다.

현재, 이 프로그램은 동기식 통신이다. 즉 한번 보내고 한번 받고 해야하는 방식이다.

여기서,

상대와 보통 채팅처럼 비동기식으로도 만들 수 있다.
내가 보내지않아도 상대가 마음껏 보낼 수 있는 상태로.

그러려면
Thread를 이용해야한다.

하나는 send만 하고 하나는 recv만 하도록 쓰레드를 열어서 실행해야한다.

하지만 현재 우리는 네트워크를 이해하는 차원에서
여기 까지 하겠다.

우리가 패킷을 분석하기 위해 만드는 프로그램이기 때문이다.

우리가 위에서 보낸 메세지나
네트워크에서 주고받는 데이터는
전달하기위해 여러가지가 붙어서 패킷을 만들어 전달된다.

이런 규칙들이 프로토콜인데
4계층의 TCP, UDP를 알아보겠다.

먼저 파이썬 코드로 어떻게 동작되는지 두 프로토콜의 차이점을 봐야한다.

동작 과정

* TCP server
 1. socket()
 2. bind()
 3. listen()
 4. accept()
 5., send(), recv()

* TCP Client
 1. socket()
 2. connect()    -> server의 accept와 연결된다.
 3. send(), recv()

* UDP server
 1. socket()
 2. bind()
 3. sendto() ,recvfrom()

* UDP server
 1. socket()
 2. sendto(), recvfrom()
-> send()를 못쓰는 이유는 send는 연결되어있는 곳으로 보내는건데
UDP는 연결된게 없으므로 sendto()로 그때그때 어디로 보내는지 적어줘야한다.

UDP의 특징
-> 연결과정 없이 바로 보내고 받는다.
-> 데이터가 갈수도있고 안갈 수도 있다. 그래서 TCP는 신회성이 있는 통신이다. 왜냐하면 안갔는지 갔는지 체크하기 때문이다. TCP는 체크하지만 UDP는 체크하지 않는다.
-> UDP는 신뢰할 수 없는 통신이다. ( 이말은 상대가 받았는지 체크할 수 없다는 뜻)
-> 인증 절차도 없다. 그냥 보내고 그냥 받는다.
보통 UDP를 사용하는 프로그램은 보통 인증과정이 없다.
UDP자체로는 인증을 할 수 없다.

그렇다면 왜 쓸까?
  위 말만 들으면 왜쓰는 걸까 싶지만 UDP의 큰 장점은 복잡하지않고 빨리빨리 보낼 수 있다는 것이다. 보내는 데이터가 크지 않다면 UDP가 적절하다. UDP는 에러체크등이 없고 그냥 보내기만 하는 것이다. 그래서 사실 예전에는 많이 쓰이지 않았다. 하지만 요즘 많이 쓰이고 있는것이 실시간 통신이 필요할 때 특히 UDP를 많이 쓴다. 빨리보낼 수 있고 에러 났다고 다시 보낼 필요가 없는 실시간 통신에 적합하다. 혹은 짧은 데이터 같은 경우가 적합하다.

- netstat -anp UDP
입력하면 UDP 포트 정보를 볼 수 있다. 여기에 상태 정보가 없다. 연결과정이 없기 때문이다.


(상태 부분이 없다.)


파이썬에서 UDP에 사용되는
recvfrom() 함수.
-> 받아온 내용보면 클라이언트 정보도 같이 출력된다.


(맨 아래 데이터와 데이터가 날라온 IP주소와 포트정보)


-> 튜블정보이므로 ip주소와 포트번호를 따로 입력받아서 출력해 봤다.


(튜플정보를 따로 받아와 출력한 모습)


TCP, UDP  -> Layer 4 (4계층)에 속한다.
-> 전송계층 (Transport Layer)

* PDU : Protocol Data Unit


-> packet : 패킷, 3계층에서 사용되는 단위
    근데 그냥 보내는 데이터 덩어리를 패킷이라고도 한다.


L4에서는 pdu가 segment 다.

-> 주소 체계 : Port번호

-> 각 계층별 사용하는 단위와 주소가 다르다.


패키징
-> Hello 데이터를 패키지화한다. 포장하듯이.
-> UDP 헤더를 붙인다. 데이터 앞에

헤더에 어떤 정보들이 들어가있는지 정해논다 -> 규약 Protocol

프로토콜에 맞게 데이터를 패키징해서 다음 계층으로 보낸다.



UDP 헤더에는 어떤 정보가 들어있을가?


UDP Header

 - dst Port 번호, src Port 번호
 - data length, checksum



-> 직접 확인해본다.

(먼저 패킷 데이터를 덤프받을 프로그램을 만들었다.)


socket.gethostname() 을 이용하면 컴퓨터의 이름을 얻어올 수 있다.

gethostbyname() 을 이용하면 이름을 가지고 호스트 정보를 가져올 수 있다. (IP정보)


-> 여기서 포트번호에 0을 쓴이유는 특정포트를 보기위해 하는게 아니라 특정 IP에 모든 포트들을 확인하는 것이다.


(여러번 실행한 경우)


뭔지 모를 데이터들이 오고가는 모습이다.


그러면 우리가 오늘 바로 작성한 UDP로 패킷을 보내고 이 패킷의 내용을 확인해보자.


(코드)


위 코드를 보면 info[0]에는 IP정보가 들어가므로 IP주소가 내꺼인 주소만 보겠다는 것이다.

이걸 안하면 이것저것 위에서 본거 처럼 구별하기가 힘들어서 그렇다.


이제 내가 UDP로 패킷을 보내고 이 프로그램으로 확인 해 볼 것이다.

보낼 데이터 : Hello


(출력 화면)


그림은 클릭하면 크게 보인다.


출력화면을 보면 끝에 Hello라고 적혀있는것이 보인다.

그리고 그 앞부분은 헤더의 내용이다.

UDP는 헤더에 많은 내용이 들어간다고 안햇는데 왜이렇게 길지???..


그건 UDP헤더만 붙는게 아니기 때문이다.


아래 계층으로 내려가면서 패키징되는데 점점 헤더가 붙어서 늘어나기 때문이다.


이제 앞으로 이 헤더 정보, 데이터 정보를 구별하여 읽는 법을 공부할 것이다.


다른 패킷을 분석하여 어떤 정보가 오고가는지 확인할 수 있게 될 것이다.







+ Recent posts