Angular

Reading time: 22 minutes

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

La Liste de Vérification

Checklist from here.

  • Angular est considĂ©rĂ© comme un framework cĂŽtĂ© client et n'est pas censĂ© fournir de protection cĂŽtĂ© serveur
  • Le sourcemap pour les scripts est dĂ©sactivĂ© dans la configuration du projet
  • Les entrĂ©es utilisateur non fiables sont toujours interpolĂ©es ou assainies avant d'ĂȘtre utilisĂ©es dans les templates
  • L'utilisateur n'a aucun contrĂŽle sur les templates cĂŽtĂ© serveur ou cĂŽtĂ© client
  • Les entrĂ©es utilisateur non fiables sont assainies en utilisant un contexte de sĂ©curitĂ© appropriĂ© avant d'ĂȘtre considĂ©rĂ©es comme fiables par l'application
  • Les mĂ©thodes BypassSecurity* ne sont pas utilisĂ©es avec des entrĂ©es non fiables
  • Les entrĂ©es utilisateur non fiables ne sont pas passĂ©es aux classes Angular telles que ElementRef, Renderer2 et Document, ou Ă  d'autres sinks JQuery/DOM

Qu'est-ce qu'Angular

Angular est un framework front-end puissant et open-source maintenu par Google. Il utilise TypeScript pour amĂ©liorer la lisibilitĂ© du code et le dĂ©bogage. Avec de forts mĂ©canismes de sĂ©curitĂ©, Angular prĂ©vient les vulnĂ©rabilitĂ©s courantes cĂŽtĂ© client comme XSS et redirections ouvertes. Il peut Ă©galement ĂȘtre utilisĂ© cĂŽtĂ© serveur, rendant les considĂ©rations de sĂ©curitĂ© importantes des deux cĂŽtĂ©s.

Architecture du framework

Afin de mieux comprendre les bases d'Angular, passons en revue ses concepts essentiels.

Un projet Angular commun ressemble généralement à :

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

Selon la documentation, chaque application Angular a au moins un composant, le composant racine (AppComponent) qui connecte une hiérarchie de composants avec le DOM. Chaque composant définit une classe qui contient des données et une logique d'application, et est associée à un modÚle HTML qui définit une vue à afficher dans un environnement cible. Le décorateur @Component() identifie la classe immédiatement en dessous comme un composant, et fournit le modÚle et les métadonnées spécifiques au composant. Le AppComponent est défini dans le fichier app.component.ts.

Les NgModules Angular déclarent un contexte de compilation pour un ensemble de composants qui est dédié à un domaine d'application, un flux de travail, ou un ensemble de capacités étroitement liées. Chaque application Angular a un module racine, conventionnellement nommé AppModule, qui fournit le mécanisme de démarrage qui lance l'application. Une application contient généralement de nombreux modules fonctionnels. Le AppModule est défini dans le fichier app.module.ts.

Le NgModule Router d'Angular fournit un service qui vous permet de définir un chemin de navigation parmi les différents états d'application et hiérarchies de vues dans votre application. Le RouterModule est défini dans le fichier app-routing.module.ts.

Pour les donnĂ©es ou la logique qui ne sont pas associĂ©es Ă  une vue spĂ©cifique, et que vous souhaitez partager entre les composants, vous crĂ©ez une classe de service. La dĂ©finition d'une classe de service est immĂ©diatement prĂ©cĂ©dĂ©e du dĂ©corateur @Injectable(). Le dĂ©corateur fournit les mĂ©tadonnĂ©es qui permettent Ă  d'autres fournisseurs d'ĂȘtre injectĂ©s en tant que dĂ©pendances dans votre classe. L'injection de dĂ©pendance (DI) vous permet de garder vos classes de composants lĂ©gĂšres et efficaces. Elles ne rĂ©cupĂšrent pas de donnĂ©es du serveur, ne valident pas les entrĂ©es utilisateur, ou ne se connectent pas directement Ă  la console ; elles dĂ©lĂšguent de telles tĂąches aux services.

Configuration de sourcemap

