I like Wireshark, I really do but it has one glaring flaw, you cannot let it run writing a trace file and then automatically stop the trace when a key packet is seen in the trace or when the packet is not seen. For example, I want to stop the trace when a FIN or RST packet is seen from a particular host on a particular port. Or when a particular host stops sending out ICMP echo reply packets.
The following kill_dumpcapVBS script lets me do this. Basically, in one command window I start dumpcap, using the "-w" and "-b" arguments to create a ring of files of a particular size. In another command window I run the kill_dumpcap.vbs script. Basically, every N seconds it monitors the current directory looking for a new dumpcap output file. If it finds one (or several) it scans the files with ngrep. If ngrep finds the key packet (or doesn't if it is a negative search) it terminates the dumpcap process based on its PID which you can find with the list_dumpcap VBS script. Two searches are needed. The ngrep search is done first and all the output is redirected into a file. The problem is that even if ngrep does not find anything the file will not be empty and depending on the number of new dumpcap output files the ngrep output file can be rather large. If ngrep is looking for a string in the packet that string will also be listed so you need another, different, search to confirm that the packet is actually found (see the examples). Why require the PID instead of just the process name. I thought that at some point I might want to run two dumpcap processes, each tracing a different interface.
The relationship between the sleep time between polls looking for new files and the number of files and size of the files is more art than science, you will probably need to experiment to find the optimum polling period. Then again the cost of extra polls is not all that significant.
File size may also be an issue for negative searches. If you are looking lets say a ping failure because a system crashed you have to make sure that the a new file is created faster than the system can be booted so that the file does not contain a response. Even one response will cause the script not to terminate the dumpcap process. Other packet types might not be as sensitive to reboot times. Actually for a ping failure test take a look at ping_trigger.vbs. You could modify the script to terminate the dumpcap process directory or send out a ping to a unique address and have this script trigger on that (see example 5).
Where | |||
Base Name | is the base name of the files being created by dumpcap | ||
Match String | is an ngrep match condition that is looked for in the trace | ||
Packet Specification | is an ngrep Berkeley Packet Filter condition that is looked for in the trace | ||
Confirm String | is a string in the ngrep output that confirms ngrep found the correct string | ||
PID | is the process ID of the dumpcap process to terminate. Use list_dumpcap to find it | ||
Sleep Time | is the time in seconds between polls | ||
Flag | indicates if dumpcap should be stopped if the "Confirm String" is found (+) or not found (-) |
In the bottom command window you see an execution of the list_dumpcap.vbs script hi-lighted in yellow. Note that the returned process ID is 6340. Next in the bottom window, hi-lighted in cyan, is the execution on the kill_dumpcap script. The match string is "Please stop tracing now", there is no BPF string and the confirmation string is "255:666". Next is the PID returned from the list_dumpcap execution. The polling time is 10 seconds and this will be a positive search, that is, kill_dumpcap will kill the dumpcap process when it sees the confirmation string. The first thing that the script does, and the last line hi-lighted in cyan, is to echo back its arguments.
Back to the top command window you see hi-lighted in cyan, the execution of the dumpcap command. It shows the current file being written and on the next line it updates the total number of packets written to all files. When the current file reaches its prescribed size it writes the new file name and goes to a new line.
Back in the bottom window with yellow highlighting again is a list of "new files". The kill_dumpcap will report the file name when it sees a new file right before it scans it. Note that the file currently being written, in this case, example1_00005_20120518131016 has not yet been scanned.
Staying in the bottom window you see a message indicating that the kill_dumpcap script found the confirmation string and terminated the process. The script then terminates itself. In the top command window you also see that we are back to the command prompt.
To the right of the command windows is the ngrep_13_4_55.txt output. This is the text written by the ngrep command. The first line is the name of the file and the second line is the condition that ngrep is looking for. In this case matching on the string "Please stop tracing now". I knew that this string was sent by a program that sends broadcasts to port 666 so the last part of the destination address is "255:666", this was my confirmation string.
In the bottom command window you see an execution of the list_dumpcap.vbs script hi-lighted in yellow. Note that the returned process ID is 5288. Next in the bottom window, hi-lighted in cyan is the execution of the kill_dumpcap script. The match string is null and the ngrep BPF string indicates that a source IP address of 172.16.1.36 and it has to be an ICMP packet. The confirmation string of "50 8:0" is the last part of the packet header, the final octet of the destination is 50 and the ICMP type and code are 8 and 0. Next is the PID returned from the list_dumpcap execution. The polling time is 10 seconds and this will be a positive search.
Back to the top command window you see hi-lighted in cyan the execution of the dumpcap command.
Back in the bottom window with yellow highlighting again is the list of "new files".
Staying in the bottom window you see a message indicating that the kill_dumpcap script found the confirmation string and terminated the process. The script then terminates itself. In the top command window you also see that we are back to the command prompt.
To the right of the command windows is the ngrep_13_23_49.txt output. Note the second line is the BPF string and not a matching string. The 172.16.1.36 host sent 4 echo requests AKA pings (ICMP type 8) to the 172.168.12.50 host, so that is where the "50 8:0" confirmation string came from.
In the middle command window you see an execution of the list_dumpcap.vbs script hi-lighted in yellow. Note that the returned process ID is 6028. Next in the middle window, hi-lighted in cyan is the execution on the kill_dumpcap script. The match string is null and the ngrep BPF string indicates that a source IP address of 172.16.1.116 and a port of 666. The confirmation string is "R]", circled in blue. This corresponds to the TCP reset flag. Next is the PID returned from the list_dumpcap execution. The polling time is 10 seconds and this will be a positive search.
In the bottom command window there is another execution of the kill_dumpcap.vbs script. The command line is almost identical. The only difference is that the confirmation string is F], circled in red, which corresponds to the TCP FIN flag.
Back to the top command window you see hi-lighted in cyan the execution of the dumpcap command.
Back in the middle window with yellow highlighting again is the list of "new files".
Staying in the middle window you see a message indicating that the kill_dumpcap script found the confirmation string and terminated the process. The script then terminates itself. In the top command window you also see that we are back to the command prompt. Note in the bottom command window that that instance of the kill_dumpcap.vbs script is still running. At this point all it will do is wake up once every 10 seconds, check the files, see that there are no new files and go back to sleep.
To the right of the command windows are two ngrep_hh-mm-ss.txt output files. Both files show exactly the same thing. This is not surprising since the BPF specifications were the same. The only difference in the two executions is the confirmation string, one looking for "F]" and the other from "R]", which is the last packet displayed. If you wanted to there is no reason why you couldn't use two completely different packet specifications if the situation calls for it.
Second, this is using a negative match, note the "-" flag value circled in light green at the end of the kill_dumpcap command line. The idea is to kill the trace when the source 172.16.1.36 is no longer sending ping replies (ICMP type 0 code 0) to the 192.168.12.50 host.
To the right of the command windows are two versions of the ngrep.txt output. In the top window you see the results of scan of the first file example4_00002*. You can see that ngrep found ICMP packets from 172.16.1.36 and that the confirmation string "50 0:0" is found in at least one of the packets. While I don't show it the results of scanning files 1 and 3 were the same. The bottom ngrep.txt window shows the results of scanning file 4. In this file there are no packets listed so the confirmation string is not found and the script kills the dumpcap process.
In the bottom command window we have the execution of the list_dumpcap script showing both an execution from the Wireshark GUI and the dumpcap command that I started for this example.. Next in the bottom window is the execution of the kill_dumpcap script. Note that there is no match string and the packet filer indicates anything with a destination of 1.1.1.1. The confirmation string is 8:0 which we saw in example 3 is part of the header for an ICMP type 8 code 0 packet. You can see that the packets were found in example_00006_20120519185011.
In the top right command window there is an execution of the ping_trigger script. This script will execute a command when a certain number of pings to a host fail. In this case the host is 192.168.0.22 and the command is to ping 1.1.1.1.
Finally in the notepad window at bottom right you can see the ngrep_18_48_8.txt file showing the packets found by ngrep and the 8:0 string in the headers.
REM == kill_dumpcap.vbs starts here REM REM kill_dumpcap.vbs REM version 1.0 12-05-18 REM Noah Davids - noah@noahdavids.org REM REM This software is provided on an "AS IS" basis, WITHOUT ANY WARRANTY OR ANY SUPPORT OF ANY KIND. REM The AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY REM PARTICULAR PURPOSE. This disclaimer applies, despite any verbal representations of any kind provided REM by the author or anyone else. REM option explicit Dim fso, folder, colFiles, sFolder Dim baseName, baseNameLen, matchString, BPFString, confirmString, confirmStringFound, flag, PID, sleepTime, ngrepOut, terminatePID Dim maxIndex, maxIndex9, index, fileList, folderIdx, ngrepRun, oldFileList, sLine Dim wShell DIM objWMIService, colProcessList, objProcess If WScript.Arguments.Count <> 7 then WScript.Echo "Usage:" WScript.Echo " csript kill_dumpcap ""Base Name"" ""matchString String"" ""Confirm String"" PID SleepTime Flag" WScript.Echo vbtab & " ""Base Name"" is the base name of the files being created by dumpcap" WScript.Echo vbtab & " ""match String String"" is an ngrep match condition that is looked for in the trace" Wscript.Echo vbtab & " ""Packet Specification"" is an ngrep Berkely Packet Filter condition that is looked for in the trace" WScript.Echo vbtab & " ""Confirm String"" is a string in the ngrep output that confirms" Wscript.Echo vbtab & vbtab & "ngrep found the correct string" Wscript.Echo vbtab & " PID is the process ID of the dumpcap process to terminate. " Wscript.Echo vbtab & vbtab & "Use list_dumpcap to find it" Wscript.Echo vbtab & " SleepTime is time in seconds" Wscript.Echo vbtab & " Flag indictaes if dumpcap should be stopped if the ""Confirm String"" " Wscript.Echo vbtab & vbtab & "is found (+) or not found (-)." WScript.Echo WScript.Quit End If Set fso = CreateObject("Scripting.FileSystemObject") Set wShell = CreateObject("WScript.Shell") baseName = Wscript.Arguments.Item (0) baseNameLen = len (baseName) matchString = Wscript.Arguments.Item (1) BPFString = Wscript.Arguments.Item (2) confirmString = Wscript.Arguments.Item (3) PID = Wscript.Arguments.Item (4) sleepTime = Wscript.Arguments.Item (5) flag = Wscript.Arguments.Item (6) if flag <> "+" AND flag <> "-" Then Wscript.Echo "The Flag argument must be either a + or - character not """ & flag & """" Wscript.Quit End If if len (matchString) = 0 AND len (BPFString) = 0 Then Wscript.Echo "Either match string OR BPF string must be specified - both cannot be null" WScript.Quit End If Wscript.Echo "cscript kill_dumpcap """ & basename & """ """ & matchString & """ """ & _ BPFString & """ """ & confirmString & """ " & PID & " " & sleepTime & " " & flag REM General flow of program REM REM Create an output file name to accummunate the results of the ngrep command by appending a time string HH_MM_SS REM to "ngrep_". This allows you to run multiples copies of the script to trigger on different things. There is REM of course a window where two instances could create the same output file but its a small window. REM Loop forever REM delete the ngrep_HH_MM_SS.txt file. Note that the HH_MM_SS corresponds to when the script was started REM create a collection of files that are in the current dir REM loop through the file collection and find the maximum index for the dumpcap base name. If it weren't for the REM fact that the index rolls over from 99999 to 00001 this would be easy. What I do is collect two maximum index REM values one for indexes starting with 9, that is 9XXXX named maxIndex9 and one for all others named maxIndex. REM if maxIndex is the initial value of 00000 I used the maxIndex9 value or if the first character of maxIndex is 8 REM and the first character of maxIndex9 is 9 I use the maxIndex9 value otherwise I use the maxIndex value. If REM you configure dumpcap to collect more than 10,000 files, that is yuo can files 89999 through 99999 and then 00001 REM this algorithm will incorrectly pick 99999 as the maxindex. It will eventually scan the file so I am not sure REM this is a fatal flaw. At any rate collecting more than 10,000 trace files seems excessive so I am not going REM to worry about it. REM loop the the file collection (again). REM For each file that matches the base name, see if it also matches the max index. If it doesn't match the max REM index add it to a file list string and then search the old file list string to see if its already there. REM NOTE that if the dumpcap ring of files is large enough we will probably exceed some maximum string size. REM I tested this with 100 files without problems. REM if there is a file that is not in the old file list then run ngrep on the file looking for the REM match string or packet specification. Put the output in the ngrep_HH_MM_SS.txt file. It is REM possible that there could be several new files so all the output is accummulated in the REM ngrep_HH_MM_ss.txt file. Note that if a match string is found don't include the -e argument REM -e causes all the packets with no data to be matched as well. You need the -e when using REM a BPF string so the confirmation string can be one of the TCP flags. REM If ngrep was run then the file list string built in the previous loop is different from the old list REM so the first thing to do is update the old file list. Then open the ngrep_HH_mm-ss.txt file and read REM each line looking for the confirmation string. This second test is needed because I couldn't figure REM out how to confirm that the ngrep found at least 1 packet that meet its specifictaions (or didn't REM as indicated by the flag variable just by looking at the ngre_HH_MM_SS.txt You cannot do it based REM on file size. We can stop reading as soon as 1 confirmation string is seen. REM If the confirmation string is found and the flag is positive we need to terminate dumpcap. If the REM confirmation string is not found and the flag is negative we need to terminate dumpcap. REM To terminate dumpcap we search the process list for the process ID that was provided as an input REM argument. Once found it is terminated and we quit out of this program as well. If the process REM cannot be found we report that and we just quit out of this program. REM Assuming we do quit the program we sleep for the indicated time and then start the loop again ngrepOut = "ngrep_" & Hour (Time) & "_" & Minute (Time) & "_" & Second (Time) & ".txt" oldFileList = "" While (1) fileList = "" wShell.Run "cmd.exe /c DEL " & ngrepOut, 7, 1 ngrepRun = 0 Set folder = fso.GetFolder(".") Set colFiles = folder.Files maxIndex = "00000" maxIndex9 = "00000" For each folderIdx In colFiles if mid (folderIdx.Name, 1, baseNameLen) = baseName Then index = mid (folderIdx.Name, baseNameLen +2, 5) if mid (index, 1, 1) = "9" Then if StrComp (maxIndex9, index, 1) = -1 Then maxIndex9 = index Else if StrComp (maxIndex, index, 1) = -1 Then maxIndex = index End If End If Next If mid (maxIndex, 1, 1) = "8" and mid (maxIndex9, 1, 1) = "9" Then maxIndex = maxIndex9 Else If maxIndex = "00000" Then maxIndex = maxIndex9 End If For each folderIdx In colFiles if mid (folderIdx.Name, 1, baseNameLen) = baseName Then if mid (folderIdx.Name, 1, baseNameLen + 6) <> baseName & "_" & maxIndex Then fileList = fileList & folderIdx.Name & " " if instr (oldFileList, folderIdx.Name) = 0 Then Wscript.Echo "New file " & folderIdx.Name if len (matchString) > 0 Then wShell.Run "cmd.exe /c ngrep -q -I" & folderIdx.Name & _ " """ & matchString & """ " & BPFString & " >>" & ngrepOut, 7, 1 Else wShell.Run "cmd.exe /c ngrep -q -e -I" & folderIdx.Name & _ " """ & matchString & """ " & """" & BPFString & """ >>" & ngrepOut, 7, 1 End If ngrepRun = 1 End If End If End If Next if ngrepRun Then oldFileList = fileList confirmStringFound = 0 Set colFiles = fso.OpenTextFile (ngrepOut) Do Until colFiles.AtEndOfStream sLine = colFiles.ReadLine if instr (sLine, confirmString) > 0 Then confirmStringFound = 1 Exit Do End If Loop colFiles.Close terminatePID = 0 If Flag = "+" AND confirmStringFound = 1 Then Wscript.Echo "Found confirmation string """ & confirmString & """" terminatePID = 1 ElseIf Flag = "-" AND confirmStringFound = 0 Then Wscript.Echo "Did not find confirmation string """ & confirmString & """" terminatePID = 1 End If if TerminatePID = 1 Then Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\.\root\cimv2") Set colProcessList = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE " & _ "ProcessId = '" & PID & "'") if colProcessList.Count = 0 Then Wscript.Echo "Could not find process with PID = " & PID Wscript.Echo "Terminating kill_dumpcap at " & (Date) & "_" & (Time) Wscript.Quit Else For Each objProcess in colProcessList Wscript.Echo "Terminating process with PID = " & objProcess.ProcessId & _ " at " & (Date) & "_" & (Time) objProcess.Terminate() NEXT End If Wscript.Quit End If End If Wscript.sleep sleepTime * 1000 Wend REM REM == kill_dumpcap.vbs end here |
REM == list_dumpcap.vbs starts here REM REM list_dumpcap.vbs REM version 1.0 12-05-20 REM Noah Davids - noah@noahdavids.org REM REM This software is provided on an "AS IS" basis, WITHOUT ANY WARRANTY OR ANY SUPPORT OF ANY KIND. REM The AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY REM PARTICULAR PURPOSE. This disclaimer applies, despite any verbal representations of any kind provided REM by the author or anyone else. REM option explicit Dim wShell DIM objWMIService, colProcessList, objProcess Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\.\root\cimv2") Set colProcessList = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE " & "Name = 'dumpcap.exe'") if colProcessList.Count = 0 Then Wscript.Echo "Could not find a dumpcap.exe process" Else For Each objProcess in colProcessList Wscript.Echo objProcess.CommandLine & " started on " & objProcess.CreationDate & _ " PID = " & objProcess.ProcessId NEXT End IF REM REM == list_dumpcap.vbs end here |