We found an APT malware running persistently in one of our staff's PC. After compromising, the malware makes a lot of communication with a C2.
TL;DR
The malware is using Telegram bot as a C2 server. Abuse the forwardMessage API to hijack conversation between the bot and it's owner.
Initial Analysis
We were given 2 files: .EXE and .DLL. Decompiling the executable file does not yield any positive result as it just calls the exported function from the .DLL file, which displays a MessageBox.
voidpossible_main(undefined8 param_1,undefined8 param_2,undefined8 param_3,undefined8 param_4) {printf("This binary has been created specifically for the SiberSiaga 2023 CTF.\n",param_2,param_3, param_4);printf("This is a malware. Please run in a safe environment.\n",param_2,param_3,param_4);printf("Proceed to run? Yes or no: ",param_2,param_3,param_4); hModule =LoadLibraryW(L"MSVCR100.dll");if (hModule != (HMODULE)0x0) { pFVar5 =GetProcAddress(hModule,"function_101009");FreeLibrary(hModule); }return; }
Decompiling the .DLL file reveals 2 exported function used by the executable.
The first function doesn't do much except for printing the SiberSiaga title using MessageBoxW API.
As described in the Telegram documentation, getUpdates is used to receive incoming updates using an identifier offset. Seeing this in action shows the message sent from DeezNutz to the Telegram Bot:
Quoting the description for offset parameter from Telegram API docs:
Identifier of the first update to be returned. Must be greater by one than the highest among the identifiers of previously received updates. By default, updates starting with the earliest unconfirmed update are returned. An update is considered confirmed as soon as getUpdates is called with an offset higher than its update_id. The negative offset can be specified to retrieve updates starting from -offset update from the end of the updates queue. All previous updates will be forgotten.
Possible Exploit Idea: By providing a negative offset, we might be able to leak previous conversations between the bot and other users. However, this requires us to fuzz the update_id value in order to locate the conversation which contains the flag. As the current update_id is a relatively large number, this would require 539+ million brute-forcing requests, not to mention that the API is rate-limited.
sendMessage()
A simple API to send messages to users on behalf of the bot. This sends the text "sibersiaga" to user DeezNutz as the Telegram Bot.
Possible Exploit Idea: Send a custom command such as /flag to an admin user to receive the flag? This would require us to have prior knowledge of the admin user's chat_id in the first place.
getChat()
Getting some basic information about the user, such as first_name and username:
Browsing through the available API calls on Telegram documentation, there's one interesting API forwardMessage that we can abuse to read old messages between the bot and another user.