Editors

Initial analysis

We were presented with the keystroke log and asked to submit a key in the following form: the number of times the editor default in sudoers is set, followed by that field's final value, followed by the number of shells invoked, followed by the state of the machine.

To decipher the special characters in the file, some used hex editors, some used 'cat -v', and others used vim to produce:

ssh user@1337box^Mcronjobscronjobscronjobscronjobs^Mksu -l^Mub3rstongdeemonsfromtehsewarsZZZ!^Mcd^Mscreen^M^M^AS^A      ^Actmux^M^B%^A  tmux^M^B%emacs --daemon^MEDITOR="emacsclient -nw"^M^A   teco^MEB/etc/sudoers^[^[P^[^[Seditor^[0TT^[^[EX^[^[^Bo^MEDITOR=vim visudo^M^[:%s/emacs/vim, /g^M^[:wq^M^B&y^A   ^AQvisudo^M^Boln -s /sbin/poweroff exec^Med /etc/sudoers^M^Bo^[OB^[OB^[OB^[OB^[OB^[OB^[OB^[OB^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[OC^[[3~^[[3~^[[3~^[[3~^[[3~^[[3~^[[3~teco^Bo9s/emacs/ed^M%l^Mw /etc/sudoers^Mq^M^Bo^X^S^X^C^B&y^Aky./exec^M

Next we manually deciphered the commands output by running them in a simulated environment. We quickly realized that we didn't have enough state information to solve the problem. Luckily, game organizers realized the issue and posted the initial editor's value. This was a good start but there were other variables that were needed to solve the solution. For instance, it isn't possible to solve (without brute forcing) unless we know if the platform is virtualized. There were other issues but that one turned out to be a big issues for us.

After numerous key rejections we moved on to automated analysis. This python/expect script opens a shell and executes the input character by charcter and then hands control back to us for analysis:

#!/usr/bin/env python

import pexpect
import time

child = pexpect.spawn('/bin/bash')
#child.logfile = sys.stdout
data = open('./input', 'r').read()
for c in data:
    print "sending:", c
    child.send(c)
    time.sleep(1)
child.interact()

We ran the above script, monitored all access to sudoers and then came up with a solution. One minor issue that come up during this phase was that the machine rebooted. Upon reboot, many different shells were invoked as part of the reboot process. Without access to the original machine, we had no way of producing a valid key. All of our keys assumed that this was an oversite by the game organizer.

In the end, we decided to do a slow, small brute-force prioritized by what we thought was correct. Our initial guess on the runlevel made that wrong, and our initial guess on the number of shells (still some debate about that answer) was also wrong.

#!/usr/bin/env python

for k in 8,6,7,9,10:
    for i in 2,3,1,4,0:
        for j in "/usr/bin/teco", "/usr/bin/ed", "/usr/bin/emacs":
            for l in "on","off":
                print str(i)+str(j)+str(k)+str(l)


The solution was: 2/usr/bin/teco6off
Our primary issue in discovering the key is that when the system is virtualized (as our test system was) and exec --> /bin/poweroff is called, the host will reboot. Depending on the runlevel of the OS as well as the ACPI config, the outcomes will be differently. It was hard to figure out which pieces were intentially "broken" (aka, the invalid regexp replacement) and which parts weren't intentionally broken but were artifacts of a different config.