Challenge Link: Silent Authenticator Tools Used: IDA Pro, CyberChef, and Reverser.space for collaborative reverse engineering.

Introduction

Welcome to my writeup for the Silent Authenticator challenge from Malops.io. In this challenge, we are tasked with reverse engineering a trojanized Linux Pluggable Authentication Module (PAM) (pam_unix.so). The objective is to uncover its hidden backdoor mechanisms, credential harvesting logic, and persistence methods.

To tackle this binary, I used Reverser.space, which provided a seamless environment for collaborative reverse engineering, allowing for synchronized function renaming, variable type mapping, and dynamic analysis. Below is a step-by-step breakdown of our analysis, detailing the answers to all 35 challenge questions.


Question 1

The malware hides sensitive strings using encryption. By analyzing the decryption function, what is the single-byte XOR key stored at offset 0x00 in each encrypted string table entry? 0x**

First, we need to locate the string encryption function. Starting from the exported function pam_sm_authenticate, we can see a function (FUN_001032a0) that takes an index and accesses a data structure at DAT_0030c042. We can rename this function to mw_string_enc, with param_1 as the index and param_2 as the out_buffer.

The disassembly shows the calculation lVar4 = (ulong)index * 0x10;, meaning the offset size for each entry is 0x10 (16 bytes). By looking at the data at DAT_0030c042, we can see that the first byte (which serves as the base XOR key) is 0x54.

Answer: 0x54


Question 2

The decryption function calculates the table entry offset by shifting the index. What is the shift value used in the ‘shl’ instruction to multiply the index by the entry size? *

The shift value can be found in the instruction SHL RDI, 0x4 at address 0x1032aa. A logical left shift by 4 is mathematically equivalent to multiplying by 16 (0x10), which matches the 16-byte size of the string entry structure.

Answer: 0x4


Question 3

Each encrypted string entry contains a pointer to the actual encrypted data. At what byte offset within the 16-byte entry structure is this pointer located? *

By reversing the memory layout, we can define the C structure as follows:

struct StringEntry // sizeof=0x10
{
     uint8_t base_key;         // Offset 0
     uint8_t padding1;         // Offset 1
     uint16_t length;          // Offset 2
     uint32_t padding2;        // Offset 4
     char *encrypted_text;     // Offset 8
};

According to this structure, the pointer to the encrypted text is located at byte offset 8.

Answer: 8


Question 4

The string length field is stored as a 16-bit value within each entry. At what byte offset is the length field located in the entry structure? *

Based on the StringEntry structure defined in the previous question, the 16-bit length field is located at byte offset 2.

Answer: 2


Question 5

Analyzing the encrypted strings table, how many total encrypted string entries does the malware store? *

By examining the data section at DAT_0030c040, we can count exactly 7 consecutive StringEntry blocks defined in memory.

Answer: 7


Question 6

The first encrypted byte of the backdoor password. What is this encrypted byte value? 0x**

The encryption logic retrieves the base key from the structure and XORs it with the character’s index to generate a rolling key. The pseudocode looks like this:

int i = 0;
do {
    uint8_t current_key = entry->base_key ^ i; 
    out_buffer[i] = entry->encrypted_text[i] ^ current_key;            
    i++;
} while (i < entry->length); 

Using this CyberChef recipe, we can replicate this logic by supplying the encrypted hex array and applying a rolling XOR with the base key 0x54 and an index byte array. The first encrypted byte evaluates to 0x6d.

Answer: 0x6d


Question 7

What is the hardcoded master password that bypasses authentication for any user? **************

After decrypting the first string entry (Index 0), the resulting plaintext reveals the hardcoded backdoor password.

Answer: 97@I7OEaF*5a92


Question 8

What libc function does the malware call to compare the user-supplied password against the decrypted backdoor password? ******

We can trace the output buffer of the first string decryption call (mw_string_enc with index 0, yielding the master_passwd). Following the cross-references to this buffer reveals a call to strcmp(master_passwd, local_58);, where the user-supplied password is compared to the master password.

Answer: strcmp


Question 9

Before checking the backdoor password, the malware retrieves the username using a PAM API function. What is the name of this function? ***_***_****

The malware calls pam_get_user to retrieve the target username attempting to authenticate. This is a standard Linux PAM API function.

Answer: pam_get_user


Question 10

After decrypting string index 2, what is the full file path where the malware stores harvested credentials? /***/***/.***.***

Decrypting the string at index 2 yields the hidden file path where the backdoor logs harvested usernames and passwords.

Answer: /usr/bin/.dbus.log


Question 11

Before writing credentials, the malware encodes them as hexadecimal. What sprintf format specifier is used for this hex encoding? %**

By tracing the file writing operations for index 2 (/usr/bin/.dbus.log), we observe the malware iterating through the password bytes and formatting them using sprintf with the %2X specifier, which converts the string into uppercase hexadecimal format.

Answer: %2X


Question 12

The credential log uses a specific format string for entries. What is the prefix text that appears before the encoded username in each log entry? ***** **************->

By examining the hardcoded strings passed into the logging format function, we can see the exact prefix used for every log entry.

Answer: error ServiceUnknown->


Question 13

What separator string appears between the encoded username and encoded password in the log format? *

Looking at the full format string error ServiceUnknown->%s : %s\n, the separator between the first %s (encoded username) and the second %s (encoded password) is a colon surrounded by spaces, but the core punctuation mark is the colon.

Answer: :


Question 14

