프로그래밍/C언어를 활용한 네트워크 해킹

RAW 소켓

cyanhe_wh 2019. 9. 3. 01:23
728x90
반응형

RAW 소켓이란

소켓을 생성할 때 지정하는 옵션을 이용하여 데이터를 전송할 때 직접 프로토콜 헤더를 만들고,

데이터를 수신할 때도 프로토콜 헤더를 포함하여 수신하겠다는 의미로 소켓을 생성하는 것이다.

 

보통 소켓 관련 라이브러리 및 운영체제에서 프로토콜 헤더를 작성하여 직접 작성하지 않아도 되지만,

간혹 직접 다뤄야 하는 경우가 필요하다.

 

참고로 대부분의 Socket API는 RAW 소켓을 지원한다.

윈도우 XP 경우도 2001년에 출시되었을 때 Winsock 인터페이스를 통해서 RAW 소켓을 지원했다.

하지만, 해커가 RAW 소켓을 이용하여 직접 프로토콜 헤더를 만들어 공격에 사용하였기 때문에 3년 후의 윈도우 XP에서는 RAW 소켓의 사용을 제한하였다. 

그래서 윈도우에서 학습할 경우 Packet Capture 라이브러리를 이용하여 기능을 구현해야 한다.

 

리눅스 환경 소켓 생성

1. RAW 소켓 생성                   sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);

2. 소켓 옵션 변경(선택사항)       setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&value, sizeof(value));

 

소켓을 생성한 후, 옵션을 변경하면 데이터를 전송하기 위하여 실제 IP 헤더를 포함한 모든 프로토콜 헤더를 직접 작성해 야한다. 또한, 데이터를 수신하게 될 때도 프로토콜 헤더를 포함하여 데이터가 수신하게 된다.

 

하지만, 위와 같이 소켓을 생성해도 2 계층에 해당하는 데이터 링크 계층의 프레임 헤더는 운영체제에서 자동으로 만들어준다.

 


sock = sockeet(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

이렇게 소켓을 생성하면 데이터 링크 계층에 해당하는 프레임 헤더까지 직접 만들어 전송할 수 있을뿐더러 데이터 링크 계층의 데이터까지 모두 수신할 수 있다.


#include<unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

ssize_t read(int fd, void *buf, size_t count);

두 함수는 파일 디스크립터로 사용하는 함수인데, 소켓 디스크립터로 적용될 수 있다.

소켓 디스크립터는 파일 디스크립터와 동일하게 처리되므로 파일에서 처리되는 입출력 관련 함수를 사용 가능하다.


RAW 데이터 수신

RAW 데이터 수신 예제

RAW 소켓을 생성하고 소켓으로부터 수신되는 데이터 링크 계층의 데이터를 읽는 예제이다.

RAW 소켓은 다른 사용자가 주고받는 데이터도 수신할 수 있을 뿐만 아니라 프로토콜 헤더를 조작하여 전송할 수 있다.

리눅스에서 보안상의 이유로 root 권한으로만 실행이 가능하다.


read() 함수와 recvfrom() 함수에 대한 차이는 부가적인 데이터의 수신 여부이다.

위의 예제처럼 read() 함수를 이용하여 소켓으로부터 수신 데이터를 읽는다면 부가적인 정보를 제외하고 순수한 데이터 정보만 읽을 수 있다.

하지만, recvfrom() 함수를 이용하는 경우에는 어떤 네트워크 인터페이스로부터 어떤 데이터가 수신되었는지 부가적인 정보까지 확인해 볼 수 있다.


기존의 소켓을 이용하여 데이터를 주고받을 때는 구조체 sockaddr_in을 이용하여 IP주소와 포트 정보 등을 저장하여 사용하였지만, RAW 소켓을 생성하는 경우 구조체 sockaddr_ll 형식의 정보로 데이터가 수신된다.

 

구조체 sockaddr_ll  => /usr/include/linux/if_packet.h 파일에 정의되어 있다.

sockaddr_ll 구조체

1. PF_PACKET 옵션으로 소켓을 생성하는 경우 sll_family의 값은 언제나 PF_PACKET이 된다.

2. sll_protocol은 네트워크에서 표준 Ethernet 프로토콜 타입으로 <linux/if_ether.h> 헤더 파일에 정의되어 있으며

   기본  값으로 소켓의 프로토콜 값을 갖게 된다.

3. sll_ifindex의 경우 네트워크 인터페이스의 인덱스 번호이다.

   0은 모든 네트워크 인터페이스를 의미하게 되는데, 0 값은 오직 네트워크 인터페이스를 바인딩할 때만 유효하다.

   (바인딩할 때도 구조체 sockaddr_ll을 동일하게 사용)

4. sll_hatype의 경우 헤더의 형태를 의미한다.

5. sll_pkttype의 경우 패킷의 타입을 의미한다.

   sll_pkttype값은 헤더 파일 /usr/include/linux/if_packet.h에 정의되어 있다.

sll_pkttype 값

6. sll_addr과 sll_halen의 경우 물리계층의 주소와 길이를 의미한다.

 

패킷을 보낼 때는 sll_family, sll_addr, sll_halen, sll_ifindex 필드만이 사용되며 그 외의 필드는 반드시 0으로 설정되어야 한다. 그리고 sll_hatype과 sll_pkttype의 경우 패킷을 받을 때만 설정되며 네트워크 인터페이스를 바인딩할 때는 sll_protocol과 sll_ifindex가 사용된다.


recvfrom() 함수를 이용한 로우 데이터 수신

recvfrom() 함수를 이용한 로우 데이터 수신 예제 코드
recvfrom() 함수를 이용한 로우 데이터 수신 결과

728x90
반응형

'프로그래밍 > C언어를 활용한 네트워크 해킹' 카테고리의 다른 글

ARP 프로토콜  (0) 2020.12.02
Ethernet 헤더  (0) 2019.09.05
체크섬(Checksum)  (0) 2019.09.03
Packet Capture 라이브러리2  (0) 2019.09.03
Packet Capture 라이브러리  (0) 2019.09.03