Need some help with my Script This works want Mac info as well

Any major updates coming, Upcoming Software, General Security advice for others and topics alike Post them here so other users can chat with you.
ultimatecodewarrior
Posts: 26
Joined: Mon Jan 13, 2025 3:04 pm

Re: Need some help with my Script This works want Mac info as well

Post by ultimatecodewarrior »

-Forum wouldn't let me update last post.
-Updated Code above, the column sort wasn't bouncing asc/desc as it should.

Code: Select all

import os
import requests
from requests.auth import HTTPDigestAuth
import ipaddress
import sys
import threading
import time
import json
import webbrowser
from http.server import SimpleHTTPRequestHandler, HTTPServer

# Replace with your camera's username
USERNAME = "admin"  # Replace with your actual username

# List of possible passwords to try
PASSWORDS = [
    "admin",  # First password to try
    "admin",  # Second password to try
    # Add more passwords here if needed
]

# Define the network range (e.g., 192.168.0.1/24)
NETWORK_RANGE = "192.168.0.1/24"

discovered_cameras = []  # Store discovered camera information
scanning = False  # Flag to control the throbber

# Function to get the MAC address of the camera
def get_mac_address(camera_ip, password):
    try:
        NETWORK_URL = f"http://{camera_ip}/cgi-bin/configManager.cgi?action=getConfig&name=Network"
        response = requests.get(NETWORK_URL, auth=HTTPDigestAuth(USERNAME, password), timeout=5)

        if response.status_code == 200:
            mac_start = response.text.find("PhysicalAddress=")
            if mac_start != -1:
                mac_address = response.text[mac_start + 16:mac_start + 33].strip()
                return mac_address
    except requests.exceptions.RequestException:
        pass
    return None

# Function to check if a camera is online and accessible
def check_camera(camera_ip):
    for i, password in enumerate(PASSWORDS, 1):
        try:
            CAMERA_URL = f"http://{camera_ip}/cgi-bin/magicBox.cgi?action=getSystemInfo"
            response = requests.get(CAMERA_URL, auth=HTTPDigestAuth(USERNAME, password), timeout=5)

            if response.status_code == 200:
                mac_address = get_mac_address(camera_ip, password)
                system_info = response.text.strip()

                # Parse the response text to extract the specified fields
                fields = {
                    "appAutoStart": None,
                    "deviceType": None,
                    "hardwareVersion": None,
                    "processor": None,
                    "serialNumber": None,
                    "updateSerial": None,
                    "updateSerialCloudUpgrade": None
                }

                for line in system_info.splitlines():
                    key, sep, value = line.partition('=')
                    if key in fields:
                        fields[key] = value.strip()

                if fields["serialNumber"] is not None:
                    system_info = "Camera Detected"

                discovered_cameras.append({
                    "ip": camera_ip,
                    "password_used": f"pass{i}",
                    "mac_address": mac_address,
                    "processor": fields["processor"],                    
                    "deviceType": fields["deviceType"],
                    "serialNumber": fields["serialNumber"],
                    "system_info": system_info,

                })

                '''
                "hardwareVersion": fields["hardwareVersion"],              
                "updateSerial": fields["updateSerial"],
                "updateSerialCloudUpgrade": fields["updateSerialCloudUpgrade"],
                "appAutoStart": fields["appAutoStart"]
                '''

                return
        except requests.exceptions.RequestException:
            pass

# Function to ping a single camera
def ping_camera(camera_ip):
    return os.system(f"ping -c 1 {camera_ip} > /dev/null 2>&1") == 0

threads_left = 0

def check_ip(ip):
    global threads_left
    camera_ip = str(ip)
    if ping_camera(camera_ip):
        check_camera(camera_ip)
    threads_left -= 1

def throbber():
    global threads_left
    while scanning:
        for char in "|/-\\":
            print(f"\rScanning waiting for {threads_left} threads to finish... {char}", end="", flush=True)
            time.sleep(0.1)
    print("\rScan complete!   ")

