X

by Keith J. Jones, Ph.D

Introduction

 The last three blog posts demonstrated how to add a JPEG file analysis plugin into the core Zeek source code or as a package.  This part will demonstrate how you can add tests to your code when distributed as part of the Zeek source code (blog posts 1 and 2) or as a package (blog post 3).  First, this post will introduce Btest, the testing mechanism used by Zeek.  Next, this post will walk you through the mechanisms you will use to test either the Zeek core source code or packages you write for Zeek.  Although this post is specific to our JPEG example from the prior three posts, it is important to note that the testing concepts presented in this post can be used for other source code development within Zeek.  Therefore, this post should be relevant no matter what type of source code development you may be performing on Zeek.  Read on to learn more.

How Does Btest Work?

You can think of btest (https://github.com/zeek/btest) as a generic driver to automate testing using whatever language is appropriate for the task.  While that explanation sounds vague, it is actually a very powerful concept.  Btest can be used to test Zeek with pretty much any language that appropriate; so for some tests you can use shell scripting, and for other tests you can use Zeek scripts.  Such a powerful testing framework would seem complex, and it is, but using the framework is nearly trivial once you learn the basics of how it works.  

 

Btest operates by reading any file in the current directory and executing the btest commands within them that are prefixed by “@TEST-EXEC” tokens.  Therefore, by placing the btest commands in comments for whatever language we want to use to test our code, we are able to test Zeek using pretty much any Unix command line tool we like.  The documentation explains this process better than I could reproduce it here, so at least skim the concepts introduced here:
Stop here and read the documentation at the link above before you continue further on this post.  No, really; it’s important.  I will wait.  I will now assume you know the basic concepts of btest before I describe how we are going to test the JPEG plugin we have been working on.
 
For this blog post, we will demonstrate some tests that will use shell and Zeek scripts to ensure our JPEG plugin is performing as expected.  Our inputs to btest will be the shell and Zeek scripts, and our tests will use the PCAP files we used to test our code in the prior blog posts.  Our commands used to run the tests will be defined in the comments of the shell and Zeek scripts.  This will make more sense as we look at a concrete example applying the concepts in the Zeek testing documentation above. 
Note that some additional documentation for Zeek testing can be found at https://www.zeek.org/development/projects/testing.html.

 

Writing Tests For The JPEG Analyzer Plugin

 

If you read parts 1-3 of this blog series, you will remember that we coded the JPEG analyzer twice.  The first time, we coded it directly into the Zeek core source code tree.  Then, we took the same logic and made it into an installable package.  We will discuss testing for both methods in this post, but we will start with the package deployment method first since it is the easier of the two methods to distribute your logic.  Then, I will show how to add some tests to the Zeek core source code method for completeness. 
  

Package Deployment

When we ran “init-plugin” in the last post, it automatically created a test for us in the “tests” directory:
The first file we will want to discuss is the “btest.cfg” configuration file:
Line 2 says that the test directories includes “jpeg”.  This is the directory we will add our new test to.  Line 15 shows where we can store pcap files.  The symbol “TRACES” is expandable within btest tests, so we do not have to discern the parent path.  We will use the trace we downloaded earlier in this series from the Wireshark project to create some tests, and this is the path we will place it in.
 
After running “init-plugin”, from the last blog post, one test is added to our package:
This file is a zeek script.  Inside the comments, “@TEST-EXEC:” says to run zeek in the following manner:
zeek -NN FileAnalyzers::JPEG |sed -e ‘s/version.*)/version)/g’ >output
This line runs Zeek in a mode where the plugins are searched for FileAnalyzers::JPEG, then the “sed” command is used to find the version, and it is all output to a file called “output”. Then, the second line says to run “btest-diff” on the “output” file generated previously.  As you recall from the btest documentation, if the output file were to change between testing, the test would fail.  It is the output that defines the tests, and deviations from the output signal a failed test.
In order to detect changes between tests, baselines must be created.  Baselines can be created with the following btest command from within the “tests” directory:
 
$ btest -U
After that, any subsequent runs of “btest” will detect changes from this baseline run.
Now, let us add a simple test to our plugin.  Create a file called “jpeg.zeek” in the “testsjpeg” directory with the following content:
# @TEST-EXEC: zeek -r $TRACES/http_with_jpegs.pcap %INPUT >jpeg.out
# @TEST-EXEC: btest-diff jpeg.out
# @TEST-EXEC: btest-diff jpeg.log
event file_jpeg_marker(f: fa_file, m: FileAnalyzers::JPEGMarker)
    {
      print m;
    }
 
The first line above tells Zeek to run with a traces file in the “$TRACES” directory, we discussed previously in the btest.cfg file.  This command uses the current file (%INPUT) as the input script.  The second two testing lines detect changes on jpeg.out and jpeg.log from the baseline.  Lastly, the event defined here outputs some of the marker information detected from the trace file.  Simply printing the marker data to the output adds it to the test because we are looking for differences in the output to the Zeek command.
 

 

We will need a PCAP file, so place the following trace file in “Traces” directory and call it “http_with_jpegs.pcap” once you have decompressed it:
Now, record the baseline with the following command:
$ btest -U
 

 

From this point forward, running “btest” again will detect changes and fail the test if the output is different.  The changes between the last blog post and this post to add these tests can be found at the following link:

 

Core Zeek Source Code Deployment

Adding the same test to the core Zeek source code deployment method is pretty much the same as the package version once you are able to locate the key areas to add the tests.  The new code we are adding is available at:
The “jpeg.zeek” script from above will be located at the path “testing/btest/scripts/base/frameworks/file-analysis/http/jpeg.zeek” based upon the matching directory structures between the code we added and this path.  Note that there are a few changes between this version of “jpeg.zeek” and packaged version.  The changes are mainly associated with record pathing and the path to our pcap file.
 
The trace from above needs to be placed at “testing/btest/Traces/http/http_with_jpegs.pcap”.  Now, enter the “testing/btest” directory and update our new baseline for this one test only:
$ btest -U scripts/base/frameworks/file-analysis/http/jpeg.zeek
Next, you can test our new test with the following command:
$ btest scripts/base/frameworks/file-analysis/http/jpeg.zeek
If there has been a change to the baseline, btest will notify you.  If you decide to test all of Zeek by simply executing “btest”, be warned that there are many and not all of them will pass.  You will need to find your plugin’s test out of many, so for development purposes you will likely want to run single tests to save time. 

Conclusion

This blog post demonstrated how to add testing to our JPEG file analyzers.  We tested the core source code with Zeek if we choose to deploy that way, and we also tested the package we created in the last blog post to cover that deployment method.  With testing added, your new custom JPEG file analyzer is ready to be consumed by the open source community.  You can either apply to add your source code to the core Zeek source code distribution on GitHub, or you can add your package to https://packages.zeek.org/ so that other users can benefit from your work. 
About Keith J. Jones, Ph.D
Dr. Jones is an internationally industry-recognized expert with over two decades of experience in cyber security, incident response, and computer forensics. His expertise includes software development, innovative prototyping, information security consulting, application security, malware analysis & reverse engineering, software analysis/design and image/video/audio analysis. 
 
Dr. Jones holds an Electrical Engineering and Computer Engineering undergraduate degrees from Michigan State University. He also earned a Master of Science degree in Electrical Engineering from MSU. Dr. Jones recently completed his Ph.D. in Cyber Operations from Dakota State University in 2019.

 

 

%d bloggers like this: