2

I've been struggling with Windows Sockets for two days not being able to just use write to socket as in Linux it is. I want to write my own shellcode and I'm playing around how to redirect stdout, stdin to socket handle (that's where my playings come from). I use Windows 7 x64, build 7601 if it's necessary. Here's my code

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int main (int argc,char ** argv)
{   
    // boring code starts
    if (argc < 2)
    {
        printf("Usage getstdhandle <ip> <port> ");
    }

    WSADATA wsadata;
    int result = WSAStartup (MAKEWORD(2,2),&wsadata);
    if (result != NO_ERROR)
    {
        printf("error with wsastartup");
    }

    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons (atoi(argv[2]));
    server.sin_addr.s_addr = inet_addr (argv[1]);

    SOCKET soc = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if (soc == INVALID_SOCKET)
    {
        printf("Error with creating socket");
    }

    if (connect(soc,(struct sockaddr *)&server,sizeof(server)) == SOCKET_ERROR)
    {
        printf("Problem with connecting");
    }

     // boring code ends

    const char * buf = "Tekscik \n"; // know it's not really good in new C standards
    const char buf[] = "Test\n";  // not working also, shouldn't have any influence

    bool isSent = WriteFile((HANDLE)soc,(LPCVOID)buf,(DWORD)10,NULL,NULL);
    DWORD ret = GetLastError();
    printf("%.08x",ret);

    closesocket(soc);
    WSACleanup();
    return 0;
}

This is how i run my program

C:\Users\Domin568\Desktop>getstdhandle 192.168.56.1 5555
Tekscik
00000057     <---- Error code in hex

On my second machine i just run nc to listen for this data like this :

15:14|domin568[21] ~ $ nc -l -v -p 5555
Connection from 192.168.56.101:50328
15:15|domin568[22] ~ $ 

I get error code 0x57 which is :

ERROR_INVALID_PARAMETER 87 (0x57) The parameter is incorrect.

Local network traffic (any data sent, pure connections handshakes and FIN)

What could be the reason of that ? I know it's not good way for sending data but MSDN says it should be possible.

Domin568
  • 31
  • 8
  • use `OVERLAPPED ov = {}; BOOL isSent = WriteFile((HANDLE)soc,(LPCVOID)buf,(DWORD)10, 0, &ov);` in this case will be work – RbMm May 12 '17 at 14:18
  • The error handling is broken, only ever call GetLastError() when the function failed. If you call it when it did not fail then you get an arbitrary number. – Hans Passant May 12 '17 at 15:22

2 Answers2

4

from WriteFile documentation

lpOverlapped [in, out, optional]

A pointer to an OVERLAPPED structure is required if the hFile parameter was opened with FILE_FLAG_OVERLAPPED, otherwise this parameter can be NULL.

but are socket function create file (socket this is file handle, it point to FILE_OBJECT structure) with FILE_FLAG_OVERLAPPED ? this is undocumented and you cannot control this. so you need use OVERLAPPED as parameter for WriteFile.

if use WSASocket we already here have dwFlags option and can set or not set WSA_FLAG_OVERLAPPED (which is equivalent of FILE_FLAG_OVERLAPPED for CreateFile)

why OVERLAPPED structure is required when we use hFile opened with FILE_FLAG_OVERLAPPED flag (no FO_SYNCHRONOUS_IO flag in FILE_OBJECT) ?

WriteFile call ZwWriteFile

look for

PLARGE_INTEGER ByteOffset [in, optional] parameter of ZwWriteFile - but it optional only if we open file as synchronous. if file opened in asynchronous i/o mode - this parameter is mandatory.

from wrk source code

if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
}
else if (!ARGUMENT_PRESENT( ByteOffset ) && !(fileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) {

        //
        // The file is not open for synchronous I/O operations, but the
        // caller did not specify a ByteOffset parameter.  This is an error
        // situation, so cleanup and return with the appropriate status.
        //

        if (eventObject) {
            ObDereferenceObject( eventObject );
        }
        ObDereferenceObject( fileObject );
        return STATUS_INVALID_PARAMETER;

    }

this is exactly your case when you call

WriteFile((HANDLE)soc,(LPCVOID)buf,(DWORD)10,NULL,NULL);

NtWriteFile return to you STATUS_INVALID_PARAMETER which converted to win32 error ERROR_INVALID_PARAMETER

but next code will be worked ok.

OVERLAPPED ov = {};
BOOL isSent = WriteFile((HANDLE)soc,(LPCVOID)buf,(DWORD)10, 0, &ov);

because in this case ByteOffset will be point to &ov.Offset

however for send data to socket much more better use WSASend

RbMm
  • 31,280
  • 3
  • 35
  • 56
  • It'd be nice if that were documented in official MS documentation somewhere. – Andrew Henle May 12 '17 at 14:54
  • @AndrewHenle - i edit own post now, really about this is said in documentation [WriteFile](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx) - A pointer to an OVERLAPPED structure is **required** if the hFile parameter was opened with FILE_FLAG_OVERLAPPED, otherwise this parameter can be NULL. – RbMm May 12 '17 at 14:57
  • Thank you so much ! My code now works, and your explanation was complete and now I understand what the problem was :) – Domin568 May 12 '17 at 21:10
  • @HarryJohnston - with **exactly** `FILE_FLAGGED_OVERLAPPED` of course no. but i check (how minimum on windows 10, can check and another systems). `socket` internally call `WSASocket` with `WSA_FLAG_OVERLAPPED` this of course binary different flags, but it have the **same** effect - `ZwCreateFile` called without `FILE_SYNCHRONOUS_IO_NONALERT` and `FILE_SYNCHRONOUS_IO_NALERT` flags. as result no `FO_SYNCHRONOUS_IO` in file object – RbMm May 12 '17 at 21:20
  • @RbMm, I think you're right, that also explains the commentary that Andrew's answer links to. That's rather surprising. Thanks for the clarification. – Harry Johnston May 12 '17 at 21:25
  • 1
    I think the upshot here is that you really, *really* should use the WSA functions, using WriteFile and assuming that the handle will be asynchronous might work but depends upon undocumented behaviour. – Harry Johnston May 12 '17 at 21:27
  • @HarryJohnston - and use `lpNumberOfBytesWritten` not help, i check the same error in this case (invalid parameter) also on xp(and may be win7, need loook) will be crash. but with overlapped work. i look under debugger. source of error exactly in code snippet which i paste. no fileoffset – RbMm May 12 '17 at 21:29
  • @HarryJohnston about use `WSA` functions full agree. – RbMm May 12 '17 at 21:31
  • @HarryJohnston - what is really unclear (for me) with sockets that `A socket handle created by the WSASocket or the socket function is inheritable by default` - for me this is how minimum no sense - because socket handle have extra context in user mode and can not be duplicated to another process. at second this can produce hard to find bugs . say we create child process with inherited handles, socket handles copied to it (for why ??). than we close connected socket. we can way that connection broken. but no - because exist extra handle in child process... – RbMm May 12 '17 at 21:38