# Scan the network and check for reachable devices
def scan_network():
    global threads_left
    ts = time.time()
    global scanning
    network = ipaddress.IPv4Network(NETWORK_RANGE, strict=False)
    scanning = True

    threads = []
    ct = 0
    for ip in network.hosts():
        ip_thread = threading.Thread(target=check_ip, args=(ip,))
        ip_thread.start()
        threads.append(ip_thread)
        threads_left += 1
        ct += 1

    print(f"[{ct}] Scanning threads launched in parallel, be patient for roughly 15 seconds give or take...")

    throbber_thread = threading.Thread(target=throbber)
    throbber_thread.start()

    for t in threads:
        t.join()
    print(f"\r\n[{ct}] Threads finished locating {len(discovered_cameras)} cameras in {round(time.time() - ts)} seconds flat....")
    scanning = False

    # Save discovered cameras to a JSON file
    with open('discovered_cameras.json', 'w') as json_file:
        json.dump(discovered_cameras, json_file, indent=4)

    # Launch the browser to display the HTML file
    webbrowser.open('http://localhost:8000')

    # Wait for all threads to finish

# HTML content to display the discovered cameras
HTML_CONTENT = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Discovered Cameras</title>
    <style>
        table {
            width: 100%;
            border-collapse: collapse;
        }
        th, td {
            padding: 8px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }
        th {
            cursor: pointer;
            background-color: black;
            color: white;
        }
        th.sort-asc::after {
            content: " ▲";
            color: red;
        }
        th.sort-desc::after {
            content: " ▼";
            color: red;
        }
        tr:nth-child(even) {
            background-color: #f2f2f2;
        }
        tr:hover {
            background-color: #ddd;
        }
    </style>
</head>
<body>
    <h1>Discovered Cameras</h1>
    <table id="cameraTable">
        <thead>
            <tr>
                <th onclick="sortTable(0)" data-sort-order="desc">IP Address</th>
                <th onclick="sortTable(1)" data-sort-order="asc">Password Used</th>
                <th onclick="sortTable(2)" data-sort-order="asc">MAC Address</th>
                <th onclick="sortTable(3)" data-sort-order="asc">Processor</th>
                <th onclick="sortTable(4)" data-sort-order="asc">Device Type</th>
                <th onclick="sortTable(5)" data-sort-order="asc">Serial Number</th>
                <th onclick="sortTable(6)" data-sort-order="asc">System Info</th>
            </tr>
        </thead>
        <tbody>
        </tbody>
    </table>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            fetch('discovered_cameras.json')
                .then(response => response.json())
                .then(data => {
                    const tableBody = document.querySelector('#cameraTable tbody');
                    data.forEach(camera => {
                        const row = document.createElement('tr');
                        row.innerHTML = `
                            <td>${camera.ip}</td>
                            <td>${camera.password_used}</td>
                            <td>${camera.mac_address}</td>
                            <td>${camera.processor}</td>
                            <td>${camera.deviceType}</td>
                            <td>${camera.serialNumber}</td>
                            <td>${camera.system_info}</td>
                        `;
                        tableBody.appendChild(row);
                    });
                    sortTable(0, true); // Default sort by IP Address descending
                });
        });

        function sortTable(columnIndex, initialSort = false) {
            const table = document.getElementById('cameraTable');
            const tbody = table.tBodies[0];
            const rows = Array.from(tbody.rows);
            const th = table.tHead.rows[0].cells[columnIndex];
            const sortOrder = th.getAttribute('data-sort-order') === 'asc' ? 'desc' : 'asc';

            rows.sort((a, b) => {
                const aText = a.cells[columnIndex].textContent.trim();
                const bText = b.cells[columnIndex].textContent.trim();
                return aText.localeCompare(bText, undefined, {numeric: true});
            });

            if (sortOrder === 'desc' || initialSort) {
                rows.reverse();
            }

            rows.forEach(row => tbody.appendChild(row));

            Array.from(th.parentNode.cells).forEach(cell => cell.classList.remove('sort-asc', 'sort-desc'));
            th.classList.add(sortOrder === 'asc' ? 'sort-asc' : 'sort-desc');
            th.setAttribute('data-sort-order', sortOrder);
        }
    </script>
