Hmm so we don't have the flag string. We have some 1000 files in directories which contain numbers nicely delimited by decimals. So some string was used to compute a file that wasn't created using a randomizing function, the rest use the lookup table and a random offset we can't reverse.
Ok lets reverse every file back into strings on the assumption that is was the winner one.
So lets read the file in using the input framework.
We get an event from we can hook into that will gives us the line in the file. Brute force some string manipulations and reverse the look table.
event file_line(description: Input::EventDescription, tpe: Input::Event, s: string) { local parts =split_string(s,/\./)[:-1]; local nn =to_count(split_string1(description$name,/_/)[1]); local msg: string="";for(el in parts) { local idx =to_count(parts[el])- nn;if(idx in rev_ascii_map) { msg += rev_ascii_map[idx]; } }}
Putting it all together
module fly;@load base/frameworks/input@load ./lookup# @load ./flagredef exit_only_after_terminate = F;global rev_ascii_map: table[count] of string = {};type FileLine: record { s: string;};event file_line(description: Input::EventDescription, tpe: Input::Event, s: string) { local parts =split_string(s,/\./)[:-1]; local nn =to_count(split_string1(description$name,/_/)[1]); local msg: string="";for(el in parts) { local idx =to_count(parts[el])- nn;if(idx in rev_ascii_map) { msg += rev_ascii_map[idx]; } }if (/flag/i in msg) { print fmt("n=%s flag=%s", nn, msg); }}function run() { local n: count =0; local pain_level: count =1000;while (n < pain_level) {Input::add_event([$source=fmt("tmp/%s", n), $name=fmt("tmp_%s", n), $reader=Input::READER_RAW, $want_record=F, $fields=FileLine, $ev=file_line]); n +=1; }}event zeek_init() { # Probably a better way but I just brute forced reversed the lookup tablefor(el in ascii_map){ rev_ascii_map[ascii_map[el]] = el; }run();}
You end up getting a fair amount of string output, but this is a CTF and your looking for flags right. So a quick case insensitive search for flag and voila.