Analysis of the backdoor found on Raspberry Pi (film, 23 minutes)
Internet Relay Chat, or IRC, is one of the oldest text-based chat systems designed for communication, and it is still used today despite decades since its inception. John Hammond, in his latest video, discusses a situation where he received an email from a user who faced an issue with their Raspberry Pi, where an unknown file appeared after an SSH session. The user had difficulty logging into their device due to a password that kept changing, preventing access. John initially specialized in malware analysis using Remnux, demonstrating how to identify the issue at hand.
The video starts with John downloading a 7-zip archive that was attached to the email. He mentions that the password for the archive is the same as its name. Upon extracting the contents, it turns out to be a bash script, which he analyzes to reveal several interesting details. John thoroughly explains how the code sets a variable to the current script path as well as the conditions surrounding user permissions and checks. Brief fragments of the code are displayed to illustrate how the malicious software obtains admin privileges.
As he continues, John describes how the malicious script implements; so-called "persistence," meaning that the code will be run again after a system reboot, which effectively means a permanent presence on the victim's machine. He highlights how the password changes and attempts to install additional tools like ZMAP reflect attack techniques used against Raspberry Pis. Additionally, it becomes evident that the victim might have unwittingly connected to multiple IRC servers, which poses a serious threat.
When diving deeper into the script's analysis, John discusses the way IRC servers are used as a command and control platform, elaborating on ping/pong confirmations, which check connectivity with the server. He also explains how the public key is used for encrypting messages for remote users, which contributes to an array of security concerns. The entire script, as revealed, resembles a malware program capable of infecting multiple devices by installing itself in the system and stalking other potentially vulnerable Raspberry Pis.
In conclusion, John notes an important aspect— at the time of writing this article, the video had 79,303 views and 1,997 likes. With so many people watching this content, his insights on malware and device security could effectively influence a broader audience, helping users understand the threats they face. Internet security is crucial, and understanding these risks can help safeguard many users from potentially malicious software in the future.
Toggle timeline summary
-
Introduction to Internet Relay Chat (IRC) as an old yet still used text-based chat system.
-
John receives an email about a suspicious file found after an SSH session on a Raspberry Pi.
-
Overview of a 7-zip archive containing a bash script related to the file.
-
The script is recognized as a bash script, not obfuscated, to be analyzed.
-
Checks if the effective user ID is not equal to zero, indicating root access.
-
Discussion of persistence in Linux through the /etc/rc.local file.
-
Explanation that the script will modify rc.local to ensure it runs on boot.
-
Indications of attempting to kill processes related to crypto miners.
-
Changing the password for the 'pi' user as part of the script.
-
Script creates a .ssh directory and stages a public key for SSH access.
-
Confirmation that the servers are IRC servers.
-
The script joins an IRC channel to receive commands.
-
Base64 encodes and decodes commands sent through IRC.
-
Culmination of the script’s command and control capabilities.
-
The script self-removes after establishing the malware's operations.
-
John concludes the overview explaining this as Raspberry Pi malware.
-
Encouragement for viewers to engage with the video content.
Transcription
Internet Relay Chat, or IRC, is one of the oldest, by decades, text-based chat systems designed for communication, but it is still used today. So I received this email, and they say, Hey John, this file was dropped on my system while I had SSH open for about 30 minutes, just to let a trusted member of a group I'm in check over a configuration file. He got kicked out of the SSH session, and every time I would log in and reset the password, it would change again on boot. I should preface, I was using the default username-password combo of Pi and Raspberry. So this is, of course, a Raspberry Pi, and they attach this file. They say, look, here is this 7-zip archive of what we saw on the system. We could download it, and we could go take a look. Now, for the sake of analysis, I'm inside of Remnux, the reverse engineering malware Linux distribution, and I have fired up a terminal with Ctrl-Alt-T, and I'll move into the directory where I have stored this file after I download it, and it is a 7-zip archive that we will go ahead and have to extract. They noted in the email that the password is the exact same as the file name, so let me 7zx to extract this, and paste in the password with Ctrl-Shift-V, and there we have it extracted. Now, it is present in my directory here, and I can go ahead and, again, run file to see a simple reconnaissance on it, and it is a bash script. So, shell commands bundled up that should be able to be ran from the command line. I can open this up in Sublime Text, and thankfully, this isn't really obfuscated. We can kind of make sense out of all of it just at first blush. First things first, we set a variable, myself, set to real path for $0. For the sake of a script that is running within bash, that is just going to be the actual, like, location of the script that's ran, and in this case, look, I'm running bash on my terminal. $0 is just simply the path of my binary. I am running bash, but had I been running a script, that would determine the path of the script. Looks like debug is set to dev null, and it is used repeatedly to store output. I'm assuming that's for logging sake, and maybe the operator will change that if they really wanted to, but for at least this case, it is currently set to dev null, or the trash can, nothing, the void, and we check if the effective user ID is not equal to 0. So, if we're not root, and if you aren't sure of that, you can normally check out your user ID based off of that $UID value, and effective user ID is if you were using, like, a setUID binary, or anything that might, like, momentarily change your user ID permissions. I'm still 1000 by the default user of this Linux system, but that will mark that logic in condition true, and then we will proceed through this block of code here. We'll set up a new myself variable, which is just simply setting up a temporary file, staged with the make temp command, given a unique format. This will actually just output the decision that it made, or the decision that it made, or the choice, what it chose to create inside of the temporary directory, this file, but it doesn't end up creating that file, it just gives you the unique name that would be used had make temp actually created that. If you wanted to, you could take a look at the man page for make temp, and that slash U will denote that. Do not create anything, but just merely print the file name. Now, note that within this condition, we tested that we are not the root user. We're not admin, we don't have super control over the system, so we have to use sudo, the super user do, to run new commands that require administrator privileges, like copying this script, again, that myself variable, into the opt directory, given the new myself variable that we just determined from that random name that make temp generated for us. We'll use this sh command with taxee to denote new commands to run, with sudo, administrative root privileges, to add a shebang line into etc.rc.local, and then the actual running script of opt new myself into etc.rc.local, and finally exit. Add that in, and just append it on into rc.local. Sleep, and then reboot. Hey, can you catch what they're doing there? That is persistence. Inside of Linux, that etc.rc.local file is one of those automatic startup scripts, or code that will run automatically once your machine turns on, and it is run as root. So that new condition, after the script runs again, after it has rebooted, as that was a previous command that we just saw, now it won't fall down into that if statement, or that block of code to stage that persistence one more time. Now let's scroll down and see what else we do. We have a new temporary directory, or a new temp file that has been created with, again, make temp, and this one will actually create the file here. If I run make temp from the command line, it'll choose this random file, but now if I try to ls this, that does in fact exist, because make temp will by default create that. Note that it's empty, but it's going to be used for the rest of the operations in the code. Add it to debug, and then we start to kill a whole lot of processes. Again, we can presume, at this point in the script, we have our root privileges, so we can do whatever we want. I have to think this is trying to kill bin s.sh, miner d, node.js, ktx. I think, is ktx a crypto miner? I'm going to assume, at least from miner d, node, and all the others, that it's likely going to be a crypto miner. Another one down here is zmap and chitin. I don't know what that is. However, part of me wonders if chitin is like a chitin coin, and a chitx or ktx is just like a miner for that. I'd have to Google, I'd have to look around and research, but that is where we are right now. And now we have a couple of longer lines, so let me go turn on WordRap, so we can see this well. But we do stage this domain, bins.dutchlandzanglungue, I'm sorry, into etc host, pointing at our own IP address local host, and then we remove our bashrc within root, and the pi user for this raspberrypis.bashrc, so their startup script invoking bash, the Linux command line, the shell. We do change the password. We do use usermod to, of course, change the password, given this string for the encrypted password for the pi user. So that must be exactly what our friend in the email that it was sent to me, it was actually experiencing. It was changing the password upon every reboot, and they were unable to get back in. Now, we could do a couple Dumbo things and maybe try to crack the password here. I don't know if I have John the Ripper inside of Remnux. Probably not. I don't know, can I install that super quick? All right, now that John the Ripper is installed, we can echo these and remove those backslashes to escape the dollar signs into like a hashes file, and then we could probably use John on those hashes, and no, it doesn't know what it's doing. Oh, I think I forgot one of those backslashes. Let me just modify that within Sublime Text, keep it easy. There we go. Will that run? Okay, cool, now it's doing its thing. I did not supply a word list here. I'm just going to let John do its thing and see if he can find anything, and we'll keep reading here, because next, we create a .ssh folder. If it does not exist, we force it with tack P of the mkdir argument and parameter inside of root's home directory, and then we stage a whole public key inside of root's ssh authorized keys, so that anyone using this public-private key pairing will be able to log in just fine. We set up Google's DNS as a name server in resolve.conf. We try to kill everything related to KTX, Kyten, and CPU miners, at least removing these with recursive enforce, and that's pretty wild. Okay, so probably trying to clean up any other logs, or artifacts, or past activity. Then we stage a public.pem file inside of the temporary directory using this here doc with cat. I'm not sure what this is going to be used for, because it's not related to ssh, it's just put in a random place, but if we see this used later, we know that it exists and we have access to it. Then we start to stage another new variable called bot, which is a little bit interesting, getting at least, again, the unique name for it, and then, ooh, writing all this code, another internal bash script inside of that bot file stored within the temp directory. This looks like where there's a lot of pretty cool meat and substance to this. Let me dive into this. What I'm going to do is I'm going to copy just about all of this, and we'll put in another Sublime Text document so we have better syntax highlighting and we can look through it. Wait just a second before we go any further. Please allow me to include some love and support for today's sponsor, Snyk. I'll be honest, I write bad code. Even though I try to hunt for vulnerabilities and lots of other software, I still have vulnerabilities even in my own projects. Everyone does. And that's why I use Snyk to scan for vulnerabilities in code, dependencies, containers, and configuration files, and Snyk helps find and fix those vulnerabilities in real time. You can try it and see for yourself. You can sign up for free with my link below. Import your repositories and sit back and let Snyk do the work for you. It'll find the flaws and vulnerabilities in your own applications. Check out this prototype pollution vulnerability that Snyk uncovered. We can see more details about the code path that introduced this vulnerability and even learn more about this kind of vulnerability or any others if you check out the Snyk Learn lesson. I've referenced the Snyk Learn lessons and their vulnerability database a ton, especially in assessments and penetration testing and even during Capture the Flag competitions. From there, you can see an explanation of the flaw, proof-of-concept exploit code and attack demonstrations, and most importantly, how to mitigate this vulnerability. But the best part? Snyk helps you fix this vulnerability with a single click. It'll automatically open a pull request so you can just merge and move on. So seriously, check out Snyk. It's crazy how many vulnerabilities could be affecting your projects and you don't even realize. Take advantage of their resources and learning material and learn all about the different vulnerabilities out there. It's completely free and you can sign up right now with my link in the video description. Huge thanks to Snyk for sponsoring this video. Okay, so now we have copy and pasted that innermost script, the bash syntax and code that we saw being staged in that temporary bot file. And it looks like they set up another variable here, sys, using these backticks for command substitution. And they actually get uname-tack-a with a MD5 some hash and cutting it up a little bit. Okay, to remove the trailing hyphen at the end of it. Looks like John the Ripper hasn't gotten anything, but let me open up another terminal and we can see what that sys command would do. It looks like it'll just give us a hash based off of our uname-tack-a representation. Then we define a nick, which is a based off of a portion of this variable here. Oh, we didn't store that variable, so that doesn't retrieve it for me. Let me paste both of these in and now let's echo what my nick would be. So we have something that looks like that. Just maybe an identifier or name for our victim. Now take a look. We define a couple of domains. Looks like domain names inside of an array variable or ARR, to note an array. And then we get a random value, mod 6, so it's going to be 0 through 5 or any of these possible choices. And then define a server, svrSet, to that random index chosen for our array. So we get a random domain here. Now, I actually want to see if I can stage these, because what they do, and they use this eval function or eval command so that it will go ahead and just run the following line of code as if it were real code, as it is. But they set up a connection. They set up a sort of a socket, open and close connection where they can communicate with this thing like you would with Netcat or Telnet or however you want to imaginate that. Choosing the server that was randomly chosen. And then this port number 6667, number of the beast. And they set that to a file descriptor as number 3. Now, that's kind of peculiar, because I'm sure they're going to use this as a socket that they can open and interact with and play with. But that means that they just connect to one of these domains on that port 6667. So let's see if we can do that too. Let me paste in all of those arrays. And yeah, proxy, whatever, I know, safe, research, et cetera. But if I were to loop through each of them, can I do like a for i in array? And you have to use this weird syntax in Bash to actually display every iteration of those. Let me just validate that I'm doing that with a simple Dumbo sanity check. Echo $i. Okay, now I have successfully looped through them. What we could do is actually try to use Netcat on that host. And then 6667 as the port that we were going to. Let me actually make sure that I do echo out $i so we know where we're going and which will respond and which don't. And then let me just let it happen. Oh, what? Okay. Notice looking at your host name, checking out, found your host name. What is this? Notice auth? What is that? Let me just Google this super duper quick. Notice auth, found your host name. Notice when connecting to an IRC server. Oh, it's an IRC server. Oh, oh, oh, all of those are. Maybe? I mean, yeah, I guess the domains look like the dot format for IRC servers. What if I actually looped through those and just did a simple timeout? Because it's probably trying to wait for me to respond to it and interact with this IRC server as a client. So if I had to timeout one second, that way I'll be able to see, hey, this is what it does, and then it'll move forward to the next one. Every single one of them is an IRC server. Okay, so we're staging an IRC server set up as a file descriptor that we can interact with. We've determined our nick variable. And oh, we literally use that as a nickname for ourself in the IRC server. Like we connect in as the bot, right? And then we send that to our three file descriptor. If that did not succeed, and we continue because the dollar sign question mark is the return status of the exit code of the previous running command. If that is not equal to zero, which means that it failed, because zero means success, then we continue onward. We set our user, user eight, IRC high, whatever. Again, we check if that succeeded or not. But then a main loop, we read in with eval, read message in from dollar sign three. So this is Bash. This is the Bash syntax to take an input, store it in this variable message in, all coming from our three file descriptors. So what the server sent back to us. If we do not get any message, then we break. But otherwise, we'll check if that message in matches ping. Now, this tilde character, super important within Bash, is like a regular expressions match. So if it has the word ping in it, then we stage pong with a string formatted as our message in five onwards, because that index within Bash will actually take an offset and then move to the very, very end of it. So pong to acknowledge that we received that, printf pong with our message, and it's actually sending back to the server. Let me turn WordRap back on. Yeah, that's sent back to the server, the IRC channel communications. So that's just a heartbeat. That's just making sure that it's alive. And then ultimately, we join a biret channel, or bi-ret. I don't know how exactly that should be read. But that must be the specific channel designated for the sort of command and control for this little Raspberry Pi trojan and malware here. That's kind of neat, because then you could check, look, if there is a private message, if the message in matches with regular expressions, our priv message, then we get h, which is cut up here. We get the data that is cut up again by this colon delimiter, and then the nick. So presumably, who sent this to the server? Who sent this to the IRC channel, and who is actually tasking this specific bot here? We stage a couple of variables for a hash and a sign. I'm assuming a signature or something. Oh, actually using the public key that we saw earlier. Oh, that must be how they're like correlating, hey, this is the victim that we're targeting or using, because the sign should equal hash based off of the private message data and the private message that thing. Is it encrypted? Is it encrypting what would otherwise be like plain text values within IRC? That's wild and crazy. Literally using IRC as command and control, because if these match, then the command or CMD value is actually taking Base64 data, decoding it, decoding this Base64 data that's included in the private message, and then running it with res, a variable set as like the result or the response, where we use bash to actually run the command, command encoding the data back into Base64 so that we can send it back to the IRC bot. That's again what our eval printf, including it in the response, sent to our file descriptor number three here. That's so cool. Like it's literally IRCC2. Now, that is the end of the main loop, which looks like it is just using this channel byret in the side of IRC with a nickname to identify every single victim or target, and then doing the regular RAT, remote access trojan, command and control stuff, where it can task every single victim or agent. Now, back to the original script, after we've written all this to our temp bot file, we mark it executable, we start it running in the background with nohub, and then we remove the nohub log, so we don't have any artifacts of that, remove nohub out, give it a little bit of time to run, and then remove the bot code from disk. RMTACRF will stop this script from being present on the file system. It'll clear that artifact, but it's still going to be running because it got started with nohub. Cool. Now, we set up another variable for name, which is again just a randomly generated make temp value, but not created. We store the date into temp.s, and we install ZMAP and SSH pass. ZMAP is like a super duper fast, like one port focus NMAP, so significantly faster than NMAP, but it's only going to target one given port. An SSH pass will be used to automatically supply a password to an SSH connection within the command line, and we see the syntax down below, it looks like. In another while true loop, we set up a file, make temp, which is randomly created in the temporary directory, use ZMAP to find any open port 22, so SSH sessions that write it to the file with N1000, is that number of threads in ZMAP? I'm not sure. And while it's doing this portion of the loop, because it looks like there's an inner for loop, but it will kill any open SSH or SCP processes that are running. But inside of this for IP cat file, where it's outputting everything that ZMAP would have found, I think just looking across the internet, like trying to go find other potentially vulnerable and open SSH connections, we use SSH pass with our password raspberry, again, the default raspberry password, with connect timeout, number of password prompts equals one, preferred location password, blah, blah, blah, arguments for SSH, but ultimately we'll end up trying to copy SCP, the myself script. So this script, the malicious malware, bash, whatever, logging to the Pi username at the IP address that we saw on the file, temp name. Okay, so it is putting itself onto this other system that it found, and these ampersands will denote a new command. So we can probably actually just for easability reading sake, let's clean that up. But all this ends with a ampersand. So it's kind of going to be ran in the background and try to like multi-thread that sort of thing. We add the IP address into an op directory of probably our records of like what we've seen, and then we try to SSH pass raspberry into that victim, that new found open SSH prompt. So maybe somewhere out on the internet is another raspberry Pi with a default password that has not been changed because ultimately we'll end up using that connection to move into the temp directory, modify the script to be ran as an executable, and then invoke it. That's pretty crazy and wild. Following that, they use this SSH pass again to use raspberry raspberry 993311, which is probably that password hash that we saw just a bit ago. Like if I move back up here, that's got to be this. That's got to be our user mod password here. Maybe that's why John the Ripper hasn't found anything. We could validate that, but I don't think we need to right now. I'm curious what they do after this. Same sort of setup. I'm going to remove these double ampersands, but they are going to end up doing the exact same things. Oh, so I wonder if it's even on ones that they've already compromised. That's odd to me, but maybe I'm just not understanding. I would love to get your hot take in the comments. What am I missing there? But that's it. It removes itself, sleeps for 10 seconds, and it's done. It's already staged the little Trojan and the RAT and command and control server with this loop that they build out into the temp bot. But man, I think that's pretty wild. Like literally using IRC, internet relay chat, as the sort of RAT, remote access Trojan, command and control server, and they can task the victim target agents, which is, as you saw, like that simple bash syntax. That's literally it. And it is self-propagating from this loop in the beginning, or the end here. Note that they're using ZMap to go find other victims from the victim they've already compromised to go beat up, change passwords, gain access, all across the internet. That's so wild. Now, when I went Googling for some of those things that I just didn't recognize, like KTX PowerPC, there were a whole lot of articles and a certain amount of, you know, real threats, viruses, people already chatting about this thing. Someone actually even shared this exact sample that was sent to me in an email, but sorry, bright lights. I know a dark theme has gone away, but take a look at this. This is a Medium article that's chatting about IRC uses the connection here, and it's literally the exact same code. They're using this as screenshots. Did they do any further analysis? Yeah, okay, cool. Basically everything that I've just said aloud. And they set this up as a honeypot. So that's kind of slick. And we could probably do the very, very same. And this was in August of 2022. So maybe about a year ago. This one, I see another article written about, where's the date on this? Okay, that blog was written in June of 2020, but they linked the article that was like, well, 2017. So this is old. Look, I cannot credit and say whatever this new groundbreaking thing. I'm sure a lot of folks probably already know about this, but it's interesting that it's the exact same thing. And the email that we got was just last week. This individual shared the raw source over on GitHub in a gist here. And I can maybe share that or if you can see it, but that is, I don't know. It's Raspberry Pi malware. This poor fellow asking, what is this? It's Raspberry Pi malware. Hey, thanks so much for watching everybody. I hope you enjoyed this video. I know it was a little bit of a long verbose one, as it tends to be when we start to look through code and chat about each and every little bit here. But I hope maybe you learned something and you had some fun. If you did, please do all those YouTube algorithm things, like, comment, subscribe. If you would be willing, you'd be phenomenal. If you could join the channel as a member, that helps support. Or if you want to try any other avenues, there are PayPal and Patreon links. Anything can kind of keep the channel growing. But with that, I'll see you in the next one. Thanks.