ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • tcp_data_change 구현하면서 정리
    Network hacking training/Knowledge 2018. 9. 27. 18:40
    목표 및 목적 : TCP Data 영역을 수정
    netfilter를 이용하여 local process로 송수신 되는 IP packet을 모두 netfilter queue로 넘겨야 하는데 이는 iptables 라는 명령어로 가능하게 해준다.

    [iptables 설정]
    ⚡ root@ubuntu  ~  iptables -A OUTPUT -j NFQUEUE --queue-num 0
    ⚡ root@ubuntu  ~  iptables -A INPUT -j NFQUEUE --queue-num 0
    ⚡ root@ubuntu  ~  iptables -F


    이제 tcp_data_change를 하기 위해서는 데이터가 변경된 후 tcp의 checksum 또한 바꿔줘야한다.

    checksum이란?
    중복 검사의 한 형태로, 오류 정저을 통해 송신된 자료의 무결성을 보호하는 단순한 방법이다.
    기본적인 메시지 구성 요소를 추가하여 결과값을 저장함을써 동작한다.
    나중에 누구나 데이터에 같은 작업을 수행할 수 있고, 무결성 검사에 대한 결과를 비교할 수 있으며, 메시지가 손상되지 않았다고 결론을 내릴 수도 있다. (Checksum이 맞아 떨어지는지 확인을 해봄으로서 가능)

    ipv4의 경우 checksum이 있고, tcp 또한 checksum이 존재한다.
    먼저 ipv4의 checksum을 구하는 방법은 아래와 같다.

    [IPv4 header checksum 구하는 공식]
    1. version 필드 값 ~ IP 필드 값까지 합한다. // 모든 필드의 값을 더해준다.(여기서 checksum 필드의 값은 0으로 초기화해준 뒤 더한다.)
    2. 더한 값의 첫 번째 값을 뒤의 4자리 값과 합산한다.
    3. 더한 갑을 2진수로 표기한 후, 1의 보수를 취한다. (0 -> 1 , 1 -> 0)
    4. 이후 16진수로 표현하면 그것이 바로 체크섬의 값이 된다.

    [code]
    checksum = (sum>>16)+(sum&0xffff)    -> 올림수 제거
    checksum = (checksum^0xffff)    -> 1의 보수

    쉽게 말해 IP header의 필드 중 checksum을 0으로 초기화 한 뒤 2byte씩 쪼개서 더한다.
    이때 2byte

    ipv4의 경우 checksum값이 존재한다. (ipv6의 경우는 checksum을 계산하지 않는다고 한다.)

    TCP의 경우도 마찮가지인데 더해주는 값이 IP header checksum을 구하는 공식과 다르다.

    [TCP header checksum 구하는 공식]
    ip header의[출발지 ip] + ip header의[도착지 ip] + NULL byte + ip header의 proto type + tcp header의 길이 + tcp 헤더의 모든 필드

    이렇게 IP header에 존재하는 src_ip, dst_ip, proto type등 tcp header의 모든 필드의 값을 더할 뿐더러 더해주는 값이 더 많다.
    이점만 빼면 checksum을 구하는 방식, 원리는 같다.

    따라서 다음과 같은 pseudo_header를 이용하면 편리하게 구할 수 있다.

    [pseudo_header]
    #pragma pack(push,1)
    struct pseudo_header{
        uint32_t src_ip;
        uint32_t dst_ip;
        uint8_t reserved = 0;
        uint8_t proto;
        uint16_t tcp_len;    // 전체 패킷의 크기에서 ip header의 크기를 뺀 값
    };
    #pragma pack(pop)


    이제 이에 맞게 checksum을 구해주는 함수를 구현하면 다음과 같이 구현할 수 있다.

    uint16_t calc_checksum(uint16_t *data, uint32_t len)
    {
        uint8_t oddbyte = 0;
        uint32_t sum = 0;
        cout << len << endl;
        while(len > 1)
        {
                sum += ntohs(*data++);
                len -= 2;
        }

        if(len == 1)
        {
            oddbyte = (uint8_t)*data;
            sum += ntohs(oddbyte);
        }

        sum = (sum >> 16) + (sum & 0xffff);

        return (uint16_t)sum;
    }

    데이터와 그 데이터에 대한 길이를 받고, checksum 값을 구하여 return 해주는 함수이다.

    다음은 데이터를 변경하는 함수와 caller 함수의 모습이다.

    [replaceString()]
    string replaceString(string subject, const string &search, const string &replace)
    {
        size_t pos = 0;
        while((pos = subject.find(search, pos)) != string::npos)
        {
            subject.replace(pos, search.length(), replace);
            pos += replace.length();
        }
        return subject;
    }

    [caller]
    string tmp_data = (char *)packet;
    string str1("hacking");
    string str2("HOOKING");
    tmp_data = replaceString(tmp_data, str1, str2);

    // change data in copied original packet( change_packet )
    memcpy((change_data + ip_tcp_len), tmp_data.c_str(), (ret - ip_tcp_len));

    들어온 data를 string 변수에 넣어준 뒤 찾고 싶은 문자열과 변경할 문자열을 지정해주고 replaceString()를 호출하여 데이터를 변경해준다.


    [결과물]


    [ETC Ref, TIP]

    [Tip] 데이터를 확인하고 싶을 때!
    /* Ubuntu 에서 c++ string 을 출력하려고 printf("%s", str); 을 했을 때 문자가 깨져서 출력되는 경우가 있는데 이 경우 cout << str << endl; 로 대체 하면 된다. */
    => 간단히 말해 printf() 사용 x -> cout 사용 o

    [Tip] libnet-headers.h에서 원하는 헤더 찾기
    vi libnet-headers.h
    :/[문자열]
    반응형

    'Network hacking training > Knowledge' 카테고리의 다른 글

    ip_change 구현하면서 정리  (0) 2018.10.01
    airodump 구현하면서 정리  (0) 2018.09.06
    [CCIT] 8/12 정리  (0) 2018.08.18
Designed by Tistory.