IP 사기: 이론과 실현

이론


배경.


인터넷을 사용할 때, 장치는 유일한 32비트 (IPv4) 또는 128비트 (IPv6) 식별자를 분배받을 것입니다. 이를 IP 주소라고 합니다.
here를 클릭하여 네트워크에 할당된 IP 주소를 찾을 수 있습니다.
당신의 IP 주소를 봉투에 있는from: 필드로 상상하고, 대상의 IP 주소를 to: 로 상상하세요.
만약 당신이 메일을 보낼 때 다른 사람인 척하고 싶다면, 당신의 주소를 쉽게 삭제하고 다른 주소를 쓸 수 있다. 이 개념은 본고에서 사기라고 불린다.
사실은 인터넷의 작업 방식이 똑같다는 것을 증명한다. 당신의 인터넷이 IP 프로토콜에 따라 보내는 모든 데이터에 당신의 메시지 앞에는 인터넷의'발신자'와'수신자'필드가 포함되어 있다.이 제목은 장치에 의해 작성됩니다.
인터넷의 기초는 IP 프로토콜이지만 대부분의 데이터는 TCP/IP 또는 UDP/IP 프로토콜 창고를 사용합니다. 이것은 우리의 메시지에 TCP 또는 UDP 헤더가 포함되어 있음을 의미합니다.TCP는 메시지의 원본 IP를 검증할 때 매우 중요하며 지속적인 IP 사기를 사용하지 않습니다.

연구하다.


IP 세트는 상당히 복잡하고 역사가 유구하지만 전체적으로 말하자면 소프트웨어 실현을 위해 하나의 규칙을 정의했는데 이를 IP 창고라고 부른다.
인터넷 프로토콜 자체는 헤더와 데이터의 유효 하중으로 구성된 데이터 보고를 중계하는 데 쓰인다.헤더 섹션은 소스 IP 주소, 대상 IP 주소 및 라우팅 및 패킷 검증에 필요한 기타 관련 필드로 구성됩니다.데이터의 유효 하중은 발송된 데이터로 구성된다.
IPv4 헤더에 포함된 기술에 대한 정보를 보려면 Internetwork Protocol Specification를 참조하십시오.
이 사양에서 IP 헤드는 15페이지에서 다음과 같이 정의됩니다.

해독은 좀 이상하지만 문자마다 1자리를 표시하고 필드마다 처음부터 읽힙니다!끝!
예를 들어 세션 편이도는 13자리이고 앞에 13글자가 있습니다!그 다음엔!
규범의 16페이지에서 우리는 몇 가지 재미있는 정의를 발견했다.

원본 주소 필드의 정의를 변경하려고 합니다. 특히 마지막 3바이트 (24비트).

그리고 검사와 필드 설명을 참고하십시오. 데이터 보고서가 유효하다고 여겨지기 위해서 변경을 해야 합니다.

구현 계획


실현을 시작하기 전에 주의해야 할 것은 우리가 TCP/IP 스택으로 IP를 속일 수 없다는 것이다.이것은 불가능하다. 왜냐하면 TCP 연결은 송신자와 수신자 간의 삼자 악수에서 시작되고, 우리 메시지의 수신자는 누구와 악수를 시도할 것인가?우리가 조작한 IP는 우리의 실제 IP가 아니다.
그러나 우리는 UDP/IP 창고에서 위조된 IP를 사용할 수 있다. UDP 프로토콜은 악수에 관심이 없고 단방향 통신, 즉 송신자가 수신자에게 보내는 것을 받아들일 수 있다.
참고: IP를 속이는 데는 TCP 또는 UDP가 더 높은 수준의 프로토콜로 필요하지 않습니다.그러나 UDP는 포트 사양을 지원하므로 테스트 프로그램을 쉽게 만들 수 있습니다.
이제 우리는 연구를 마쳤고, 우리가 무엇을 바꾸고 싶은지 확인하는 데 필요한 정보를 얻었다.그러나 IP 헤더는 어떻게 수정할 것인가?
코드에서 IP 헤더를 어떻게 수정하는지 검색하기 전에 프로그램을 설계해 봅시다.

프로그램 설계


