daily pastebin goal
66%
SHARE
TWEET

DiabloHorn

a guest Dec 1st, 2010 359 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
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top