Skip to content

Instantly share code, notes, and snippets.

@laoshaw
Forked from stokito/README.md
Created December 11, 2023 04:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laoshaw/238d8dca1b399151550d769381a7a13a to your computer and use it in GitHub Desktop.
Save laoshaw/238d8dca1b399151550d769381a7a13a to your computer and use it in GitHub Desktop.
CGI shell scripts samples

CGI samples

CGI Variables

Standard set of Common Gateway Interface environment variable are described in RFC3875. For example:

CONTENT_TYPE=application/x-www-form-urlencoded
GATEWAY_INTERFACE=CGI/1.1
REMOTE_ADDR=192.168.1.180
QUERY_STRING=Zbr=1234567&SrceMB=&ime=jhkjhlkh+klhlkjhlk+%A9%D0%C6%AE%C6%AE&prezime=&sektor=OP
REMOTE_PORT=2292
CONTENT_LENGTH=128
REQUEST_URI=/cgi-bin/printenvs
SERVER_SOFTWARE=busybox httpd/1.35 6-Oct-2004
PATH=/bin:/sbin:/usr/bin:/usr/sbin
HTTP_REFERER=http://192.168.1.1/index1.html
SERVER_PROTOCOL=HTTP/1.0
PATH_INFO=
REQUEST_METHOD=POST
PWD=/www/cgi-bin
SERVER_PORT=80
SCRIPT_NAME=/cgi-bin/printenvs
REMOTE_USER=[http basic auth username]

Example of CGI script that prints them /cgi-bin/printenvs.cgi Environment variables are set up and the script is invoked with pipes for stdin/stdout.

Other samples

httpd expects it's CGI script files to be in the subdirectory cgi-bin under main web directory set by options -h (default is /www, so /www/cgi-bin). The CGI script files must also have permission to be executed (min mode 700) e.g chmod +x /cgi-bin/index.cgi. If directory URL is given, no index.html is found and CGI support is enabled, then cgi-bin/index.cgi will be executed.

BusyBox sources contains two useful CGI programs:

Also there is and example of shell script to process File Upload httpd_post_upload.cgi

