天天看點

Ryu控制器代碼解析-DNS欺騙

  軟體定義網絡利用控制器對網絡的控制,實作一些傳統網絡中難以實作的功能,控制器在這個網絡中扮演一個上帝的角色,上一篇文章裡已經介紹了控制器可以實作代理應答,本次要介紹的是利用控制器和python來對資料包内容進行解析,實作DNS欺騙。

原了解析

  主機在進行域名解析的時候,先向DNS伺服器發送DNS Request封包,而後DNS伺服器回複一個Reply封包,主機接收此封包即可完成解析。既然控制器可以造出ICMP應答封包,也能造出DNS回複封包。

思路說明

  • 先給交換機下發流表項,讓交換機把DNS封包傳給控制器處理。
  • 控制器對封包進行解析,提取出域名,編号等關鍵資訊。
  • 構造一個新的DNS Reply封包,通過交換機傳回給主機。

關鍵要素

  要完成這樣一個過程并不簡單,雖然我們平常用抓包軟體比如Wireshark之類的看到的資料包内容非常清楚,條理分明,但是如果一個資料包到了我們手上,我們要把它研究透徹還是很複雜的,下面列出一些關鍵性的步驟:

  • 資料包編碼
  • 提取DNS域名
  • 擷取資料包編号

代碼分析

  控制器擷取到的DNS資料包資料如果不加任何修改,直接輸出就是亂碼,整個的資料包裡隻有域名是明文,我們可以先把域名提取出來,但是Ryu并沒有處理DNS封包的庫,這裡可以采用截取字元串的方法,這就出現了一個問題:域名長度不固定,沒關系,因為域名出現的位置是固定的,我們擷取了整個資料包的長度,到那個固定的位置找就可以了。

pkt_len = len(data)
domain = (data[55:pkt_len-5])
           

我是怎麼知道域名長度固定的呢?

用wireshark抓包,資料包的具體字段,長度wireshark都能顯示。

  這樣我們算是提取出了域名,不過有關域名的事還沒完,後面會講到。

  主機在送出請求的時候請求封包會有一個ID号,回複封包也必須攜帶一樣的ID才能被主機認可,這個ID在封包中位置也固定,隻是他被編碼了,是以我們看不出來它是什麼,可以從wireshark裡看一看是4個十六進制數,它的位置是

flag = data[42:44]

,是以我們首先需要對其進行解碼,但解碼我們需要知道編碼方式,是以問題就是如何擷取編碼方式,這裡推薦使用Python的chardet子產品,這是個用來檢測檔案或者字元編碼的子產品,讀者可用

pip install chardet

來安裝,然後開始解碼:

b=chardet.detect(data[:])
        #print(b)
        if b['encoding'] == None:
            c=flag.encode("hex")
        else:
            flag.decode(b['encoding'])
            c=flag.encode("hex")
           

  這裡檢測的時候不一定每次ID都是有編碼的,偶爾有一次會出現沒有編碼的情況,這時就不需要解碼了,得到的變量c就是wireshark裡面的十六進制ID。

  好了,域名有了,ID有了,可以開始構造資料包了,這裡推薦使用Scapy,它是一個功能強大的資料包處理程式。鑒于官網教程有限,我們可以用它發送一個DNS請求封包,看一下它的解析的應答包,照着構造一個。

a = Ether(dst=pkt_ethernet.src,src=self.hw_addr)/IP(dst=ip_dst,src=ip_src)/UDP(sport=sport,dport=dport)/DNS(opcode=,id=d,qr=,rd=,ra=,aa=,tc=,z=,ad=,cd=,rcode=,qdcount=,ancount=,nscount=,arcount=,qd=DNSQR(qname=domain),
an=DNSRR(rrname=domain,ttl=,rdata=ip_src),ns=DNSRR(rrname=domain,type=,ttl=,rdata="ns1."+domain),ar=None)
           

  這裡面的ID值是一個十進制數,是以我們要轉化一下。這裡面我把DNS伺服器位址作為解析的目标位址,關于裡面每個字段的含義讀者有興趣可以自行查閱相關資料。

  構造完畢之後用Packet-Out封包發給交換機即可。

  如果僅僅按照上面的步驟,我們就會發現,解析的域名如果沒有小數點,那可以得到正确的回複,一旦我們加上小數點,運氣好的話主機會提示你傳回的域名不符。這就涉及到在封包中域名的格式了,小數點的位置上是一個數,表示後面有幾位。例如下面的域名

blog.csdn.net

在封包中格式是:

4 b l o g 4 c s d n 3 n e t 0

最後一位是結束符。是以我們提取出來的其實是

b l o g 4 c s d n 3 n e t

而中間的數字是不可見字元,是以我們還要對提取出來的域名進行一些轉化,通過ASCII碼來判斷是否是不可見字元。

for g in range(,len(domain)-):
            if ord(domain[g])< or ord(domain[g])>:
                domain=domain[:g]+"."+domain[g+:]
           

這樣域名就是正确的了。

看一下結果,域名解析已經成功。

Ryu控制器代碼解析-DNS欺騙

完整代碼已經放到github上,讀者可自行檢視。