> For the complete documentation index, see [llms.txt](https://shangs.gitbook.io/shine/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://shangs.gitbook.io/shine/write-up-ctf/ctf-wargame/root-me-writeup-sever-side.md).

# \[Root me] Writeup Sever Side

## Mở đầu

Đây là trang write up về challenges root me về sever side. Mặc dù hiện tại có rất nhiều người write up về root me nhưng mình vẫn muốn làm và write up lại để một phần nhớ kiến thức. Nó mang theo kiểu note là chính. \[Mức độ Medium trở lên \_ но не все]

## JSON Web Token (JWT) - Introduction

Khi vào trang web chúng ta sẽ có một form đăng nhập như sau:&#x20;

<figure><img src="/files/gqdOxTw8GxvdcMsh3pV4" alt=""><figcaption></figcaption></figure>

Ở đây chúng ta sẽ login như là khách, sau khi login được tài khoản khách chúng ta sẽ check cookie xem có gì.

<figure><img src="/files/8Hv0JXbSWXTuftlerbOv" alt=""><figcaption></figcaption></figure>

Ở đây mình nhận ra cookie có sử dụng jwt, thì mình thử decode xem nó như nào.

<figure><img src="/files/M7zMBEyo83VUu24wmidh" alt=""><figcaption></figcaption></figure>

Ở đây mình check tool jwt nhưng không thể có được secret nào nên mình set lại jwt bằng cách không sử dụng algorithm

Đoạn code trên sẽ như này:

<figure><img src="/files/orH7KnnTclvXJ5QDNGxe" alt=""><figcaption></figcaption></figure>

Thay thế cookie hiện tại ta có flag

<figure><img src="/files/EfGTMKBQdWnSCe5dpDBM" alt=""><figcaption></figcaption></figure>

## JSON Web Token (JWT) - Weak secret

Ở bài này như tiêu đề thì là weak secret mình có thẻ brute foce được secret.

<figure><img src="/files/oQyA3qIs2nB3ELu8mjjP" alt=""><figcaption></figcaption></figure>

Chúng ta truy cập /token có mã token như trên:&#x20;

<figure><img src="/files/UMsiiMt7xwmUW91mWw93" alt=""><figcaption></figcaption></figure>

Mình dùng tool [`jwt`](https://github.com/ticarpi/jwt_toolhttps://github.com/ticarpi/jwt_tool) để brute foce secret mã trên:&#x20;

<figure><img src="/files/AtKYJRzWz5hyXvTUauDP" alt=""><figcaption></figcaption></figure>

Ở đây mình có được secret bắt đầu encode một  token với role:admin

<figure><img src="/files/Ec2J30beuTiwWAjjc0sW" alt=""><figcaption></figcaption></figure>

Oke bay giờ post nó lên và thêm Authorization để xác nhận là xong.

<figure><img src="/files/GOFkjRE55Ll4fkQ0ucCg" alt=""><figcaption></figcaption></figure>

## JWT - Revoked token

Ở bài này cho sẵn code để phân tích.&#x20;

<pre class="language-python" data-overflow="wrap" data-line-numbers><code class="lang-python"><strong>#!/usr/bin/env python3
</strong># -*- coding: utf-8 -*-
from flask import Flask, request, jsonify
from flask_jwt_extended import JWTManager, jwt_required, create_access_token, decode_token
import datetime
from apscheduler.schedulers.background import BackgroundScheduler
import threading
import jwt
from config import *
 
# Setup flask
app = Flask(__name__)
 
#Creat key
app.config['JWT_SECRET_KEY'] = SECRET
jwtmanager = JWTManager(app)
blacklist = set()
lock = threading.Lock()
 
# Free memory from expired tokens, as they are no longer useful
def delete_expired_tokens():
    with lock:
        to_remove = set()
        global blacklist
        for access_token in blacklist:
            try:
                jwt.decode(access_token, app.config['JWT_SECRET_KEY'],algorithm='HS256')
            except:
                to_remove.add(access_token)
       
        blacklist = blacklist.difference(to_remove)
 
@app.route("/web-serveur/ch63/")
def index():
    return "POST : /web-serveur/ch63/login &#x3C;br>\nGET : /web-serveur/ch63/admin"
 
# Standard login endpoint
@app.route('/web-serveur/ch63/login', methods=['POST'])
def login():
    try:
        username = request.json.get('username', None)
        password = request.json.get('password', None)
    except:
        return jsonify({"msg":"""Bad request. Submit your login / pass as {"username":"admin","password":"admin"}"""}), 400
 
    if username != 'admin' or password != 'admin':
        return jsonify({"msg": "Bad username or password"}), 401
 
    access_token = create_access_token(identity=username,expires_delta=datetime.timedelta(minutes=3))
    ret = {
        'access_token': access_token,
    }
   
    with lock:
        blacklist.add(access_token)
 
    return jsonify(ret), 200
 
# Standard admin endpoint
@app.route('/web-serveur/ch63/admin', methods=['GET'])
@jwt_required
def protected():
    access_token = request.headers.get("Authorization").split()[1]
    with lock:
        if access_token in blacklist:
            return jsonify({"msg":"Token is revoked"})
        else:
            return jsonify({'Congratzzzz!!!_flag:': FLAG})
 
 
if __name__ == '__main__':
    scheduler = BackgroundScheduler()
    job = scheduler.add_job(delete_expired_tokens, 'interval', seconds=10)
    scheduler.start()
    app.run(debug=False, host='0.0.0.0', port=5000)
</code></pre>

Chúng ta sẽ phân tích đoạn code này như sau:

1. Đoạn code trên có 3 hàm quan trọng đó là:
   * ```python
     def delete_expired_tokens(): 
     ```

     ```python
     #ở hàm này sẽ đưa các token hết hạn vào blacklist 
     ```
   * ```python
     def login(): 
     ```

     <pre class="language-python" data-overflow="wrap"><code class="lang-python">#Ở đây yêu cầu login với user/pass là admin->sau khi login thì sẽ tạo ra một token có hiệu lực trong 3 phút ** 
     </code></pre>
   * <pre class="language-python" data-overflow="wrap"><code class="lang-python">def protected(): 
     </code></pre>

     <pre class="language-python" data-overflow="wrap"><code class="lang-python">#ở hàm này nếu xác thực được token mà token đó không ở trong blacklist thì sẽ có flag
     </code></pre>

\*\* -> như đã nói ở trên rằng token sẽ có hạn là 3p nhưng có điều là khi token được tạo ra đã bị add vào blacklist.

<figure><img src="/files/BNZqb8QsPSvaWYCvGYW1" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Q2gngg5SJae8pfZStzTi" alt=""><figcaption></figcaption></figure>

Chú ý cách tạo token JWT `header.payload.signature`

Ở đây cần chú ý tới cách tạo ra signature:&#x20;

```python
data = base64urlEncode( header ) + “.” + base64urlEncode( payload )
hashedData = hash( data, secret )
signature = base64urlEncode( hashedData )
```

Ở đây theo gợi ý ở metarial trang root-me cho thì có thể bypass bằng cách dùng ký tự non-alphabet nhưng ở đây chúng ta thấy rằng signature được `base64urlEncode()` . Thì trong base64 thường có dấu = kết thúc ở cuối mà mình nhận ra dù bạn thêm hay bớt dấu = thì nó vẫn decode ra một giá trị.

Ví dụ như: `aG9haG9uZ2Rv=` và `aG9haG9uZ2Rv` đều decode ra `hoahongdo`

<figure><img src="/files/uLHF38rNUSYf5pBxPcdl" alt=""><figcaption></figcaption></figure>

Oke bây giờ thêm Authorization header và thêm dấu = ở cuối JWT hoặc một non-alphabet như tiếng Nga(л), tiêng Trung...

<figure><img src="/files/O9iG6yV8IX0TlfNCXUhw" alt=""><figcaption></figcaption></figure>

## PHP - assert()

<figure><img src="/files/UMBweHhSYXx3eAGYlihs" alt=""><figcaption></figcaption></figure>

Bài này có lỗ hổng LFI nhìn qua khi mình thử xem đọc được file passwd không thì nó hiện ra như này: &#x20;

<figure><img src="/files/4fEjSGM306uIvnO2F6gY" alt=""><figcaption></figcaption></figure>

Ở đây hiện ra hai hàm `assert()` và `strpos()`. Trong đó hàm assert() kiểm tra đầu vào và trả về giá trị bool. Nếu kết quả là fallse thì nó sẽ thực hiện ném lỗi ra. Còn hàm strpos() dùng để tìm vị trí xuất hiện đầu tiên của chuỗi con trong chuỗi cha.

&#x20;Đối với hàm assert() thì có hai tham số **`assert`**`(`[`mixed`](https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.mixed) `$assertion,` [`Throwable`](https://www.php.net/manual/en/class.throwable.php) `$exception = ?): bool`  nếu mà nó check $assertion false thì sẽ ném ra $exception, còn đối với hàm cũng thể `strpos( $str, $char, $position)` .

Chú ý rằng khi đúng tra truyền ../../../etc/passwd thì thấy rằng chúng ta có thể inject được dòng code.&#x20;

Code PHP ở dòng có thể là:&#x20;

`assert("strpos('includes/$file.php', '..') === false") or die("Detected hacking attempt!");`

Payload lúc này sẽ là: `','')+or+die(show_source('.passwd'));//`

Lúc đó đoạn code:

{% code overflow="wrap" %}

```php
assert("strpos('includes/','')+or+die(show_source('.passwd'));//.php', '..') === false") or die("Detected hacking attempt!");
```

{% endcode %}

<figure><img src="/files/pFBI8pRhx4AhaQYBUYRI" alt=""><figcaption><p><strong>Show_source file .passwd</strong></p></figcaption></figure>

## PHP - Apache configuration


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://shangs.gitbook.io/shine/write-up-ctf/ctf-wargame/root-me-writeup-sever-side.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
