✏️[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:

Ở đâ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ì.

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

Ở đâ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:

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

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.

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

Mình dùng tool jwt để brute foce secret mã trên:

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

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

JWT - Revoked token

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

#!/usr/bin/env python3
# -*- 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 <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)

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à:

    • def delete_expired_tokens(): 
      #ở hàm này sẽ đưa các token hết hạn vào blacklist 
    • def login(): 
      #Ở đâ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 ** 
    • def protected(): 
      #ở hàm này nếu xác thực được token mà token đó không ở trong blacklist thì sẽ có flag

** -> 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.

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

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

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=aG9haG9uZ2Rv đều decode ra hoahongdo

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...

PHP - assert()

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:

Ở đây hiện ra hai hàm assert()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.

Đối với hàm assert() thì có hai tham số assert(mixed $assertion, Throwable $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.

Code PHP ở dòng có thể là:

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:

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

PHP - Apache configuration

Last updated