Le framework Angular traduit les fichiers TypeScript en code JavaScript en suivant les options de tsconfig.json et construit ensuite un projet avec la configuration angular.json. En regardant le fichier angular.json, nous avons observé une option pour activer ou désactiver un sourcemap. Selon la documentation Angular, la configuration par défaut a un fichier sourcemap activé pour les scripts et n'est pas caché par défaut :

json
"sourceMap": {
"scripts": true,
"styles": true,
"vendor": false,
"hidden": false
}

Généralement, les fichiers sourcemap sont utilisés à des fins de débogage car ils associent les fichiers générés à leurs fichiers d'origine. Par conséquent, il n'est pas recommandé de les utiliser dans un environnement de production. Si les sourcemaps sont activés, cela améliore la lisibilité et aide à l'analyse des fichiers en reproduisant l'état d'origine du projet Angular. Cependant, s'ils sont désactivés, un examinateur peut toujours analyser manuellement un fichier JavaScript compilé en recherchant des motifs anti-sécurité.

De plus, un fichier JavaScript compilĂ© avec un projet Angular peut ĂȘtre trouvĂ© dans les outils de dĂ©veloppement du navigateur → Sources (ou DĂ©bogueur et Sources) → [id].main.js. Selon les options activĂ©es, ce fichier peut contenir la ligne suivante Ă  la fin //# sourceMappingURL=[id].main.js.map ou il peut ne pas l'avoir, si l'option hidden est dĂ©finie sur true. NĂ©anmoins, si le sourcemap est dĂ©sactivĂ© pour scripts, les tests deviennent plus complexes, et nous ne pouvons pas obtenir le fichier. De plus, le sourcemap peut ĂȘtre activĂ© lors de la construction du projet comme ng build --source-map.

Liaison de données

La liaison fait rĂ©fĂ©rence au processus de communication entre un composant et sa vue correspondante. Elle est utilisĂ©e pour transfĂ©rer des donnĂ©es vers et depuis le framework Angular. Les donnĂ©es peuvent ĂȘtre transmises par divers moyens, tels que par le biais d'Ă©vĂ©nements, d'interpolation, de propriĂ©tĂ©s ou par le mĂ©canisme de liaison bidirectionnelle. De plus, les donnĂ©es peuvent Ă©galement ĂȘtre partagĂ©es entre des composants liĂ©s (relation parent-enfant) et entre deux composants non liĂ©s en utilisant la fonctionnalitĂ© Service.

Nous pouvons classer la liaison par flux de données :

  • Source de donnĂ©es vers cible de vue (inclut interpolation, propriĂ©tĂ©s, attributs, classes et styles); peut ĂȘtre appliquĂ© en utilisant [] ou {{}} dans le modĂšle ;
  • Cible de vue vers source de donnĂ©es (inclut Ă©vĂ©nements); peut ĂȘtre appliquĂ© en utilisant () dans le modĂšle ;
  • Bidirectionnelle ; peut ĂȘtre appliquĂ© en utilisant [()] dans le modĂšle.

La liaison peut ĂȘtre appelĂ©e sur des propriĂ©tĂ©s, des Ă©vĂ©nements et des attributs, ainsi que sur tout membre public d'une directive source :

