IPTables - 16진수 문자열 블록 DNS 쿼리

IPTables - 16진수 문자열 블록 DNS 쿼리

내 DNS 서버의 특정 도메인에 많은 쿼리를 보내는 클라이언트가 있습니다. 해당 쿼리를 차단하고 싶은데 이를 수행하는 16진수 문자열을 찾았습니다. 그것은 문자열입니다:

iptables -I INPUT 1 -p udp --dport 53 --match string --algo kmp --hex-string '|77 70 61 64 2e 64 6f 6d 61 69 6e 2e 6e 61 6d 65|' -j DROP

-

0     0 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:53 STRING match  "wpad.domain.name" ALGO name kmp TO 65535

하지만 해당 이름에 대해 서버를 쿼리하면 응답을 볼 수 있고 카운터가 0으로 유지되기 때문에 작동하지 않는 것 같습니다.

root@banana:~# dig @5.172.120.59 wpad.domain.name

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> @5.172.120.59 wpad.domain.name
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 29891
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;wpad.domain.name.              IN      A

;; Query time: 136 msec
;; SERVER: 5.172.120.59#53(5.172.120.59)
;; WHEN: Thu Nov 26 22:55:30 2015
;; MSG SIZE  rcvd: 34

몇 가지 오류를 발견할 수 있나요?

감사해요

답변1

이러지 마세요

...적어도 이 특정 DNS 요청에는 해당되지 않습니다. 왜 안 돼? 글쎄요, 우선, 여러분 자신과 CPU를 실제로 더 쉽게 만드는 것은 아니며 클라이언트에게는 상황을 더욱 악화시키고 있습니다. 모든 플랫폼의 거의 모든 브라우저는 DHCP 주소를 얻을 때 "자동 프록시 감지"를 사용합니다. 이 자동 감지는 호스트 이름에 대한 DNS 항목을 찾는 방식으로 작동합니다 wpad.subdomain.subdomain.currentdomain.xx. wpad.currentdomain.xx둘째, 브라우저는 OS에 DNS를 가져오도록 요청하고 OS(다양한 TCP/UDP 매개변수에 따라)는계속 노력해응답을 받을 때까지 DNS 서버에 요청이 이루어집니다. 입력을 차단하면 DNS 서버가 전혀 답변을 제공할 수 없으므로 클라이언트는다시 시도하십시오계속해서. 이를 차단함으로써 클라이언트가 요청 전송을 중지하도록 "훈련"하는 것이 아닙니다. 응답을 얻지 못하면 프록시 사용 시도를 중지하고 직접 연결을 사용합니다.동시에사용자는 단지기다리다브라우저가 직접 연결을 시도할 수 있습니다. 브라우저가 응답하기 전에 15초 동안 기다릴 수도 있습니다. 이 메커니즘은 이제 모든 Android 및 iOS 장치에 내장되어 있으므로 모든 iPad, AppleTV, Samsung 스마트폰이 인터넷에 연결하는 데 오랜 시간이 걸립니다. 그래서 기본적으로 당신은 거시기를 가져옵니다.

수행 방법(최선, 정확함)

하지만 QNAME을 기반으로 DNS 쿼리를 차단하고 싶다고 가정해 보겠습니다. QNAME에는 "태그" 세트가 포함되어 있습니다. 하지만우리를점 표기법의 태그를 참조하세요. 쿼리 패킷에서 각 태그의 앞에는 해당 길이(바이트)가 붙고 모든 태그는 NUL로 종료됩니다. 1

1 OP에서는 이 부분을 알아냈지만 16진수 문자열과 관련이 있는 것처럼 들립니다.

1.4.9iptables의 소스코드를 보고 확인한 바와 같이, 그 동작을 적절하게 설명하는 매뉴얼을 찾을 수 없기 때문에 hex 문자열은 (quasi-BNF) 형식으로 되어 있습니다.

HEXSTRING := SUBSTRING [ SUBSTRING ... ]

각각은 다음 SUBSTRING중 하나입니다.

'\' CHAR
'|' HEXDIGIT HEXDIGIT [ SPACE ] '|'
CHAR

여기서 CHAR는 입력이 처리할 수 있는 거의 모든 것이며 HEXDIGIT는 isxdigit()가 말하는 것으로 sscanf(s,"%x",buf)"16진수 패턴"을 우회하고 리터럴 문자열 "|"과 일치시킬 수 있도록 .escape 문자와 결합됩니다. 그렇지 않으면 특별한 일이 없습니다. 현재 SUBSTRING이 16진수 문자열의 마지막인 경우 후행은 |반드시 필요하지 않습니다.

다음으로 검색을 최적화합니다. 쿼리 부분은 DNS 요청의 13번째 바이트보다 빠르지 않게 시작됩니다. 즉, 바이트 40( 20(IP) + 8(UDP) + 13 - 1 )부터 시작됩니다. 패킷이 쿼리인지 테스트할 수 있다면(그리고 그렇게 해야 함) 검색 제한에 대해 걱정할 필요가 없습니다. 패킷 끝까지 검색하면 됩니다. 쿼리인지 테스트하려면 패킷에서 바이트 31의 상위 5비트를 테스트합니다. 또한 IP 헤더의 미묘한 차이를 고려할 수도 있습니다. 드문 경우지만 20이 아닌 24+바이트이므로 테스트할 바이트가 35(또는 39)가 됩니다.

bm(Boyer-Moore) 알고리즘을 사용하여 추가 최적화가 수행됩니다. 아무런 문제가 없지만 kmp전반적으로 Boyer-Moore는 더 빠르고 더 적은 리소스를 사용합니다.

그것들을 결합하면 다음과 같은 결과가 나올 것입니다:

-A INPUT -s 5.172.121.170/32 -p udp -m udp --dport 53 \
-m u32 --u32 "28 & 0xF8 = 0" \
-m string --algo bm --from 40 \
--hex-string "|04|wpad|08|mydomain|03|isa|04|dick" 

--u32부분은 "패킷의 28번째(0 인덱스) 바이트부터 시작하여 4바이트를 가져옵니다... 즉, 바이트 28, 29, 30, 31을 잡고 32비트 값을 0x000000F8로 마스크합니다... 이것은 단지 보기 위한 것입니다. 상위 5개 바이트 31의 비트... 0이면 일치합니다." 앞에서 언급한 대로 이 --from섹션에서는 패킷의 "문제" 부분에서 문자열 검색을 시작합니다. 이렇게 하면 거짓 긍정을 방지할 수 있습니다.

RHEL 6.5 iptables 1.4.7에서 테스트되었습니다.

현명하게 말하면 IP 헤더 필드 바이트 0의 헤더 길이를 테스트하고 바이트 32에서 시작하는 DNS 쿼리와 일치하는 또 다른 규칙을 만드십시오.

답변2

나는 그것을 스스로 발견했다. 16진수 문자열이 잘못되었습니다. 좋아요.

또한 더 간단한 형식에서 --hex-string "|04|wpad|06|domanin|04|name|"숫자 값은 단어의 길이를 나타냅니다.

-A INPUT -s 5.172.121.170/32 -p udp -m udp --dport 53 -m string \
--hex-string "|047770616406646f6d61696e046e616d65|" --algo kmp \
--to 65535 -m comment --comment "wpad.domain.name" -j DROP

관련 정보