For my Zeek Roulette #2 I picked a recently submitted sample off of ANY.Run that ended up being Amadey:
https://app.any.run/tasks/31ba58da-30d1-4a08-940d-2412fc629221/
You can download the PCAP from the link above if you navigate to the “PCAP” button in the upper right corner of the lower network connections pane.
If you want to just get to the code, you can find it here:
https://github.com/keithjjones/zeek-amadey-detector
I did some online research to see if anyone has published the C2 protocol. Luckily, a Blackberry blog did just that! According to the blog, Amadey sends C2 information over the clear text HTTP protocol via a POST. The blog lists the C2 fields Amadey will send over the HTTP POST:
Key | Value |
id | Identification. Computed based on Volume Serial Number. |
vs | Amadey version (1.09 for these samples) |
ar | If victim user has administrative privilege, the value is 1. Otherwise, it is 0. |
bi | “1” for 64 bit. “0” for 32 bit. |
lv | Install additional malware if the value is 0. |
os | OS version. (e.g., Windows 7 is 9). |
av | If there is no antivirus product, it is 0. Otherwise, it is assigned to a number in Table 1. |
pc | Computer name from GetComputerNameA |
un | User name from GetUserNameA |
If you open the PCAP in Wireshark and Follow the TCP stream for the HTTP connection, you will see the following data:
POST /joomla/index.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: 212.113.119.255
Content-Length: 87
Cache-Control: no-cache
id=896776584425&vs=3.70&sd=5d3738&os=9&bi=1&ar=0&pc=USER-PC&un=admin&dm=&av=0&lv=0&og=1
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 04 May 2023 16:35:21 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
6
<c><d>
0
GET /joomla/Plugins/cred64.dll HTTP/1.1
Host: 212.113.119.255
HTTP/1.1 404 Not Found
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 04 May 2023 16:36:11 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.18.0 (Ubuntu)</center>
</body>
</html>
GET /joomla/Plugins/clip64.dll HTTP/1.1
Host: 212.113.119.255
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 04 May 2023 16:36:11 GMT
Content-Type: application/octet-stream
Content-Length: 91136
Last-Modified: Fri, 14 Apr 2023 17:01:49 GMT
Connection: keep-alive
ETag: "643986fd-16400"
Accept-Ranges: bytes
MZ......................@............................................. .!..L.!This program cannot be run in DOS mode.
The data continues for the PE file, but I truncated the output above. The key line in this output that we will try to detect is:
id=896776584425&vs=3.70&sd=5d3738&os=9&bi=1&ar=0&pc=USER-PC&un=admin&dm=&av=0&lv=0&og=1
This line matches the fields listed in the Blackberry blog.
We can try to detect this line using 2 methodologies:
You can make a Zeek signature to catch this string with the following logic:
signature amadey {
ip-proto == tcp
payload /.*application\/x-www-form-urlencoded.*\nid=[0-9]+&vs=[0-9\.]+.*&os=[0-9]+.*&pc=.*&un=.*/
eval Amadey::match
}
But, in my opinion, this is limited because if the “un” field comes before “pc” field this signature will miss it.
Another, and in my opinion better, option to detect this malware is to handle the http_entity_data event:
… and search for the string in the “data” field. Do note that if you have a lot of HTTP on your network, this could add significant CPU load on your sensor. Only you can accurately weigh if this logic is worth the CPU to detect Amadey on your network.
The logic for the detector is fairly simple. While most of main.zeek is boilerplate code to create logs and notices, the meat of the logic lies here:
event http_entity_data(c: connection, is_orig: bool, length: count, data: string)
{
if (/id=[0-9]+/ in data &&
/&vs=[0-9\.]+/ in data &&
/&os=[0-9]+/ in data &&
/&bi=[01]/ in data &&
/&ar=[01]/ in data &&
/&pc=/ in data &&
/&un=/ in data)
{
# This is probably Amadey!
hook set_session(c);
c$amadey$payload = data;
c$amadey$is_orig = is_orig;
emit_log(c);
NOTICE([$note=Amadey::Amadey,
$msg=fmt("Potential Amadey C2 between source %s and dest %s", c$id$orig_h, c$id$resp_h),
$conn=c,
$identifier=cat(c$id$orig_h,c$id$resp_h)]);
}
}
This logic tests each field in the HTTP data using consecutive “ands”. If one of the anded conditions fails, processing stops. In this case, Amadey was not detected.
An example amadey.log for a detection in the PCAP we downloaded earlier from ANY.Run is:
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path amadey
#open XXXX-XX-XX-XX-XX-XX
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p is_orig payload
#types time string addr port addr port bool string
XXXXXXXXXX.XXXXXX C9rXSW3KSpTYvPrlI1 192.168.100.64 49200 212.113.119.255 80 T id=896776584425&vs=3.70&sd=5d3738&os=9&bi=1&ar=0&pc=USER-PC&un=admin&dm=&av=0&lv=0&og=1
#close XXXX-XX-XX-XX-XX-XX
As you can see, the payload here matches the payload in the PCAP we downloaded earlier. This proves we detected Amadey and we also get to see the data it sent!
Sources:
- https://app.any.run/tasks/31ba58da-30d1-4a08-940d-2412fc629221/#
- https://blogs.blackberry.com/en/2020/01/threat-spotlight-amadey-bot
- https://www.virustotal.com/gui/file/121c452418772be07136bd8d273006783bc52db49c317a962901cce0ee3818a8/details
Transcript:
[00:00:00]
[00:00:08] Keith: Hey, welcome. Today we are going to talk about detecting Amadey malware with Zeek. And this is my second Zeek Roulette where I just picked something on the internet interesting, hopefully interesting, and try to solve it with Zeek. So in this case, I just picked a piece of malware off of any.run, and I looked at some research online and some C2 communication.
[00:00:36] And I came up with a couple of detections, so I thought I would share it with you. All right, so what I’m gonna do is take you to my blog post and you’re seeing a draft version of my blog post. So it might look a little different once you actually go to it once I’ve published this video. But what I wanted to show you was the process I went through to understand this piece of malware and to write a detection for it in Zeek.
[00:01:02] Now, this is my blog here and I gave you the link to the Any.Run URL where you can go and actually look at all this research outside my blog, and in there on the lower pane there’s a network connections pane, and there’s a little word that says Pcap up in the upper right hand corner. If you click on that, you can download the same PCAP that I used in this example, if you’d like to follow along.
[00:01:33] If you want to just get to the code, well, I’ve got that for you too here. And I’m showing you with my cursor. You just go into my GitHub repository and I’ve got all the scripts there for you. But I’ve pulled out all the relevant parts into this blog article, so that way I can walk you through it and we can understand it.
[00:01:53] So once I downloaded the Pcap and I took a look at it, I immediately tried to see if anybody else had done work on trying to understand the C2 protocol. Blackberry threat research, they published a blog article about how they picked it apart. And one of the subsections of that blog article is the C2 protocol.
[00:02:16] So it’s really helpful for us. So what I did was, took a look at their article, so you didn’t have to, you don’t have to dig into the weeds. And basically it says that the Amadey. Malware sends an HTTP post with some fields. Okay. And it’s not, the fields aren’t embedded in the URL directly or the headers or anything like that.
[00:02:45] It’s actually in the body of the HTTP. And I’m gonna show you that. I’m gonna show you the network capture of the follow TCP stream, if you think of it in wireshark terms, so that you can see what this actually looks like. So in a nutshell, the way the C2 works is it fills out fields in a form and sends it across an http.
[00:03:14] Now, the fields were documented by Blackberry, and I re documented them here in this table that you see, and I link to their blog down here and I’ve got a link in the sources section at the bottom as well. And there’s a bunch of fields in here and there’s a few fields that I noticed when I looked at a pcap that seems like they always will be in there.
[00:03:37] One of them’s gonna be the ID field. That is the identification volume, serial number, basically when this malware infects your computer and it checks in to its command and control center, it’s gonna identify itself, and that’s what’s filled out here in this ID field.
[00:03:58] And I’m, I realize I’m pointing in its exact opposite way on video.
[00:04:04] I’ll never learn.
[00:04:06] But anyways, there’s a couple other fields in there that are of interest. There’s the vs, which is the version, and that’s the Amadey malware version. There’s the ar, which is whether or not you have administrative privileges, if it’s run under administrative privileges or not. There’s this BI and LV and both of that can be a one or a zero and it says whether or not this is a 64 bit, a 32 bit, or the LV says install additional malware. The OS version is given and that is in the OS field. The antivirus, if it’s installed, is given . It’s a number that corresponds to a table in the Blackberry blog of the different types of antivirus that can be on a computer.
[00:04:53] Now, two other interesting ones are the pc, which is the computer name, and the un, which is the username. Okay, so knowing this, we should look for these fields to see if the Amadey malware is communicating via its C2 protocol across the network. That’s what we’re gonna do here in theory.
[00:05:18] Now what I wanna show you is if you open that pcap that I talked about earlier in Wire Shark and you do the tcp, the follow TCP stream on the HTTP connection, you’re gonna get something like I’m showing you in your window right now. This is the post that I told you about, and I’m not so sure if Joomla index is all that important.
[00:05:41] That’s probably something that can be changed very easily by the malware. So I did not try to key on that. But down here where I highlight now, you can see the actual string with all the fields in it. So in theory, we watch for this type of string to go across a network. And if we see it, we alert on it.
[00:06:12] Now, I’m just gonna show you more down here, and I did a little more research into it, and I’m gonna tell you, I’m not an expert on this malware. I’m just trying to show you a good network defense detection. But if you go into Blackberry’s article, they talk about what the command and control center can respond with and so forth.
[00:06:32] And this is the response, which actually means something. But when I tried to match it up at the Blackberry article, it didn’t match up exactly. So I’m not really sure if this is because it’s a different strain of malware or if something’s broken when this malware was run on any run, but it didn’t match up exactly even though the structure kind of looks like what we expect.
[00:06:58] Now down here you can see it tries to get this cred 64 dll, and it says 4 0 4 not found, and then it changes the case and you can see that it’s now found and it’s an octet stream. And if you’ve done any type of malware analysis, and you look at this beginning of the string and you go, Hey, that looks like a Windows executable, especially with this big phrase right here that says Cannot be run in DOS mode.
[00:07:33] And you say, Hey, it looks like over HTTP, an executable was grabbed, which is what you’d expect in some type of malware C2 communication. It doesn’t happen all the time, but when you get other stages to the malware, and it looks like in this case there was another stage possibly given to it, this is how it’s typically done.
[00:07:58] All right, and I’ll just note that I truncated the output. It’s a lot longer than that. So the key line was this, and I highlighted it for you here because this whole phrase, this is what we’re gonna be searching for.
[00:08:15] Okay, so I sat back and I was like, all right, how if I could pick out the ways that I could solve this realistically with Zeek, what would I code up?
[00:08:27] And I came up with two general methods. The first one is just using Zeek’s signatures. Zeek’s signatures are limited. Now, it only searches the first 1024 bytes, but, from what I’ve read about this malware strain, it continues to beacon this string. So you’d expect it to end up pretty close to the beginning of these connections.
[00:08:52] So that’s saying Zeek signatures, maybe we could use that to do a type of a detection. So set that aside for a second. The other way we can do it is by handling the HTTP events. And there’s this one called HTTP Entity Data that actually gives you the body data that we just saw on that follow TCP stream.
[00:09:18] So I’m gonna show you two different methods of doing this. One that would work in theory. And then the other one that I would probably run for myself in practice. So the one that would work in theory is the Zeek signatures and that is probably the simplest way of going about this. Now, I gave you the signature here and I said, we’re looking on the TCP protocol.
[00:09:44] We’re looking for this payload. Okay? And it’s actually a regular expression here. And what I did is I went back to my follow TCP stream and I said, okay, well we are gonna expect this form URL encoded. That’s something that appears this malware does is it sends it across in this encoding, and then I look for a new line and then I start looking for things that could be in that phrase, like this id, I said It has to be a digit, and the plus says any size digit, and then you have the ampersand, the VS is the version, and you’re looking for a version here, which could have a dot in it and it could be any size.
[00:10:31] And then here’s where things kind of get hairy. I say there’s gonna be some stuff in here because these malware variants aren’t gonna all send the same fields all the time in all the same order. So we gotta code this so that we can try to hit the most variants of the Amadey malware. So what I said is there can be stuff in here, other fields that we may not know about, that somebody may have coded into other variants.
[00:11:00] But what I wanna see is an OS version, which we talked about in our table, which is just a number. We wanna see the PC and the ampersands are part of it. We wanna see the PC and we wanna see the username. And I did put a catchall in between the OS and the PC and the username here to just give you some more leeway if there’s other fields in there.
[00:11:27] And then I say, okay, anything at the end, and the PC and the username are pretty freeform, so I left that as just anything as well. So you can see. Now, let me back up for a second. This will call a function inside Zeek. Now I’m gonna tell you right now we’re not gonna use Zeek’s signatures, so we’re not actually calling this, so you’re not gonna see it in main.zeek, I’m just telling you, if you were to go about it this way, this is how I would do it. I would make a function in there and I would call it through the signature. Now, what I wanna say is this, when I sat there and thought about it, yeah, it would hit on the PCAP that we found, but we don’t know what it will miss that would be valid Amadey malware C2 traffic. Things could be different. Like for instance, we could have fields that were flip flopped, you know, the username and the PC could be flip flopped and we wouldn’t catch it with this Zeek signature because of the way we had to code it. We’re not, we had to give it all one regular expression.
[00:12:35] And with that comes some order and with order comes some constraints on what we’re gonna be able to find. So, with that, I said, all right, if I want to get the most amount of detections of this Amadey malware, what would I do? I would probably look in the http data and I would then look for specific fields in that data, sort of like the signature, but I’d be a little looser in my matches so I could get more variance of this malware.
[00:13:07] Now what I wanna do is tell you about a better option, in my opinion, to detect this malware using this event handler. And I gave you the link. If you don’t know what this is, I gave you the link to the instructions so you can actually go there and see what the Zeek Project says about it. But, what I wanna do is basically there’s one field that comes into this event called data, and it is the data, and we’re gonna search this data for our fields using regular expressions.
[00:13:45] What I want to tell you though, is do note that every HTTP session and every entity in that session is being sent through this event. So you wanna use this event very, very sparingly. In my case, I’m trying to show you the two different ways you can go about detecting this malware.
[00:14:06] So in some networks, this may cause a lot of CPU usage, and I can’t even tell you what quote unquote a lot means because it just depends on the networks, how you have your cluster set up and so forth.
[00:14:21] So what I’m saying here is I’m putting a big red warning sign that says, do know when you run this logic, and we’re looking at all the content of HTTP sessions that go across. This can be taxing on your sensor and do know that you may decide the CPU load is just not for you, and you don’t care about the Amadey malware at all, so you don’t wanna run this.
[00:14:46] Other people, they may really care a lot about this, and they will give up the CPU cycles in order to be able to run this. So with that said, I try to do as little computation as possible in this event because it’s gonna be called many, many, many, many times.
[00:15:06] Now, the logic is actually fairly simple and I just cut out. There’s a lot of boiler plate stuff in the code to make logs and so forth. So I just wanted to cut out the event handler and show you the guts of this detection and it’s on your screen right now. And you can see this is the event that we are handling.
[00:15:28] It’s just this one of the standard Zeek events. We didn’t have to do anything fancy to get it. And what we do is we have a giant if statement. And what that if statement does is the first part of the IF statement, which I’ll highlight for you. Now here, this looks for the ID in data. If that matches, if it’s in there, if it’s true, the two ampers hand says, okay, go compute the next thing.
[00:16:01] Which is, let’s find the ampersand vs in there. If that is true, let’s look for the next field, which is the os. If that’s true, then we look for the bi, the ar, the pc, and the un.
[00:16:18] Now, why this is different than our Zeek signature is this gets rid of order, so, for instance, if it finds the ID first, cuz that’s what it looks like, it always gets sent first here, we have then a Vs that it’s searching for, right? Let’s say the variant tried to be tricky and it goes, ah, I’m gonna put the OS before the Vs. So that way if people are looking for things in certain order, this is gonna break it. Well, the Zeek code I’m showing you right now will detect it because what it’s doing is it’s simply looking for the field in the data.
[00:17:01] Okay? And we’re giving up computation because we have to handle the HTTP entity data event. We’re giving up computation in order to be more inclusive of more variants of this Amadey malware.
[00:17:18] Okay, and I may change this. I was thinking maybe instead of doing an in, I do a carrot there and actually look for the ID at the beginning. I’ll ponder whether or not I change it. Maybe it’ll be a little different by the time you see this video, but you get the, the gist of what I’m trying to say here. Right?
[00:17:38] All right, so, First thing I’m gonna do is if we have a detection, so we’re inside the IF statement now, if we have a detection, I’m gonna set my session, which is, this is just boiler plate. It sets the info record on the connection record so we can then start to save data and make it into logs and stuff.
[00:18:01] This is a pretty common Zeek methodology.
[00:18:04] Now what I do in the next line is I take the data that came in up here. See up here where I’m moving my mouse? Well, we’re taking that data and we’re slapping it into our Amadey dot log payload field. So I’m making a brand new log and there’s a payload field, and the payload’s gonna have whatever was sent across the C2 that we detected.
[00:18:33] And then so we know which way the connection happened, I’m gonna save the is_orig in there as well. And then once it’s saved, we just emit it. So like I said, this is very, very simple logic.
[00:18:46] Now another thing I’m gonna do is we are in the IF statement, so we’re assuming we’ve seen the malware. At this point, I’m gonna also fire a notice.
[00:18:55] So we get this notice in our notice log as well because some investigators like it in the notice log and some investigators like it in its own log. Me, I personally like it in its own log, so that’s why I made an Amadey dot log to do more analysis deeper rather than just seeing something in the notice log.
[00:19:18] It’s a hotly debated to topic in the Zeek community, I’m sure.
[00:19:23] All right, so what I did is I explained why I use all these different, and it basically cuts down on processing cuz if any one of those ands fails, the rest of ’em aren’t computed. So here’s an example Amadey dot log. And this came from the tests that’s why you see a bunch of X’s in there. But you can see the Pcap, when I ran it through, it picked up on this connection. And lo and behold, we have that string that Amadey sends out for its C2 protocol. We detected it and it’s in our log, so that way we can actually, as an investigator now look at the same data that the C2 control panel is getting from these malware infections on the network we’re monitoring.
[00:20:14] That’s it, and you’ll see that I put sources in here. So all this stuff that I talked about, you can go through here and click it. And I obviously can’t put it in now because I’m recording, but it will have a transcript of this video as well. So, you can search for things very quickly or if you have difficulty hearing, you can read this instead of having to watch a video.
[00:20:38] That’s all I got to say. I hope you catch us on the next video soon. Thanks. Bye.
[00:20:44]
#zeek #opensource #cybersecurity #amadey #malware
Leave a Reply