Playing With Named Pipe and NotPetya
A long time ago, in a galaxy far far away, I was having fun reversing NotPetya.
Files dropped by NotPetya
During the dynamical analysis, I identified some files dropped on the disk by the sample.
An executed file using named pipe
One of them caught my eye: it is executed by the sample with a named pipe argument.
Finding named pipe in NotPetya
I’ve never played with named pipe before and I was curious about the data that will potentially be exchanged through it. I searched for references of an API using named pipe in the sample.
And I found some: CreateNamedPipeW
, ConnectNamedPipe
and so on. I searched through the code calls to these functions and found a section calling:
CreateNamedPipeW
ConnectNamedPipe
PeekNamedPipe
Stealing the data exchanged through the named pipe!
During the analysis, I noticed that the binary using named pipe was always dropped in the same directory: C:\Users\%USERNAME%\AppData\Local\Temp
. The file name followed a pattern: 4 alpha-numeric characters and a .tmp
extension.
I managed to retrieve the target binary dropped by the sample to perform some tests.
To access the data exchange between the sample and this binary, I needed to emulate the “named pipe server” set up by the sample. I gathered from the assembly code:
- The sample is creating a named pipe set up as a server on its side
- Waits for a connection on it
- One connection is made, gets all the data in the named pipe.
I coded something reproducing this part of the sample code:
// Emulation of the NotPetya named pipe server
// By Alice Climent-Pommeret
// To compile on linux
// sudo apt install g++-mingw-w64
// i686-w64-mingw32-g++ -static NamedPipeServerNotPetya.cpp -o NamedPipeServerNotPetya.exe
#include <iostream>
#include <windows.h>
using namespace std;
int main(int argc, const char **argv)
{
wcout << "" << endl;
wcout << "Creation of a named pipe called \\\\.\\pipe\\my_pipe" << endl;
//pipe creation
HANDLE pipe = CreateNamedPipe(
"\\\\.\\pipe\\my_pipe", // name of the pipe
3, // PIPE_ACCESS_DUPLEX
6, // PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE
1, // only one instance of the named pipe
0, // no outbound buffer
0, // no inbound buffer
0, // use default wait time
NULL // use default security attributes
);
if (pipe == NULL || pipe == INVALID_HANDLE_VALUE) {
wcout << "The named pipe creation failed";
return 1;
}
wcout << "Waiting for a client connection" << endl;
if (ConnectNamedPipe(pipe, NULL)){// This call blocks the process here until a client connection to the pipe
wcout << "Reading data from the named pipe" << endl;
wchar_t buffer[2048];
DWORD numBytesRead = 0;
// Read data from the pipe
while (ReadFile(pipe, buffer, 2048 * sizeof(wchar_t), &numBytesRead, NULL)){
wcout << "Credentials sent by the NotPetya dropped binary: " << buffer << endl;
}
}
//Close the pipe
CloseHandle(pipe);
wcout << "Done !" << endl;
return 0;
}
To test it, I ran the “named pipe server” in a terminal. At first, the server waits for incoming connections. Then I ran, in an administrator terminal, the dropped binary.
Since the “named pipe server” creates a named pipe called \\.\pipe\my_pipe
, give this as a parameter to the dropped binary.
Annnnnnd…
User creds are sent by the mysterious dropped binary… It may be some kind of Mimikatz like…
But this is another topic :)
You can find the C++ source code in this article in my GitHub repository