Yeah I have come across the wordlists for 3-7 letter words that could be combined to create a dictionary, however as others have discovered the possible keyspace is still huge. I had a bit of time over the weekend to play with the data, and I am happy to report that I made some progress! With a little more data collection/processing I should be able to generate all of the Serial numbers based on MAC address. Without an algorithm, it isn’t super exciting... but it does allow me to at least validate the MAC and serials I collect are accurate since the characters 0 8 B all look similar in blurry photos. If we ever do discover the algorithm, the serial number could likely be part of it.
Here’s my analysis...
I noticed that there seemed to be a pattern in the last digit of the MAC address, with many ending in 0/8, or 4/C especially when grouped together by serial number. So I separated the data by MAC address using the first 3 octets (ie B8.F8.53.XX.XX.XX), and then combined the last 3 octets (ie DD.4A.98) removed the decimals (DD4A98) and converted the hex to decimal value (14502552). This gave me a numerical value for the MAC that I could plot vs the serial number. We can see there is a very strong correlation, but we can’t accurately calculate the serial number.
![[Image: attachment.php?aid=1242]](https://hashcat.net/forum/attachment.php?aid=1242)
To try to determine the relationship, I kept the serial numbers sorted in order. Then I took the hex2dec and serial number of one entry, and subtracted it from the next. I then took the (Mac difference / Serial difference). Seeing the same whole digit pop up several times gives us a clue that we’re on to something!
![[Image: attachment.php?aid=1243]](https://hashcat.net/forum/attachment.php?aid=1243)
However, there are still several entries that don’t make any sense at all. I tried to look at the serial numbers individually, but there were huge jumps that didn’t seem explainable. I fed the data to our favorite AI, and it couldn’t make much sense of it either. However, it did suggest that perhaps the digits 21 in all of the serial numbers (E302120090812958) was a date code. I investigated this a little bit, but it didn’t seem to work out. Eventually I broke the digits into smaller numbers, which then allowed me to recognize there is a date code, just in a slightly different spot! The format is 2-digit year, 2 digit month, 2 digit day starting on the 6th character (E302120090812958 = 09/08/2020). I was able to verify this because the month spot is never greater than 12, the day spot is never greater than 31 and is only 31 on months that have that many days, and the years are between 19-23. The first 5 characters in the serial always stay the same, so that leaves us with the last 5 digits as the incremental serial (E302120090812958). With this information in hand, I sorted the list by date codes, and everything starts to line up more. The number 8 that shows up is how many steps there are between MAC addresses, so if the MAC is 3C.BD.C5.42.22.50, the next address in the sequence will be 3C.BD.C5.42.22.58. Using this information, I can actually back calculate the starting MAC address for each date code if we assume each block starts @ 00000 serial. Once all of the starting blocks are calculated, we can calculate the end of the previous block by subtracting 1 step. The E3200 MACS step by 6 digits instead of 8, some of the earlier g3100 jump by 11. Several of the ending blocks stop on seemingly non-random numbers, which is another clue that we're on the right track. I have gone though and done this for the 3C.BD.C5 MACs I have on hand, and ended up covering most of the address space. I was also able to identify and correct several places where the MAC or Serial was slightly off in my original data set (and validated using the saved photos)
![[Image: attachment.php?aid=1244]](https://hashcat.net/forum/attachment.php?aid=1244)
With this bit of success, I created a python script to calculate the serial based on a given MAC. There are still a few “UNKNOWN” blocks when there seems to be a large gap of MACs between blocks. I will work on adding the other MAC prefixes, so that we can enumerate all possible devices. I also stopped on serial 00001 earlier instead of 00000. I am still not sure which is correct honestly. Eventually I will correct them all to 00000 add code to detect these edges and give you both Serials. If you test the code, please report back. If you want to give me a MAC address and have me try to guess the serial I can. Otherwise, I have another batch of recently scraped images that I still need to validate and add to the database. I will be testing these on the script. My next post should have an updated data set!
Here’s my analysis...
I noticed that there seemed to be a pattern in the last digit of the MAC address, with many ending in 0/8, or 4/C especially when grouped together by serial number. So I separated the data by MAC address using the first 3 octets (ie B8.F8.53.XX.XX.XX), and then combined the last 3 octets (ie DD.4A.98) removed the decimals (DD4A98) and converted the hex to decimal value (14502552). This gave me a numerical value for the MAC that I could plot vs the serial number. We can see there is a very strong correlation, but we can’t accurately calculate the serial number.
To try to determine the relationship, I kept the serial numbers sorted in order. Then I took the hex2dec and serial number of one entry, and subtracted it from the next. I then took the (Mac difference / Serial difference). Seeing the same whole digit pop up several times gives us a clue that we’re on to something!
However, there are still several entries that don’t make any sense at all. I tried to look at the serial numbers individually, but there were huge jumps that didn’t seem explainable. I fed the data to our favorite AI, and it couldn’t make much sense of it either. However, it did suggest that perhaps the digits 21 in all of the serial numbers (E302120090812958) was a date code. I investigated this a little bit, but it didn’t seem to work out. Eventually I broke the digits into smaller numbers, which then allowed me to recognize there is a date code, just in a slightly different spot! The format is 2-digit year, 2 digit month, 2 digit day starting on the 6th character (E302120090812958 = 09/08/2020). I was able to verify this because the month spot is never greater than 12, the day spot is never greater than 31 and is only 31 on months that have that many days, and the years are between 19-23. The first 5 characters in the serial always stay the same, so that leaves us with the last 5 digits as the incremental serial (E302120090812958). With this information in hand, I sorted the list by date codes, and everything starts to line up more. The number 8 that shows up is how many steps there are between MAC addresses, so if the MAC is 3C.BD.C5.42.22.50, the next address in the sequence will be 3C.BD.C5.42.22.58. Using this information, I can actually back calculate the starting MAC address for each date code if we assume each block starts @ 00000 serial. Once all of the starting blocks are calculated, we can calculate the end of the previous block by subtracting 1 step. The E3200 MACS step by 6 digits instead of 8, some of the earlier g3100 jump by 11. Several of the ending blocks stop on seemingly non-random numbers, which is another clue that we're on the right track. I have gone though and done this for the 3C.BD.C5 MACs I have on hand, and ended up covering most of the address space. I was also able to identify and correct several places where the MAC or Serial was slightly off in my original data set (and validated using the saved photos)
With this bit of success, I created a python script to calculate the serial based on a given MAC. There are still a few “UNKNOWN” blocks when there seems to be a large gap of MACs between blocks. I will work on adding the other MAC prefixes, so that we can enumerate all possible devices. I also stopped on serial 00001 earlier instead of 00000. I am still not sure which is correct honestly. Eventually I will correct them all to 00000 add code to detect these edges and give you both Serials. If you test the code, please report back. If you want to give me a MAC address and have me try to guess the serial I can. Otherwise, I have another batch of recently scraped images that I still need to validate and add to the database. I will be testing these on the script. My next post should have an updated data set!
Code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
from datetime import datetime
# Your MAC ranges data
mac_data = """
3C.BD.C5.00.00.00:3C.BD.C5.01.F5.6A,G3100,8,Unknown
3C.BD.C5.01.F5.70:3C.BD.C5.09.3B.F8,G3100,8,121011516659
3C.BD.C5.09.3C.00:3C.BD.C5.0C.30.38,G3100,8,121030100001
3C.BD.C5.0C.30.40:3C.BD.C5.16.4A.C8,G3100,8,121021700001
3C.BD.C5.16.4A.D0:3C.BD.C5.1C.C1.58,G3100,8,121031200001
3C.BD.C5.1C.C1.5E:3C.BD.C5.22.C3.EA,G3100,8,Unknown
3C.BD.C5.22.C3.F0:3C.BD.C5.2B.5B.E8,G3100,8,121033100001
3C.BD.C5.2B.5B.F0:3C.BD.C5.31.1E.60,G3100,8,121041400001
3C.BD.C5.31.1E.66:3C.BD.C5.37.5C.92,G3100,8,Unknown
3C.BD.C5.37.5C.98:3C.BD.C5.3D.D3.40,G3100,8,121051800001
3C.BD.C5.3D.D3.48:3C.BD.C5.42.22.58,G3100,8,121060700001
3C.BD.C5.42.22.60:3C.BD.C5.46.3E.C4,G3100,8,121062200000
3C.BD.C5.46.3E.CC:3C.BD.C5.47.F6.C4,G3100,8,121071300000
3C.BD.C5.47.F6.CC:3C.BD.C5.49.AE.C4,G3100,8,121072100000
3C.BD.C5.49.AE.CC:3C.BD.C5.50.05.44,G3100,8,121070100000
3C.BD.C5.50.05.4C:3C.BD.C5.56.95.D4,G3100,8,121072000000
3C.BD.C5.56.95.DA:3C.BD.C5.60.3B.72,E3200,6,121072000000
3C.BD.C5.60.3B.74:3C.BD.C5.69.B8.CC,G3100,8,121081100000
3C.BD.C5.69.B8.D4:3C.BD.C5.71.07.FC,G3100,8,121082000000
3C.BD.C5.71.08.00:3C.BD.C5.76.8D.C8,G3100,8,121082600000
3C.BD.C5.76.8D.CC:3C.BD.C5.7D.27.9C,G3100,8,121090800000
3C.BD.C5.7D.27.A2:3C.BD.C5.85.4C.98,G3100,8,Unknown
3C.BD.C5.83.03.D4:3C.BD.C5.85.4C.9E,E3200,6,121091600001
3C.BD.C5.85.4C.A4:3C.BD.C5.8C.CB.C6,E3200,6,Unknown
3C.BD.C5.8C.CB.CC:3C.BD.C5.93.FF.8C,G3100,8,121101500000
3C.BD.C5.93.FF.92:BD.C5.93.9B.67.6C,G3100,8,Unknown
3C.BD.C5.9B.67.72:3C.BD.C5.A1.71.B2,G3100,8,121110500000
3C.BD.C5.A1.71.BA:3C.BD.C5.A3.FE.1C,E3200,6,121110500001
3C.BD.C5.A3.FE.22:3C.BD.C5.AD.16.64,E3200,6,Unknown
3C.BD.C5.AD.16.6A:3C.BD.C5.AE.AE.2E,E3200,6,122010100001
3C.BD.C5.AE.AE.34:3C.BD.C5.B4.2D.5E,E3200,6,121122100000
3C.BD.C5.B4.2D.62:3C.BD.C5.B5.09.9A,G3100,8,122021400000
3C.BD.C5.B5.09.A2:3C.BD.C5.B5.E5.9A,G3100,8,122031000000
3C.BD.C5.B5.E5.A2:3C.BD.C5.B8.0B.9A,G3100,8,122031100000
3C.BD.C5.B8.0B.A2:3C.BD.B8.C1.ED.A2,G3100,8,122031500000
3C.BD.C5.C1.ED.A4:3C.BD.C5.C2.40.1E,E3200,6,122031300000
3C.BD.C5.C2.40.24:3C.BD.C5.C2.89.E0,E3200,6,122031400000
3C.BD.C5.C2.89.E6:3C.BD.C5.CD.A1.1A,E3200,6,Unknown
3C.BD.C5.CD.A1.20:3C.BD.C5.CF.39.86,E3200,6,122052200000
3C.BD.C5.CF.39.8C:3C.BD.C5.D2.C8.06,E3200,6,122091400000
3C.BD.C5.D2.C8.0C:3C.BD.C5.D3.41.F2,E3200,6,122091500000
3C.BD.C5.D3.41.F8:3C.BD.C5.DA.E1.12,E3200,6,Unknown
3C.BD.C5.DA.E1.18:3C.BD.C5.DD.EE.80,E3200,6,122110900000
3C.BD.C5.DD.EE.86:3C.BD.C5.E5.83.8A,E3200,6,Unknown
3C.BD.C5.E5.83.90:3C.BD.C5.E8.44.B0,E3200,6,123011000000
3C.BD.C5.E8.34.96:3C.BD.C5.E8.44.B6,E3200,6,123030400000
3C.BD.C5.E8.44.BC:3C.BD.C5.F1.11.4A,E3200,6,Unknown
3C.BD.C5.F1.11.50:3C.BD.C5.F1.E1.E2,E3200,6,123042100000
3C.BD.C5.F1.E1.E8:3C.BD.C5.F4.B3.C2,E3200,6,123042600000
3C.BD.C5.F4.B3.C8:3C.BD.C5.F8.7A.CA,E3200,6,123052000000
3C.BD.C5.F8.7A.D0:3C.BD.C5.F9.F9.FE,E3200,6,123080600000
""".strip().splitlines()
# Helper to convert MAC string to integer
def mac_to_int(mac):
return int(mac.replace(".", ""), 16)
# Helper to extract the last 3 octets as integer
def last_3_octets_to_int(mac):
return int(mac.replace(".", "")[-6:], 16)
def format_date_from_serial(serial):
if serial.lower() == 'unknown' or not serial.isdigit():
return "Unknown"
try:
year = int(serial[1:3])
month = int(serial[3:5])
day = int(serial[5:7])
# Normalize year
year += 2000 if year < 100 else 0
date = datetime(year, month, day)
return date.strftime("%m-%d-%y")
except Exception:
return "Invalid"
def calculate_serial(mac_input):
mac_input_clean = mac_input.upper().replace(":", ".").replace("-", ".")
mac_value = mac_to_int(mac_input_clean)
mac_last = last_3_octets_to_int(mac_input_clean)
for line in mac_data:
mac_range, model, step_str, serial_start = line.split(",")
mac_start_str, mac_end_str = mac_range.split(":")
step = int(step_str)
mac_start_val = mac_to_int(mac_start_str)
mac_end_val = mac_to_int(mac_end_str)
if mac_start_val <= mac_value <= mac_end_val and serial_start != "Unknown":
mac_start_last = last_3_octets_to_int(mac_start_str)
delta = (mac_last - mac_start_last) // step
calculated_serial = str(int(serial_start) + delta).zfill(12)
date_str = format_date_from_serial(calculated_serial)
return {
"Given MAC": mac_input_clean,
"Start MAC": mac_start_str,
"Calculated Serial": calculated_serial,
"Model": model,
"Date": date_str
}
return {"error": "MAC not found in any known range or serial unknown."}
# Main loop
if __name__ == "__main__":
user_mac = input("Enter a MAC address (e.g., 3C:BD:C5:09:3C:12): ")
result = calculate_serial(user_mac)
if "error" in result:
print(result["error"])
else:
for k, v in result.items():
print(f"{k}: {v}")