Hash Yourself

This Zeek script calculates a levenshtein distance between two strings but doesn't print it :(
See if you can figure out what line 42 evaluates to. But be careful, you might not want to edit the script.
(CAUTION: You only have three attempts!)
redef exit_only_after_terminate = T;
​
module Baz; export {global f: function();}
module Foo;
​
​
global do_it = Exec::run;
module Bar;
​
​
module Foo::Bar;
export {
​
module Bar;
export {
global Bar: string = "Foo";
​
global Foo: string = "";
global s: string = "Bar";
}
​
module Foo::Bar;
export {
global Bar: string = "";
global s: string = "Foo";
global Foo: string = "Bar";
}
​
module Foo;
global s: string = "";
global Bar: string = "Bar";
global Foo: string = "Foo";
​
}
​
function Baz::f() {
local magic = "rFj3eGxkRR5";
when (local result = do_it([$cmd=fmt("cat %s", @FILENAME), $uid=magic])) {
levenshtein_distance(md5_hash(join_string_vec(result$stdout, "\n")), s) - 3;
terminate();
}
}
​
event zeek_init() &priority=10 {
local c: count = 10;
Foo += "::s";
while (-100 > -101) {
s += string_cat(fmt("%s",double_to_count(floor(haversine_distance(1.0, 1.0, 2.0, c)))));
c -= 1;
if (Foo in global_ids()) {
s = lookup_ID(Foo);
}
if (c <= 0) break;
}
Baz::f();
}
​
So it takes the script path and cats the file contents into a variable for hashing. So that explains why we can't edit it. Any adjustment to the contents would change the hash and that would change the levenshtien distance.
So how to introspect the file during runtime. Interesting, why the call terminate after the computation.
aah trace might be the tool we need.
zeek --help
usage: zeek [options] [file ...]
<file> | policy file, or read stdin
-a|--parse-only | exit immediately after parsing scripts
-b|--bare-mode | don't load scripts from the base/ directory
-d|--debug-policy | activate policy file debugging
-e|--exec <zeek code> | augment loaded policies by given code
-f|--filter <filter> | tcpdump filter
-h|--help | command line help
-i|--iface <interface> | read from given interface
-p|--prefix <prefix> | add given prefix to policy file resolution
-r|--readfile <readfile> | read from given tcpdump file
-s|--rulefile <rulefile> | read rules from given file
-t|--tracefile <tracefile> | activate execution tracing
-v|--version | print version and exit
-w|--writefile <writefile> | write to given tcpdump file
-C|--no-checksums | ignore checksums
-F|--force-dns | force DNS
-G|--load-seeds <file> | load seeds from given file
-H|--save-seeds <file> | save seeds to given file
-I|--print-id <ID name> | print out given ID
-N|--print-plugins | print available plugins and exit (-NN for verbose)
-P|--prime-dns | prime DNS
-Q|--time | print execution time summary to stderr
-S|--debug-rules | enable rule debugging
-T|--re-level <level> | set 'RE_level' for rules
-U|--status-file <file> | Record process status in file
-W|--watchdog | activate watchdog timer
-X|--zeekygen <cfgfile> | generate documentation based on config file
--pseudo-realtime[=<speedup>] | enable pseudo-realtime for performance evaluation (default 1)
$ZEEKPATH | file search path (.:/opt/lg/i8/share/zeek:/opt/lg/i8/share/zeek/policy:/opt/lg/i8/share/zeek/site)
$ZEEK_PLUGIN_PATH | plugin search path (/opt/lg/i8/lib/zeek/plugins)
$ZEEK_PLUGIN_ACTIVATE | plugins to always activate ()
$ZEEK_PREFIXES | prefix list ()
$ZEEK_DNS_FAKE | disable DNS lookups (off)
$ZEEK_SEED_FILE | file to load seeds from (not set)
$ZEEK_LOG_SUFFIX | ASCII log file extension (.log)
$ZEEK_PROFILER_FILE | Output file for script execution statistics (not set)
$ZEEK_DISABLE_ZEEKYGEN | Disable Zeekygen documentation support (not set)
$ZEEK_DNS_RESOLVER | IPv4/IPv6 address of DNS resolver to use (not set, will use first IPv4 address from /etc/resolv.conf)
​
zeek ./hash-yourself_challenge_hash-yourself.zeek -t trace.txt
​
27M Oct 15 01:28 trace.txt
Whoaa that is a big text file! Lets take a look, remember that terminate call, I bet we could skip to the end of the trace file.
tail -n 23 trace.txt
​
1602725332.782193 <no filename>:0 Function return: 780b5850a7c924f2fef8409ecef45111
1602725332.782193 <no filename>:0 Builtin Function called: levenshtein_distance(s1 = '780b5850a7c924f2fef8409ecef45111', s2 = '6255564884203522842181549769')
1602725332.782193 <no filename>:0 Function return: 26
1602725332.782193 <no filename>:0 Builtin Function called: terminate()
1602725332.782193 <no filename>:0 Function return: T
​
The wrong solution!
26
Wrong!? Two tries left!, Wait a minute, the answer is right there!?
Ohhhhhh right what the entire line 42 evaluates to!
The solution.
23