Skip to content
Home » Writing a Eternal blue ms17-010 Network Vulnerability scanner in C

Writing a Eternal blue ms17-010 Network Vulnerability scanner in C

The scanner is based on https://github.com/bhassani/EternalBlueC/blob/master/ms17_vuln_status.cpp

Credits to https://github.com/bhassani for this awesome work.

He has created a ms17 Vulnerability checker among many other things. The first thing that came into my mind after seeing that was that this can be made into a network vulnerability scanner!

For tests, I got the source (https://github.com/bhassani/EternalBlueC/blob/master/ms17_vuln_status.cpp) and edited it to take user input instead of command line argument as the target host to check. Just to make things easier for me.

std::string target;
    WSAStartup(MAKEWORD(2, 2), &ws);
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock <= 0)
    {
        return 0;
    }

    std::cout << "Enter Host : ";
    std::getline(std::cin, target);
    server.sin_family = AF_INET;
    //server.sin_addr.s_addr = inet_addr(argv[1]);
    server.sin_addr.s_addr = inet_addr(target.c_str());

Tested on Windows 7 Virtual machine that is indeed vulnerable to MS17.

Awesome!

Now to make a Network scanner with this, I’m going to use my Maalik Framework (https://github.com/quantumcored/maalik). I can’t make a Reflective DLL payload with this because sending the host to it from a file and then reading output from the same file would take alot of time for it.

I’m going to have to add this to the Maalik client itself.

The maalik scanner works by sending fhdawn (the maalik client) hosts to check. Their existence is then reported back to the server for later information gathering such as port scans.

I can also add same functionality for the eternal blue scanner.

The server sends host targets to check for eternal blue, Fhdawn scans and reports back. To do so, I had to modify the vulnerability scanner just a teeny bit.

Converted that code into a function that reports back to server.

https://github.com/quantumcored/maalik/blob/master/fhdawn/network.c#L124

// Thanks to @bhassani
// https://github.com/bhassani/EternalBlueC
void EternalBlueScan(const char* host)
{
    char output[BUFFER];
    do {
        int len = 0;
        memset(output, '\0', BUFFER);
        struct sockaddr_in server;
        SOCKET    sock;
        DWORD    ret;
        sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock <= 0)
        {
            break;
        }
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = inet_addr(host);
        server.sin_port = htons((USHORT)445);

        ret = connect(sock, (struct sockaddr*)&server, sizeof(server));
        if (ret == -1)
        {
            len += snprintf(output + len, sizeof(output) - len, "[X] %s Connection Error, Port 445 Firewalled or unreachable.\n", host);
            break;
        }

        //send SMB negociate packet
        send(sock, (char*)SmbNegociate, sizeof(SmbNegociate) - 1, 0);
        recv(sock, (char*)recvbuff, sizeof(recvbuff), 0);

        //send Session Setup AndX request
        len += snprintf(output + len, sizeof(output) - len, "[+] Sending Session_Setup_AndX_Request!\n");
        ret = send(sock, (char*)Session_Setup_AndX_Request, sizeof(Session_Setup_AndX_Request) - 1, 0);
        if (ret <= 0)
        {
            len += snprintf(output + len, sizeof(output) - len, "[X] Send Session_Setup_AndX_Request error!\n");
            break;
        }
        recv(sock, (char*)recvbuff, sizeof(recvbuff), 0);

        char userid[2];
        char treeid[2];
        //copy userID from recvbuff @ 32,33
        userid[0] = recvbuff[32];
        userid[1] = recvbuff[33];

        //update userID in the tree connect request
        treeConnectRequest[32] = userid[0];
        treeConnectRequest[33] = userid[1];

        //send TreeConnect request
        len += snprintf(output + len, sizeof(output) - len, "[+] Sending TreeConnect Request!\n");
        ret = send(sock, (char*)treeConnectRequest, sizeof(treeConnectRequest) - 1, 0);
        if (ret <= 0)
        {
            len += snprintf(output + len, sizeof(output) - len, "[X] Send TreeConnect_AndX_Request error!\n");
            break;
        }
        recv(sock, (char*)recvbuff, sizeof(recvbuff), 0);

        //copy treeID from recvbuff @ 28, 29
        treeid[0] = recvbuff[28];
        treeid[1] = recvbuff[29];
        //update treeid & userid in the transNamedPipe Request
        transNamedPipeRequest[28] = treeid[0];
        transNamedPipeRequest[29] = treeid[1];
        transNamedPipeRequest[32] = userid[0];
        transNamedPipeRequest[33] = userid[1];

        //send transNamedPipe request
        len += snprintf(output + len, sizeof(output) - len, "[+] Sending transNamedPipeRequest!\n");
        ret = send(sock, (char*)transNamedPipeRequest, sizeof(transNamedPipeRequest) - 1, 0);
        if (ret <= 0)
        {
            len += snprintf(output + len, sizeof(output) - len, "[X] Send modified transNamedPipeRequest error!\n");
            break;
        }
        recv(sock, (char*)recvbuff, sizeof(recvbuff), 0);

        //compare the NT_STATUS response to 0xC0000205 ( STATUS_INSUFF_SERVER_RESOURCES)
        if (recvbuff[9] == 0x05 && recvbuff[10] == 0x02 && recvbuff[11] == 0x00 && recvbuff[12] == 0xc0)
        {
            len += snprintf(output + len, sizeof(output) - len, "[+] %s is vulnerable to MS17-010\n", host);
        }
        else {
            len += snprintf(output + len, sizeof(output) - len, "[X] %s is not vulnerable to MS17-010\n", host);
        }

        //cleanup
        closesocket(sock);
    } while (0);
    
    sockSend(output);
}

