레이블이 네임쿼리인 게시물을 표시합니다. 모든 게시물 표시
레이블이 네임쿼리인 게시물을 표시합니다. 모든 게시물 표시

2013년 10월 16일 수요일

SQL 쿼리로 패킷 데이터를 조회한다고 ?

패킷데이터를 SQL 쿼리문 형태로 출력할 수 있는 PacketQ 에 대해서 소개해 볼까합니다. 패킷데이터를 간단하고 빠르게 출력해 낼 수 있는 도구입니다. 원래 이 도구가 DNS2db 라는 이름으로 사용되다가 2011년에 이름을 PacketQ 로 변경했습니다. 변경한 이유는 원래의 이름에서 알 수 있듯이 주로 DNS 데이터 중심으로 데이터를 뽑아냈었는데, 다른 프로토콜 까지 확장해 SQL 쿼리문으로 뽑아내고자 하였기 때문입니다. 하지만 아직까지는 자유롭게 처리할 수 있는 것이 DNS 데이터쪽으로 맞춰져 있습니다. 그러므로 DNS 에 한해 쉽게 데이터를 뽑아내고자 하시는 분들한테는 유용할 수 있습니다. DNS 관리자 분들에게는 더욱 유용할수도 있겠습니다.

일단 다운로드 및 세부 정보는 다음 경로에서 확인할 수 있습니다:

https://github.com/dotse/packetq

주요한 기능을 보면 PCAP 파일을 빠르게 파싱할 수 있다는 것을 강점으로 내세우고 있고요 SQL 쿼리문 형태로 사용이 가능합니다. SQL 에 익숙하신 분에게는 더없이 좋겠죠. XML, CSV, JSON, Table 형태로도 데이터를 출력시킬 수 있습니다. 아직은 DNS 와 ICMP 프로토콜 정도만 지원하고 있다는 점입니다. 그리고 PacketQ 가 SQL 쿼리문 형태로 사용할 수 있다고 하지만 완벽한 SQL 문 형태로 지원하는 것은 아닙니다. 조인, 서브쿼리, distinct, like 같은것은 사용할 수 없습니다. 사용가능한 문법은 다음 페이지를 참고해 보시면 됩니다.

https://github.com/dotse/PacketQ/blob/master/src/grammar

간단한 사용방법을 몇개 살펴보겠습니다. SQL 쿼리 같이 * 로 해서 전체 데이터를 다 출력할 수도 있지만 특정필드로도 제한할 수 있습니다. 일단, DNS 데이터에서 추출해 낼 수 있는 데이터 형태는 다음과 같습니다.

      { "name": "id","type": "int" },
      { "name": "s","type": "int" },
      { "name": "us","type": "int" },
      { "name": "ether_type","type": "int" },
      { "name": "src_port","type": "int" },
      { "name": "dst_port","type": "int" },
      { "name": "src_addr","type": "text" },
      { "name": "dst_addr","type": "text" },
      { "name": "protocol","type": "int" },
      { "name": "ip_ttl","type": "int" },
      { "name": "fragments","type": "int" },
      { "name": "qname","type": "text" },
      { "name": "aname","type": "text" },
      { "name": "msg_id","type": "int" },
      { "name": "msg_size","type": "int" },
      { "name": "opcode","type": "int" },
      { "name": "rcode","type": "int" },
      { "name": "extended_rcode","type": "int" },
      { "name": "edns_version","type": "int" },
      { "name": "z","type": "int" },
      { "name": "udp_size","type": "int" },
      { "name": "qd_count","type": "int" },
      { "name": "an_count","type": "int" },
      { "name": "ns_count","type": "int" },
      { "name": "ar_count","type": "int" },
      { "name": "qtype","type": "int" },
      { "name": "qclass","type": "int" },
      { "name": "atype","type": "int" },
      { "name": "aclass","type": "int" },
      { "name": "attl","type": "int" },
      { "name": "aa","type": "bool" },
      { "name": "tc","type": "bool" },
      { "name": "rd","type": "bool" },
      { "name": "cd","type": "bool" },
      { "name": "ra","type": "bool" },
      { "name": "ad","type": "bool" },
      { "name": "do","type": "bool" },
      { "name": "edns0","type": "bool" },
      { "name": "qr","type": "bool" }

이중에서 qtype 과 opcode 를 출력하고 총 3개의 데이터로 제한을 한다면 다음과 같이 쿼리가 만들어질 수 있습니다. -s 뒤에 사용할 쿼리를 넣어주면 됩니다.

