Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions setup/generate.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,49 @@
// the connection is direct to the target (not an HTTP proxy).
$squid_socks = 'cache_peer %s parent %d 0 no-digest no-netdb-exchange connect-fail-limit=2 connect-timeout=8 round-robin no-query allow-miss proxy-only originserver name=%s %s';

// Reject any byte that could break squid.conf tokenization or inject
// a new directive (whitespace, control chars, quotes, backslash, '#').
// Applied to host/user/pass to prevent config injection from a tainted
// proxyList.txt (e.g. one fetched from a remote URL).
$reject_unsafe = '/[\s"#\\\\\x00-\x1F\x7F]/';

while ($line = fgets($proxies)){
$line = trim($line);
if ($line === '' || $line[0] === '#') {
continue;
}
$proxyInfo = array_combine($keys, array_pad((explode(":", $line, 5)), 5, ''));
$squid_conf = [];
$cred = '';
if(!$proxyInfo['host'] && !$proxyInfo['port']){
continue;
}

// Validate host: hostname or IPv4/IPv6 literal. No shell/conf metachars.
if (preg_match($reject_unsafe, $proxyInfo['host']) ||
!preg_match('/^[A-Za-z0-9.:\[\]_-]+$/', $proxyInfo['host'])) {
fwrite(STDERR, "Skipping proxy with invalid host: " . $proxyInfo['host'] . PHP_EOL);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

ログインジェクション: 拒否理由に不正値を素のままで埋め込んでいます。

$reject_unsafe\s(改行含む)にマッチすると即 continue しますが、その直前に $proxyInfo['host'] をそのまま STDERR に書き出しています。悪意ある proxyList.txt の 1 行に evil\nFAKE LOG LINE のような値が含まれる場合、ログが複数行に分割され、下流のログ集約で偽のエントリを注入できます。port 側(Line 49)も、非数値で任意バイトが来る可能性があるため同じリスクがあります(Line 57/61 の host はこの時点で既に検証済みなので安全)。

出力前にサニタイズ(例えば rawurlencode もしくは addcslashes による制御文字のエスケープ)するのが安全です。

🛡️ 提案パッチ
     // Validate host: hostname or IPv4/IPv6 literal. No shell/conf metachars.
     if (preg_match($reject_unsafe, $proxyInfo['host']) ||
         !preg_match('/^[A-Za-z0-9.:\[\]_-]+$/', $proxyInfo['host'])) {
-        fwrite(STDERR, "Skipping proxy with invalid host: " . $proxyInfo['host'] . PHP_EOL);
+        fwrite(STDERR, "Skipping proxy with invalid host: " . rawurlencode($proxyInfo['host']) . PHP_EOL);
         continue;
     }
     // Validate port: 1-65535.
     if (!ctype_digit((string)$proxyInfo['port']) ||
         (int)$proxyInfo['port'] < 1 || (int)$proxyInfo['port'] > 65535) {
-        fwrite(STDERR, "Skipping proxy with invalid port: " . $proxyInfo['port'] . PHP_EOL);
+        fwrite(STDERR, "Skipping proxy with invalid port: " . rawurlencode((string)$proxyInfo['port']) . PHP_EOL);
         continue;
     }

Also applies to: 49-49

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@setup/generate.php` at line 43, The STDERR log writes raw values from
$proxyInfo['host'] (and similarly $proxyInfo['port'] before its check) which
allows log injection; sanitize these values before embedding in the message used
in fwrite(STDERR, ...) by escaping control characters (e.g. with
addcslashes($proxyInfo['host'], "\0..\37") or rawurlencode) and use the
sanitized variable in the "Skipping proxy with invalid host" and corresponding
port rejection messages; keep the existing $reject_unsafe validation but ensure
you never print unsanitized $proxyInfo['host'] or $proxyInfo['port'] to STDERR.

continue;
}
// Validate port: 1-65535.
if (!ctype_digit((string)$proxyInfo['port']) ||
(int)$proxyInfo['port'] < 1 || (int)$proxyInfo['port'] > 65535) {
fwrite(STDERR, "Skipping proxy with invalid port: " . $proxyInfo['port'] . PHP_EOL);
continue;
}
// Validate credentials: no whitespace/control chars/quotes/backslash/#.
// (SOCKS5 RFC1929 allows up to 255 bytes of arbitrary octets, but we
// conservatively reject bytes that would break squid.conf.)
if (($proxyInfo['user'] !== '' && preg_match($reject_unsafe, $proxyInfo['user'])) ||
($proxyInfo['pass'] !== '' && preg_match($reject_unsafe, $proxyInfo['pass']))) {
fwrite(STDERR, "Skipping proxy with unsafe characters in credentials: " . $proxyInfo['host'] . PHP_EOL);
continue;
}
if (strlen($proxyInfo['user']) > 255 || strlen($proxyInfo['pass']) > 255) {
fwrite(STDERR, "Skipping proxy with credentials exceeding 255 bytes: " . $proxyInfo['host'] . PHP_EOL);
continue;
}

if(!$proxyInfo['scheme']){
//open proxy server IP:Port Pattern.
//No create gost
Expand Down
29 changes: 14 additions & 15 deletions squid_patch/src/SocksPeerConnector.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,20 +127,15 @@ static inline bool socks5Connect(int fd,
const bool hasAuth = (!user.empty() && !pass.empty());

/* --- greeting ---------------------------------------------------- */
uint8_t greeting[4];
size_t gLen;
if (hasAuth) {
greeting[0] = 0x05; /* VER */
greeting[1] = 0x02; /* NMETHODS */
greeting[2] = 0x00; /* NO AUTHENTICATION */
greeting[3] = 0x02; /* USERNAME / PASSWORD */
gLen = 4;
} else {
greeting[0] = 0x05;
greeting[1] = 0x01;
greeting[2] = 0x00;
gLen = 3;
}
/* When credentials are configured, advertise ONLY USER/PASS to
* prevent a rogue SOCKS5 server from silently downgrading to
* "no authentication" and accepting traffic without verifying
* the credentials the operator explicitly provided. */
uint8_t greeting[3];
greeting[0] = 0x05; /* VER */
greeting[1] = 0x01; /* NMETHODS */
greeting[2] = hasAuth ? 0x02 : 0x00; /* USER/PASS or NO AUTH */
const size_t gLen = 3;

if (!syncSend(fd, greeting, gLen))
return false;
Expand Down Expand Up @@ -182,7 +177,11 @@ static inline bool socks5Connect(int fd,
return false; /* auth failed or wrong sub-negotiation version */

} else if (gResp[1] == 0x00) {
/* no auth required */
/* Server chose "no authentication". Only accept this when the
* operator did NOT configure credentials; otherwise the server
* is downgrading away from the authentication we required. */
if (hasAuth)
return false;
} else {
return false; /* unsupported or unacceptable method (includes 0xFF) */
}
Expand Down
Loading