LabyREnth CTF Unix Level1 Writeup
This is the writeup for ievel 1 challenge in Pan Labyrenth CTF - Unix track.
Download the original challenge file
The given file is an obfuscated perl script. There are chunks of base64
strings which are decoded
and
appended to $a
and then at last a huge chunk 0f base64
string is decoded and then eval
-ed. Decoding
the string to be evaluated, we can find more eval
statements in it.
The first step is to remove the first layer of eval
obfuscation. So, keep replacing eval
statements
with the original code until there are no more eval
statements left in the source code. Did this by the
following script
squash_eval.py
#!/usr/bin/python3
from subprocess import check_output
from pprint import pprint
PERL_DECODER = """
use MIME::Base64();
print {};
"""
lines = ''
def get_eval_line(lines, start, end):
for i in range(start, end + 1):
try:
if lines[i].strip().startswith('eval'):
print(i)
return i
except IndexError:
print(lines)
exit()
raise KeyError("Not fucking found!")
def deobfuscate_code(lines, line_n):
line = lines[line_n].strip()
assert line.startswith('eval')
code = check_output(['perl'], input=str.encode(PERL_DECODER.format(line[5:])))
#code = check_output(["ls", '-l'])
code = list(map(bytes.decode, code.split(b"\n")))
lines = lines[:line_n] + code +lines[line_n+1:]
return lines, [line_n, line_n + len(code)]
def main():
count = 0
with open('bowie.pl', 'r') as fp:
lines = fp.read().split("\n")
line_n = get_eval_line(lines, 0, len(lines) - 1)
while True:
try:
print("Deobfuscation round {}".format(count))
count += 1
lines, pos = deobfuscate_code(lines, line_n)
line_n = get_eval_line(lines, pos[0], pos[1])
except KeyError:
break
with open('output.pl', 'w') as fp:
fp.write('\n'.join(lines))
print("Done")
if __name__ == '__main__':
main()
Running this script, we get
189
Deobfuscation round 0
194
Deobfuscation round 1
199
Deobfuscation round 2
204
Deobfuscation round 3
209
Deobfuscation round 4
214
Deobfuscation round 5
219
Deobfuscation round 6
224
Deobfuscation round 7
229
Deobfuscation round 8
234
Deobfuscation round 9
239
Deobfuscation round 10
244
Deobfuscation round 11
249
Deobfuscation round 12
254
Deobfuscation round 13
259
Deobfuscation round 14
264
Deobfuscation round 15
269
Deobfuscation round 16
274
Deobfuscation round 17
279
Deobfuscation round 18
284
Deobfuscation round 19
Done
We have output.pl
script which consists of no eval
statements. We can see that the script is writing
all the contents of $a
to a file at the end.
open(my $fh, ">", "entrevue.gif");
print $fh $a;
close $fh;
Now, we just need to remove all those unnecessary if
statements and just append everything to $a.
Stripping off these checks can be done by a simple script.
cat > reduced.pl << EOF
use MIME::Base64();
my \$a = "";
EOF
grep -o "\$a = \$a . MIME::Base64::decode.*" output.pl >> reduced.pl
cat >> reduced.pl << EOF
open(my \$fh, ">", "entrevue.gif");
print \$fh \$a;
close \$fh;
EOF
reduced.pl
is the patched script, without any checks and will just write to entrevue.gif
base64
decoding all the chunks.
Opening the gif file, we get our flag as
PAN{L3ts_533_h0W_U_deal_w_th1s_little_511CE}