Of course that needs improvements, I’m going to add more error handlers and do more tests before I make a release for this.

If you would like to make one yourself, Without using maalik. You can either use the same methods I use in maalik, Which are, sending information over sockets. Information such as the host to scan for ms17 etc.

Or you can make the scanner load the targets from a text file.

Let’s make a really simple socket based network scanner for you. 🙂

We will be

  • Making the TCP Server in Python, Which will accept connection from client, And give the user the ability to send target hosts to scan.
  • Making the Client in C, That receives the instruction to scan for ms17, And scans it using EternalBlueScan(host);

The Simple Socket Server

import socket # import socket module


server = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
# some socket settings I think are important
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
server.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 1)
server.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 1)
server.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 5)

host = "0.0.0.0" # localhost
port = 1234

# Bind the host and port
try:
    server.bind((host, port))
except PermissionError:
    print("Can't bind, Run as sudo.")
except Exception as i:
    raise i
# Listen for connections
try:
    server.listen(1)
except Exception as S:
    raise S

while(True):
    client, addr = server.accept() # Accept connection
    print("Connection from : " + str(addr[0]) +  ":"+str(addr[1])) # print client information
    while(True):
        ask = input("Enter Host to Scan : ")
        if(len(ask) > 0):
            client.send(ask.encode())
            answer = client.recv(1024).decode()
            print(answer)

The Simple Scanner Client

#include <stdio.h>
#include <windows.h>
#include <winsock.h>
#include <tchar.h>
#pragma comment(lib, "wsock32.lib")
#define BUFFER 1024

unsigned char SmbNegociate[] =
"\x00\x00\x00\x85\xff\x53\x4d\x42\x72\x00\x00\x00\x00\x18\x53\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x40\x00\x00"
"\x62\x00\x02\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00"
"\x02\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00\x02\x4c\x4d\x31\x2e\x32\x58\x30"
"\x30\x32\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00";

unsigned char Session_Setup_AndX_Request[] =
"\x00\x00\x00\x88\xff\x53\x4d\x42\x73\x00\x00\x00\x00\x18\x07\xc0\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x40\x00"
"\x0d\xff\x00\x88\x00\x04\x11\x0a\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00"
"\x00\x00\x00\x00\x00\xd4\x00\x00\x00\x4b\x00\x00\x00\x00\x00\x00\x57\x00"
"\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00"
"\x30\x00\x30\x00\x20\x00\x32\x00\x31\x00\x39\x00\x35\x00\x00\x00\x57\x00"
"\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00"
"\x30\x00\x30\x00\x20\x00\x35\x00\x2e\x00\x30\x00\x00\x00";

unsigned char treeConnectRequest[] = 
"\x00\x00\x00\x60\xff\x53\x4d\x42\x75\x00\x00\x00\x00\x18\x07\xc0"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe"
"\x00\x08\x40\x00\x04\xff\x00\x60\x00\x08\x00\x01\x00\x35\x00\x00"
"\x5c\x00\x5c\x00\x31\x00\x39\x00\x32\x00\x2e\x00\x31\x00\x36\x00"
"\x38\x00\x2e\x00\x31\x00\x37\x00\x35\x00\x2e\x00\x31\x00\x32\x00"
"\x38\x00\x5c\x00\x49\x00\x50\x00\x43\x00\x24\x00\x00\x00\x3f\x3f\x3f\x3f\x3f\x00";

unsigned char transNamedPipeRequest[] = 
"\x00\x00\x00\x4a\xff\x53\x4d\x42\x25\x00\x00\x00\x00\x18\x01\x28\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x8e\xa3\x01\x08"
"\x52\x98\x10\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x4a\x00\x00\x00\x4a\x00\x02\x00\x23\x00\x00"
"\x00\x07\x00\x5c\x50\x49\x50\x45\x5c\x00";

unsigned char recvbuff[2048];

// Thanks to @bhassani
// https://github.com/bhassani/EternalBlueC
void EternalBlueScan(SOCKET socks, const char* host)
{
    char output[BUFFER];
    do {
        int len = 0;
        memset(output, '\0', BUFFER);
        struct sockaddr_in server;
        SOCKET    sock;
        DWORD    ret;
        sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock <= 0)
        {
            break;
        }
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = inet_addr(host);
        server.sin_port = htons((USHORT)445);

        ret = connect(sock, (struct sockaddr*)&server, sizeof(server));
        if (ret == -1)
        {
            len += snprintf(output + len, sizeof(output) - len, "[X] %s Connection Error, Port 445 Firewalled or unreachable.\n", host);
            break;
        }

        //send SMB negociate packet
        send(sock, (char*)SmbNegociate, sizeof(SmbNegociate) - 1, 0);
        recv(sock, (char*)recvbuff, sizeof(recvbuff), 0);

        //send Session Setup AndX request
        len += snprintf(output + len, sizeof(output) - len, "[+] Sending Session_Setup_AndX_Request!\n");
        ret = send(sock, (char*)Session_Setup_AndX_Request, sizeof(Session_Setup_AndX_Request) - 1, 0);
        if (ret <= 0)
        {
            len += snprintf(output + len, sizeof(output) - len, "[X] Send Session_Setup_AndX_Request error!\n");
            break;
        }
        recv(sock, (char*)recvbuff, sizeof(recvbuff), 0);

        char userid[2];
        char treeid[2];
        //copy userID from recvbuff @ 32,33
        userid[0] = recvbuff[32];
        userid[1] = recvbuff[33];

        //update userID in the tree connect request
        treeConnectRequest[32] = userid[0];
        treeConnectRequest[33] = userid[1];

        //send TreeConnect request
        len += snprintf(output + len, sizeof(output) - len, "[+] Sending TreeConnect Request!\n");
        ret = send(sock, (char*)treeConnectRequest, sizeof(treeConnectRequest) - 1, 0);
        if (ret <= 0)
        {
            len += snprintf(output + len, sizeof(output) - len, "[X] Send TreeConnect_AndX_Request error!\n");
            break;
        }
        recv(sock, (char*)recvbuff, sizeof(recvbuff), 0);

        //copy treeID from recvbuff @ 28, 29
        treeid[0] = recvbuff[28];
        treeid[1] = recvbuff[29];
        //update treeid & userid in the transNamedPipe Request
        transNamedPipeRequest[28] = treeid[0];
        transNamedPipeRequest[29] = treeid[1];
        transNamedPipeRequest[32] = userid[0];
        transNamedPipeRequest[33] = userid[1];

        //send transNamedPipe request
        len += snprintf(output + len, sizeof(output) - len, "[+] Sending transNamedPipeRequest!\n");
        ret = send(sock, (char*)transNamedPipeRequest, sizeof(transNamedPipeRequest) - 1, 0);
        if (ret <= 0)
        {
            len += snprintf(output + len, sizeof(output) - len, "[X] Send modified transNamedPipeRequest error!\n");
            break;
        }
        recv(sock, (char*)recvbuff, sizeof(recvbuff), 0);

        //compare the NT_STATUS response to 0xC0000205 ( STATUS_INSUFF_SERVER_RESOURCES)
        if (recvbuff[9] == 0x05 && recvbuff[10] == 0x02 && recvbuff[11] == 0x00 && recvbuff[12] == 0xc0)
        {
            len += snprintf(output + len, sizeof(output) - len, "[+] %s is vulnerable to MS17-010\n", host);
        }
        else {
            len += snprintf(output + len, sizeof(output) - len, "[X] %s is not vulnerable to MS17-010\n", host);
        }

        //cleanup
        closesocket(sock);
    } while (0);
    
    send(socks, output, BUFFER, 0);
}

int main()
{
    SOCKET socks;
    WSADATA wsa;
    struct sockaddr_in server;
    char buf[BUFFER];
    if(WSAStartup(MAKEWORD(2,2), &wsa)!=0)
    {
        printf("Failed to start Winsock api Error : %ld", WSAGetLastError());
        exit(1);
    }
    socks = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_port = htons(1234);
    server.sin_family = AF_INET;
    connect(socks, (struct sockaddr*)&server, sizeof(server));
    while(TRUE){
        memset(buf, '\0', BUFFER);
        recv(socks, buf, BUFFER, 0);
        EternalBlueScan(socks, buf);
    }

    
}

And that is a basic prototype for all you who want to create their own ms17 scanner. 🙂

If you look closely you can see I modified the EternalBlue scan function. Just to pass in the socket parameter.

Compile And run the Code :

python3 tcpServer.py
gcc main.c -lws2_32 -o test_client.exe
./test_client

Here’s how it looks like when working :

Keep one thing in mind, That prototype lacks many many important things. Such as checks if the socket was created or not, IF the client connected or not. That is just basic code written to give you and understanding.

Thanks for reading.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x