httpsplitting.md 3.6 KB

[http_splitting] HTTP Splitting

HTTP Splitting - уязвимость, возникающая из-за неправильной обработки входных данных. Зачастую может быть для атак на приложение стоящее за Nginx (HTTP Request Splitting) или на клиентов приложения (HTTP Response Splitting).

Уязвимость возникает в случае, когда атакующий может внедрить символ перевода строки \n в запрос или ответ формируемый Nginx.

Как самостоятельно обнаружить?

При анализе конфигурации всега стоит обращать внимание на:

  • какие переменные используются в директивах, отвечающих за формирование запросов (могут ли они содержать CRLF), например: rewrite, return, add_header, proxy_set_header или proxy_pass;
  • используются ли переменные $uri и $document_uri и если да, то в каких директивах, т.к. они гарантированно содержат урлдекодированное значение;
  • переменные, выделенные из групп с исключающим диапазоном: (?P<myvar>[^.]+).

Пример плохой конфигурации с переменной, полученной из группы с исключающим диапазоном:

server {
    listen 80 default;

    location ~ /v1/((?<action>[^.]*)\.json)?$ {
        add_header X-Action $action;
        return 200 "OK";
    }
}

Пример эксплуатации данной конфигурации:

GET /v1/see%20below%0d%0ax-crlf-header:injected.json HTTP/1.0
Host: localhost

HTTP/1.1 200 OK
Server: nginx/1.11.10
Date: Mon, 13 Mar 2017 21:21:29 GMT
Content-Type: application/octet-stream
Content-Length: 2
Connection: close
X-Action: see below
x-crlf-header:injected

OK

Из примера видно, что злоумышленник смог добавить заголовок ответа x-crlf-header: injected. Это случилось благодаря стечению нескольких обстоятельств:

  • add_header не кодирует/валидирует переданные ему значения, считая что автор знает о последствиях;
  • значение пути нормализуется перед обработкой локейшена;
  • переменная $action была выделена из группы регулярного выражения с исключающим диапазоном: [^.]*;
  • таким образом, значение переменной $action равно see below\r\nx-crlf-header:injected и при её использовании в формировании ответа добавился заголовок.

Что делать?

  • старайтесь использовать более безопасные переменные, например, $request_uri вместо $uri;
  • запретите перевод строки в исключающем диапазоне, например, /some/(?<action>[^/\s]+) вместо /some/(?<action>[^/]+;
  • возможно, хорошей идеей будет добавить валидацию $uri (только если вы знаете, что делаете).