# ./packetq -s "select qname,opcode from dns limit 3" test.pcap
[
  {
    "table_name": "result-0",
    "query": "select qname,opcode from dns limit 3",
    "head": [
      { "name": "qname","type": "text" },
      { "name": "opcode","type": "int" }
    ],
    "data": [
      ["n.search.naver.com.",0],
      ["n.search.naver.com.",0],
      ["n.search.naver.com.",0]
    ]
  }
]


어떤 출발지에서 가장 많은 DNS 쿼리 요청을 했는지 출력해 봅니다.

# ./packetq -s "select src_addr,count(*) as count from dns group by src_addr order by count desc limit 1" sample.pcap
[
size = 2
  {
    "table_name": "result-0",
    "query": "select src_addr,count(*) as count from dns group by src_addr order by count desc limit 1",
    "head": [
      { "name": "src_addr","type": "text" },
      { "name": "count","type": "int" }
    ],
    "data": [
      ["172.xx.xx.52",4]
    ]
  }
]


만약 가장 많은 쿼리가 요청된 것을 뽑아낸다면 다음과 같이 합니다. qname 으로 groupby 를 해 줍니다. SQL 에 익숙하신 분들이라면 쿼리만 보고서도 쉽게 이해가 되실 것입니다. 하지만 SQL 경험이 없으신 분들은 group by 가 무엇인지도 혼란스러울 수도 있습니다. 여기서는 SQL 쿼리문 까지는 다루기 힘들기 때문에 의미만을 설명드리겠습니다. qname 으로 그룹을 만들어 주고 각 qname 마다의 카운트를 생성합니다. 그리고 정렬을 count 로 해서 가장 많은 숫자가 처음에 나오게 하고 limit 를 통해 출력데이터를 1개로만 합니다. 그 결과가 아래와 같습니다 :

# ./packetq -s "select qname,count(*) as count from dns group by qname order by count desc limit 1 " test.pcap
[
size = 1513
  {
    "table_name": "result-0",
    "query": "select qname,count(*) as count from dns group by qname order by count desc limit 1 ",
    "head": [
      { "name": "qname","type": "text" },
      { "name": "count","type": "int" }
    ],
    "data": [
      ["resolver3.xxxx[삭제].com.",238]
    ]
  }
]

이번에는 쿼리타입을 출력해 볼까요? 쿼리타입이 기본적으로는 정수 값입니다. 그런데 정수값으로 보면 사람한테는 익숙하지 않습니다. 이때 NAME 펑션 기능을 이용해 쿼리타입(qtype)을 텍스트 형태로 출력시킬 수 있습니다. qtype 으로 그룹을 묶고 타입과, 카운트 정보를 뽑아서 가장 많은 순서대로 출력을 시킵니다.

# ./packetq -s "SELECT NAME( 'qtype' , qtype ) AS qt, COUNT(*) AS antal FROM dns GROUP BY qtype ORDER BY Antal DESC" test.pcap
[
size = 10
  {
    "table_name": "result-0",
    "query": "SELECT NAME( 'qtype' , qtype ) AS qt, COUNT(*) AS antal FROM dns GROUP BY qtype ORDER BY Antal DESC",
    "head": [
      { "name": "qt","type": "text" },
      { "name": "antal","type": "int" }
    ],
    "data": [
      ["A",8626],
      ["AAAA",680],
      ["PTR",566],
      ["TXT",202],
      ["SRV",113],
      ["MX",16],
      ["SOA",8],
      ["0",8],
      ["*",8],
      ["NS",8]
    ]
  }
]

패킷 데이터를 SQL 쿼리문으로 추출해 낼 수 있다는 점에서 굉장히 유용한 부분이 있습니다. 아쉬운 점은 일부 프로토콜로만 한정되어 사용할 수 없지만 광범위하게 프로토콜을 지원한다면 정말 편할거 같은 느낌입니다. 예전에 DNS 프로토콜을 파싱하여 활용할 일이 있어서 찾다가 보게되었는데 나름 유용하게도 이용할 수 있겠다는 생각이 들었습니다.

SQL 쿼리로 패킷데이터를 조회한다는 점, 흥미롭지 않나요.  더 많은 예제는 해당 홈페이지 위키 페이지를 참고하시면 됩니다.

P.S 참고로 ICMP 로 출력할 수 있는 데이터는 다음과 같습니다:

      { "name": "id","type": "int" },
      { "name": "s","type": "int" },
      { "name": "us","type": "int" },
      { "name": "ether_type","type": "int" },
      { "name": "src_port","type": "int" },
      { "name": "dst_port","type": "int" },
      { "name": "src_addr","type": "text" },
      { "name": "dst_addr","type": "text" },
      { "name": "protocol","type": "int" },
      { "name": "ip_ttl","type": "int" },
      { "name": "fragments","type": "int" },
      { "name": "type","type": "int" },
      { "name": "code","type": "int" },
      { "name": "echo_identifier","type": "int" },
      { "name": "echo_sequence","type": "int" },
      { "name": "du_protocol","type": "int" },
      { "name": "du_src_addr","type": "text" },
      { "name": "du_dst_addr","type": "text" },
      { "name": "desc","type": "text" }

아래와 같은 형태로 사용하면 되겠죠. 
./packetq -s "select * from icmp limit 3" 

2010년 7월 15일 목요일

윈도우 비스타, 7 환경에서 많이 보이는 LLMNR 프로토콜 정체는?

이전 포스팅에서 살짝 언급된 LLMNR 프로토콜에 대해서 소개해 볼까 한다.

LLMNR(Link Local Multicast Name Resolution)은 DNS 패킷 포맷형태로 로컬 링크상에서 호스트들의 이름을 조회하는데 이용되는 프로토콜이다. 윈도우 비스트, 윈도우 7, 윈도우 서버 2008 에 기본으로 포함되어 있다.
그렇기 때문에 같은 서브넷 상에 이런 호스트가 존재하면 LLMNR 프로토콜이 많이 나타난다. 윈도우 7 출시 이후로는 로컬 네트워크 상에서 패킷 캡쳐시 LLMNR 형태가 많이 보이는데, 그 많큼 앞서 언급한 운영체제가 증가하고 있는 것으로도 간접적 추측이 가능하다.

LLMNR은 UDP 5355 포트를 사용하며 멀티캐스트 주소이다.

IPv4 - 224.0.0.252 이고 맥 주소는 01-00-5E-00-00-FC
IPv6 - FF02:0:0:0:0:0:1:3 (이 주소는 줄여서 -> FF02::1:3 표현이 가능하다)

아래 그림은 와이어샤크에서 패킷 캡쳐된 것으로 주소를 확인할 수 있다.

LLMNR 의 헤더 포맷은 아래와 같다. DNS 의 헤더 포맷과 크게 다르지는 않다.
QR 은 Query/Response 로 1비트 필드를 사용하며 설정되어 있을 경우 LLMNR 의 응답,설정되어 있지 않을 경우 LLMNR 쿼리이다. OPCODE 는 4비트로 쿼리 타입의 형태를 가리킨다.

                                      1  1  1  1  1  1
        0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      |                      ID                       |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      |QR|   Opcode  | C|TC| T| Z| Z| Z| Z|   RCODE   |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      |                    QDCOUNT                    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      |                    ANCOUNT                    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      |                    NSCOUNT                    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      |                    ARCOUNT                    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

세부적인 사항은 RFC 4795 를 살펴보기 바란다. 아래 이미지는 IPv6 의 LLMNR 세부 정보로 목적지 포트가 5355 임을 알 수 있고, Questions 필드가 1로 Set 되어 있다.

그런데, 이제 LLMNR 은 알겠는데. 왜 이게 사용되어야 하는 것일까?
IPv4 호스트에서는 네트워크 상 주변에 있는 컴퓨터 이름을 Resolving 하기 위해서 NetBIOS 를 이용하여 네임쿼리를 요청하는 메시지를 브로드캐스팅한다. 이때 노드상에 요청한 쿼리에 해당하는 호스트가 있다면 네임쿼리를 응답하게 된다. 이런 형태가 일반적인 네트워크 상에서 많이 보는 형태이다. 그런데, NetBIOS 가 IPv4 환경에서만 동작한다. 그러므로 양 환경에서 모두 이용될 수 있는 LLMNR 프로토콜이 요구되었다. 얻을 수 있는 이점에 대해서는 다음 글을 참고해 보길 바란다.


실 환경에서는 LLMNR 로 인한 네트워크 트래픽 폭주를 경험했다는 사례를 들었다.(초당 2만개) IPv4,IPv6 로 함께 요청되다 보니 Request 되는게 NetBIOS 보다 많은 경우가 있다. 만약 악성코드에 감염되었는데, 이것이 Name Query 가 많은 형태라면 아무래도 영향을 미칠수도 있을 것이다. 어찌되었든 이것은 참고하시고, 만약 LLMNR 을 중지하기 위해서는 다음과 같은 방법을 이용하면 된다.

<윈도우7의 경우>
제어판->네트워크 및 인터넷 -> 네트워크 및 공유센터 -> 고급공유 설정 -> 홈 또는 회사 선택 후
네트워크 검색 끄기를 설정.


[참고]
1. RFC 4795
http://tools.ietf.org/html/rfc4795
2. The Cable Guy - Link-Local Multicast Name Resolution
http://technet.microsoft.com/en-us/library/bb878128.aspx