When opening the credential log for writing new entries, what fopen mode string is used? *

The fopen call uses the mode "a" (opened_stream = fopen(filename: write_filename__1, modes: "a");). This opens the file in append mode, ensuring existing logs are not overwritten.

Answer: a


Question 15

After decrypting string index 3, what is the full path to the legitimate file used as a timestamp reference? /***/***/id

Decrypting the string at index 3 reveals the path to a legitimate system binary. The malware uses this file’s timestamp to disguise its own malicious files (timestomping).

Answer: /usr/bin/id


Question 16

After decrypting string index 4, what Unix command is used to copy the timestamp from the reference file? (First word only) *****

Decrypting the string at index 4 provides the full command: touch -r /usr/bin/id /usr/bin/.dbus.log. The first word is the Unix utility used to modify file timestamps.

Answer: touch


Question 17

The timestamp manipulation command uses what flag to reference another file’s timestamp? -*

From the decrypted command touch -r /usr/bin/id /usr/bin/.dbus.log, the -r (reference) flag is used to apply the timestamp of /usr/bin/id to the log file.

Answer: -r


Question 18

What is the full path to the hidden directory where the malware looks for scripts to execute? /***/*****/.*******/

Decrypting the string at index 1 reveals the hidden directory path where the malware searches for additional payloads to run.

Answer: /var/spool/.network/


Question 19

What libc function is called to open the hidden directory for reading its contents? *******

The malware uses the standard libc directory stream function opendir to open the /var/spool/.network/ directory.

Answer: opendir


Question 20

What libc function is called in a loop to iterate through each file in the hidden directory? *******

Inside the opendir loop, the malware continuously calls readdir to iterate through all the files present in the hidden directory.

Answer: readdir


Question 21

The malware checks the d_type field to identify regular files. What decimal value indicates a regular file (DT_REG)? *

The code checks the d_type field of the dirent structure. It compares it against the decimal value 8, which corresponds to the DT_REG macro in C (indicating a regular file).

Answer: 8


Question 22

After decrypting string index 5, what Unix utility is prepended to commands to run them detached from the terminal? *****

Decrypting the string at index 5 reveals the utility used to run dropped scripts in the background, ignoring hangup signals.

Answer: nohup


Question 23

After decrypting string index 6, what is the full output redirection string appended to executed commands? >/***/**** *>&* &

Decrypting the string at index 6 reveals the standard output redirection payload appended to the command to suppress output and run it as a background job.

Answer: >/dev/null 2>&1 &


Question 24

What libc function is used to execute the constructed command string containing nohup and the script path? ******

After concatenating nohup, the script path, and the redirection string using sprintf, the malware passes the resulting buffer to the standard libc function system for execution.

Answer: system


Question 25

Before logging credentials, the malware checks if it has root privileges. What libc function returns the effective user ID? *******

To verify if the compromised process currently has root privileges (which allows for stealthier logging and execution without permission errors), the malware calls geteuid.

Answer: geteuid


Question 26

What return value from geteuid indicates the process is running as root? *

In Unix-like systems, a return value of 0 from geteuid() indicates that the process is running as the root user.

Answer: 0


Question 27

What libc function is called to check if the credential log file already exists before writing? ******

Before attempting to read or append to the credential log, the malware verifies the file’s existence and permissions using the access libc function.

Answer: access


Question 28

What is the name of the main PAM export function that contains all the backdoor logic? pam_sm_************

The core backdoor logic is injected directly into the standard PAM authentication routine. Throughout this process, we have been reverse engineering this specific exported function.

Answer: pam_sm_authenticate


Question 29

How many PAM module functions (pam_sm_*) are exported by this malicious module? *

By looking at the Export Address Table (EAT) of the compiled shared object, we can see exactly 6 standard PAM Service Module (pam_sm_*) functions exported by this library.

Answer: 6


Question 30

What string identifier is passed to pam_set_data to store the authentication return value? ****_*******_******

We can observe a call to pam_set_data used to store state or credential pointers. The string identifier passed into this function is clearly visible in the decompiled code.

Answer: unix_setcred_return


Question 31

What PAM internal data identifier string is used when prompting for and storing the user’s password? -UN**-****

When wrapping the PAM prompt mechanism to grab the password, the malware uses a specific internal identifier string (visible in plaintext) to store/retrieve the password item.

Answer: -UN*X-PASS


Question 32

When authentication fails, pam_fail_delay is called. What is the delay value in microseconds passed to this function? *******

By cross-referencing calls to pam_fail_delay inside the authentication failure logic, we can see the hardcoded delay parameter passed to it.

Answer: 2000000


Question 33

What is the size in bytes of the stack buffer used to construct command strings before execution? (Decimal) ***

By tracing the destination buffer of the sprintf call that builds the system command, we can find an associated memset operation that initializes it. The memset size parameter is 0x200.

Answer: 512


Question 34

When reading lines from the credential log, what is the maximum line length passed to fgets? 0x***

When the malware reads existing lines from the credential log using fgets, the maximum buffer length parameter passed to the function is 0x200.

Answer: 0x200


Question 35

When updating an existing credential log entry, the malware uses a temporary file. What single-character filename is used for this temporary file? *

If the malware needs to recreate or update the log file, it writes to a temporary file first and then calls rename(). The temporary filename is a single-character string visible in the disassembly.

Answer: a


<
Previous Post
JerseyCTF IV rev/bin challenges
>
Blog Archive
Archive of all previous blog posts