mirror of
https://github.com/3proxy/3proxy.git
synced 2026-08-05 17:20:11 +08:00
fix: compare CL passwords by actual length
Short cleartext (CL:) passwords were compared with ctmemcmp over pwl_table.recsize-1 bytes, reading past the client password buffer and rejecting valid short passwords. Compare only password bytes plus NUL. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
c60af54c98
commit
0eb4cb8812
@ -247,7 +247,13 @@ int strongauth(struct clientparam * param){
|
||||
int pwlen = strlen((char *)param->password);
|
||||
if(pwlen > 255) pwlen = 255;
|
||||
if((unsigned)pwlen < pwl_table.recsize) {
|
||||
if(strlen(pass + 1) == strlen((char *)param->password) && !ctmemcmp(pass + 1, param->password, pwl_table.recsize - 1)) return 0;
|
||||
/* Compare only the password bytes plus NUL. Using
|
||||
* recsize-1 here read past the client password buffer
|
||||
* (typically strdup of pwlen+1) and rejected valid
|
||||
* short CL: passwords whenever trailing heap bytes
|
||||
* were non-zero. */
|
||||
if(strlen(pass + 1) == (size_t)pwlen &&
|
||||
!ctmemcmp(pass + 1, param->password, (size_t)pwlen + 1)) return 0;
|
||||
} else {
|
||||
mdh_ctx *bctx;
|
||||
unsigned hashsz;
|
||||
|
||||
163
tests/cl-cleartext-auth/run.sh
Executable file
163
tests/cl-cleartext-auth/run.sh
Executable file
@ -0,0 +1,163 @@
|
||||
#!/bin/sh
|
||||
# Regression: users NAME:CL:password must accept short cleartext passwords.
|
||||
# Long passwords (>= pwl_table.recsize) use the BLAKE2 path and already worked.
|
||||
#
|
||||
# Cases:
|
||||
# 1) short correct password -> HTTP success through proxy (not 407 / error 6)
|
||||
# 2) short wrong password -> 407 and error 00006
|
||||
# 3) long (>=64) correct password -> HTTP success
|
||||
#
|
||||
# Usage:
|
||||
# ./tests/cl-cleartext-auth/run.sh [path-to-3proxy]
|
||||
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
ROOT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/../.." && pwd)
|
||||
PROXYBIN=${1:-"$ROOT_DIR/bin/3proxy"}
|
||||
WORKDIR=${TMPDIR:-/tmp}/3proxy-cl-cleartext-auth-$$
|
||||
LONGPW=$(python3 -c 'print("L"*64)')
|
||||
|
||||
if [ ! -x "$PROXYBIN" ]; then
|
||||
echo "FAIL: 3proxy binary not found or not executable: $PROXYBIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
echo "FAIL: curl is required" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
echo "FAIL: python3 is required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cleanup() {
|
||||
for f in short.pid wrong.pid long.pid dest.pid; do
|
||||
if [ -f "$WORKDIR/$f" ]; then
|
||||
kill "$(cat "$WORKDIR/$f")" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
pkill -f "$WORKDIR" 2>/dev/null || true
|
||||
rm -rf "$WORKDIR"
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
mkdir -p "$WORKDIR"
|
||||
cd "$WORKDIR"
|
||||
|
||||
# Local plain HTTP target (no external network dependency)
|
||||
python3 - <<'PY' >dest.out 2>&1 &
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
class H(BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
body = b"OK-AUTH\n"
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Length", str(len(body)))
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
def log_message(self, *a):
|
||||
pass
|
||||
print("ready", flush=True)
|
||||
HTTPServer(("127.0.0.1", 19460), H).serve_forever()
|
||||
PY
|
||||
echo $! > dest.pid
|
||||
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
grep -q ready dest.out 2>/dev/null && break
|
||||
i=$((i + 1))
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
cat > short.cfg <<EOF
|
||||
log $WORKDIR/short.log
|
||||
logformat "%Y%m%d%H%M%S.%. %p %E %U %T"
|
||||
users admin:CL:testpassword
|
||||
auth strong
|
||||
allow admin
|
||||
proxy -a -n -p18650
|
||||
EOF
|
||||
|
||||
cat > wrong.cfg <<EOF
|
||||
log $WORKDIR/wrong.log
|
||||
logformat "%Y%m%d%H%M%S.%. %p %E %U %T"
|
||||
users admin:CL:testpassword
|
||||
auth strong
|
||||
allow admin
|
||||
proxy -a -n -p18651
|
||||
EOF
|
||||
|
||||
cat > long.cfg <<EOF
|
||||
log $WORKDIR/long.log
|
||||
logformat "%Y%m%d%H%M%S.%. %p %E %U %T"
|
||||
users admin:CL:${LONGPW}
|
||||
auth strong
|
||||
allow admin
|
||||
proxy -a -n -p18652
|
||||
EOF
|
||||
|
||||
"$PROXYBIN" short.cfg > short.out 2>&1 &
|
||||
echo $! > short.pid
|
||||
"$PROXYBIN" wrong.cfg > wrong.out 2>&1 &
|
||||
echo $! > wrong.pid
|
||||
"$PROXYBIN" long.cfg > long.out 2>&1 &
|
||||
echo $! > long.pid
|
||||
sleep 0.4
|
||||
|
||||
SHORT_CODE=$(curl -s --max-time 10 -o /tmp/cl-short.body -w '%{http_code}' \
|
||||
-x http://admin:testpassword@127.0.0.1:18650 \
|
||||
http://127.0.0.1:19460/ || echo fail)
|
||||
WRONG_CODE=$(curl -s --max-time 10 -o /tmp/cl-wrong.body -w '%{http_code}' \
|
||||
-x http://admin:wrongpassword@127.0.0.1:18651 \
|
||||
http://127.0.0.1:19460/ || echo fail)
|
||||
LONG_CODE=$(curl -s --max-time 10 -o /tmp/cl-long.body -w '%{http_code}' \
|
||||
-x "http://admin:${LONGPW}@127.0.0.1:18652" \
|
||||
http://127.0.0.1:19460/ || echo fail)
|
||||
|
||||
for f in short.pid wrong.pid long.pid; do
|
||||
if [ -f "$f" ]; then
|
||||
kill "$(cat "$f")" 2>/dev/null || true
|
||||
wait "$(cat "$f")" 2>/dev/null || true
|
||||
rm -f "$f"
|
||||
fi
|
||||
done
|
||||
sleep 0.1
|
||||
|
||||
echo "=== short correct: http=$SHORT_CODE body=$(cat /tmp/cl-short.body 2>/dev/null || true) ==="
|
||||
echo "=== short wrong: http=$WRONG_CODE ==="
|
||||
echo "=== long correct: http=$LONG_CODE body=$(cat /tmp/cl-long.body 2>/dev/null || true) ==="
|
||||
echo "=== short.log ==="; cat short.log 2>/dev/null || true
|
||||
echo "=== wrong.log ==="; cat wrong.log 2>/dev/null || true
|
||||
echo "=== long.log ==="; cat long.log 2>/dev/null || true
|
||||
|
||||
fail=0
|
||||
|
||||
if [ "$SHORT_CODE" != "200" ] || [ "$(cat /tmp/cl-short.body 2>/dev/null || true)" != "OK-AUTH" ]; then
|
||||
echo "FAIL: short correct CL password did not authenticate (http=$SHORT_CODE)" >&2
|
||||
fail=1
|
||||
fi
|
||||
if grep -E ' 00006 +admin ' short.log >/dev/null 2>&1; then
|
||||
echo "FAIL: short correct password logged error 00006" >&2
|
||||
fail=1
|
||||
fi
|
||||
|
||||
if [ "$WRONG_CODE" != "407" ]; then
|
||||
echo "FAIL: short wrong password expected HTTP 407, got $WRONG_CODE" >&2
|
||||
fail=1
|
||||
fi
|
||||
if ! grep -E ' 00006 +admin ' wrong.log >/dev/null 2>&1; then
|
||||
echo "FAIL: short wrong password did not log error 00006" >&2
|
||||
fail=1
|
||||
fi
|
||||
|
||||
if [ "$LONG_CODE" != "200" ] || [ "$(cat /tmp/cl-long.body 2>/dev/null || true)" != "OK-AUTH" ]; then
|
||||
echo "FAIL: long correct CL password did not authenticate (http=$LONG_CODE)" >&2
|
||||
fail=1
|
||||
fi
|
||||
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "PASS: CL cleartext auth accepts short and long passwords; rejects wrong short password"
|
||||
exit 0
|
||||
Loading…
Reference in New Issue
Block a user