#!/bin/sh
# Echo CGI envs as headers and body
CONTENT=$(cat -)
printf "Content-Length: ${#CONTENT}\r\n"
printf "Content-Type: text/html\r\n"
printf "ENV_REQUEST_METHOD: \"$REQUEST_METHOD\"\r\n"
printf "ENV_CONTENT_TYPE: \"$CONTENT_TYPE\"\r\n"
printf "ENV_CONTENT_LENGTH: \"$CONTENT_LENGTH\"\r\n"
printf "ENV_REMOTE_ADDR: \"$REMOTE_ADDR\"\r\n"
printf "ENV_REMOTE_PORT: \"$REMOTE_PORT\"\r\n"
printf "ENV_SERVER_PORT: \"$SERVER_PORT\"\r\n"
printf "ENV_REQUEST_URI: \"$REQUEST_URI\"\r\n"
printf "ENV_QUERY_STRING: \"$QUERY_STRING\"\r\n"
# all headers from request now available with the HTTP_ prefix
printf "ENV_HTTP_HOST: \"$HTTP_HOST\"\r\n"
printf "ENV_HTTP_USER_AGENT: \"$HTTP_USER_AGENT\"\r\n"
printf "ENV_HTTP_ACCEPT: \"$HTTP_ACCEPT\"\r\n"
printf "ENV_HTTP_REFERER: \"$HTTP_REFERER\"\r\n"
# username from basic auth (e.g. without password)
printf "ENV_REMOTE_USER: \"$REMOTE_USER\"\r\n"
printf "ENV_SCRIPT_NAME: \"$SCRIPT_NAME\"\r\n"
printf "ENV_PATH_INFO: \"$PATH_INFO\"\r\n"
printf "ENV_PATH: \"$PATH\"\r\n"
printf "ENV_PWD: \"$PWD\"\r\n"
printf "ENV_SERVER_PROTOCOL: \"$SERVER_PROTOCOL\"\r\n"
printf "ENV_SERVER_SOFTWARE: \"$SERVER_SOFTWARE\"\r\n"
printf "\r\n"
printf "$CONTENT"
#!/usr/bin/perl
use strict;
use warnings;
print "Content-type: text/html\r\n";
print "\r\n";
my $name = '';
if ($ENV{QUERY_STRING}) {
($name) = $ENV{QUERY_STRING} =~ /^name=(.*)$/;
}
print "Hello $name\n";
#!/bin/sh
# Imitation of webdav to read and edit a file
if [ "$REMOTE_USER" != "admin" ]; then
printf "Status: 403\r\n"
printf "\r\n"
printf "Only admin can change users but you are %s" "$REMOTE_USER"
exit
fi
if [ "$REQUEST_METHOD" = "GET" ]; then
printf "Content-Type: text/plain\r\n"
printf "\r\n"
cat /etc/hosts
elif [ "$REQUEST_METHOD" = "PUT" ]; then
CONTENT=$(cat -)
printf "%s" "$CONTENT" > /etc/hosts
printf "Status: 204\r\n"
printf "\r\n"
else
printf "Status: 405\r\n"
fi
#!/usr/bin/python
print("Content-type:text/html\r\n")
print("\r\n")
print('<html>')
print('<head>')
print('<title>Hello from CGI in Python</title>')
print('</head>')
print('<body>')
print('<h1>Hello World!</h2>')
print('</body>')
print('</html>')
#!/bin/sh
# GPLv2. From BuxyBox https://git.busybox.net/busybox/tree/networking/httpd_post_upload.cgi
# post_upload.htm example:
# <html>
# <body>
# <form action=/cgi-bin/httpd_post_upload.cgi method=post enctype=multipart/form-data>
# File to upload: <input type=file name=file1> <input type=submit>
# </form>
# POST upload format:
# -----------------------------29995809218093749221856446032^M
# Content-Disposition: form-data; name="file1"; filename="..."^M
# Content-Type: application/octet-stream^M
# ^M <--------- headers end with empty line
# file contents
# file contents
# file contents
# ^M <--------- extra empty line
# -----------------------------29995809218093749221856446032--^M
file=$(mktemp)
CR=`printf '\r'`
# CGI output must start with at least empty line (or headers)
printf '\r\n'
IFS="$CR"
read -r delim_line
IFS=""
while read -r line; do
test x"$line" = x"" && break
test x"$line" = x"$CR" && break
done
cat >"$file"
# We need to delete the tail of "\r\ndelim_line--\r\n"
tail_len=$((${#delim_line} + 6))
# Get and check file size
filesize=`stat -c"%s" "$file"`
test "$filesize" -lt "$tail_len" && exit 1
# Check that tail is correct
dd if="$file" skip=$((filesize - tail_len)) bs=1 count=1000 >"$file.tail" 2>/dev/null
printf "\r\n%s--\r\n" "$delim_line" >"$file.tail.expected"
if ! diff -q "$file.tail" "$file.tail.expected" >/dev/null; then
printf "<html>\n<body>\nMalformed file upload"
exit 1
fi
rm "$file.tail"
rm "$file.tail.expected"
# Truncate the file
dd of="$file" seek=$((filesize - tail_len)) bs=1 count=0 >/dev/null 2>/dev/null
printf "<html>\n<body>\nFile upload has been accepted"
#!/bin/bash
# list files in a directory. Please not that it needs for Bash
printf "Content-Type: text/html\r\n"
printf "\r\n"
echo "<p>List of files in </strong><code>/</code></p>"
files=($(ls /))
for file in "${files[@]}"
do
echo "<code>$file</code><br>"
done
#!/bin/sh
# print all env variables
printf "Content-Type: text/plain\r\n"
printf "\r\n"
echo "Environment variables:"
env
#!/bin/sh
# Redirect from HTTP to HTTPS
printf "Status: 302 Redirect\r\n"
printf "Location: https://$SERVER_NAME:$SERVER_PORT/\r\n"
printf "\r\n"
#!/bin/sh
printf "Content-Type: text/html\r\n"
printf "\r\n"
cat <<EOF
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CGI render HTML sample</title>
</head>
<body>
<h1>Hello from CGI</h1>
</body>
</html>
EOF
#!/bin/sh
# Slowly read and write back the request
printf "Content-Type: text/plaint\r\n"
printf "\r\n"
set | while read line; do echo $line; sleep 1; done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment