This commit is contained in:
2025-05-15 02:34:51 +01:00
commit 2ef6b6fcd0
5 changed files with 443 additions and 0 deletions

174
.gitignore vendored Normal file
View File

@@ -0,0 +1,174 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# Ruff stuff:
.ruff_cache/
# PyPI configuration file
.pypirc

73
app.py Normal file
View File

@@ -0,0 +1,73 @@
from __future__ import annotations
from flask import Flask, render_template
import subprocess
from time import sleep
app = Flask(__name__)
def extractAsciiFromDump(dump: [str]) -> [str]:
res = ""
for line in dump:
res += line.split("|")[-1].strip()
return res
usingPm3 = False
@app.route('/api/uid')
def uid():
'''
Read the UID of a visible ISO-14443A card.
'''
uid = None
global usingPm3
while usingPm3:
sleep(0.1)
usingPm3 = True
try:
output = subprocess.check_output(["proxmark3", "/dev/ttyACM0", "-c", "hf 14a read"], text=True, stderr=subprocess.DEVNULL).split("\n")
for line in output:
if "UID: " in line:
uid = line[line.index("UID: ")+4:].strip()
break
except Exception as e:
print(repr(e))
finally:
print(uid)
usingPm3 = False
return {
"uid": uid
}
@app.route('/api/sector/<sector>')
def sector(sector):
'''
Read a sector from a visible Mifare Classic card.
'''
dump = None
global usingPm3
while usingPm3:
sleep(0.1)
usingPm3 = True
try:
output = subprocess.check_output(["proxmark3", "/dev/ttyACM0", "-c", f"hf mf cgetsc -s {sector}"], text=True, stderr=subprocess.DEVNULL).split("\n")
for i, line in enumerate(output):
if "--> hf mf cgetsc -s " in line:
dump = extractAsciiFromDump(output[i+4:])
break
finally:
usingPm3 = False
return {
"dump": dump
}
@app.route('/')
def index():
return render_template("door.html",
allowed_ids={
# "44 61 76 65": ["Welcome CEO", [(3, "I am a very important CEO so open this door now!.........i......")]],
"44 61 76 65": ["Welcome CEO<br/></br>flag{yep_big_boss}", []], # CEO
"3C 36 6A 22": ["The site manager would like to see you in their office. Please speak to APO Grove, and tell him the cleaner sent you.<br/></br>flag{ooh_a_manager}", []], # Developer
"2F 92 5D B2": ["Thanks for doing our cleaning! I found a card on a desk earlier. It has a label saying \"UID: 3C 36 6A 22\". Not sure what to do with it.<br/></br>flag{another_lost_card}", []], # Cleaner
})
app.run(host='127.0.0.1', port=8080)

70
app_2.py Normal file
View File

@@ -0,0 +1,70 @@
from __future__ import annotations
from flask import Flask, render_template
import subprocess
from time import sleep
app = Flask(__name__)
def extractAsciiFromDump(dump: [str]) -> [str]:
res = ""
for line in dump:
res += line.split("|")[-1].strip()
return res
usingPm3 = False
@app.route('/api/uid')
def uid():
'''
Read the UID of a visible ISO-14443A card.
'''
uid = None
global usingPm3
while usingPm3:
sleep(0.1)
usingPm3 = True
try:
output = subprocess.check_output(["proxmark3", "/dev/ttyACM1", "-c", "hf 14a read"], text=True, stderr=subprocess.DEVNULL).split("\n")
for line in output:
if "UID: " in line:
uid = line[line.index("UID: ")+4:].strip()
break
except Exception as e:
print(repr(e))
finally:
print(uid)
usingPm3 = False
return {
"uid": uid
}
@app.route('/api/sector/<sector>')
def sector(sector):
'''
Read a sector from a visible Mifare Classic card.
'''
dump = None
global usingPm3
while usingPm3:
sleep(0.1)
usingPm3 = True
try:
output = subprocess.check_output(["proxmark3", "/dev/ttyACM1", "-c", f"hf mf cgetsc -s {sector}"], text=True, stderr=subprocess.DEVNULL).split("\n")
for i, line in enumerate(output):
if "--> hf mf cgetsc -s " in line:
dump = extractAsciiFromDump(output[i+4:])
break
finally:
usingPm3 = False
return {
"dump": dump
}
@app.route('/')
def index():
return render_template("door.html",
allowed_ids={
"44 61 76 65": ["Welcome CEO<br/></br>flag{open_them_all}", [(3, "I am a very important CEO so open this door now!.........i......")]], # CEO
})
app.run(host='127.0.0.1', port=8081)

1
requirements.txt Normal file
View File

@@ -0,0 +1 @@
Flask==3.1.0

125
templates/door.html Normal file
View File

@@ -0,0 +1,125 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Smart Door Lock</title>
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<style>
body {
font-family: 'Arial', sans-serif;
background-color: #f0f0f0;
margin: 0;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
#lockContainer {
text-align: center;
background-color: #fff;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
#lockIcon {
font-size: 60px;
color: #3498db; /* Default color for locked icon */
}
#idCardStatus {
margin-top: 20px;
}
p {
margin: 0;
font-size: 18px;
color: #555;
}
p.accessGranted {
color: #2ecc71;
}
p.accessDenied {
color: #e74c3c;
}
</style>
</head>
<body>
<div id="lockContainer">
<div id="lockIcon">&#128274;</div>
<div id="idCardStatus">
<p>Waiting for card...</p>
</div>
</div>
<script>
var requestInProgress = false;
var currentUid = null;
const checkIdCardContents = async (sector, requiredContents) => {
const data = await fetch("/api/sector/" + sector);
const dump = (await data.json()).dump;
console.log(dump === requiredContents);
return dump === requiredContents;
};
const checkIdCardStatus = () => {
fetch("/api/uid").then(async (data) => {
const uid = (await data.json()).uid;
if (uid === currentUid) {
setTimeout(checkIdCardStatus, 0);
return;
}
currentUid = uid;
if (uid) {
const item = {{allowed_ids|tojson}}[uid];
if (item === undefined) updateStatus("Access Denied - ID: " + uid, "accessDenied", "&#128274;"); // Change to locked icon
else if (item[1].length > 0) {
updateStatus("ID: " + uid, "", "&#128274;", "<b>Reading card, please wait...</b>");
let contentsCorrect = true;
for (let sectorInfo of item[1]) {
if (!(await checkIdCardContents(...sectorInfo))) {
contentsCorrect = false;
break;
}
}
if (contentsCorrect) {
updateStatus("Unlocked - ID: " + uid, "accessGranted", "&#128275;", item[0] + "<br/></br><b>Card contents correct</b>");
} else {
updateStatus("Access Denied - ID: " + uid, "accessDenied", "&#128274;", "<b>Card contents incorrect</b>");
}
} else {
updateStatus("Unlocked - ID: " + uid, "accessGranted", "&#128275;", item[0]);
}
} else {
updateStatus("Waiting for card...", "", "&#128274;"); // No loading icon
}
setTimeout(checkIdCardStatus, 0);
}).catch((err) => {
console.log(err);
updateStatus("Error occurred while checking ID card status.", "", "&#128274;"); // No loading icon
setTimeout(checkIdCardStatus, 0);
});
}
const updateStatus = (status, className, icon, message = '') => {
$("#idCardStatus").html("<p class='" + className + "'>" + status + "</p>");
if (message != '') {
$("#idCardStatus").append("<br/><p class='" + className + "'>" + message + "</p>");}
$("#lockIcon").html(icon);
};
// Initial check when the page loads
checkIdCardStatus();
</script>
</body>
</html>