TYPECIBLEEXEMPLES
PropriétéPropriété d'élément, Propriété de composant, Propriété de directive<img [alt]="hero.name" [src]="heroImageUrl">
ÉvĂ©nementÉvĂ©nement d'Ă©lĂ©ment, ÉvĂ©nement de composant, ÉvĂ©nement de directive<button type="button" (click)="onSave()">Sauvegarder
BidirectionnelleÉvĂ©nement et propriĂ©tĂ©<input [(ngModel)]="name">
AttributAttribut (l'exception)<button type="button" [attr.aria-label]="help">aide
Classepropriété de classe<div [class.special]="isSpecial">Spécial
Stylepropriété de style<button type="button" [style.color]="isSpecial ? 'red' : 'green'">

ModÚle de sécurité Angular

La conception d'Angular inclut l'encodage ou la désinfection de toutes les données par défaut, rendant de plus en plus difficile la découverte et l'exploitation des vulnérabilités XSS dans les projets Angular. Il existe deux scénarios distincts pour le traitement des données :

  1. Interpolation ou {{user_input}} - effectue un encodage sensible au contexte et interprÚte l'entrée utilisateur comme du texte ;
jsx
//app.component.ts
test = "<script>alert(1)</script><h1>test</h1>";

//app.component.html
{{test}}

Résultat : &lt;script&gt;alert(1)&lt;/script&gt;&lt;h1&gt;test&lt;/h1&gt; 2. Liaison aux propriétés, attributs, classes et styles ou [attribute]="user_input" - effectue une désinfection basée sur le contexte de sécurité fourni.

jsx
//app.component.ts
test = "<script>alert(1)</script><h1>test</h1>";

//app.component.html
<div [innerHtml]="test"></div>

Résultat : <div><h1>test</h1></div>

Il existe 6 types de SecurityContext :

  • None;
  • HTML est utilisĂ©, lors de l'interprĂ©tation de la valeur comme HTML ;
  • STYLE est utilisĂ©, lors de la liaison de CSS dans la propriĂ©tĂ© style ;
  • URL est utilisĂ© pour les propriĂ©tĂ©s d'URL, telles que <a href> ;
  • SCRIPT est utilisĂ© pour le code JavaScript ;
  • RESOURCE_URL comme une URL qui est chargĂ©e et exĂ©cutĂ©e comme code, par exemple, dans <script src>.

Vulnérabilités

Contourner les méthodes de confiance en matiÚre de sécurité

Angular introduit une liste de mĂ©thodes pour contourner son processus de dĂ©sinfection par dĂ©faut et indiquer qu'une valeur peut ĂȘtre utilisĂ©e en toute sĂ©curitĂ© dans un contexte spĂ©cifique, comme dans les cinq exemples suivants :

  1. bypassSecurityTrustUrl est utilisé pour indiquer que la valeur donnée est une URL de style sûre :
jsx
//app.component.ts
this.trustedUrl = this.sanitizer.bypassSecurityTrustUrl('javascript:alert()');

//app.component.html
<a class="e2e-trusted-url" [href]="trustedUrl">Cliquez moi</a>

//résultat
<a _ngcontent-pqg-c12="" class="e2e-trusted-url" href="javascript:alert()">Cliquez moi</a>
  1. bypassSecurityTrustResourceUrl est utilisé pour indiquer que la valeur donnée est une URL de ressource sûre :
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>

//résultat
<img _ngcontent-nre-c12="" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png">
  1. bypassSecurityTrustHtml est utilisé pour indiquer que la valeur donnée est un HTML sûr. Notez que l'insertion d'éléments script dans l'arbre DOM de cette maniÚre ne les fera pas exécuter le code JavaScript contenu, en raison de la façon dont ces éléments sont ajoutés à l'arbre 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>

//résultat
<h1>tag html</h1>
<svg onclick="alert('bypassSecurityTrustHtml')" style="display:block">blah</svg>
  1. bypassSecurityTrustScript est utilisé pour indiquer que la valeur donnée est un JavaScript sûr. Cependant, nous avons trouvé que son comportement était imprévisible, car nous n'avons pas pu exécuter de code JS dans les modÚles en utilisant cette méthode.
jsx
//app.component.ts
this.trustedScript = this.sanitizer.bypassSecurityTrustScript("alert('bypass Security TrustScript')");

//app.component.html
<script [innerHtml]="trustedScript"></script>

//résultat
-
  1. bypassSecurityTrustStyle est utilisé pour indiquer que la valeur donnée est un CSS sûr. L'exemple suivant illustre l'injection 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">

//résultat
Request URL: GET example.com/exfil/a

Angular fournit une méthode sanitize pour désinfecter les données avant de les afficher dans les vues. Cette méthode utilise le contexte de sécurité fourni et nettoie l'entrée en conséquence. Il est cependant crucial d'utiliser le bon contexte de sécurité pour les données et le contexte spécifiques. Par exemple, appliquer un désinfectant avec SecurityContext.URL sur du contenu HTML ne protÚge pas contre les valeurs HTML dangereuses. Dans de tels scénarios, un mauvais usage du contexte de sécurité pourrait conduire à des vulnérabilités XSS.

Injection HTML

Cette vulnérabilité se produit lorsque l'entrée utilisateur est liée à l'une des trois propriétés : innerHTML, outerHTML ou iframe srcdoc. Bien que la liaison à ces attributs interprÚte le HTML tel quel, l'entrée est désinfectée en utilisant SecurityContext.HTML. Ainsi, l'injection HTML est possible, mais le cross-site scripting (XSS) ne l'est pas.

Exemple d'utilisation de innerHTML :

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>

Injection de modĂšle

Rendu cÎté client (CSR)

Angular utilise des modÚles pour construire des pages de maniÚre dynamique. L'approche consiste à enfermer les expressions de modÚle que Angular doit évaluer dans des accolades doubles ({{}}). De cette maniÚre, le framework offre des fonctionnalités supplémentaires. Par exemple, un modÚle tel que {{1+1}} s'afficherait comme 2.

En gĂ©nĂ©ral, Angular Ă©chappe les entrĂ©es utilisateur qui peuvent ĂȘtre confondues avec des expressions de modĂšle (par exemple, des caractĂšres tels que `< > ' " ``). Cela signifie que des Ă©tapes supplĂ©mentaires sont nĂ©cessaires pour contourner cette restriction, comme l'utilisation de fonctions qui gĂ©nĂšrent des objets de chaĂźne JavaScript pour Ă©viter d'utiliser des caractĂšres sur liste noire. Cependant, pour y parvenir, nous devons prendre en compte le contexte Angular, ses propriĂ©tĂ©s et ses variables. Par consĂ©quent, une attaque par injection de modĂšle peut apparaĂźtre comme suit :

jsx
//app.component.ts
const _userInput = '{{constructor.constructor(\'alert(1)\'()}}'
@Component({
selector: 'app-root',
template: '<h1>title</h1>' + _userInput
})

Comme indiqué ci-dessus : constructor fait référence à la portée de la propriété Object constructor, nous permettant d'invoquer le constructeur String et d'exécuter un code arbitraire.

Rendu cÎté serveur (SSR)

Contrairement Ă  CSR, qui se produit dans le DOM du navigateur, Angular Universal est responsable du SSR des fichiers de modĂšle. Ces fichiers sont ensuite livrĂ©s Ă  l'utilisateur. MalgrĂ© cette distinction, Angular Universal applique les mĂȘmes mĂ©canismes de dĂ©sinfection utilisĂ©s dans CSR pour amĂ©liorer la sĂ©curitĂ© du SSR. Une vulnĂ©rabilitĂ© d'injection de modĂšle dans le SSR peut ĂȘtre dĂ©tectĂ©e de la mĂȘme maniĂšre que dans le CSR, car le langage de modĂšle utilisĂ© est le mĂȘme.

Bien sûr, il existe également une possibilité d'introduire de nouvelles vulnérabilités d'injection de modÚle lors de l'utilisation de moteurs de modÚle tiers tels que Pug et Handlebars.

XSS

Interfaces DOM

Comme indiqué précédemment, nous pouvons accéder directement au DOM en utilisant l'interface Document. Si l'entrée de l'utilisateur n'est pas validée au préalable, cela peut entraßner des vulnérabilités de script intersite (XSS).

Nous avons utilisé les méthodes document.write() et document.createElement() dans les exemples ci-dessous :

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 Angular

Il existe certaines classes qui peuvent ĂȘtre utilisĂ©es pour travailler avec des Ă©lĂ©ments DOM dans Angular : ElementRef, Renderer2, Location et Document. Une description dĂ©taillĂ©e des deux derniĂšres classes est donnĂ©e dans la section Open redirects. La principale diffĂ©rence entre les deux premiĂšres est que l'API Renderer2 fournit une couche d'abstraction entre l'Ă©lĂ©ment DOM et le code du composant, tandis que ElementRef ne contient qu'une rĂ©fĂ©rence Ă  l'Ă©lĂ©ment. Par consĂ©quent, selon la documentation Angular, l'API ElementRef ne doit ĂȘtre utilisĂ©e qu'en dernier recours lorsque l'accĂšs direct au DOM est nĂ©cessaire.

  • ElementRef contient la propriĂ©tĂ© nativeElement, qui peut ĂȘtre utilisĂ©e pour manipuler les Ă©lĂ©ments DOM. Cependant, une utilisation incorrecte de nativeElement peut entraĂźner une vulnĂ©rabilitĂ© d'injection XSS, comme montrĂ© ci-dessous :
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);
}
}
  • Bien que Renderer2 fournisse une API qui peut ĂȘtre utilisĂ©e en toute sĂ©curitĂ© mĂȘme lorsque l'accĂšs direct aux Ă©lĂ©ments natifs n'est pas pris en charge, elle prĂ©sente encore certaines failles de sĂ©curitĂ©. Avec Renderer2, il est possible de dĂ©finir des attributs sur un Ă©lĂ©ment HTML en utilisant la mĂ©thode setAttribute(), qui n'a pas de mĂ©canismes de prĂ©vention 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()">Click me!</button>
  • Pour dĂ©finir la propriĂ©tĂ© d'un Ă©lĂ©ment DOM, vous pouvez utiliser la mĂ©thode Renderer2.setProperty() et dĂ©clencher une attaque 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()">Click me!</button>

Au cours de nos recherches, nous avons également examiné le comportement d'autres méthodes Renderer2, telles que setStyle(), createComment(), et setValue(), en relation avec les injections XSS et CSS. Cependant, nous n'avons pas pu trouver de vecteurs d'attaque valides pour ces méthodes en raison de leurs limitations fonctionnelles.

jQuery

jQuery est une bibliothĂšque JavaScript rapide, lĂ©gĂšre et riche en fonctionnalitĂ©s qui peut ĂȘtre utilisĂ©e dans le projet Angular pour aider Ă  manipuler les objets DOM HTML. Cependant, comme il est connu, les mĂ©thodes de cette bibliothĂšque peuvent ĂȘtre exploitĂ©es pour atteindre une vulnĂ©rabilitĂ© XSS. Afin de discuter de la maniĂšre dont certaines mĂ©thodes jQuery vulnĂ©rables peuvent ĂȘtre exploitĂ©es dans des projets Angular, nous avons ajoutĂ© cette sous-section.

  • La mĂ©thode html() obtient le contenu HTML du premier Ă©lĂ©ment dans l'ensemble des Ă©lĂ©ments correspondants ou dĂ©finit le contenu HTML de chaque Ă©lĂ©ment correspondant. Cependant, par conception, tout constructeur ou mĂ©thode jQuery qui accepte une chaĂźne HTML peut potentiellement exĂ©cuter du code. Cela peut se produire par injection de balises <script> ou utilisation d'attributs HTML qui exĂ©cutent du code comme montrĂ© dans l'exemple.
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>Click me</button>
<p>some text here</p>
  • La mĂ©thode jQuery.parseHTML() utilise des mĂ©thodes natives pour convertir la chaĂźne en un ensemble de nƓuds DOM, qui peuvent ensuite ĂȘtre insĂ©rĂ©s dans le document.
tsx
jQuery.parseHTML(data [, context ] [, keepScripts ])

Comme mentionné précédemment, la plupart des API jQuery qui acceptent des chaßnes HTML exécuteront des scripts qui sont inclus dans le HTML. La méthode jQuery.parseHTML() ne lance pas de scripts dans le HTML analysé à moins que keepScripts ne soit explicitement true. Cependant, il est toujours possible dans la plupart des environnements d'exécuter des scripts indirectement ; par exemple, via l'attribut <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>Click me</button>
<p id="palias">some text</p>

Open redirects

Interfaces DOM

Selon la documentation W3C, les objets window.location et document.location sont traitĂ©s comme des alias dans les navigateurs modernes. C'est pourquoi ils ont une mise en Ɠuvre similaire de certaines mĂ©thodes et propriĂ©tĂ©s, ce qui pourrait causer un redirection ouverte et un XSS DOM avec des attaques au schĂ©ma javascript:// comme mentionnĂ© ci-dessous.

  • window.location.href(et document.location.href)

La maniĂšre canonique d'obtenir l'objet de localisation DOM actuel est d'utiliser window.location. Il peut Ă©galement ĂȘtre utilisĂ© pour rediriger le navigateur vers une nouvelle page. En consĂ©quence, avoir le contrĂŽle sur cet objet nous permet d'exploiter une vulnĂ©rabilitĂ© de redirection ouverte.

tsx
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.href = "https://google.com/about"
}
}

//app.component.html
<button type="button" (click)="goToUrl()">Click me!</button>

Le processus d'exploitation est identique pour les scénarios suivants.

  • window.location.assign()(et document.location.assign())

Cette mĂ©thode fait en sorte que la fenĂȘtre charge et affiche le document Ă  l'URL spĂ©cifiĂ©e. Si nous avons le contrĂŽle sur cette mĂ©thode, cela pourrait ĂȘtre un point d'entrĂ©e pour une attaque de redirection ouverte.

tsx
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.assign("https://google.com/about")
}
}
  • window.location.replace()(et document.location.replace())

Cette méthode remplace la ressource actuelle par celle à l'URL fournie.

Cela diffÚre de la méthode assign() en ce sens qu'aprÚs avoir utilisé window.location.replace(), la page actuelle ne sera pas enregistrée dans l'historique de session. Cependant, il est également possible d'exploiter une vulnérabilité de redirection ouverte lorsque nous avons le contrÎle sur cette méthode.

tsx
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.replace("http://google.com/about")
}
}
  • window.open()

La mĂ©thode window.open() prend une URL et charge la ressource qu'elle identifie dans un nouvel onglet ou une nouvelle fenĂȘtre existante. Avoir le contrĂŽle sur cette mĂ©thode pourrait Ă©galement ĂȘtre une opportunitĂ© de dĂ©clencher une vulnĂ©rabilitĂ© XSS ou de redirection ouverte.

tsx
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.open("https://google.com/about", "_blank")
}
}

Classes Angular

  • Selon la documentation Angular, Document Angular est le mĂȘme que le document DOM, ce qui signifie qu'il est possible d'utiliser des vecteurs communs pour le document DOM afin d'exploiter des vulnĂ©rabilitĂ©s cĂŽtĂ© client dans Angular. Les propriĂ©tĂ©s et mĂ©thodes Document.location pourraient ĂȘtre des points d'entrĂ©e pour des attaques de redirection ouverte rĂ©ussies comme montrĂ© dans l'exemple :
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()">Click me!</button>
  • Au cours de la phase de recherche, nous avons Ă©galement examinĂ© la classe Location d'Angular pour des vulnĂ©rabilitĂ©s de redirection ouverte, mais aucun vecteur valide n'a Ă©tĂ© trouvĂ©. Location est un service Angular que les applications peuvent utiliser pour interagir avec l'URL actuelle du navigateur. Ce service a plusieurs mĂ©thodes pour manipuler l'URL donnĂ©e - go(), replaceState(), et prepareExternalUrl(). Cependant, nous ne pouvons pas les utiliser pour rediriger vers un domaine externe. Par exemple :
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"));
}
}

Résultat : http://localhost:4200/http://google.com/about

  • La classe Router d'Angular est principalement utilisĂ©e pour naviguer au sein du mĂȘme domaine et n'introduit aucune vulnĂ©rabilitĂ© supplĂ©mentaire Ă  l'application :
jsx
//app-routing.module.ts
const routes: Routes = [
{ path: '', redirectTo: 'https://google.com', pathMatch: 'full' }]

Résultat : http://localhost:4200/https:

Les méthodes suivantes naviguent également dans le cadre du domaine :

jsx
const routes: Routes = [ { path: '', redirectTo: 'ROUTE', pathMatch: 'prefix' } ]
this.router.navigate(['PATH'])
this.router.navigateByUrl('URL')

Références

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks