Running EXE and BATCH Files As CGI Scripts In Apache Under Windows

Posted: 2015-03-24 19:58:24

If you need to run an executable file as part of the request made to your server, get its output, and pass that output back to the client, there are 3 things that you have to be aware of:

  1. EXE files are typically Windows command-line (or Desktop) binary files that where not built/compiled to be executed through CGI.
  2. Everything that is ran through CGI, has to conform to the CGI 1.1 Specification.
  3. The CGI specification only requires that the first two output lines are: a Header line (e.g., “Content-type: text/html”) followed by an empty line.

To execute regular EXE files as CGI scripts, read on…

Mistake #1. “AddHandler cgi-script .exe”

The most common mistake is to treat all EXE files as CGI compliant script files by using configuration:

AddHandler cgi-script .exe

This is not going to work because the EXE file:

Mistake #2. “#!C:\windows\system32\cmd.exe /c”

Another common mistake is to wrap the EXE file into a BATCH (BAT) file, and then using the “shebang” line to tell Apache to execute the script via cmd.exe.

This will not work, and will either produce an “500 / Internal Server Error” or a blank page, as when that BATCH script is ran it will output an error as its first line is read (i.e., the regular “#!…” shebang line is not a valid BATCH ignore/comment line).

The Right Way To Execute Regular EXE and BAT Files as CGI Scripts

1. Wrap the EXE in a BATCH (.bat) file, with the proper cgi-compliant header and header-body separator.

@echo off
echo Content-Type: text/plain
echo.
dir

“dir” is a standard command-line binary that outputs the current directory’s file + folder names. Substitute your binary in.

2. Do not use a “shebang” line, by directly telling Apache to execute it via cmd.exe

Update Apache configuration for the directory either in the main configuration, the website’s VirtualHost file, or the .htaccess file:

ScriptInterpreterSource Registry-Strict
AddHandler cgi-script .bat
Options +ExecCGI +FollowSymlinks
<IfModule mod_ssl.c>
    SSLOptions +StdEnvVars
</IfModule>

WampDeveloper Pro already has this configuration for /cgi-bin.

You can also set a cgi error log with line: ScriptLog /path/to/logs/cgilog.txt

Create and set Registry Key/Value to shell execute .bat files via cmd.exe:

Key: HKEY_CLASSES_ROOT\.bat\Shell\ExecCGI\Command
Value name: (default)
Value type: REG_SZ
Value data: "C:\windows\system32\cmd.exe /c %s %s"

Run “regedit” to open the Registry editor. You will need to create key “Shell\ExecCGI\Command” as it’s unlikely to already exist.

3. And if elevated privileges are needed to run this EXE file, switch Apache to use a different account in its Service Properties / Log On field.

BATCH HTML

To output HTML, you’ll have to set the proper Content-type header, and escape special BATCH characters…

@echo off
echo Content-Type: text/html
echo.
echo ^<HTML^>
echo.
echo ^<HEAD^>
echo ^<TITLE^>Hello, world!^</TITLE^>
echo ^</HEAD^>
echo.
echo ^<BODY^>
echo ^<H1^>Hello, world!^</H1^>
echo ^<p^>Hello, world!^</p^>
echo ^</BODY^>
echo.
echo ^</HTML^>

BATCH Environment

The environment of the CGI has variables containing passed in parameters (QUERY_STRING) and other info

Script:

@echo off
echo Content-Type: text/plain
echo.
set

Output:

PROMPT=$P$G
SCRIPT_URL=/cgi-bin/test.bat
SCRIPT_URI=http://example.com/cgi-bin/test.bat
MYSQL_HOME=C:\WampDeveloper\Components\Mysql
PHPRC=C:\WampDeveloper\Components\Php
TMP=C:\WampDeveloper\Temp
MAGICK_HOME=C:/WampDeveloper/Tools/ImageMagick
OPENSSL_CONF=C:/WampDeveloper/Components/Apache/bin/openssl.cnf
HTTP_HOST=example.com
HTTP_CONNECTION=keep-alive
HTTP_CACHE_CONTROL=max-age=0
HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
HTTP_USER_AGENT=Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36
HTTP_ACCEPT_ENCODING=gzip, deflate, sdch
HTTP_ACCEPT_LANGUAGE=en-US,en;q=0.8
PATH=...removed for brevity...
SystemRoot=C:\Windows
COMSPEC=C:\Windows\system32\cmd.exe
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
WINDIR=C:\Windows
SERVER_SIGNATURE=<address>Apache/2.4.10 (Win32) OpenSSL/1.0.1j PHP/5.6.4 Server at example.com Port 80</address>
SERVER_SOFTWARE=Apache/2.4.10 (Win32) OpenSSL/1.0.1j PHP/5.6.4
SERVER_NAME=example.com
SERVER_ADDR=127.0.0.1
SERVER_PORT=80
REMOTE_ADDR=127.0.0.1
DOCUMENT_ROOT=C:/WampDeveloper/Websites/www.example.com/webroot
REQUEST_SCHEME=http
CONTEXT_PREFIX=/cgi-bin/
CONTEXT_DOCUMENT_ROOT=C:/WampDeveloper/Websites/www.example.com/cgi-bin/
SERVER_ADMIN=admin@httpd.host
SCRIPT_FILENAME=C:/WampDeveloper/Websites/www.example.com/cgi-bin/test.bat
REMOTE_PORT=56464
GATEWAY_INTERFACE=CGI/1.1
SERVER_PROTOCOL=HTTP/1.1
REQUEST_METHOD=GET
QUERY_STRING=
REQUEST_URI=/cgi-bin/test.bat
SCRIPT_NAME=/cgi-bin/test.bat