ransomwatch trails the extortion sites used by ransomware groups and surfaces an aggregated feed of claims
please use the issue template when submitting new groups
content within ransomwatch.telemetry.ltd
, posts.json
, groups.json
alongside the docs/
& source/
directories is dynamically generated based on hosting choices of real-world threat actors in near-real-time.
whilst sanitisation efforts have been taken, by viewing or accessing ransomwatch you acknowledge you are doing so at your own risk
if you leverage ransomwatch in commercial platforms, please consider becoming a sponsor π
web://
ransomwatch.telemetry.ltd
json://
ransomwhat.telemetry.ltd/posts
json://
ransomwhat.telemetry.ltd/groups
groups.json
contains hosts, nodes, relays and mirrors for a tracked group or actorposts.json
contains extracted posts, noted by their discovery time and accountable group
this is a live repository that utilizes a combination of GitHub actions and a service container. it visits, parses, and reports on monitored hosts in near-real-time in a self-contained manner
content fetching is done with psf/requests - if rendering is required mozilla/geckodriver and seleniumhq/selenium are leveraged.
The frontend is ultimately generated with markdown, using markdown.py and served with docsifyjs/docsify thanks to pages.github.com
graphs or visualisations are generated with plotting.py with the help of matplotlib/matplotlib
post indexing is done with a mix of grep
, awk
and sed
within parsers.py - it's brittle and like any Μ΄ΜΜHΜΆΜ€ΜTΜΈΜΜ
MΜΆΝΜΎLΜ·ΝΝ
Μ΄ΜΜpΜΈΜ‘ΝaΜ·ΜΜ¦rΜ΅Μ¬ΜΏsΜ΄ΜΝΔ©Μ΄ΜΊnΜΈΜΝgΜΈΜΜ, has a limited lifetime.
rendered HTML for each page is viewable within the source directory
- screenshotter.py a playwright script to generate high-resolution screenshots of online hosts
- srcanalyser.py a basic extractor for emails, internal and external links found within page source
- browse-hosts.sh a simple cURL based iterator for sweeping URL checks
- sources.zsh an aggregator of various locations that surface new groups for ransomwatch
- uptimekuma-importer.py a script to convert the group data into a uptime-kuma configuration file
- parsers.sh a health-check script that provides details on parsers that are returning no fields
a flattened version of groups.json with each host as its own object can be found at assets/groups-kv.json. the structure is an array of objects, each representing a distinct entity/group with each containing all properties (like name
, captcha
, parser
, etc.) at the same level, including potential repetition on elements such as profile
and meta
. some data analysis tools work with this structure in an easier manner requiring less transposing.
fetching hidden services requires a tor circuit! establish one with;
docker run -p9050:9050 ghcr.io/joshhighet/torsocc:latest
usage: ransomwatch.py [-h] [--name NAME] [--location LOCATION] {add,scrape,parse,markdown}
positional arguments:
{add,scrape,parse,markdown}
operation to execute
optional arguments:
-h, --help show this help message and exit
--name NAME provider name
--location LOCATION target web location (full URI)
_______________ |*\_/*|________
| ___________ | ||_/-\_|______ |
| | | | | | | |
| | 0 0 | | | | 0 0 | |
| | - | | | | - | |
| | \___/ | | | | \___/ | |
| |___ ___| | | |___________| |
|_____|\_/|_____| |_______________|
_|__|/ \|_|_.............π.............._|________|_
/ ********** \ / ********** \
/ ************ \ π π¦
ransomwatch / ************ \
-------------------- --------------------
newly indexed posts can be sent to discord by providing a DISCORD_WEBHOOK
var when running parse
.
DISCORD_WEBHOOK=https://discord.com/api/webhooks/xxxxx/xxx ./ransomwatch.py parse
![](https://private-user-images.githubusercontent.com/17993143/240205717-53226d1e-475b-4e80-8af5-727c153e6b4c.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM5NTU5MjcsIm5iZiI6MTcyMzk1NTYyNywicGF0aCI6Ii8xNzk5MzE0My8yNDAyMDU3MTctNTMyMjZkMWUtNDc1Yi00ZTgwLThhZjUtNzI3YzE1M2U2YjRjLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MTglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODE4VDA0MzM0N1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTc0MDU0NmMyZjE3NjhmYjVjNzBkNmZlZGJkOGUzNzlkZTcyMjJiN2U4MjFhZDI2YzFjZDM1YjVhNTI2MTdiNWQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.RnnJSnelDh5L_3mAXfltxtDTa0KFzWT9myPpbCTsVn0)
erDiagram
groups_json ||--|{ group : contains
group {
string name "group name"
boolean captcha "captcha status"
boolean parser "parser status"
boolean javascript_render "javascript status"
string meta "freeform text"
string url "notable articles and references"
}
group ||--|{ locations : has
locations {
string fqdn "fully qualified domain name"
string title "page title"
int version "hidden service version"
string slug "full URI"
boolean available "availability status"
datetime updated "timestamp of last update"
datetime lastscrape "timestamp of last scrape"
boolean enabled "status"
}
group ||--|{ post : references
post {
string post_title "post title"
string group_name "associated group name"
datetime discovered "timestamp of discovery"
}
curl -sL ransomwhat.telemetry.ltd/posts \
| jq -r '.[] | select(.group_name == "lockbit3") | .post_title' \
| tail -n 10
curl -sL ransomwhat.telemetry.ltd/groups \
| jq -r '.[] | .locations[] | select(.available == true) | .slug'
curl -sL ransomwhat.telemetry.ltd/groups \
| jq -r '.[] | select(.name == "lockbit3")'
curl -sL ransomwhat.telemetry.ltd/posts \
| jq -r '.[] | [.group_name, .post_title] | @tsv' \
| sed 's/ /_/g' | column -t | tail -n 20
ransomwatch is licensed under unlicense.org