TorCap is a personal tool that:
- Captures screenshots on your own Windows accounts at a fixed interval.
- Sends them over Tor to your own Debian server running a private
.onionsite. - Lets you browse screenshots per Windows username and date via a simple web UI in Tor Browser.
⚠️ This is for your own machines and accounts only.
Do not use it to spy on other people or devices you do not own or control.
The design is transparent and avoids stealthy / malware-style behavior as much as possible.
Note: Tools compiled with PyInstaller often trigger generic flags such as
"Win64:Malware-gen", "Suspicious PE", or "BehavesLike.Win64.Generic".
These are false positives caused by:
-
The executable being packed into a single file
-
Screenshots being taken programmatically
-
Network communication through Tor
There are two components:
-
Server (Debian 13) –
tor_server.py- Runs a Flask web app on
127.0.0.1:5000. - Exposed via Tor as a hidden service (e.g.
xyz123.onion). - Stores screenshots on disk under a root folder, like:
/home/youruser/TorCap_data/ ├─ CiscoAnass/ │ ├─ 21-11-2025/ │ │ ├─ screenshot_20251121_000918.png │ │ └─ ... └─ AnotherUser/ └─ 22-11-2025/ - Web UI (via Tor Browser):
- Login with your admin credentials.
- See users → days → thumbnails, and click thumbnails to preview full images.
- Runs a Flask web app on
-
Client (Windows) –
app.py→TorCap.exe- Runs in the background when the user logs in (via Task Scheduler).
- Takes screenshots every N seconds (default
10). - Stores them temporarily in a local folder (e.g.
C:\Users\CiscoAnass\Pictures\Security\DD-MM-YYYY). - Periodically batches uploads to the Tor server over a SOCKS proxy (
Tor). - After a successful upload, it deletes the local screenshot.
- Enforces a max local folder size (MB) and deletes oldest non-pending files when above the limit.
Everything is configured through JSON files, no environment variables needed.
- Debian 13 (or similar Linux)
python3,python3-venv,python3-piptor- Python packages (inside a venv):
flaskgunicorn(recommended for production)
For building the EXE:
- Windows 10/11 64-bit
- Python 3.10+ (you used 3.14)
pip- Python packages (inside a venv):
mssrequestspysockspyinstaller(for building the EXE)
For running the EXE on each Windows PC:
- Only the built EXE (e.g.
TorCap.exe) - A matching
config.jsonin the same folder - Tor connectivity (typically Tor Browser or Tor service providing a SOCKS proxy on
127.0.0.1:9050or127.0.0.1:9150)
sudo apt update
sudo apt install python3 python3-venv python3-pip tor
mkdir -p ~/TorCap
cd ~/TorCap
python3 -m venv venv
source venv/bin/activate
pip install flask gunicornCopy these files into ~/TorCap:
tor_server.pyserver_config.json(you will create it in the next step)
In ~/TorCap/server_config.json:
{
"root_folder": "/home/youruser/TorCap_data",
"web_username": "anass",
"web_password": "",
"web_password_hash": "",
"upload_password": "CHANGE_THIS_UPLOAD_PASSWORD",
"site_name": "TorCap",
"session_secret": "CHANGE_THIS_SESSION_SECRET"
}root_folder– where screenshots are stored on the server.web_username– username for the web UI (Tor Browser).web_password– leave as""(we will replace it with a hashed password).web_password_hash– will be filled automatically bytor_server.py --set-admin-password(see below).upload_password– shared secret between server and Windows clients.- This must match
upload_passwordin each Windowsconfig.json. - This is used only for the upload API, not for the web UI.
- This must match
site_name– title displayed on the site.session_secret– long random string used to secure Flask sessions.
⚠️ Keep this file private. It never leaves your Debian server.
Set file permissions to restrict access (see section 8).
The admin password for the web UI is never stored in plain text.
Instead, tor_server.py can hash it and store only the hash (PBKDF2-SHA256).
From ~/TorCap:
cd ~/TorCap
source venv/bin/activate
python tor_server.py --set-admin-passwordYou will see prompts:
This will set (or reset) the ADMIN web password for the TorCap UI.
New web password: ********
Repeat web password: ********
Admin web password updated successfully.
After this, server_config.json will have something like:
"web_username": "anass",
"web_password": "",
"web_password_hash": "pbkdf2_sha256$200000$<salt_hex>$<hash_hex>",From now on:
/logincompares your typed password with the stored hash.- Even if an attacker steals
server_config.json, they do not see your raw admin password.
3.4 Configure Tor Hidden Service
Edit Tor config:
sudo nano /etc/tor/torrcAdd this at the end (if not already present):
HiddenServiceDir /var/lib/tor/TorCap_service/
HiddenServicePort 80 127.0.0.1:5000
Save and restart Tor:
sudo systemctl restart torGet your .onion address:
sudo cat /var/lib/tor/TorCap_service/hostnameExample output:
nlbsg4kl2itgwcu5g6ysikwmx77lavxb5kh2c36mg7wlmazn2332hhid.onion
This is the URL you will use in:
- Tor Browser (to access the web UI)
- Windows
config.jsonasserver_url.
cd ~/TorCap
source venv/bin/activate
python tor_server.py- Runs Flask’s built-in dev server.
- Good for quick tests, not recommended for long-term production.
cd ~/TorCap
source venv/bin/activate
gunicorn --bind 127.0.0.1:5000 --workers 3 --threads 4 tor_server:apptor_server:app= module nametor_serverand Flask objectappinside it.- Multiple workers + threads handle concurrent requests better than
app.run().
Tor still points to 127.0.0.1:5000 via:
HiddenServicePort 80 127.0.0.1:5000
Open Tor Browser and go to:
http://YOUR_ONION_HOSTNAME.onion/
Log in using web_username and the password you set with --set-admin-password.
You should see:
- A Users list (e.g.
CiscoAnass,AnassWork, etc.) - Clicking a user shows available days.
- Clicking a day shows all screenshots as thumbnails.
- Clicking a thumbnail opens a full preview modal.
You only need to do this on the machine where you build TorCap.exe.
On Windows (PowerShell):
cd C:\Users\YourUser\Desktop
mkdir TorCap
cd .\TorCap
python -m venv venv
.\venv\Scripts\activate
pip install mss requests pysocks pyinstallerCopy into this folder:
app.py(TorCap client)config.json(client config template)
Example config.json:
{
"interval_seconds": 10,
"screenshot_folder": "C:/Users/CiscoAnass/Pictures/Security",
"server_url": "http://nlbsg4kl2itgwcu5g6ysikwmx77lavxb5kh2c36mg7wlmazn2332hhid.onion",
"upload_password": "CHANGE_THIS_UPLOAD_PASSWORD",
"upload_batch_size": 10,
"max_folder_size_mb": 500,
"tor_socks_proxy": "socks5h://127.0.0.1:9050",
"log_file": "screen_guard.log"
}interval_seconds– capture interval in seconds.screenshot_folder– base folder; client will create subfolders per day (DD-MM-YYYY).server_url– your.onionaddress fromhostname(usehttp://, not https).upload_password– must matchupload_passwordfromserver_config.json(used for the upload API).upload_batch_size– how many screenshots to upload at once.max_folder_size_mb– maximum local disk usage before rotation starts deleting oldest non-pending files.tor_socks_proxy:- If Tor is running as a service: usually
socks5h://127.0.0.1:9050 - If using Tor Browser only: often
socks5h://127.0.0.1:9150
- If Tor is running as a service: usually
log_file– log file name (stored next to the EXE by default).
You can test with:
.\venv\Scripts\activate
python .\app.pyCheck screen_guard.log and your server’s root_folder to confirm uploads are working.
Use PyInstaller to build a single-file EXE with a clean, honest name (e.g. TorCap.exe):
.\venv\Scripts\activate
pyinstaller --onefile --noconsole `
--icon="C:\Users\YourUser\Desktop\TorCap\TorCap.ico" `
--name="TorCap" `
"C:\Users\YourUser\Desktop\TorCap\app.py"After it finishes, you will get:
C:\Users\YourUser\Desktop\TorCap\dist\TorCap.exe
This file is what you deploy to your Windows PCs.
You do not need Python on every PC, only the EXE + config.
On each Windows machine, choose a folder like:
C:\Program Files\TorCap\
Copy into that folder:
TorCap.execonfig.json
You can adjust config.json per machine if needed (e.g. different screenshot_folder).
- Open Task Scheduler.
- Click Create Task… (not “Basic Task” for more options if you prefer).
- General tab:
- Name:
TorCap - “Run only when user is logged on” (recommended for a transparent tool).
- Name:
- Triggers tab → New…:
- Begin the task: “At log on”
- Settings: “Any user” or a specific user (your choice).
- Actions tab → New…:
- Action: “Start a program”
- Program/script:
C:\Program Files\TorCap\TorCap.exe - Start in (optional but recommended):
C:\Program Files\TorCap\
- Click OK to save.
Now, each time that user logs in, TorCap.exe will start, capture screenshots, and upload them to your Tor server.
- On startup:
- Loads
config.jsonfrom the same directory as the EXE. - Ensures the
screenshot_folderexists. - Scans that folder for existing
*.pngfiles and treats them as pending uploads (useful when internet / Tor was down).
- Loads
- Every
interval_seconds:- Creates a folder for today:
DD-MM-YYYYinside the screenshot folder. - Captures a screenshot into
screenshot_YYYYMMDD_HHMMSS.pnginside that day folder. - Adds the new file to the pending list.
- Runs rotation if total size >
max_folder_size_mb, deleting oldest files that are not currently pending.
- Creates a folder for today:
- Upload logic:
- When
pendinglength ≥upload_batch_size, it tries to upload them toserver_url + "/api/upload"via the Tor SOCKS proxy (tor_socks_proxy). - Sends:
username– the Windows username (getpass.getuser()).day– derived from filename or file’s mtime (DD-MM-YYYY).file– the PNG screenshot.- Header
X-Upload-Password: <upload_password>.
- On HTTP 200 → deletes the local file.
- On error → keeps the file for the next attempt.
- When
-
Reads
server_config.jsonat startup. -
Stores screenshots under:
root_folder / <username> / <day> / <filename>.png -
Web UI structure:
/login→ login form (Tor only). Password is checked against a PBKDF2-SHA256 hash stored inweb_password_hash./→ list of users/user/<username>→ list of days & file counts/user/<username>/<day>→ grid of thumbnails- Clicking a thumbnail opens a full preview modal.
-
API endpoint for uploads:
POST /api/upload- Requires header
X-Upload-Passwordequal toupload_passwordinserver_config.json. - Form fields:
usernameday(optional; if empty, server uses current UTC date)file→ screenshot
- Rejects bad credentials or invalid paths with error JSON.
-
Admin web password (
/login):- Stored as a PBKDF2-SHA256 hash in
server_config.json(web_password_hash). - Set via
python tor_server.py --set-admin-password. - Never stored in plain text after that.
- Stored as a PBKDF2-SHA256 hash in
-
Upload password (
upload_password):- Shared between server and client.
- Needed so the client can authenticate to
/api/upload. - If an attacker steals
config.jsonon a Windows machine, they can impersonate that client.
This is unavoidable because the client must know the secret to use it. - Keep
config.jsonon Windows machines as private as possible (only your account, protected device).
Lock down sensitive files on Debian:
sudo chown youruser:youruser /home/youruser/TorCap/server_config.json
chmod 600 /home/youruser/TorCap/server_config.jsonSame for the data folder if you want to restrict which local users can view raw PNGs:
sudo chown -R youruser:youruser /home/youruser/TorCap_data
chmod -R 700 /home/youruser/TorCap_data- This tool is intentionally designed for personal use on your own machines:
- You own the Debian server.
- You own the Windows PCs / user accounts.
- Do not deploy it on machines you don’t own, or users you don’t have a clear agreement with.
- The client:
- Uses a clear folder (
TorCap,TorCap.exe) if you choose so. - Uses standard, legitimate persistence (Windows Task Scheduler).
- Avoids stealth techniques like hiding processes, rootkits, registry abuse, etc.
- Uses a clear folder (
- Some AV engines may flag any app that:
- Captures screens,
- Auto-starts with Windows,
- Uses Tor.
- Since this is for your own lab, the honest and safe approach is:
- Use a clear, honest program name (
TorCap.exe). - Keep the code readable and documented.
- If needed, add an exception in your own AV for this file/folder (because you trust your own code).
- Use a clear, honest program name (
- Check that screenshots are actually being created on Windows:
- Look inside
screenshot_folder(and sub-folders by date).
- Look inside
- Check that uploads succeed:
- Look at the Windows log file (
screen_guard.lognext to the EXE). - Look under
root_folderon Debian:ls -R /home/youruser/TorCap_data
- Look at the Windows log file (
- If you only see folders on disk but not in UI, ensure:
root_folderinserver_config.jsonis exactly the parent directory containing the username folders.
- Means
upload_passwordin Windowsconfig.jsondoes not matchupload_passwordinserver_config.json. - Fix both to use the same secret string.
- On Debian:
- Check Tor status:
sudo systemctl status tor
- Check Tor status:
- On Windows:
- Ensure Tor Browser or Tor service is running.
- Verify the
tor_socks_proxyinconfig.json:socks5h://127.0.0.1:9050(Tor service)socks5h://127.0.0.1:9150(Tor Browser)
- Check Windows logs for errors like “Network error while uploading …”.
- Lower
max_folder_size_mbinconfig.json. - Increase
upload_batch_sizeso uploads happen more frequently. - Make sure the server is reachable so uploads can succeed and local files are removed.
- All code and config here is intentionally simple and transparent.
- You are responsible for how you use this tool; keep it ethical and legal.
- If you expand it (tray icon, GUI, encryption, multi-user web auth, etc.), keep the same principles:
- No stealth.
- Clear configuration.
- Respect for privacy and consent.