{
	"id": "5809d04b-fd02-474a-90f9-7b939e578a58",
	"created_at": "2026-04-06T00:09:14.085551Z",
	"updated_at": "2026-04-10T03:21:38.059981Z",
	"deleted_at": null,
	"sha1_hash": "21742f2bde5bb2069271c7705404ee476e9de615",
	"title": "Hunting Koadic Pt. 2 - JARM Fingerprinting",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 66384,
	"plain_text": "Hunting Koadic Pt. 2 - JARM Fingerprinting\r\nPublished: 2020-11-28 · Archived: 2026-04-05 18:44:37 UTC\r\nA year ago, I looked into Koadic C2, a post-exploitation tool used by APTs and Pentesters alike.\r\nAt the time, I was able to fingerprint all non-fronted Koadic C2 servers across the internet, due to mismatches in\r\nit’s 404 page, where it fails to make the server look like a benign Apache web server.\r\nKoadic hasn’t had many updates in the last 12 months, but in the meantime Salesforce have released JARM, a\r\nmethod of fingerprinting TLS Servers. According to Salesforce, it works by querying the server in various ways to\r\ngather information about things such:\r\nOperating system\r\nOperating system version\r\nLibraries used\r\nVersions of those libraries used\r\nThe order in which the libraries were called\r\nCustom configuration\r\nI wanted to revisit Koadic, and see if JARM would be able to pick up the C2 server as good as or better than my\r\n404 analysis.\r\nStep 1. Get Koadic’s JARM\r\nKoadic C2 is written in Python, so already what OS we run it on will have an impact on it’s JARM signature. But\r\nI decided to run it on an Ubuntu server, as that was probably a common place it was deployed.\r\nFirst I started a Koadic Server, making sure to run it over HTTPS:\r\n# First Create TLS keypair for the websever\r\n# enter a password and enter defaults for everything else\r\nsudo apt-get install openssl git python3 python3-pip\r\nopenssl req -x509 -newkey rsa:4096 -days 365 -keyout koadic-key.pem -out koadic-cert.pem\r\n# Clone Koadic and install dependecies\r\ngit clone https://github.com/zerosum0x0/koadic.git\r\ncd koadic\r\npip3 install -r requirements.txt\r\n# Start Koadic and run the server in in HTTPS mode:\r\n./koadic\r\nset SRVHOST 127.0.0.1\r\nset SRVPORT 8000\r\nhttps://blog.tofile.dev/2020/11/28/koadic_jarm.html\r\nPage 1 of 4\n\nset KEYPATH ../koadic-key.pem\r\nset CERTPATH ../koadic-cert.pem\r\nrun\r\nThen I grabbed the JARM tools from SalesForce and calculated my server’s fingerprint:\r\ngit clone https://github.com/salesforce/jarm.git\r\ncd jarm\r\npython3 jarm.py 127.0.0.1 -p 8000\r\nMy Result:\r\nJARM: 2ad2ad0002ad2ad00042d42d000000ad9bf51cc3f5a1e29eecb81d0c7b06eb\r\nStep 2. Search for JARM Fingerprint\r\nShodan is currently looking to implement JARM fingerprinting, but it doesn’t do so currently.\r\nThankfully, Silascutler on Twitter recently did an internet scan and generated JARM fingerprints from all hosts\r\nlistening on port 443.\r\nThis isn’t going to see all servers, but it’s a place to start, so I grabbed their archive and looked for our JARM\r\nsignature:\r\n# First got a sample of the data to find the format\r\nzcat 202011-443_fingerprint.json.gz | head -n 10 \u003e sample.json\r\n# Format was very simple and 1 event per line, so can just use zgrep\r\n# Keep data gzipped in case there are lots of hits\r\nzgrep '\"fingerprint\":\"2ad2ad0002ad2ad00042d42d000000ad9bf51cc3f5a1e29eecb81d0c7b06eb\"' 202011-443_fingerprint.js\r\n# Get a count of the number of entries\r\nzcat koadic_filtered.json.gz | wc -l\r\nWhen I ran the last line, it listed 16,268 hits of our fingerprint 😐\r\nSo Why didn’t this work?\r\n16,000 hits is way too high a number to be all Koadic servers, so I did some investigation into why I got so many\r\nfalse positives. I grapped the IP addresses from the first 10 entries in the list:\r\n# Get the first 10 entries in plain text\r\nzcat koadic_filtered.json.gz | head -n 10 \u003e possible_koadic.json\r\nhttps://blog.tofile.dev/2020/11/28/koadic_jarm.html\r\nPage 2 of 4\n\n# jq is a great tool to pretty-print JSON from the commandline\r\n# but if you don't have it you could also just use cat/vin/notepad\r\n# and strain your eyeballs for a bit\r\ncat possible_koadic.json | jq -r '.ip'\r\nAnd then just looked up these IP addresses in Shodan. Our data might be slightly stale, but hopefully it can give us\r\nsome indication as to what went wrong.\r\nThe data from Shodan starts to paint a picture of what has happened: A number of the IP addresses returned\r\nheaders like the following:\r\nServer: Python/3.8 aiohttp/3.6.2\r\nServer: Python/3.8 aiohttp/3.7.1\r\nServer: Python/3.8 aiohttp/3.6.1\r\nWe know Koadic C2 is written in Python, so it is possibly just running the default Python web server, which\r\nwould mean the fingerprint is not Koadic’s, but Python’s.\r\nSure enough, we can create a simple Python TLS Server using the inbuilt http.server :\r\nfrom http.server import HTTPServer, BaseHTTPRequestHandler\r\nimport ssl\r\nhttpd = HTTPServer(('localhost', 8000), BaseHTTPRequestHandler)\r\nhttpd.socket = ssl.wrap_socket (httpd.socket,\r\n keyfile=\"koadic-key.pem\",\r\n certfile=\"koadic-cert.pem\", server_side=True)\r\nprint(\"Stating Server https://localhost:8000\")\r\nhttpd.serve_forever()\r\nBy running that code, then running JARM, we get the exact same fingerprint:\r\nJARM: 2ad2ad0002ad2ad00042d42d000000ad9bf51cc3f5a1e29eecb81d0c7b06eb\r\nConclusion\r\nJARM definitely looks to be an interesting addition to the TLS Fingerprinting suite, alongside the client\r\nfingerprinting tool JA3. But it won’t pick up all malicious servers.\r\nOn top of this example of a known-bad server using language defaults to look benign, the more common issue\r\nwill be that a lot of C2 servers sit behind legitimate web server reverse-proxies, such as Apache HTTPd or NGinx.\r\nhttps://blog.tofile.dev/2020/11/28/koadic_jarm.html\r\nPage 3 of 4\n\nThis means the JARM fingerprints will match only the legitimate outer layer, and not the C2 server’s fingerprint\r\nthat sits behind the legitimate servers.\r\nSource: https://blog.tofile.dev/2020/11/28/koadic_jarm.html\r\nhttps://blog.tofile.dev/2020/11/28/koadic_jarm.html\r\nPage 4 of 4",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://blog.tofile.dev/2020/11/28/koadic_jarm.html"
	],
	"report_names": [
		"koadic_jarm.html"
	],
	"threat_actors": [],
	"ts_created_at": 1775434154,
	"ts_updated_at": 1775791298,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/21742f2bde5bb2069271c7705404ee476e9de615.pdf",
		"text": "https://archive.orkl.eu/21742f2bde5bb2069271c7705404ee476e9de615.txt",
		"img": "https://archive.orkl.eu/21742f2bde5bb2069271c7705404ee476e9de615.jpg"
	}
}