</body>
</html>
"""

class CustomHandler(SimpleHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
            self.wfile.write(HTML_CONTENT.encode('utf-8'))
        elif self.path == '/discovered_cameras.json':
            self.send_response(200)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            with open('discovered_cameras.json', 'r') as json_file:
                self.wfile.write(json_file.read().encode('utf-8'))
        else:
            self.send_error(404, "File not found")

def run_server():
    server_address = ('', 8000)
    httpd = HTTPServer(server_address, CustomHandler)
    print("Serving on port 8000...")
    httpd.serve_forever()

# Main function to run the scan
if __name__ == "__main__":
    try:
        scan_network()
        
        print("\nScan complete. Discovered devices:")
        for cam in discovered_cameras:
            print(f"\nCamera IP: {cam['ip']}\nPassword Used: {cam['password_used']}\nMAC Address: {cam['mac_address']}\nSystem Info:\n{cam['system_info']}")

        # Run the server to display the HTML content
        run_server()
    except KeyboardInterrupt:
        print("\n\nScan aborted by user. Exiting script gracefully...")
        sys.exit(0)
User avatar
Revo2Maxx
Site Admin
Posts: 6726
Joined: Sat Jun 15, 2019 3:05 pm

Re: Need some help with my Script This works want Mac info as well

Post by Revo2Maxx »

Thank you.. Very interesting. Now I just need to edit to where it don't scan my switches IP address because the junk it takes into the html makes it a mess lol.. So for now I edit the JSON file to remove the bad IPs for now and makes it look better.. Thank you..
Be Safe.
User avatar
Revo2Maxx
Site Admin
Posts: 6726
Joined: Sat Jun 15, 2019 3:05 pm

Re: Need some help with my Script This works want Mac info as well

Post by Revo2Maxx »

Again thank you. That format is interesting and have to go over the script to understand it more seeing it is above my oldish man skill level lol. Oddly this time there are some things missing that I don't remember being missing from old scans. Yet seeing I printed off a list before making the color change idea lol. It did show 31 type and didn't think about it because it was showing the device in the updateserial line so didn't notice now with all the data being in a line it is easier to notice things. Plus the update info is missing so makes the fact the name showing up as 31 a larger deal lol..
Screenshot from 2025-02-19 09-56-43.png
Screenshot from 2025-02-19 09-56-43.png (208.57 KiB) Viewed 818 times
Be Safe.
ultimatecodewarrior
Posts: 26
Joined: Mon Jan 13, 2025 3:04 pm

Re: Need some help with my Script This works want Mac info as well

Post by ultimatecodewarrior »

If you only want to see cameras, you could do something like this:


Code: Select all


                if fields["serialNumber"] is not None:
                    system_info = "Camera Detected"
                else:
                    system_info = "Camera Not Detected"

Code: Select all

Or you could omit writing them out in the JSON.

                if fields["serialNumber"] is not None:
                    system_info = "Camera Detected"
                else:
                    continue


If you want to quickly level-up your Coding Game, I would recommend you get VS Code installed, and then do the Copilot / Chat GPT integration. I think you can start with a free version, but after that it's like $10/month and well worth it for any type of coding. You can have a conversation with it to crank out python javascript html whatever you wish and it will crank out the code for you in like 20-30 seconds. I've been developing software for 35 years, and this Copilot integration is a quantum leap. It's like when we jumped from hand coded assembly to a compiler with an IDE and debugger. :)
User avatar
Revo2Maxx
Site Admin
Posts: 6726
Joined: Sat Jun 15, 2019 3:05 pm

Re: Need some help with my Script This works want Mac info as well

Post by Revo2Maxx »

Wow looking at that on the web page for them that is crazy but there is a lot to take in too lol.. I don't like the idea that I have to make an account and log in to Github or what ever it was he said but will look over things more. Looks cool
Be Safe.
ultimatecodewarrior
Posts: 26
Joined: Mon Jan 13, 2025 3:04 pm

Re: Need some help with my Script This works want Mac info as well

Post by ultimatecodewarrior »

Well, you could always start with either https://claude.ai/new or https://chatgpt.com/ and ask it to write some code for you and it can crank it out there without an account. Just to see what it can do. Later on, it's nice to have it in an I.D.E. (Integrate Development Environment) like VS Code because of the debugger and not having to fumble around switching windows. These newer AI coders were able to beat about 98% of coders, so ... that's a pretty good level up within a couple of hours vs a couple of decades learning.

They are good for about 500 ~ 1000 lines of code, once it gets beyond that they are limited. The UI's they crank out will be terrible but they will get you in the vicinity very quickly.
User avatar
Revo2Maxx
Site Admin
Posts: 6726
Joined: Sat Jun 15, 2019 3:05 pm

Re: Need some help with my Script This works want Mac info as well

Post by Revo2Maxx »

Awesome, will have to give it a try. I am always behind the times when it comes to tech.
Be Safe.
ultimatecodewarrior
Posts: 26
Joined: Mon Jan 13, 2025 3:04 pm

Re: Need some help with my Script This works want Mac info as well

Post by ultimatecodewarrior »

Another thing you could use a script like yours to do is set the time on all your Cameras to keep them all in sync.

WARNING: This will probably mess up the feeds because it might scramble the packet dts/pts timings causing the feed to fumble. Might be a good test to see how robust your NVR's record though :)

Something like this will get the current time, so you could first list to see if your cameras were in sync
http://192.168.0.109/cgi-bin/global.cgi ... urrentTime

If you wanted to cut to the chase, just apply the current server time to your cameras.
http://192.168.0.109/cgi-bin/global.cgi ... 2025-02-18 04:46:00

So a script like that might be good like for myself in AZ where we don't have daylight savings time, but ...the cameras might believe we do and mess things up, and this would be a quick way to straighten everything out. Could do it with a reboot loop at 12:01 AM. First set the time, then reboot the camera.

http://192.168.0.109/cgi-bin/magicBox.cgi?action=reboot
User avatar
Revo2Maxx
Site Admin
Posts: 6726
Joined: Sat Jun 15, 2019 3:05 pm

Re: Need some help with my Script This works want Mac info as well

Post by Revo2Maxx »

Sorry just got back from a couple of Doctors Apts.. Anyway I thought I would give the Ai thing a try.. Taking your script that works but as I said had some junk from a couple of my switches.. So took the script as you had it, Gave it to the Ai and asked them to rewrite it so it would work as it is setup right now but removing a few IPs from the scan list.. It rewrote it and then when I ran it it did take out the Ips and listed the found cameras in terminal but when chrome loaded for display there was an error because it took out the loading of the web service that was in your script. So I told it about the error and started to write again but after a few tries it still failed to understand what was missing from your code to the updated code to make it work.. So not sure how others make this thing work lol.. It is like here is kind of what you want if you really want it to work buy an upgrade lol.. geez so I changed one of the switches password and now only 2 switches are an issue. so asking the Ai to update the code and fresh off yours that works to not scan 10.0.0.169 or 10.0.0.170 and again fails lol.. Oh well. I will just do it my self lol..
Be Safe.
User avatar
Revo2Maxx
Site Admin
Posts: 6726
Joined: Sat Jun 15, 2019 3:05 pm

Re: Need some help with my Script This works want Mac info as well

Post by Revo2Maxx »

Ok got it to work once but still not as good as yours but thought I wouldn't give up to fast here is the output after giving it to Ai and telling them it failed like 4 other times to do what expected lol..
Screenshot from 2025-02-19 17-34-04.png
Screenshot from 2025-02-19 17-34-04.png (158.99 KiB) Viewed 804 times
Be Safe.
Post Reply