CVE-2022-37109 (published 2022-11-14T21:15Z)

patrickfuller camp up to and including commit bbd53a256ed70e79bd8758080936afbf6d738767 is vulnerable to Incorrect Access Control. Access to the password.txt file is not properly restricted as it is in the root directory served by StaticFileHandler and the Tornado rule to throw a 403 error when password.txt is accessed can be bypassed. Furthermore, it is not necessary to crack the password hash to authenticate with the application because the password hash is also used as the cookie secret, so an attacker can generate his own authentication cookie.

CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-522
cwe_name: Insufficiently Protected Credentials
description: The product transmits or stores authentication credentials, but it uses an insecure method that is susceptible to unauthorized interception and/or retrieval.
extended_description: 
            
            
            
         
         

Fix information:
repo_url: https://github.com/patrickfuller/camp
commit_details: repo_url: https://github.com/patrickfuller/camp
author: Patrick Fuller
author_date: 2022-07-21 09:03:39-05:00
msg: Fix vulnerability and add warning
repository: repo_url: https://github.com/patrickfuller/camp
repo_name: patrickfuller/camp
description: A websocket-powered raspberry pi camera webserver
repo_language: Python
owner: patrickfuller
file_changes: filename: README.md
change_type: ModificationType.MODIFY
diff: @@ -3,7 +3,9 @@ camp
 
 Another Raspberry Pi camera webserver.
 
-![](img/example.png)
+**USE AT YOUR OWN RISK. SEE [#11](https://github.com/patrickfuller/camp/issues/11) FOR MORE.**
+
+![](static/img/example.png)
 
 What it does
 ============
@@ -52,11 +54,11 @@ python camp/server.py
 
 Navigate to http://your.r.pi.ip:8000 and check out your webcam.
 
-#### USB Camera
+### USB Camera
 
 Use with `python server.py --use-usb`.
 
-#### Password
+### Password
 
 ![](img/login.png)
 
@@ -73,10 +75,9 @@ python -c "import hashlib; import getpass; print(hashlib.sha512(getpass.getpass(
 This will prompt you for a password, encrypt it, and save the result in
 `password.txt`.
 
-Note that this level of password protection is basic - it's fine for keeping the
-occasional stranger out, but won't stand up to targeted hacking.
+**Note that this level of password protection is basic.** It's fine for keeping the occasional stranger out but won't stand up to targeted hacking.
 
-#### Run on startup
+### Run on startup
 
 It's nice to have your pi start camp whenever it turns on. Let's make that
 happen. Type `sudo nano /etc/rc.local` to open this file for editing, and add
@@ -84,7 +85,7 @@ the line `nohup python /home/pi/camp/server.py &` before the last line. Note
 that you may need to change the path (`/home/pi/camp/server.py`) to point to
 the right file.
 
-#### Customization
+### Customization
 
 The website consists of `index.html`, `login.html`, and `style.css`. These can be
 edited to change the look of camp.

programming_language: Markdown
filename: server.py
change_type: ModificationType.MODIFY
diff: @@ -7,7 +7,6 @@ import base64
 import hashlib
 import os
 import time
-import threading
 import webbrowser
 
 try:
@@ -42,7 +41,7 @@ class LoginHandler(tornado.web.RequestHandler):
 
     def post(self):
         password = self.get_argument("password", "")
-        if hashlib.sha512(password).hexdigest() == PASSWORD:
+        if hashlib.sha512(password.encode()).hexdigest() == PASSWORD:
             self.set_secure_cookie(COOKIE_NAME, str(time.time()))
             self.redirect("/")
         else:
@@ -50,11 +49,6 @@ class LoginHandler(tornado.web.RequestHandler):
             self.redirect(u"/login?error")
 
 
-class ErrorHandler(tornado.web.RequestHandler):
-    def get(self):
-        self.send_error(status_code=403)
-
-
 class WebSocket(tornado.websocket.WebSocketHandler):
 
     def on_message(self, message):
@@ -128,9 +122,10 @@ else:
 
 handlers = [(r"/", IndexHandler), (r"/login", LoginHandler),
             (r"/websocket", WebSocket),
-            (r"/static/password.txt", ErrorHandler),
-            (r'/static/(.*)', tornado.web.StaticFileHandler, {'path': ROOT})]
-application = tornado.web.Application(handlers, cookie_secret=PASSWORD)
+            (r'/static/(.*)', tornado.web.StaticFileHandler, {'path': os.path.join(ROOT, 'static')})]
+
+secret = base64.b64encode(os.urandom(50)).decode('ascii')
+application = tornado.web.Application(handlers, cookie_secret=secret)
 application.listen(args.port)
 
 webbrowser.open("http://localhost:%d/" % args.port, new=2)

programming_language: Python