Guest User

DiabloHorn

a guest
Dec 1st, 2010
577
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env lua
  2. --[[
  3.     Author: DiabloHorn http://diablohorn.wordpress.com
  4.     DnsCat traffic decoder, can be easily converted to a wireshark dissector :)
  5.     This could be written a lot more efficient, but hey it's one of my first serious LUA scripts.
  6. ]]--
  7. -- testdata
  8. local testdata = {"dnscat.21.fgnlglmh.7718fc12.0.dgqt.directdns","dnscat.31.hihuznqd.2cedf05e.1.636174202f6574632f69737375650a.tvtm.directdns", "dnscat.29.gnwbuhls.699c9c36.3.sryi.directdns", "dnscat.21.gnwbuhls.699c9c2f.1.ffgchfgohehfcadbdacodadecodbcaemfefdcafmgocafmgmakak.rypw.directdns"}
  9.  
  10. -- requires the bitopt library to be installed
  11. local bit = require("bit")
  12.  
  13. -- start base parser
  14.  
  15. -- split the request into an array of subdomain
  16. function getsubs(data)
  17.     -- empty table to hold the subs
  18.     local subs = {}
  19.     for sub in data:gmatch("[^%.]+") do
  20.         table.insert(subs,sub)
  21.     end
  22.     return subs
  23. end
  24.  
  25. -- decode the flags to human readable strings
  26. function decodeflags(data)
  27.     -- protocol flags
  28.     local FLAG_STREAM = 0x00000001
  29. -- deprecated
  30.     local FLAG_SYN = 0x00000002
  31.     local FLAG_ACK = 0x00000004
  32. -- end of deprecated
  33.     local FLAG_RST = 0x00000008
  34.     local FLAG_HEX = 0x00000010
  35.     local FLAG_SESSION = 0x00000020
  36.     local FLAG_IDENTIFIER = 0x00000040
  37.  
  38.     -- convert string to number
  39.     local hFlags = tonumber(data,16)
  40.     --setup the flags table
  41.     local Flags = {} -- st=nil,sy=nil,ac=nil,rs=nil,he=nil,se=nil,id=nil
  42.     -- let's see which are set
  43.     if bit.band(hFlags,FLAG_STREAM) ~= 0 then
  44.         table.insert(Flags,"stream")
  45.     end
  46. -- deprecated
  47.     if bit.band(hFlags,FLAG_SYN) ~= 0 then
  48.         table.insert(Flags,"syn")
  49.     end        
  50.     if bit.band(hFlags,FLAG_ACK) ~= 0 then
  51.         table.insert(Flags,"ack")
  52.     end        
  53. -- end of deprecated
  54.     if bit.band(hFlags,FLAG_RST) ~= 0 then
  55.         table.insert(Flags,"rst")
  56.     end        
  57.     if bit.band(hFlags,FLAG_HEX) ~= 0 then
  58.         table.insert(Flags,"hex")
  59.     end        
  60.     if bit.band(hFlags,FLAG_SESSION) ~= 0 then
  61.         table.insert(Flags,"session")
  62.     end        
  63.     if bit.band(hFlags,FLAG_IDENTIFIER) ~= 0 then
  64.         table.insert(Flags,"identifier")                                
  65.     end
  66.     return Flags
  67. end
  68.  
  69. -- decode the error code to something human readable
  70. -- overcomplicated...but hey I wanted to use the bitopt lib again
  71. function decoderr(data)
  72.     local ERR_SUCCESS = 0x00000000
  73.     local ERR_BUSY = 0x00000001
  74.     local ERR_INVSTATE = 0x00000002
  75.     local ERR_FIN = 0x00000003
  76.     local ERR_BADSEQ = 0x00000004
  77.     local ERR_NOTIMPLEMENTED = 0x00000005
  78.     local ERR_TEST = 0xFFFFFFFF
  79.     local err = {}
  80.     local herr = tonumber(data,16)
  81.  
  82.     if bit.tobit(ERR_SUCCESS) == bit.tobit(herr) then
  83.         table.insert(err,"success")
  84.     end
  85.    
  86.     if bit.tobit(ERR_BUSY) == bit.tobit(herr) then
  87.         table.insert(err,"busy")
  88.     end
  89.    
  90.     if bit.tobit(ERR_INVSTATE) == bit.tobit(herr) then
  91.         table.insert(err,"invalidstate")
  92.     end
  93.    
  94.     if bit.tobit(ERR_FIN) == bit.tobit(herr) then
  95.         table.insert(err,"confin")
  96.     end
  97.    
  98.     if bit.tobit(ERR_BADSEQ) == bit.tobit(herr) then
  99.         table.insert(err,"badseqnum")
  100.     end
  101.    
  102.     if bit.tobit(ERR_NOTIMPLEMENTED) == bit.tobit(herr) then
  103.         table.insert(err,"notimplemented")
  104.     end
  105.    
  106.     if bit.tobit(ERR_TEST) == bit.tobit(herr) then
  107.         table.insert(err,"contest")
  108.     end  
  109.     return err                    
  110. end
  111.  
  112. -- decode netbios data to ascii
  113. function decodenetbios(data)
  114.     local ldata = data:upper()
  115.     local dec = ""
  116.     for sub in ldata:gmatch("%u%u") do
  117.         -- perform operation in decimal and convert final value from hex XX to decimal  
  118.         --local decnum = tonumber(((sub:byte(1)-65) .. (sub:byte(2)-65)),16)
  119.         -- Thanks to Animal for making me realize the concat has to be with hexnumbers
  120.         local decnum = tonumber((bit.tohex(sub:byte(1)-65,1) .. bit.tohex(sub:byte(2)-65,1)),16)      
  121.         print(bit.tohex(sub:byte(1)-65,1))
  122.         print(decnum,sub)
  123.         if decnum > 31 and decnum < 127 then
  124.             dec = dec .. string.char(decnum)
  125.         else
  126.             dec = dec .. "."
  127.         end
  128.         decnum = 0
  129.         sub = ""
  130.     end
  131.     return dec
  132. end
  133.  
  134. -- decode hex data to ascii
  135. function decodehex(data)
  136.     local dec = ""
  137.     for sub in data:gmatch("%x%x") do
  138.         decnum = tonumber(sub,16)
  139.         if decnum > 31 and decnum < 127 then
  140.             dec = dec .. string.char(decnum)
  141.         else
  142.             dec = dec .. "."
  143.         end
  144.     end
  145.     return dec
  146. end
  147.  
  148. -- main flow implementation
  149. -- lacks implementation of syn/ack since it's deprecated
  150. function parseDC(data)
  151.     local finalparsed = {}
  152.     local x = getsubs(data)
  153.  
  154.     finalparsed["signature"] = x[1]
  155.     table.remove(x,1)
  156.     finalparsed["flags"] = table.concat(decodeflags(x[1]),",")
  157.     table.remove(x,1)
  158.  
  159.     if finalparsed["flags"]:find("identifier") ~= nil then
  160.         finalparsed["identifier"] = x[1]
  161.         table.remove(x,1)
  162.         if finalparsed["flags"]:find("session") ~= nil then
  163.             finalparsed["session"] = x[1]
  164.             table.remove(x,1)
  165.         end
  166.     elseif finalparsed["flags"]:find("session") ~= nil then
  167.         finalparsed["session"] = x[1]
  168.         table.remove(x,1)
  169.     end
  170.  
  171.     if finalparsed["flags"]:find("stream") ~= nil then
  172.         finalparsed["seqnum"] = x[1]
  173.         table.remove(x,1)
  174.     end
  175.    
  176.     if finalparsed["flags"]:find("rst") ~= nil then
  177.         finalparsed["err"] = table.concat(decoderr(x[1]),",")
  178.         table.remove(x,1)
  179.         finalparsed["garbage"] = x[1]
  180.         finalparsed["domain"] = x[2]
  181.     else
  182.         finalparsed["count"] = x[1]
  183.         table.remove(x,1)
  184.         -- if you wonder the character # == len()
  185.         finalparsed["garbage"] = x[#x-1]
  186.         finalparsed["domain"] = x[#x]
  187.         table.remove(x,(#x))
  188.         table.remove(x,(#x))
  189.         -- so we either got data or we don't
  190.         finalparsed["asciidata"] = ""
  191.         while #x > 0 do
  192.             if finalparsed["flags"]:find("hex") == nil then
  193.                 finalparsed["asciidata"] = finalparsed["asciidata"] .. decodenetbios(x[1])
  194.             else
  195.                 finalparsed["asciidata"] = finalparsed["asciidata"] .. decodehex(x[1])
  196.             end
  197.             table.remove(x,1)
  198.         end
  199.     end -- end of rst check
  200.    
  201.     return finalparsed
  202. end -- end of parseDC function
  203.  
  204. -- end of base parser
  205.  
  206. for i,v in ipairs(testdata) do
  207.     local fp = parseDC(v)
  208.     print("TestData: " .. v)
  209.     print("Signature: " .. tostring(fp.signature))
  210.     print("Flags: " .. tostring(fp.flags))
  211.     print("Identifier: " .. tostring(fp.identifier))
  212.     print("Session: " .. tostring(fp.session))
  213.     print("Seqnum: " .. tostring(fp.seqnum))
  214.     print("Count: " .. tostring(fp.count))
  215.     print("Error: " .. tostring(fp.err))
  216.     print("Data: " .. tostring(fp.asciidata))
  217.     print("Garbage: " .. tostring(fp.garbage))
  218.     print("Domain: " .. tostring(fp.domain))
  219. end
RAW Paste Data