Translated ['src/pentesting-web/h2c-smuggling.md'] to es

This commit is contained in:
Translator 2025-05-03 00:05:19 +00:00
parent 625ab86da5
commit d47a2f39fd
4 changed files with 88 additions and 552 deletions

View File

@ -58,7 +58,7 @@ En este escenario, un backend que ofrece una API WebSocket pública junto con un
2. El backend responde con un código de estado `426`, indicando la versión de protocolo incorrecta en el encabezado `Sec-WebSocket-Version`. El proxy inverso, ignorando el estado de respuesta del backend, asume que está listo para la comunicación WebSocket y reenvía la respuesta al cliente.
3. En consecuencia, el proxy inverso es engañado para creer que se ha establecido una conexión WebSocket entre el cliente y el backend, mientras que en realidad, el backend había rechazado la solicitud de Upgrade. A pesar de esto, el proxy mantiene una conexión TCP o TLS abierta entre el cliente y el backend, permitiendo al cliente acceder sin restricciones a la API REST privada a través de esta conexión.
Los proxies inversos afectados incluyen Varnish, que se negó a abordar el problema, y la versión 1.8.0 o anterior de Envoy proxy, con versiones posteriores que han alterado el mecanismo de actualización. Otros proxies también pueden ser susceptibles.
Los proxies inversos afectados incluyen Varnish, que se negó a abordar el problema, y la versión 1.8.0 o anterior del proxy Envoy, con versiones posteriores que han alterado el mecanismo de actualización. Otros proxies también pueden ser susceptibles.
![https://github.com/0ang3el/websocket-smuggle/raw/master/img/2-4.png](https://github.com/0ang3el/websocket-smuggle/raw/master/img/2-4.png)

10
theme/elasticlunr.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,554 +1,40 @@
/*
Polyfill so requestIdleCallback works everywhere (IE 11/Safari)
*/
if (typeof window.requestIdleCallback !== "function") {
window.requestIdleCallback = function (cb) {
const start = Date.now();
return setTimeout(function () {
cb({
didTimeout: false,
timeRemaining: function () {
return Math.max(0, 50 - (Date.now() - start));
}
/* ht_searcher.js --------------------------------------------------------- */
(() => {
const WRAPPER = document.getElementById('search-wrapper');
const TOGGLE = document.getElementById('search-toggle');
const INPUT = document.getElementById('searchbar');
const LIST = document.getElementById('searchresults');
const HOTKEY = 83; // “s”
let worker, debounce;
function startWorker() {
if (worker) return;
worker = new Worker('/search-worker.js', { type:'module' });
worker.onmessage = ({data}) => {
LIST.innerHTML = data.slice(0,30).map(h =>
`<li><a href="${h.doc.url}">${h.doc.title}</a></li>`
).join('');
};
}
async function openUI() {
WRAPPER.classList.remove('hidden');
INPUT.focus();
startWorker(); // fetches CDN/GitHub in parallel
}
TOGGLE.addEventListener('click', openUI);
document.addEventListener('keydown', e => {
if (!e.metaKey && !e.ctrlKey && !e.altKey && e.keyCode === HOTKEY) {
e.preventDefault(); openUI();
}
});
}, 1);
};
window.cancelIdleCallback = window.clearTimeout;
}
INPUT.addEventListener('input', e => {
clearTimeout(debounce);
debounce = setTimeout(() => {
worker?.postMessage(e.target.value.trim());
}, 120); // small debounce keeps typing smooth
});
})();
/*
search.js
*/
"use strict";
window.search = window.search || {};
(function search(search) {
// Search functionality
//
// You can use !hasFocus() to prevent keyhandling in your key
// event handlers while the user is typing their search.
if (!Mark || !elasticlunr) {
return;
}
//IE 11 Compatibility from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
if (!String.prototype.startsWith) {
String.prototype.startsWith = function(search, pos) {
return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
};
}
var search_wrap = document.getElementById('search-wrapper'),
search_modal = document.getElementById('search-modal'),
searchbar = document.getElementById('searchbar'),
searchbar_outer = document.getElementById('searchbar-outer'),
searchresults = document.getElementById('searchresults'),
searchresults_outer = document.getElementById('searchresults-outer'),
searchresults_header = document.getElementById('searchresults-header'),
searchicon = document.getElementById('search-toggle'),
content = document.getElementById('content'),
searchindex = null,
doc_urls = [],
results_options = {
teaser_word_count: 30,
limit_results: 30,
},
search_options = {
bool: "AND",
expand: true,
fields: {
title: {boost: 1},
body: {boost: 1},
breadcrumbs: {boost: 0}
}
},
mark_exclude = [],
marker = new Mark(content),
current_searchterm = "",
URL_SEARCH_PARAM = 'search',
URL_MARK_PARAM = 'highlight',
teaser_count = 0,
SEARCH_HOTKEY_KEYCODE = 83,
ESCAPE_KEYCODE = 27,
DOWN_KEYCODE = 40,
UP_KEYCODE = 38,
SELECT_KEYCODE = 13;
function hasFocus() {
return searchbar === document.activeElement;
}
function removeChildren(elem) {
while (elem.firstChild) {
elem.removeChild(elem.firstChild);
}
}
// Helper to parse a url into its building blocks.
function parseURL(url) {
var a = document.createElement('a');
a.href = url;
return {
source: url,
protocol: a.protocol.replace(':',''),
host: a.hostname,
port: a.port,
params: (function(){
var ret = {};
var seg = a.search.replace(/^\?/,'').split('&');
var len = seg.length, i = 0, s;
for (;i<len;i++) {
if (!seg[i]) { continue; }
s = seg[i].split('=');
ret[s[0]] = s[1];
}
return ret;
})(),
file: (a.pathname.match(/\/([^/?#]+)$/i) || [,''])[1],
hash: a.hash.replace('#',''),
path: a.pathname.replace(/^([^/])/,'/$1')
};
}
// Helper to recreate a url string from its building blocks.
function renderURL(urlobject) {
var url = urlobject.protocol + "://" + urlobject.host;
if (urlobject.port != "") {
url += ":" + urlobject.port;
}
url += urlobject.path;
var joiner = "?";
for(var prop in urlobject.params) {
if(urlobject.params.hasOwnProperty(prop)) {
url += joiner + prop + "=" + urlobject.params[prop];
joiner = "&";
}
}
if (urlobject.hash != "") {
url += "#" + urlobject.hash;
}
return url;
}
// Helper to escape html special chars for displaying the teasers
var escapeHTML = (function() {
var MAP = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&#34;',
"'": '&#39;'
};
var repl = function(c) { return MAP[c]; };
return function(s) {
return s.replace(/[&<>'"]/g, repl);
};
})();
function formatSearchMetric(count, searchterm) {
if (count == 1) {
return count + " search result for '" + searchterm + "':";
} else if (count == 0) {
return "No search results for '" + searchterm + "'.";
} else {
return count + " search results for '" + searchterm + "':";
}
}
function formatSearchResult(result, searchterms) {
var teaser = makeTeaser(escapeHTML(result.doc.body), searchterms);
teaser_count++;
// The ?URL_MARK_PARAM= parameter belongs inbetween the page and the #heading-anchor
var url = doc_urls[result.ref].split("#");
if (url.length == 1) { // no anchor found
url.push("");
}
// encodeURIComponent escapes all chars that could allow an XSS except
// for '. Due to that we also manually replace ' with its url-encoded
// representation (%27).
var searchterms = encodeURIComponent(searchterms.join(" ")).replace(/\'/g, "%27");
return '<a href="' + path_to_root + url[0] + '?' + URL_MARK_PARAM + '=' + searchterms + '#' + url[1]
+ '" aria-details="teaser_' + teaser_count + '">' + result.doc.breadcrumbs
+ '<span class="teaser" id="teaser_' + teaser_count + '" aria-label="Search Result Teaser">'
+ teaser + '</span>' + '</a>';
}
function makeTeaser(body, searchterms) {
// The strategy is as follows:
// First, assign a value to each word in the document:
// Words that correspond to search terms (stemmer aware): 40
// Normal words: 2
// First word in a sentence: 8
// Then use a sliding window with a constant number of words and count the
// sum of the values of the words within the window. Then use the window that got the
// maximum sum. If there are multiple maximas, then get the last one.
// Enclose the terms in <em>.
var stemmed_searchterms = searchterms.map(function(w) {
return elasticlunr.stemmer(w.toLowerCase());
});
var searchterm_weight = 40;
var weighted = []; // contains elements of ["word", weight, index_in_document]
// split in sentences, then words
var sentences = body.toLowerCase().split('. ');
var index = 0;
var value = 0;
var searchterm_found = false;
for (var sentenceindex in sentences) {
var words = sentences[sentenceindex].split(' ');
value = 8;
for (var wordindex in words) {
var word = words[wordindex];
if (word.length > 0) {
for (var searchtermindex in stemmed_searchterms) {
if (elasticlunr.stemmer(word).startsWith(stemmed_searchterms[searchtermindex])) {
value = searchterm_weight;
searchterm_found = true;
}
};
weighted.push([word, value, index]);
value = 2;
}
index += word.length;
index += 1; // ' ' or '.' if last word in sentence
};
index += 1; // because we split at a two-char boundary '. '
};
if (weighted.length == 0) {
return body;
}
var window_weight = [];
var window_size = Math.min(weighted.length, results_options.teaser_word_count);
var cur_sum = 0;
for (var wordindex = 0; wordindex < window_size; wordindex++) {
cur_sum += weighted[wordindex][1];
};
window_weight.push(cur_sum);
for (var wordindex = 0; wordindex < weighted.length - window_size; wordindex++) {
cur_sum -= weighted[wordindex][1];
cur_sum += weighted[wordindex + window_size][1];
window_weight.push(cur_sum);
};
if (searchterm_found) {
var max_sum = 0;
var max_sum_window_index = 0;
// backwards
for (var i = window_weight.length - 1; i >= 0; i--) {
if (window_weight[i] > max_sum) {
max_sum = window_weight[i];
max_sum_window_index = i;
}
};
} else {
max_sum_window_index = 0;
}
// add <em/> around searchterms
var teaser_split = [];
var index = weighted[max_sum_window_index][2];
for (var i = max_sum_window_index; i < max_sum_window_index+window_size; i++) {
var word = weighted[i];
if (index < word[2]) {
// missing text from index to start of `word`
teaser_split.push(body.substring(index, word[2]));
index = word[2];
}
if (word[1] == searchterm_weight) {
teaser_split.push("<em>")
}
index = word[2] + word[0].length;
teaser_split.push(body.substring(word[2], index));
if (word[1] == searchterm_weight) {
teaser_split.push("</em>")
}
};
return teaser_split.join('');
}
function init(config) {
results_options = config.results_options;
search_options = config.search_options;
searchbar_outer = config.searchbar_outer;
doc_urls = config.doc_urls;
searchindex = elasticlunr.Index.load(config.index);
// Set up events
searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false);
search_wrap.addEventListener('click', function(e) { searchIconClickHandler(); }, false);
search_modal.addEventListener('click', function(e) { e.stopPropagation(); }, false);
searchbar.addEventListener('keyup', function(e) { searchbarKeyUpHandler(); }, false);
document.addEventListener('keydown', function(e) { globalKeyHandler(e); }, false);
// If the user uses the browser buttons, do the same as if a reload happened
window.onpopstate = function(e) { doSearchOrMarkFromUrl(); };
// Suppress "submit" events so the page doesn't reload when the user presses Enter
document.addEventListener('submit', function(e) { e.preventDefault(); }, false);
// If reloaded, do the search or mark again, depending on the current url parameters
doSearchOrMarkFromUrl();
}
function unfocusSearchbar() {
// hacky, but just focusing a div only works once
var tmp = document.createElement('input');
tmp.setAttribute('style', 'position: absolute; opacity: 0;');
searchicon.appendChild(tmp);
tmp.focus();
tmp.remove();
}
// On reload or browser history backwards/forwards events, parse the url and do search or mark
function doSearchOrMarkFromUrl() {
// Check current URL for search request
var url = parseURL(window.location.href);
if (url.params.hasOwnProperty(URL_SEARCH_PARAM)
&& url.params[URL_SEARCH_PARAM] != "") {
showSearch(true);
searchbar.value = decodeURIComponent(
(url.params[URL_SEARCH_PARAM]+'').replace(/\+/g, '%20'));
searchbarKeyUpHandler(); // -> doSearch()
} else {
showSearch(false);
}
if (url.params.hasOwnProperty(URL_MARK_PARAM)) {
var words = decodeURIComponent(url.params[URL_MARK_PARAM]).split(' ');
marker.mark(words, {
exclude: mark_exclude
});
var markers = document.querySelectorAll("mark");
function hide() {
for (var i = 0; i < markers.length; i++) {
markers[i].classList.add("fade-out");
window.setTimeout(function(e) { marker.unmark(); }, 300);
}
}
for (var i = 0; i < markers.length; i++) {
markers[i].addEventListener('click', hide);
}
}
}
// Eventhandler for keyevents on `document`
function globalKeyHandler(e) {
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || e.target.type === 'textarea' || e.target.type === 'text' || !hasFocus() && /^(?:input|select|textarea)$/i.test(e.target.nodeName)) { return; }
if (e.keyCode === ESCAPE_KEYCODE) {
e.preventDefault();
searchbar.classList.remove("active");
setSearchUrlParameters("",
(searchbar.value.trim() !== "") ? "push" : "replace");
if (hasFocus()) {
unfocusSearchbar();
}
showSearch(false);
marker.unmark();
} else if (!hasFocus() && e.keyCode === SEARCH_HOTKEY_KEYCODE) {
e.preventDefault();
showSearch(true);
window.scrollTo(0, 0);
searchbar.select();
} else if (hasFocus() && e.keyCode === DOWN_KEYCODE) {
e.preventDefault();
unfocusSearchbar();
searchresults.firstElementChild.classList.add("focus");
} else if (!hasFocus() && (e.keyCode === DOWN_KEYCODE
|| e.keyCode === UP_KEYCODE
|| e.keyCode === SELECT_KEYCODE)) {
// not `:focus` because browser does annoying scrolling
var focused = searchresults.querySelector("li.focus");
if (!focused) return;
e.preventDefault();
if (e.keyCode === DOWN_KEYCODE) {
var next = focused.nextElementSibling;
if (next) {
focused.classList.remove("focus");
next.classList.add("focus");
}
} else if (e.keyCode === UP_KEYCODE) {
focused.classList.remove("focus");
var prev = focused.previousElementSibling;
if (prev) {
prev.classList.add("focus");
} else {
searchbar.select();
}
} else { // SELECT_KEYCODE
window.location.assign(focused.querySelector('a'));
}
}
}
function showSearch(yes) {
if (yes) {
search_wrap.classList.remove('hidden');
searchicon.setAttribute('aria-expanded', 'true');
} else {
search_wrap.classList.add('hidden');
searchicon.setAttribute('aria-expanded', 'false');
var results = searchresults.children;
for (var i = 0; i < results.length; i++) {
results[i].classList.remove("focus");
}
}
}
function showResults(yes) {
if (yes) {
searchresults_outer.classList.remove('hidden');
} else {
searchresults_outer.classList.add('hidden');
}
}
// Eventhandler for search icon
function searchIconClickHandler() {
if (search_wrap.classList.contains('hidden')) {
showSearch(true);
window.scrollTo(0, 0);
searchbar.select();
} else {
showSearch(false);
}
}
// Eventhandler for keyevents while the searchbar is focused
function searchbarKeyUpHandler() {
var searchterm = searchbar.value.trim();
if (searchterm != "") {
searchbar.classList.add("active");
doSearch(searchterm);
} else {
searchbar.classList.remove("active");
showResults(false);
removeChildren(searchresults);
}
setSearchUrlParameters(searchterm, "push_if_new_search_else_replace");
// Remove marks
marker.unmark();
}
// Update current url with ?URL_SEARCH_PARAM= parameter, remove ?URL_MARK_PARAM and #heading-anchor .
// `action` can be one of "push", "replace", "push_if_new_search_else_replace"
// and replaces or pushes a new browser history item.
// "push_if_new_search_else_replace" pushes if there is no `?URL_SEARCH_PARAM=abc` yet.
function setSearchUrlParameters(searchterm, action) {
var url = parseURL(window.location.href);
var first_search = ! url.params.hasOwnProperty(URL_SEARCH_PARAM);
if (searchterm != "" || action == "push_if_new_search_else_replace") {
url.params[URL_SEARCH_PARAM] = searchterm;
delete url.params[URL_MARK_PARAM];
url.hash = "";
} else {
delete url.params[URL_MARK_PARAM];
delete url.params[URL_SEARCH_PARAM];
}
// A new search will also add a new history item, so the user can go back
// to the page prior to searching. A updated search term will only replace
// the url.
if (action == "push" || (action == "push_if_new_search_else_replace" && first_search) ) {
history.pushState({}, document.title, renderURL(url));
} else if (action == "replace" || (action == "push_if_new_search_else_replace" && !first_search) ) {
history.replaceState({}, document.title, renderURL(url));
}
}
function doSearch(searchterm) {
// Don't search the same twice
if (current_searchterm == searchterm) { return; }
else { current_searchterm = searchterm; }
if (searchindex == null) { return; }
// Do the actual search
var results = searchindex.search(searchterm, search_options);
var resultcount = Math.min(results.length, results_options.limit_results);
// Display search metrics
searchresults_header.innerText = formatSearchMetric(resultcount, searchterm);
// Clear and insert results
var searchterms = searchterm.split(' ');
removeChildren(searchresults);
for(var i = 0; i < resultcount ; i++){
var resultElem = document.createElement('li');
resultElem.innerHTML = formatSearchResult(results[i], searchterms);
searchresults.appendChild(resultElem);
}
// Display results
showResults(true);
}
(async function loadSearchIndex(lang = window.lang || "en") {
const branch = lang === "en" ? "master" : lang;
const rawUrl =
`https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/refs/heads/${branch}/searchindex.js`;
const localJs = "/searchindex.js";
const TIMEOUT_MS = 10_000;
const injectScript = (src) =>
new Promise((resolve, reject) => {
const s = document.createElement("script");
s.src = src;
s.onload = () => resolve(src);
s.onerror = (e) => reject(e);
document.head.appendChild(s);
});
try {
/* 1 — download raw JS from GitHub */
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
const res = await fetch(rawUrl, { signal: controller.signal });
clearTimeout(timer);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
/* 2 — wrap in a Blob so the browser sees application/javascript */
const code = await res.text();
const blobUrl = URL.createObjectURL(
new Blob([code], { type: "application/javascript" })
);
/* 3 — execute it */
await injectScript(blobUrl);
/* PATCH
heavy parsing now deferred to idle time
*/
requestIdleCallback(() => init(window.search));
return; // ✔ UI remains responsive
} catch (eRemote) {
console.warn("Remote JS failed →", eRemote);
}
/* ───────── fallback: local copy ───────── */
try {
await injectScript(localJs);
/* ───────────── PATCH ───────────── */
requestIdleCallback(() => init(window.search));
return;
} catch (eLocal) {
console.error("Local JS failed →", eLocal);
}
})();
// Exported functions
search.hasFocus = hasFocus;
})(window.search);

40
theme/search-worker.js Normal file
View File

@ -0,0 +1,40 @@
/* search-worker.js ------------------------------------------------------- */
/* Make code written for window work in a worker: */
self.window = self;
////////////////////////////////////////////////////////////////////////////
// 1. elasticlunr.min.js : CDN first → local fallback
////////////////////////////////////////////////////////////////////////////
try {
importScripts('https://cdn.jsdelivr.net/npm/elasticlunr@0.9.5/elasticlunr.min.js');
} catch (e) {
importScripts('/elasticlunr.min.js'); // ship this with your site
}
////////////////////////////////////////////////////////////////////////////
// 2. searchindex.js : GitHub Raw first → local fallback
// We fetch → wrap in a Blob({type:'application/javascript'}) to bypass
// GitHubs text/plain + nosniff MIME blocking.
////////////////////////////////////////////////////////////////////////////
try {
const res = await fetch(
'https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/refs/heads/master/searchindex.js',
{mode: 'cors'}
);
if (!res.ok) throw new Error(res.status);
const blobUrl = URL.createObjectURL(
new Blob([await res.text()], { type:'application/javascript' })
);
importScripts(blobUrl); // correct MIME, runs once
} catch (e) {
importScripts('/searchindex.js'); // offline fallback
}
////////////////////////////////////////////////////////////////////////////
// 3. Build the index once and answer queries
////////////////////////////////////////////////////////////////////////////
const idx = elasticlunr.Index.load(self.search.index);
self.onmessage = ({data: q}) => {
postMessage(idx.search(q, { bool:'AND', expand:true }));
};