mirror of
https://github.com/sigmasternchen/ShellSpider
synced 2025-03-16 00:19:06 +00:00
full cgi support. \o/ + some other stuff
This commit is contained in:
parent
bc76c14000
commit
94098cb2e0
11 changed files with 185 additions and 46 deletions
4
404.html
4
404.html
|
@ -5,6 +5,8 @@
|
|||
</head>
|
||||
<body>
|
||||
<h1>Not found</h1>
|
||||
The resource [path] was not found on server [host].
|
||||
The resource [path] was not found on the server.
|
||||
<hr />
|
||||
[signature]
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -10,6 +10,7 @@ Requirements
|
|||
- an up-to-date version of bash
|
||||
- socat (for networking)
|
||||
- python (for url-encoding)
|
||||
- dig (for reverse lookup)
|
||||
- some other basic tools, like sed, grep, awk, getopt
|
||||
|
||||
Usage
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
. $1
|
||||
|
||||
if test "${server[query]}" == ""; then
|
||||
if test "${server[queryString]}" == ""; then
|
||||
setStatusCode 200
|
||||
|
||||
cat<<EOF
|
||||
|
@ -27,7 +27,7 @@ fi
|
|||
name=""
|
||||
text=""
|
||||
|
||||
fields=$(echo "${server[query]}" | tr "&" "\n")
|
||||
fields=$(echo "${server[queryString]}" | tr "&" "\n")
|
||||
for field in $fields; do
|
||||
key=$(echo "$field" | awk -F= '{ print $1 }')
|
||||
value=$(echo "$field" | awk -F= '{for (i=2; i<=NF; i++) print $i}')
|
||||
|
|
18
home/test/cgi-test-c.c
Normal file
18
home/test/cgi-test-c.c
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main() {
|
||||
|
||||
if (strlen(getenv("QUERY_STRING")) == 0) {
|
||||
printf("Status: 302 Found\n");
|
||||
printf("Location: ?foo=bar\n\n");
|
||||
} else {
|
||||
printf("Content-Type: text/plain\n\n");
|
||||
|
||||
printf("This Server is running %s.\n", getenv("SERVER_SOFTWARE"));
|
||||
printf("The query string is %s.\n", getenv("QUERY_STRING"));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
BIN
home/test/cgi-test-c.cgi
Executable file
BIN
home/test/cgi-test-c.cgi
Executable file
Binary file not shown.
5
home/test/cgi-test-shell.cgi
Executable file
5
home/test/cgi-test-shell.cgi
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
printf "%s\n\n" "Content-Type: text/plain"
|
||||
|
||||
env
|
|
@ -1,8 +0,0 @@
|
|||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
|
||||
printf("Hello World");
|
||||
|
||||
return 0;
|
||||
}
|
Binary file not shown.
18
index.sh
18
index.sh
|
@ -8,10 +8,10 @@ cat <<EOF
|
|||
<!DOCTYPE>
|
||||
<html>
|
||||
<head>
|
||||
<title>Index of ${server[path]}</title>
|
||||
<title>Index of ${server[scriptName]}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Index of ${server[path]}</h1>
|
||||
<h1>Index of ${server[scriptName]}</h1>
|
||||
<hr />
|
||||
<table>
|
||||
<tr>
|
||||
|
@ -30,23 +30,23 @@ cat <<EOF
|
|||
</tr>
|
||||
EOF
|
||||
|
||||
for file in $(ls -a "${server[real_path]}"); do
|
||||
if test "$file" = ".." -a "${server[path]}" = "/"; then
|
||||
for file in $(ls -a "${server[scriptFilename]}"); do
|
||||
if test "$file" = ".." -a "${server[scriptName]}" = "/"; then
|
||||
continue;
|
||||
fi
|
||||
cat <<EOF
|
||||
<tr>
|
||||
<td>
|
||||
<a href="$(realpath -sm "${server[path]}/$file")">$file</a>
|
||||
<a href="$(realpath -sm "${server[scriptName]}/$file")">$file</a>
|
||||
</td>
|
||||
<td>
|
||||
$(file -b "${server[real_path]}/$file")
|
||||
$(file -b "${server[scriptFilename]}/$file")
|
||||
</td>
|
||||
<td>
|
||||
$(if test ! -d "${server[real_path]}/$file"; then if test -x "${server[real_path]}/$file"; then echo yes; else echo no; fi; fi)
|
||||
$(if test ! -d "${server[scriptFilename]}/$file"; then if test -x "${server[scriptFilename]}/$file"; then echo yes; else echo no; fi; fi)
|
||||
</td>
|
||||
<td>
|
||||
$(if test ! -d "${server[real_path]}/$file"; then du -kh "${server[real_path]}/$file" | cut -f1; fi)
|
||||
$(if test ! -d "${server[scriptFilename]}/$file"; then du -kh "${server[scriptFilename]}/$file" | cut -f1; fi)
|
||||
</td>
|
||||
</tr>
|
||||
EOF
|
||||
|
@ -55,7 +55,7 @@ done
|
|||
cat <<EOF
|
||||
</table>
|
||||
<hr />
|
||||
${headers[Host]} (${settings[server]})
|
||||
${server[serverSignature]}
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
|
161
response.sh
161
response.sh
|
@ -8,8 +8,16 @@ eval "$(cat $settingsfile)" # declare settings array
|
|||
declare -A server
|
||||
server[remoteAddress]="$SOCAT_PEERADDR"
|
||||
server[remotePort]="$SOCAT_PEERPORT"
|
||||
server[localAddress]="$SOCAT_SOCKADDR"
|
||||
server[localPort]="$SOCAT_SOCKPORT"
|
||||
server[remoteHost]="$(dig +noall +answer -x $SOCAT_PEERADDR | awk '{ print $5 }')"
|
||||
server[serverAddress]="$SOCAT_SOCKADDR"
|
||||
server[serverPort]="$SOCAT_SOCKPORT"
|
||||
server[serverName]="${settings[name]}"
|
||||
server[serverAdmin]="${settings[admin]}"
|
||||
server[serverSoftware]="${settings[server]}"
|
||||
server[documentRoot]="$(realpath "${settings[home]}")"
|
||||
server[requestTime]="$(date +%s)"
|
||||
server[requestTimeFloat]="$(($(date +%s%N)/1000))"
|
||||
server[requestTimeReadable]="$(date --rfc-3339=ns)"
|
||||
|
||||
declare -A headers
|
||||
first=1
|
||||
|
@ -19,13 +27,15 @@ while true; do
|
|||
break
|
||||
fi
|
||||
if test $first = 1; then
|
||||
server[method]="$(echo "$header" | awk '{ print $1 }')"
|
||||
server[requestMethod]="$(echo "$header" | awk '{ print $1 }')"
|
||||
server[http]="$(echo "$header" | awk '{ print $3 }' | awk -F/ '{ print $2} ')"
|
||||
server[user_path]=$(echo "$header" | awk '{ print $2 }')
|
||||
server[path]="$(realpath -sm "${server[user_path]}")"
|
||||
server[query]="$(echo "${server[path]}" | awk -F? '{for (i=2; i<=NF; i++) print $i}')"
|
||||
server[path]="$(echo "${server[path]}" | awk -F? '{ print $1 }')"
|
||||
server[real_path]="$(realpath -sm "${settings[home]}${server[path]}")"
|
||||
server[https]="off"
|
||||
server[serverProtocol]="$(echo "$header" | awk '{ print $3 }')"
|
||||
server[request_unchecked]=$(echo "$header" | awk '{ print $2 }')
|
||||
server[requestURI]="$(realpath -sm "${server[request_unchecked]}")"
|
||||
server[queryString]="$(echo "${server[requestURI]}" | awk -F? '{for (i=2; i<=NF; i++) print $i}')"
|
||||
server[scriptName]="$(echo "${server[requestURI]}" | awk -F? '{ print $1 }')"
|
||||
server[scriptFilename]="$(realpath -sm "${settings[home]}${server[scriptName]}")"
|
||||
first=0
|
||||
continue
|
||||
fi
|
||||
|
@ -38,11 +48,30 @@ if test "$first" = 1; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
server[httpAccept]="${headers[Accept]}"
|
||||
server[httpAcceptCharset]="${headers[Accept-Charset]}"
|
||||
server[httpAcceptEncoding]="${headers[Accept-Encoding]}"
|
||||
server[httpAcceptLanguage]="${headers[Accept-Language]}"
|
||||
server[httpConnection]="${headers[Accept-Connection]}"
|
||||
server[httpHost]="${headers[Host]}"
|
||||
server[httpReferer]="${headers[Referer]}"
|
||||
server[httpUserAgent]="${headers[User-Agent]}"
|
||||
|
||||
server[remoteUser]="" # TODO not implemented
|
||||
server[redirectRemoteUser]="" # TODO not implemented
|
||||
server[authType]="" # TODO not implemented
|
||||
|
||||
server[serverSignature]=""
|
||||
if true; then # TODO add condition setting
|
||||
server[serverSignature]="${server[httpHost]} (${server[serverSoftware]})"
|
||||
fi
|
||||
|
||||
placeholder() {
|
||||
declare -A tokens
|
||||
tokens[path]="${server[path]}"
|
||||
tokens[host]="${headers[Host]}"
|
||||
tokens[server]="${settings[server]}"
|
||||
tokens[path]="${server[scriptName]}"
|
||||
tokens[host]="${server[httpHost]}"
|
||||
tokens[server]="${server[serverSoftware]}"
|
||||
tokens[signature]="${server[serverSignature]}"
|
||||
|
||||
text="$(cat)"
|
||||
|
||||
|
@ -76,13 +105,41 @@ removeStatusContainer() {
|
|||
rm "$container"
|
||||
}
|
||||
|
||||
isExecutable() {
|
||||
isExecutableShell() {
|
||||
path="$1"
|
||||
if test ! -x "$path" -o ! -f "$path"; then
|
||||
return 1
|
||||
fi
|
||||
ext="$(echo "$path" | awk -F. '{ print $NF }')"
|
||||
for i in ${settings[executeable]}; do
|
||||
for i in ${settings[shellExec]}; do
|
||||
if test "$ext" = "$i"; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
isExecutableCGI() {
|
||||
path="$1"
|
||||
if test ! -x "$path" -o ! -f "$path"; then
|
||||
return 1
|
||||
fi
|
||||
ext="$(echo "$path" | awk -F. '{ print $NF }')"
|
||||
for i in ${settings[cgiExec]}; do
|
||||
if test "$ext" = "$i"; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
isExecutablePHP() {
|
||||
path="$1"
|
||||
if test ! -x "$path" -o ! -f "$path"; then
|
||||
return 1
|
||||
fi
|
||||
ext="$(echo "$path" | awk -F. '{ print $NF }')"
|
||||
for i in ${settings[phpExec]}; do
|
||||
if test "$ext" = "$i"; then
|
||||
return 0
|
||||
fi
|
||||
|
@ -101,13 +158,13 @@ responseHeaders[Connection]="max=1"
|
|||
|
||||
type=""
|
||||
|
||||
if test ! -e "${server[real_path]}"; then
|
||||
if test ! -e "${server[scriptFilename]}"; then
|
||||
status=404
|
||||
|
||||
content="$(placeholder < ./404.html)"
|
||||
|
||||
type="-"
|
||||
elif test "${settings[index]}" = "true" -a -d "${server[real_path]}"; then
|
||||
elif test "${settings[index]}" = "true" -a -d "${server[scriptFilename]}"; then
|
||||
container="$(addStatusContainer)"
|
||||
content="$(./index.sh "$baseSource" "$container" "$(declare -p settings)" "$(declare -p server)" "$(declare -p headers)")"
|
||||
status=$(head -n 1 "$container")
|
||||
|
@ -121,10 +178,10 @@ elif test "${settings[index]}" = "true" -a -d "${server[real_path]}"; then
|
|||
removeStatusContainer "$container"
|
||||
|
||||
type="index"
|
||||
elif $(isExecutable "${server[real_path]}"); then
|
||||
elif isExecutableShell "${server[scriptFilename]}"; then
|
||||
container="$(addStatusContainer)"
|
||||
pushd "$(dirname "${server[real_path]}")" > /dev/null
|
||||
content=$("${server[real_path]}" "$baseSource" "$container" "$(declare -p settings)" "$(declare -p server)" "$(declare -p headers)")
|
||||
pushd "$(dirname "${server[scriptFilename]}")" > /dev/null
|
||||
content=$("${server[scriptFilename]}" "$baseSource" "$container" "$(declare -p settings)" "$(declare -p server)" "$(declare -p headers)")
|
||||
popd > /dev/null
|
||||
status=$(head -n 1 "$container")
|
||||
if test "$status" = ""; then
|
||||
|
@ -139,12 +196,67 @@ elif $(isExecutable "${server[real_path]}"); then
|
|||
|
||||
removeStatusContainer "$container"
|
||||
|
||||
type="exec"
|
||||
type="shell"
|
||||
elif isExecutableCGI "${server[scriptFilename]}"; then
|
||||
content=""
|
||||
status=200
|
||||
headerDone=0
|
||||
while read line; do
|
||||
if test $headerDone = 1; then
|
||||
content="${content}${line}"$'\n'
|
||||
continue
|
||||
fi
|
||||
if test "$(echo "$line" | grep ':')" = ""; then
|
||||
headerDone=1
|
||||
continue
|
||||
fi
|
||||
if test "$(echo "$line" | awk -F: '{print $1}')" = "Status"; then
|
||||
status="$(echo "$line" | awk '{print $2}')"
|
||||
continue
|
||||
fi
|
||||
responseHeaders[$(echo "$line" | awk -F: '{ print $1 }')]="$(echo "$line" | awk '{for (i=2; i<=NF; i++) print $i}')"
|
||||
done <<< $( # open subshell
|
||||
export GATEWAY_INTERFACE="CGI/1.1"
|
||||
|
||||
export AUTH_TYPE="${server[authType]}"
|
||||
export DOCUMENT_ROOT="${server[documentRoot]}"
|
||||
export HTTP_ACCEPT_CHARSET="${server[httpAcceptCharset]}"
|
||||
export HTTP_ACCEPT_ENCODING="${server[httpAcceptEncoding]}"
|
||||
export HTTP_ACCEPT_LANGUAGE="${server[httpAcceptLanguage]}"
|
||||
export HTTP_ACCEPT="${server[httpAccept]}"
|
||||
export HTTP_CONNECTION="${server[httpConnection]}"
|
||||
export HTTP_HOST="${server[httpHost]}"
|
||||
export HTTPS="${server[https]}"
|
||||
export HTTP_USER_AGENT="${server[httpUserAgent]}"
|
||||
export QUERY_STRING="${server[queryString]}"
|
||||
export REDIRECT_REMOTE_USER="${server[redirectRemoteUser]}"
|
||||
export REMOTE_ADDR="${server[remoteAddress]}"
|
||||
export REMOTE_HOST="${server[remoteHost]}"
|
||||
export REMOTE_PORT="${server[remotePort]}"
|
||||
export REMOTE_USER="${server[remoteUser]}"
|
||||
export REQUEST_METHOD="${server[requestMethod]}"
|
||||
export REQUEST_TIME_FLOAT="${server[requestTimeFloat]}"
|
||||
export REQUEST_TIME="${server[requestTime]}"
|
||||
export REQUEST_URI="${server[requestURI]}"
|
||||
export SCRIPT_FILENAME="${server[scriptFilename]}"
|
||||
export SCRIPT_NAME="${server[scriptName]}"
|
||||
export SERVER_ADDR="${server[serverAddress]}"
|
||||
export SERVER_ADMIN="${server[serverAdmin]}"
|
||||
export SERVER_NAME="${server[serverName]}"
|
||||
export SERVER_PORT="${server[serverPort]}"
|
||||
export SERVER_PROTOCOL="${server[serverProtocol]}"
|
||||
export SERVER_SIGNATURE="${server[serverSignature]}"
|
||||
export SERVER_SOFTWARE="${server[serverSoftware]}"
|
||||
|
||||
${server[scriptFilename]}
|
||||
)
|
||||
|
||||
type="cgi"
|
||||
else
|
||||
status=200
|
||||
#responseHeaders['Content-Type']="$(file -b --mime-type ${server[real_path]})"
|
||||
responseHeaders['Content-Type']="$(mimetype -b "${server[real_path]}")"
|
||||
content="$(cat ${server[real_path]})"
|
||||
#responseHeaders['Content-Type']="$(file -b --mime-type ${server[scriptFilename]})"
|
||||
responseHeaders['Content-Type']="$(mimetype -b "${server[scriptFilename]}")"
|
||||
content="$(cat ${server[scriptFilename]})"
|
||||
|
||||
type="static"
|
||||
fi
|
||||
|
@ -152,13 +264,14 @@ fi
|
|||
length=$(printf "%s" "$content" | wc -c)
|
||||
|
||||
if test "${settings[verbose]}" -ge "0"; then
|
||||
echo "$(date --rfc-3339=ns) - ${server[remoteAddress]}:${server[remotePort]} - ${headers[Host]}${server[path]} - $type - $status - $length bytes" 1>&2
|
||||
echo "$(date --rfc-3339=ns) - ${server[remoteAddress]}:${server[remotePort]} - ${headers[Host]}${server[queryURI]} - $type - $status - $length bytes" 1>&2
|
||||
fi
|
||||
|
||||
echo -en "HTTP/1.1 $status $(./statusString.sh $status)\r\n"
|
||||
echo -en "Content-Length: $length\r\n"
|
||||
for key in ${!responseHeaders[@]}; do
|
||||
echo -en "$(urlencode "$key"): $(urlencode "${responseHeaders[$key]}")\r\n"
|
||||
#echo -en "$(urlencode "$key"): $(urlencode "${responseHeaders[$key]}")\r\n"
|
||||
echo -en "$key: ${responseHeaders[$key]}\r\n"
|
||||
done
|
||||
echo -en "\r\n"
|
||||
printf "%s" "$content"
|
||||
|
|
12
server.sh
12
server.sh
|
@ -27,7 +27,7 @@ echoOnVerbose() {
|
|||
|
||||
progname="$0"
|
||||
|
||||
OPTS=$(getopt -o "p:vqh:" -l "port:,verbose,quiet,home:" -- $@)
|
||||
OPTS=$(getopt -o "p:vqh:n:" -l "port:,verbose,quiet,home:,name:admin:" -- $@)
|
||||
if test $? != 0; then
|
||||
exit $EXIT_FAILURE
|
||||
fi
|
||||
|
@ -35,6 +35,8 @@ fi
|
|||
eval set -- "$OPTS"
|
||||
|
||||
home="./home/"
|
||||
name="localhost"
|
||||
admin="admin@localhost"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
|
@ -42,6 +44,8 @@ while true; do
|
|||
-v|--verbose) verboselevel=$(($verboselevel+1)); shift;;
|
||||
-q|--quiet) verboselevel=-1; shift;;
|
||||
-h|--home) home=$2; shift 2;;
|
||||
-n|--name) name=$2; shift 2;;
|
||||
--admin) admin=$2; shift 2;;
|
||||
--) shift; break;;
|
||||
esac
|
||||
done
|
||||
|
@ -55,8 +59,12 @@ settingsfile="/dev/shm/wserver-$$"
|
|||
declare -A settings
|
||||
settings[serverDirectory]="$(pwd)"
|
||||
settings[home]="$home"
|
||||
settings[name]="$name"
|
||||
settings[admin]="$admin"
|
||||
settings[verbose]=$verboselevel
|
||||
settings[executeable]="sh php py cgi"
|
||||
settings[shellExec]="sh"
|
||||
settings[cgiExec]="cgi"
|
||||
settings[phpExec]="php"
|
||||
settings[server]="ShellSpider V1"
|
||||
settings[index]="true"
|
||||
declare -p settings > $settingsfile
|
||||
|
|
Loading…
Reference in a new issue