이건 보안적인 관점에서 봐도 발생되는 같은 이치인데, 대표적인 SQL Injection 을 생각해 보자.
웹 개발을 할때, 개발자가 생각한 것 이외의 값이 들어오지 않을 것이라 가정하고, 개발하면서 보안적인 문제점이 생긴다. 프로그램 관점에서 정해진 폼에 따라 사용자가 데이터를 입력하면 아무런 문제가 없을 것이다. 하지만, 사용자가 인자값을 직접 수정할 수도 있다는 가정이 되어야 한다. 인자값을 임의로 수정해 전송해 버리면, 프로그램에서는 그 값에 대한 체크가 없는 이상 사용자가 정상적으로 입력한 값으로 인지해 버려 SQL Injection 과 같은 취약점이 발생되어 버린다.
패킷파일도 마찬가지이다. 나 또한 보안적 관점에서 패킷 파일 분석을 수행하다 보면,이 패킷파일들이 별에별 형태로 다양하다는 것이다. 악성코드가 생성한 패킷파일이면 더욱 그러하다. 예를 들어, DNS 는 UDP 53 번을 기본으로 사용한다. 그리고 Zone Transfer 와 같은 상황등에서는 TCP 53 번을 사용하기도 한다. 흔히, UDP 53 번을 사용하면 DNS 데이터라고 가정한다. 그런데, DNS 가 아닌 어뚱하게도 어떤 통신을 위해 사용되는 것이라면 어떨까? DNS 쿼리 데이터의 일정 값을 사용하는데 이상하게도 알수없는 페이로드로 채워져 있다면 말이다.
패킷분석을 수행하는 도구 입장에서는 DNS 로 판별했는데, 실제 데이터가 정확하지 않아 Exception 과 같은 오류가 발생할 수 있다. 이런류의 패킷파일 데이터 판단은 힘들어지는데, 실제 이 패킷 데이터를 알아내기 위해서는 직접 악성코드를 리버싱을 해야 정확한 데이터 의미를 파악할 수 있게된다.
비정상적인 DNS 데이터를 가지고 있는 패킷파일을 Scapy 를 통해서 확인해 보면 아래와 같다.
>>> a=rdpcap("test_dns.pcap")
WARNING: wrong value: DNS.ancount=38440
WARNING: wrong value: DNS.nscount=27668
WARNING: more wrong value: DNS.arcount=45458
WARNING: DNS RR prematured end (ofs=73, len=44)
WARNING: DNS RR prematured end (ofs=77, len=44)
WARNING: more DNS RR prematured end (ofs=81, len=44)
자 일단 읽어 들이는 과정에서도 경고 메시지가 나타난다. DNS 의 ancount 나 nscount 값이 지나치게 크게 나온다는 것이다.
>>> a
<test_dns.pcap: TCP:6 UDP:1115 ICMP:0 Other:28>
다음은 패킷파일 중 정상적인 DNS 패킷 데이터를 본 것이다.
>>> a[1145]
<Ether dst=[삭제] src=[삭제] type=0x800 |<IP version=4L ihl=5L tos=0x0 len=68 id=956 flags= frag=0L ttl=128 proto=udp chksum=0x52c9 src=[삭제] dst=[삭제] options=[] |<UDP sport=1039 dport=domain len=48 chksum=0xfdec |<DNS id=52467 qr=0L opcode=QUERY aa=0L tc=0L rd=1L ra=0L z=0L rcode=ok qdcount=1 ancount=0 nscount=0 arcount=0 qd=<DNSQR qname='1.1.1.1.in-addr.arpa.' qtype=PTR qclass=IN |> an=None ns=None ar=None |>>>>
정상적인 형태는 각 필드정보가 정확히 확인이 된다. 그런데, 아래의 경우를 보면 다르다.
몇몇 필드의 데이터 값이 이상하고, Raw 페이로드 값이 존재한다.
>>> a[176]
<Ether dst=[삭제] src=[삭제] type=0x800 |<IP version=4L ihl=5L tos=0x0 len=84 id=16541 flags= frag=0L ttl=24 proto=udp chksum=0xfe73 src=[삭제] dst=[삭제] options=[] |<UDP sport=domain dport=7783 len=64 chksum=0xf167 |<DNS id=56 qr=0L opcode=QUERY aa=0L tc=1L rd=1L ra=0L z=1L rcode=server-failure qdcount=0 ancount=38440 nscount=27668 arcount=45458 qd=None an='' ns='' ar='' |<Raw load='$\xabn\x00z\xb6\x0bl\x98Q\xff\x87\xf9\xe2\xd0\xaeu\xa2[삭제]0305rh\x02\xbe\x18\xc0\x00\x00' |>>>>>
>>>
HEX 값을 확인해 보면 아래와 같다.
>>> hexdump(a[176][Raw])
0000 24 AB 6E 00 7A B6 0B 6C 98 51 FF 87 F9 E2 D0 AE $.n.z..l.Q......
0010 75 A2 [삭제] 3 37 37 42 u..[삭제]C77B
0020 30 33 30 35 72 68 02 BE 18 C0 00 00 0305rh......
ancount, nscount 가 이렇게 큰 데이터를 가질 수 있는가? 즉, 큰 데이터 값만 보고도 조작된 패킷 가능성이 크다고 볼 수 있다. 그러므로 Scapy 에서도 로드할때 경고 메시지가 나타난다. UDP/53 번에 패킷을 전송하니 이것을 DNS 패킷으로 인식하고 그 값 데이터를 필드 값으로 사용하면서 엉뚱하게 이상한 값으로 설정된 것이다.
이와 같은 경우에는 다양한 Exception 처리를 해 주어야 하는데, 어떤 형태가 들어오기 예측하기 쉽지 않다보니 특수한 환경의 패킷 분석에서는 상당한 어려움이 발생할 수 있다. 이러한 이유로 어떤 자동화된 형태로 패킷을 분석 처리하기에는 많은 경험도 필요하고, 각각의 상황에 따라 처리도 해주어야 하다 보니 안정화 되기까지는 시간도 필요하다. 물론, 안정화 후에도 계속 이런 가능성은 존재하게 된다. 사용하려는 목적은 다르겠지만, 완벽하게 패킷 데이터를 분석하여 사용한다는 관점보다는 좀더 쉽게 패킷 분석가를 도와준다는 관점에서 생각하고 사용하면 이런 작업을 진행하는 분들에게는 좀더 마음이 편해지지 않을까?
/Rigel