SSTIC - show_password

The next step is a brute forcing challenge with a small problem space 263 but with a software that uses up to 30 seconds per iteration. A bit of stracing the program shows a lot of subprocesses being fired, so reversing or debugging looks like not the right way to go. The good thing is that the challenge comes with an example of a successful password, which leads to observing that the right password will lead to a much faster response time (around 5 seconds).

The strace log indicates that subprocesses call into the kernel's sleep syscall, which leads to hopes that one can remove them with the following code loaded with LD_PRELOAD :

/* nosleep.c */
#include 
#include 

unsigned int sleep(unsigned int seconds)
{
    return 0;
}
int usleep(useconds_t usec)
{
    return 0;
}
int nanosleep(const struct timespec *req, struct timespec *rem)
{
    return 0;
}

Unfortunately, due to synchronisations in place between threads, this technique does not bring any improvement.

The following is an attempt to drive subprocesses from Python, but this approach does not work because it relies on wall clock time instead of CPU usage, so depending on other CPU loads, and especially when running high loads associated with brute forcing, it will give false negatives at times.

#!/usr/bin/python

import sys
from pwn import process

words=('Allo', 'Bruine', 'Crachin', 'Dour', 'Etudiant', 'Fransez', 'Gwrizienn', 'Hacktheplanet', 'Iliz', 'Jablus', 'Kerez', 'Lukachenn', 'Mabig', 'Nebeut', 'Oskeg', 'Postel', 'Quidditch', 'Roazhon', 'Sivi', 'Tabut', 'Ubuntu', 'Vaksin', 'Warantugin', 'Xkcd', 'Yaek', 'Zedig' );
#words=('Allo', 'Bruine', 'Crachin', 'Dour', 'Etudiant')

for un in words:
    for deux in words:
        for trois in words:
            passwd = bytearray()
            passwd.extend("%s%s%s"%(un, deux, trois))
            p=process(["./show_password",'hashes.txt', 'meteo'])
            prompt = p.recv(timeout=0.2)
            p.sendline(passwd)
            ok=p.recv(timeout = 12)
            if not ok:
                p.kill()
            else:
                print(passwd)
                with open("result", "wa") as file:
                        file.write(passwd)
                        file.close()
                sys.exit(0)

sys.exit(-1)

My solution has been to use the ulimit command to automatically kill processes after a threshold of execution time was reached. The following simple bash script did the job (on a core i7 it still took around 20 hours).

#!/bin/bash

ulimit -t 22

for f in Allo Bruine Crachin Dour Etudiant Fransez Gwrizienn Hacktheplanet Iliz Jablus Kerez Lukachenn Mabig Nebeut Oskeg Postel Quidditch Roazhon Sivi Tabut Ubuntu Vaksin Warantugin Xkcd Yaek Zedig
do
	for g in Allo Bruine Crachin Dour Etudiant Fransez Gwrizienn Hacktheplanet Iliz Jablus Kerez Lukachenn Mabig Nebeut Oskeg Postel Quidditch Roazhon Sivi Tabut Ubuntu Vaksin Warantugin Xkcd Yaek Zedig
	do
		for h in Allo Bruine Crachin Dour Etudiant Fransez Gwrizienn Hacktheplanet Iliz Jablus Kerez Lukachenn Mabig Nebeut Oskeg Postel Quidditch Roazhon Sivi Tabut Ubuntu Vaksin Warantugin Xkcd Yaek Zedig
		do
			echo $f$g$h
			echo $f$g$h |./show_password hashes.txt chat
			if [[ $? == 0 ]]; then
				echo $f$g$h >>soluce
				exit
			fi
		done
	done
done

The password is "OskegLukachennMabig" which corresponds to "OLM", which is the protocol used in synapse... One could have guessed it I suppose, and I did try a few acronyms before brute forcing, but not this one.

The last flag I found is

SSTIC{556c34304f6279736e516f3267794e4963637a637051}

The following challenge is running in a Windows 98 VM, which is damned hard to use (VGA display, anyone ?) and super slow. After fiddling with it, I stopped, because I could not bear the slowness and stupidity of this OS. See you next year.