1

MSDN says it should be possible.

Does it really? The socket handles documentation states:

A socket handle can optionally be a file handle in Windows Sockets 2. A socket handle from a Winsock provider can be used with other non-Winsock functions such as ReadFile, WriteFile, ReadFileEx, and WriteFileEx.

Note the word "optionally".

Per this discussion:

WriteFile with SocketHandle Fails

...

Not sure how you can read that page and think that it is a good idea to use a socket handle with ReadFile et al.

Let's start with this sentence "A socket handle can optionally be a file handle in Windows Sockets 2". That can be read two different ways:

  1. You can optionally use any socket handle as a file handle for ReadFile and friends

  2. A socket provider can optionally provide dual-use sockets that work with ReadFile as well as the socket functions.

Unfortunately there is not enough information in that article to conclusively decide whether #1 or #2 is correct. However the fact that ReadFile returns ERROR_INVALID_PARAMETER (per Mike Danes' comment) I am going to assume that #2 is the correct interpretation and your network socket is not also a file handle. (Note that frequently the MSDN documentation is written more from the perspective of the team that implemented API than from a consumer of the API. If you look at it in that light, #2 is the more likely interpretation -- I will agree that it is annoying because a consumer of the API is more likely to understand the sentence as #1)

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • socket is file handle. always. if it was not a file handle - error be `ERROR_INVALID_HANDLE` but not `ERROR_INVALID_PARAMETER` – RbMm May 12 '17 at 14:23
  • `WriteFile` can and will be work with sockets, if use `OVERLAPPED` – RbMm May 12 '17 at 14:28
  • 1
    Arguably, though, the reason Microsoft decided that the socket could be made asynchronous without documenting the fact may have been that it was never *required* to be a valid handle in the first place. :-) – Harry Johnston May 12 '17 at 21:38