daily pastebin goal
50%
SHARE
TWEET

DiabloHorn

a guest Dec 5th, 2010 385 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- postdissector to make dnscat traffic more human readable
  2. -- DiabloHorn http://diablohorn.wordpress.com
  3. -- Thanks to #wireshark on freenode for the quick and excellent response,
  4. -- which resulted into the patch for the dns dissector that made access to dns.resp.primaryname possible
  5. -- http://www.skullsecurity.org/wiki/index.php/Dnscat#Structure
  6.  
  7. -- required libs
  8. local bit = require("bit")
  9.  
  10. -- info
  11. print("dnscat postdissector loaded")
  12.  
  13. -- we need these fields from the dns packets
  14. dc_dns_name = Field.new("dns.qry.name")
  15. --this will only work if you have the developer version which includes a patch
  16. dc_dns_rname = Field.new("dns.resp.primaryname")
  17. dc_udp_dport = Field.new("udp.dstport")
  18. dc_udp_sport = Field.new("udp.srcport")
  19.  
  20. -- declare our postdissector
  21. dc_pd = Proto("dnscat","dnscat postdissector")
  22.  
  23. -- our fields
  24. dc_tunneldata = ProtoField.string("dc_pd.tunneldata","Encoded Tunnel Data")
  25. dc_td_sig = ProtoField.string("dc_pd.td_sig","Signature")
  26. dc_td_flags = ProtoField.string("dc_pd.td_flags","Flags")
  27. dc_td_ident = ProtoField.string("dc_pd.td_ident","Identifier")
  28. dc_td_sess = ProtoField.string("dc_pd.td_session","Session")
  29. dc_td_seqnum = ProtoField.string("dc_pd.td_seqnum","SeqNum")
  30. dc_td_count = ProtoField.string("dc_pd.td_count","Count")
  31. dc_td_err = ProtoField.string("dc_pd.td_error","Error")
  32. dc_td_data = ProtoField.string("dc_pd.td_data","Data")
  33. dc_td_gar = ProtoField.string("dc_pd.td_garbage","Garbage")
  34. dc_td_dom = ProtoField.string("dc_pd.td_domain","Domain")
  35. -- add our fields
  36. dc_pd.fields = {dc_tunneldata,dc_td_sig,dc_td_flags,dc_td_ident,dc_td_sess,dc_td_seqnum,dc_td_count,dc_td_err,dc_td_data,dc_td_gar,dc_td_dom}
  37.  
  38. -- dissect each packet
  39. function dc_pd.dissector(buffer,pinfo,tree)
  40.     local udpsport = dc_udp_sport()
  41.     local udpdport = dc_udp_dport()
  42.     local dnsqryname = dc_dns_name()
  43.     --this will only work if you have the developer version which includes a patch
  44.     local dnsresname = dc_dns_rname()
  45.     local subtree
  46.     local parsed = {}
  47.    
  48.     subtree = tree:add(dc_pd,"dnscat data")
  49.     if tostring(udpdport) == "53" then
  50.         subtree:add(dc_tunneldata,tostring(dnsqryname))
  51.         parsed = parseDC(tostring(dnsqryname))
  52.     end
  53.    
  54.     --this will only work if you have the developer version which includes a patch
  55.     if tostring(udpsport) == "53" then
  56.         subtree:add(dc_tunneldata,tostring(dnsresname))
  57.         parsed = parseDC(tostring(dnsresname))
  58.     end
  59.        
  60.     subtree:add(dc_td_sig,tostring(parsed.signature))
  61.     subtree:add(dc_td_flags,tostring(parsed.flags))
  62.     subtree:add(dc_td_ident,tostring(parsed.identifier))
  63.     subtree:add(dc_td_sess,tostring(parsed.session))
  64.     subtree:add(dc_td_seqnum,tostring(parsed.seqnum))
  65.     subtree:add(dc_td_count,tostring(parsed.count))
  66.     subtree:add(dc_td_err,tostring(parsed.err))
  67.     subtree:add(dc_td_data,tostring(parsed.asciidata))
  68.     subtree:add(dc_td_gar,tostring(parsed.garbage))
  69.     subtree:add(dc_td_dom,tostring(parsed.domain))        
  70. end -- end dissector function
  71.  
  72. -- main dissecting logic
  73.  
  74. -- split the request into an array of subdomain
  75. function getsubs(data)
  76.     -- empty table to hold the subs
  77.     local subs = {}
  78.     for sub in data:gmatch("[^%.]+") do
  79.         table.insert(subs,sub)
  80.     end
  81.     return subs
  82. end
  83.  
  84. -- decode the flags to human readable strings
  85. function decodeflags(data)
  86.     -- protocol flags
  87.     local FLAG_STREAM = 0x00000001
  88. -- deprecated
  89.     local FLAG_SYN = 0x00000002
  90.     local FLAG_ACK = 0x00000004
  91. -- end of deprecated
  92.     local FLAG_RST = 0x00000008
  93.     local FLAG_HEX = 0x00000010
  94.     local FLAG_SESSION = 0x00000020
  95.     local FLAG_IDENTIFIER = 0x00000040
  96.  
  97.     -- convert string to number
  98.     local hFlags = tonumber(data,16)
  99.     --setup the flags table
  100.     local Flags = {} -- st=nil,sy=nil,ac=nil,rs=nil,he=nil,se=nil,id=nil
  101.     -- let's see which are set
  102.     if bit.band(hFlags,FLAG_STREAM) ~= 0 then
  103.         table.insert(Flags,"stream")
  104.     end
  105. -- deprecated
  106.     if bit.band(hFlags,FLAG_SYN) ~= 0 then
  107.         table.insert(Flags,"syn")
  108.     end        
  109.     if bit.band(hFlags,FLAG_ACK) ~= 0 then
  110.         table.insert(Flags,"ack")
  111.     end        
  112. -- end of deprecated
  113.     if bit.band(hFlags,FLAG_RST) ~= 0 then
  114.         table.insert(Flags,"rst")
  115.     end        
  116.     if bit.band(hFlags,FLAG_HEX) ~= 0 then
  117.         table.insert(Flags,"hex")
  118.     end        
  119.     if bit.band(hFlags,FLAG_SESSION) ~= 0 then
  120.         table.insert(Flags,"session")
  121.     end        
  122.     if bit.band(hFlags,FLAG_IDENTIFIER) ~= 0 then
  123.         table.insert(Flags,"identifier")                                
  124.     end
  125.     return Flags
  126. end
  127.  
  128. -- decode the error code to something human readable
  129. -- overcomplicated...but hey I wanted to use the bitopt lib again
  130. function decoderr(data)
  131.     local ERR_SUCCESS = 0x00000000
  132.     local ERR_BUSY = 0x00000001
  133.     local ERR_INVSTATE = 0x00000002
  134.     local ERR_FIN = 0x00000003
  135.     local ERR_BADSEQ = 0x00000004
  136.     local ERR_NOTIMPLEMENTED = 0x00000005
  137.     local ERR_TEST = 0xFFFFFFFF
  138.     local err = {}
  139.     local herr = tonumber(data,16)
  140.  
  141.     if bit.tobit(ERR_SUCCESS) == bit.tobit(herr) then
  142.         table.insert(err,"success")
  143.     end
  144.    
  145.     if bit.tobit(ERR_BUSY) == bit.tobit(herr) then
  146.         table.insert(err,"busy")
  147.     end
  148.    
  149.     if bit.tobit(ERR_INVSTATE) == bit.tobit(herr) then
  150.         table.insert(err,"invalidstate")
  151.     end
  152.    
  153.     if bit.tobit(ERR_FIN) == bit.tobit(herr) then
  154.         table.insert(err,"confin")
  155.     end
  156.    
  157.     if bit.tobit(ERR_BADSEQ) == bit.tobit(herr) then
  158.         table.insert(err,"badseqnum")
  159.     end
  160.    
  161.     if bit.tobit(ERR_NOTIMPLEMENTED) == bit.tobit(herr) then
  162.         table.insert(err,"notimplemented")
  163.     end
  164.    
  165.     if bit.tobit(ERR_TEST) == bit.tobit(herr) then
  166.         table.insert(err,"contest")
  167.     end  
  168.     return err                    
  169. end
  170.  
  171. -- decode netbios data to ascii
  172. function decodenetbios(data)
  173.     local ldata = data:upper()
  174.     local dec = ""
  175.     for sub in ldata:gmatch("%u%u") do
  176.         -- perform operation in decimal and convert final value from hex XX to decimal  
  177.         --local decnum = tonumber(((sub:byte(1)-65) .. (sub:byte(2)-65)),16)
  178.         -- Thanks to Animal for making me realize the concat has to be with hexnumbers
  179.         local decnum = tonumber((bit.tohex(sub:byte(1)-65,1) .. bit.tohex(sub:byte(2)-65,1)),16)  
  180.         --print(decnum,sub)
  181.         if decnum > 31 and decnum < 127 then
  182.             dec = dec .. string.char(decnum)
  183.         else
  184.             dec = dec .. "."
  185.         end
  186.         decnum = 0
  187.         sub = ""
  188.     end
  189.     return dec
  190. end
  191.  
  192. -- decode hex data to ascii
  193. function decodehex(data)
  194.     local dec = ""
  195.     for sub in data:gmatch("%x%x") do
  196.         local decnum = tonumber(sub,16)
  197.         if decnum > 31 and decnum < 127 then
  198.             dec = dec .. string.char(decnum)
  199.         else
  200.             dec = dec .. "."
  201.         end
  202.     end
  203.     return dec
  204. end
  205.  
  206. -- main flow implementation
  207. -- lacks implementation of syn/ack since it's deprecated
  208. function parseDC(data)
  209.     local finalparsed = {}
  210.     local x = getsubs(data)
  211.  
  212.     finalparsed["signature"] = x[1]
  213.     table.remove(x,1)
  214.     finalparsed["flags"] = table.concat(decodeflags(x[1]),",")
  215.     table.remove(x,1)
  216.  
  217.     if finalparsed["flags"]:find("identifier") ~= nil then
  218.         finalparsed["identifier"] = x[1]
  219.         table.remove(x,1)
  220.         if finalparsed["flags"]:find("session") ~= nil then
  221.             finalparsed["session"] = x[1]
  222.             table.remove(x,1)
  223.         end
  224.     elseif finalparsed["flags"]:find("session") ~= nil then
  225.         finalparsed["session"] = x[1]
  226.         table.remove(x,1)
  227.     end
  228.  
  229.     if finalparsed["flags"]:find("stream") ~= nil then
  230.         finalparsed["seqnum"] = x[1]
  231.         table.remove(x,1)
  232.     end
  233.    
  234.     if finalparsed["flags"]:find("rst") ~= nil then
  235.         finalparsed["err"] = table.concat(decoderr(x[1]),",")
  236.         table.remove(x,1)
  237.         finalparsed["garbage"] = x[1]
  238.         finalparsed["domain"] = x[2]
  239.     else
  240.         finalparsed["count"] = x[1]
  241.         table.remove(x,1)
  242.         -- if you wonder the character # == len()
  243.         finalparsed["garbage"] = x[#x-1]
  244.         finalparsed["domain"] = x[#x]
  245.         table.remove(x,(#x))
  246.         table.remove(x,(#x))
  247.         -- so we either got data or we don't
  248.         finalparsed["asciidata"] = ""
  249.         while #x > 0 do
  250.             if finalparsed["flags"]:find("hex") == nil then
  251.                 finalparsed["asciidata"] = finalparsed["asciidata"] .. decodenetbios(x[1])
  252.             else
  253.                 finalparsed["asciidata"] = finalparsed["asciidata"] .. decodehex(x[1])
  254.             end
  255.             table.remove(x,1)
  256.         end
  257.     end -- end of rst check
  258.    
  259.     return finalparsed
  260. end -- end of parseDC function
  261.  
  262. -- end of main dissecting logic
  263.  
  264. -- register ourselfs
  265. register_postdissector(dc_pd)
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