우리의 프로그램은 이런 저급 프로젝트에 적합하기 때문에 C 언어를 사용할 것이다.대상 주소라는 매개 변수를 받아들입니다.
모든 다른 설정은 코드에서 완성하고 다시 컴파일할 수 있습니다.$ ./ipspoofer 127.0.0.1TCP IP 사기 때문에 삼자 악수를 할 수 없기 때문에 UDP 프로토콜을 사용하여 데이터를 보낼 것이다.

API 연구


연구 과정에서 다음과 같은 라이브러리에서 IP 헤더를 수정할 수 있습니다.
libpcap
디바이스/dev/에 있는 네트워크 디바이스의 전송 및 전송 TCP/IP 패킷을 분석하는 패킷 캡처 라이브러리그러나 패키지를 수정하기 위한 것은 아닌 것 같습니다.윈도우즈 포트는 winpcap입니다.
libnet
Libnet은 자신을 "네트워크 패킷을 구축하고 주입하는 데 도움을 주는 API[...]
Libnet에는 IP 및 링크 계층에 패킷 생성 및 보완 및 보완 기능이 포함됩니다."
원시 소켓 (unix 커널 API)
만약 linux 시스템의 플러그인 라이브러리 socket() 함수를 호출한 적이 있다면, TCP와 UDP에 각각 대응하기 때문에 SOCK_STREAM 또는 SOCK_DGRAM 를 사용한 적이 있을 것입니다.
그러나 코드에 사용된 플러그인 형식도 있습니다. SOCK_RAW이런 플러그인 형식은 우리가 수동으로 protocol 헤드를 구성할 수 있도록 허용하고, 우리는 IPPROTO_RAW 협의를 사용할 것이다.
즉, IP 및 UDP 헤더를 구성하여 커널에 제공할 것입니다.
설계를 총괄하기 위해서, 우리는 C 코드를 작성하여 프로그램을 만들고 있으며, 이 프로그램은 UDP/IP 데이터 보고서를 구성하여 목표 IP로 전송할 것이다.우리는 linux 라이브러리에서 제공하는 원시 플러그인과 시스템 호출을 사용할 것이다. 왜냐하면 그들은 제3자 라이브러리를 사용하는 것보다 훨씬 간단하기 때문이다.
원본 플러그인을 사용하는 것은 IP와 UDP 헤더를 수동으로 만들어야 하며,libpcap과libnet처럼 포획된 패키지를 간단하게 수정하고 주입하는 것이 아니라 주의해야 한다.

구현


이 프로젝트의 전체 소스 코드 here 를 작성하기 시작합시다.그러나 우리는 주요 부분을 되돌아볼 것이다.
참고 코드는 Linux, FreeBSD 및 MacOS에서 테스트되었습니다.그것은 모든 3개 플랫폼에서 컴파일되지만 MacOS에서 데이터 보고서를 보내지 않는다.
필요한 헤드가 포함된 후에는 다음 매개변수를 사용하여 소켓을 생성합니다.
int s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
AF_INET IPv4를 사용할 예정입니다.SOCK_RAW는 우리가 우리의 프로토콜 헤더를 구축할 것을 의미한다.IPPROTO_RAW는 IP 프로토콜의 모든 헤더를 우리가 사용하고 있는 더 높은 수준의 프로토콜에 제공한다고 밝혔다.
우리는 두 개의 미리 정의된 구조를 제목ip_headerudp_header로 사용할 것이다netinet/ip.hnetinet/udp.h.
// IP header
struct ip ip_header;
ip_header.ip_hl = sizeof(struct ip) / 4; // Header length is size of header in 32bit words, always 5.
ip_header.ip_v = 4;                      // IPv4
ip_header.ip_tos = 0;                    // Type of service, See RFC for explanation.
ip_header.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + datalen);
ip_header.ip_id = 0;                     // Can be incremented each time by setting datagram[4] to an unsigned short.
ip_header.ip_off = 0;                    // Fragment offset, see RFC for explanation.
ip_header.ip_ttl = IPDEFTTL;             // Time to live, default 60.
ip_header.ip_p = IPPROTO_UDP;            // Using UDP protocol.
ip_header.ip_sum = 0;                    // Checksum, set by kernel.

// Source IP
struct in_addr src_ip;
src_ip.s_addr = inet_addr(src_addr);
ip_header.ip_src = src_ip;

// Destination IP
struct in_addr dst_ip;
dst_ip.s_addr = inet_addr(dest_addr);
ip_header.ip_dst = dst_ip;

// UDP Header
struct udphdr udp_header;
udp_header.uh_sport = htons(src_port);                          // Source port.
udp_header.uh_dport = htons(dest_port);                         // Destination port.
udp_header.uh_ulen = htons(sizeof(struct udphdr) + datalen);    // Length of data + udp header length.
udp_header.uh_sum = 0;                                          // udp checksum (not set by us or kernel).
전송할 데이터 보고서를 구성하기 위해서 우리는 데이터로 버퍼를 채워야 한다. 먼저 IP 헤더, 그 다음에 UDP 헤더, 마지막으로 데이터의 유효 부하이다.
우리는 memcpy()를 사용하여 구조를 메모리에 복제할 수 있다.
// Construct datagram
int datagram_size = sizeof(struct ip) + sizeof(struct udphdr) + datalen;
unsigned char datagram[datagram_size];
memcpy(datagram, &ip_header, sizeof(struct ip));
memcpy(datagram+sizeof(struct ip), &udp_header, sizeof(struct udphdr));
마지막으로, 우리는 데이터 보고서를 어디로 보낼지에 대한 정보를 저장하고, ctrl+c를 통해SIGTERM을 보낼 때까지 struct sockaddr_in 를 사용하여 반복해서 보냅니다.
// sendto() destination
struct sockaddr_in destaddr;
destaddr.sin_family = AF_INET;
destaddr.sin_port = htons(dest_port);
destaddr.sin_addr.s_addr = inet_addr(dest_addr);

// Send until SIGTERM
for(;;) {
    sendto(s, datagram, datagram_size, 0,(struct sockaddr*)&destaddr, sizeof(destaddr));
    sleep(1);
}
이것은 코드의 총체적인 요점입니다. 이 절의 맨 끝에 있는github 링크의 원본 코드에 대해 더 많은 작업을 해야 합니다.

수신기에서 보기


데이터 보고서가 발송되었는지 확인하기 위해서 넷캣을 사용하여 열린 포트에서 전송된 데이터를 감청하고 표시할 수 있습니다.sendto() $ nc -lvu <port> - 경청(수신기로 실행됨).-l - 세부 정보(들어오는 연결 IP가 표시됨).-v - UDP를 사용합니다.
프로그램을 실행하면 다음과 같은 내용이 표시됩니다.
Connection from 1.2.3.4 2000 received!
...random data...
참고 MacOS는 자세한 출력이 없으며 데이터만 볼 수 있습니다.

Wireshark 분석


장치가 트래픽을 보내고 있는지 확인하려면 Wireshark를 사용하여 전송된 패킷을 캡처하고 분석할 수 있습니다.

만일 모든 것이 순조롭다면,wireshark는 이렇게 해야 한다. 파란색 UDP 프로토콜 패키지, 원본은 우리가 위조한 주소이다.

포장 검사를 통해 우리는 위의 내용을 볼 수 있다.
소스 IP, 대상 IP, 포트가 모두 설정되어 있는 것처럼 보입니다.검사와 내부 핵이 설정되어 검증을 거쳤습니다.

버그 해결


MTU

-u가 MTU보다 크도록 설정되면 데이터 보고서를 보내지 않고wireshark에 나타나지 않습니다.
네트워크 장치 MTU는 itMaximum Transmission Unit를 가리키며 IP 데이터 보고서에서 전송할 수 있는 최대 데이터량으로 단락을 나누지 않아도 된다.일반적으로 MTU는 1500입니다.
MacOS와FreeBSD에서 packet_size 와 linux에서 ifconfig | grep mtu 가 있는 네트워크 장치 MTU를 찾을 수 있습니다.
다음과 같은 방법으로 장치의 MTU를 설정할 수도 있습니다.ip addr | grep mtu(Linux)ip link set dev <interface> mtu <size>(FreeBSD,MacOS)

마커스


이 코드는 MacOS에서 작동하지 않습니다.Wireshark 분석에 의하면 커널이 원본 IP를 덮어쓰고 UDP 헤더를 삭제하고 있습니다.MacOS 커널도 체크섬 계산을 하지 않습니다. 이것이 바로 배후의 원인일 수도 있습니다.

좋은 웹페이지 즐겨찾기