wannaShare | Writeup Crypto CTF 2021

PHAPHA_JIàN
1:17 02/08/2021

CLB An toàn Thông tin Wanna.One chia sẻ một số Challenges giải được và việc chia sẻ writeup nhằm mục đích giao lưu học thuật. Mọi đóng-góp ý-kiến bọn mình luôn-luôn tiếp nhận qua mail: wannaone.uit@gmail.com hoặc inseclab@uit.edu.vn và thông qua fanpage: fb.com/inseclab.


lttn

Symbol

Ta dễ dàng thấy đây là 1 dãy các kí hiệu toán học được đại diện cho các kí tự của flag

Sau 1 lúc google mò mẫm thì mình thấy các kí tự cuối của flag là LaTeX. Nên mình nghĩ các kí tự này có liên quan đến LaTeX. Mình thấy các kí hiệu được biểu diễn bằng LaTeX với công thức lần lượt là

\Cap \Cap` `\Theta` `\Findv` `\Pi` `\ltime` `\alept` `y` kiếm không ra :( `\wp` `\infty` `\therefore` `\heart` `\Lsh` `\alepth` `\Theta` `\eth` `\Xi

Ghép các chữ cái đầu lài ta được : CCTF{Play_with_LaTeX} :v

Farm

#!/usr/bin/env sage
from sage.all import *
import string, base64, math
from flag import flag
ALPHABET = string.printable[:62] + '\\='
F = list(GF(64))
def keygen(l):
    key = [F[randint(1, 63)] for _ in range(l)] 
    key = math.prod(key) # Optimization the key length :D
    return key
def maptofarm(c):
    assert c in ALPHABET
    return F[ALPHABET.index(c)]
def encrypt(msg, key):
    m64 = base64.b64encode(msg)
    enc, pkey = '', key**5 + key**3 + key**2 + 1
    for m in m64:
        enc += ALPHABET[F.index(pkey * maptofarm(chr(m)))]
    return enc
# KEEP IT SECRET 
key = keygen(14) # I think 64**14 > 2**64 is not brute-forcible :P
enc = encrypt(flag, key)
print(f'enc = {enc}')

Để tạo key thì đầu tiên chương trình lấy ngẫu nhiên l phần tư trong GF(64)` và nhân tất cả chúng lại với nhau được 1 key, cuồi cùng lấy `key = key^5 +key^3 +key^2 +1

Do tính chất khép kín nên khi trải qua nhìu bước làm phía trên thì key cũng sẽ chỉ nằm trong GF(64) -> Vậy chỉ chó 64 key tất cả có thẻ gen ra nên ta có thể brute force để tìm

Đã có key thì ta hoàn toàn có thể đảo ngược lại code để tìm flag.

Hoặc nếu lười như mình thì có thể brute force tiếp để tìm m` sao cho thỏa `enc = ALPHABET[F.index(pkey * maptofarm(chr(m)))]` với mỗi vị trí của `enc``m

Solution của mình

from sage.all import *
import string, base64, math
from base64 import *
ALPHABET = string.printable[:62] + '\\='
F = list(GF(64))
def maptofarm(c):
    assert c in ALPHABET
    return F[ALPHABET.index(c)]
def decrypt(key,c):
    flag=""
    for i in c:
        for m in ALPHABET.encode():
            if ALPHABET[F.index(key * maptofarm(chr(m)))]==i:
                flag+=chr(m)
    try:
        flag=b64decode(flag)
        return flag
    except:
        return flag.encode()
for key in F:
    flag=decrypt(key,'805c9GMYuD5RefTmabUNfS9N9YrkwbAbdZE0df91uCEytcoy9FDSbZ8Ay8jj')
    if b'CCTF' in flag:
        print(flag)

4rtist

Keybase

Source

#!/usr/bin/env python3
from Crypto.Util import number
from Crypto.Cipher import AES
import os, sys, random
from flag import flag
def keygen():
    iv, key = [os.urandom(16) for _ in '01']
    return iv, key
def encrypt(msg, iv, key):
    aes = AES.new(key, AES.MODE_CBC, iv)
    return aes.encrypt(msg)
def decrypt(enc, iv, key):
    aes = AES.new(key, AES.MODE_CBC, iv)
    return aes.decrypt(enc)
def die(*args):
    pr(*args)
    quit()
def pr(*args):
    s = " ".join(map(str, args))
    sys.stdout.write(s + "\n")
    sys.stdout.flush()
def sc():
    return sys.stdin.readline().strip()
def main():
    border = "+"
    pr(border*72)
    pr(border, " hi all, welcome to the simple KEYBASE cryptography task, try to    ", border)
    pr(border, " decrypt the encrypted message and get the flag as a nice prize!    ", border)
    pr(border*72)
    iv, key = keygen()
    flag_enc = encrypt(flag, iv, key).hex()
    while True:
        pr("| Options: \n|\t[G]et the encrypted flag \n|\t[T]est the encryption \n|\t[Q]uit")
        ans = sc().lower()
        if ans == 'g':
            pr("| encrypt(flag) =", flag_enc)
        elif ans == 't':
            pr("| Please send your 32 bytes message to encrypt: ")
            msg_inp = sc()
            if len(msg_inp) == 32:
                enc = encrypt(msg_inp, iv, key).hex()
                r = random.randint(0, 4)
                s = 4 - r
                mask_key = key[:-2].hex() + '*' * 4
                mask_enc = enc[:r] + '*' * 28 + enc[32-s:]
                pr("| enc =", mask_enc)
                pr("| key =", mask_key)
            else:
                die("| SEND 32 BYTES MESSAGE :X")
        elif ans == 'q':
            die("Quitting ...")
        else:
            die("Bye ...")
if __name__ == '__main__':
    main()

Connect to the server and get the encrypted flag and request server to encrypt the string The message is protected by AES! We've know:

+ Plaintext 
+ The encryption algorithm (AES CBC with block size 16)
+ first 14 characters of the 16 character key
+ The complete second block and parts of the first ciphertext block

In the Cipher Block Chaining (CBC) mode of operation, each plaintext block is XORed with the previous ciphertext block before being encrypted.

CBC

If the encryption function is Eₖ, then we have the following recurrence relation:

CBC1

The decrypted result is XORed with the previous ciphertext block. It follows that if the decryption function is Dₖ, then the decryption is:

CBC2

Brute force 2 last characters of key by decrypt the 2nd block with the IV is 1st block. If the plaintext's started with r and end with S!, accept the key.

Scince xor is revertable a ⊕ b = c ⇔ c ⊕ b = a and we now know the key, we can simply change the role of the first cipher text block and second plaintext block and do AES decryption on the second ciphertext block with the second plaintext block as IV (instead of the first cipher text block), which leads to the first ciphertext block as "decrypted paintext".

Do it again but this time we change the role of first plaintext block and IV when doing decryption on the first ciphertext block, which leads to the IV as decrypted plaintext.

Finally have key, IV, encrypted flag => decrypt to see flag.

from Crypto.Util import number
from Crypto.Cipher import AES
from operator import xor
import binascii, sys
ALPHABET ='0123456789abcdef'
KEY_first = "3247c8d03aa36ca1270aee48458c"
cipher1 = "67390000000000000000000000006660" 
cipher2 = "2e51675f978784997032ffffe2b6bbfd"
plain1 = "The message is p"
plain2 = "rotected by AES!"
realkey = ''
def decrypt(cipher, passphrase):
    aes = AES.new(passphrase, AES.MODE_CBC, binascii.unhexlify(cipher1))
    return aes.decrypt(cipher)
def decrypt2(enc, iv, key):
    aes = AES.new(key, AES.MODE_CBC, iv)
    return aes.decrypt(enc)
# iterate through relavent ascii range
for i in ALPHABET:
    for j in ALPHABET:
        for k in ALPHABET:
            for l in ALPHABET:
                key = KEY_first + i + j + k + l
                keyed = binascii.unhexlify(key)
                dec_plain2 = decrypt(binascii.unhexlify(cipher2),  keyed)
                if "S!" in str(dec_plain2) and "r" in str(dec_plain2):
                    print("decrypted plain2: " + str(dec_plain2) + " with key: " + str(keyed))
                    realkey = keyed
print(realkey)
realcipher1 = decrypt2(binascii.unhexlify(cipher2),plain2.encode(),realkey)
print(realcipher1.hex())assert md5(salt).hexdigest()    == '5f72c4360a2287bc269e0ccba6fc24ba'
assert sha1(pepper).hexdigest() == '3e0d000a4b0bd712999d730bc331f400221008e0'
IV = decrypt2(realcipher1,plain1.encode(),realkey)
print(IV)
ct = "2b98362a49d61c9438d4c889a1c2bd23142cf196b84e57cf886682c0165a3e7d"
print(decrypt2(binascii.unhexlify(ct),IV,realkey))

Flag: CCTF{h0W_R3cOVER_7He_5eCrET_1V?}

Salt pepper

Source

#!/usr/bin/env python3
from hashlib import md5, sha1
import sys
from secret import salt, pepper
from flag import flag
assert len(salt) == len(pepper) == 19
assert md5(salt).hexdigest()    == '5f72c4360a2287bc269e0ccba6fc24ba'
assert sha1(pepper).hexdigest() == '3e0d000a4b0bd712999d730bc331f400221008e0'
def auth_check(salt, pepper, username, password, h):
    return sha1(pepper + password + md5(salt + username).hexdigest().encode('utf-8')).hexdigest() == h
def die(*args):
    pr(*args)
    quit()
def pr(*args):
    s = " ".join(map(str, args))
    sys.stdout.write(s + "\n")
    sys.stdout.flush()
def sc():
    return sys.stdin.readline().strip()
def main():
    border = "+"
    pr(border*72)
    pr(border, "  welcome to hash killers battle, your mission is to login into the ", border)
    pr(border, "  ultra secure authentication server with provided information!!    ", border)
    pr(border*72)
    USERNAME = b'n3T4Dm1n'
    PASSWORD = b'P4s5W0rd'
    while True:
        pr("| Options: \n|\t[L]ogin to server \n|\t[Q]uit")
        ans = sc().lower()
        if ans == 'l':
            pr('| send your username, password as hex string separated with comma: ')
            inp = sc()
            try:
                inp_username, inp_password = [bytes.fromhex(s) for s in inp.split(',')]
            except:
                die('| your input is not valid, bye!!')
            pr('| send your authentication hash: ')
            inp_hash = sc()
            if USERNAME in inp_username and PASSWORD in inp_password:
                if auth_check(salt, pepper, inp_username, inp_password, inp_hash):
                    die(f'| Congrats, you are master in hash killing, and it is the flag: {flag}')
                else:
                    die('| your credential is not valid, Bye!!!')
            else:
                die('| Kidding me?! Bye!!!')
        elif ans == 'q':
            die("Quitting ...")
        else:
            die("Bye ...")
if __name__ == '__main__':
    main()

This challenge request to sign in, and send the authentication hash.

In source code I see:

assert len(salt) == len(pepper) == 19
assert md5(salt).hexdigest()    == '5f72c4360a2287bc269e0ccba6fc24ba'
assert sha1(pepper).hexdigest() == '3e0d000a4b0bd712999d730bc331f400221008e0'
def auth_check(salt, pepper, username, password, h):
    return sha1(pepper + password + md5(salt + username).hexdigest().encode('utf-8')).hexdigest() == h

So they give length of messenger and 2 hash. Searching GG I see that i could use hashlength extension attack. My pro brother support me hash_extender to solve this.

First, I solve md5(salt + username).hexdigest().

HSH

Now my new username string is: 8000000000000000000000000000000000000000000000000000000000000000000000000098000000000000006e335434446d316e

After that, I solve sha1(pepper + password).hexdigest() to get new password.

HSH2

My new password: 8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000985034733557307264

Finally solve (pepper + password + md5(salt + username).hexdigest().encode('utf-8')).hexdigest() to get the hash.

HSH3

Send them to server and get the flag.

HSH4

Flag: CCTF{Hunters_Killed_82%_More_Wolves_Than_Quota_Allowed_in_Wisconsin}

4rtist ft dunglq

Tuti

#!/usr/bin/env python3
from Crypto.Util.number import *
from flag import flag
l = len(flag)
m_1, m_2 = flag[: l // 2], flag[l // 2:]
x, y = bytes_to_long(m_1), bytes_to_long(m_2)
k = '''
000bfdc32162934ad6a054b4b3db8578674e27a165113f8ed018cbe9112
4fbd63144ab6923d107eee2bc0712fcbdb50d96fdf04dd1ba1b69cb1efe
71af7ca08ddc7cc2d3dfb9080ae56861d952e8d5ec0ba0d3dfdf2d12764
'''.replace('\n', '')
assert((x**2 + 1)*(y**2 + 1) - 2*(x - y)*(x*y - 1) == 4*(int(k, 16) + x*y))

Solving ((x**2 + 1)*(y**2 + 1) - 2*(x - y)*(x*y - 1) == 4*(int(k, 16) + x*y)) we have (x + 1) * (y - 1) = k2 with k2 = sqrt(4 * k). I brute force (x + 1) and convert to bytes. If CCTF{ in the result then calculate (y - 1).

from Crypto.Util.number import *
from sage.all import *
k = 992752253935874779143952218845275961347009322164731344882417010624071055636710540798045985678351986133612
b=divisors(k)
for i in b:
    ct1 =long_to_bytes(i-1)
    if b'CCTF' in ct1:
        ct2 =(k//i) + 1
        print(i - 1, ct2)
        print(ct1, long_to_bytes(ct2))

Flag: CCTF{S1mPL3_4Nd_N!cE_Diophantine_EqUa7I0nS!}

Ở đây là nửa đầu và nửa sau của flag, là một số cho trước thỏa mãn . Biến đổi một tí mình có

Như vậy nên mình chỉ cần factor số này là tìm được . Do có thể có nhiều cách chọn nên mình tìm cái "hợp lí" nhất


dunglq

Rima

#!/usr/bin/env python
from Crypto.Util.number import *
from flag import FLAG
def nextPrime(n):
    while True:
        n += (n % 2) + 1
        if isPrime(n):
            return n
f = [int(x) for x in bin(int(FLAG.hex(), 16))[2:]]
f.insert(0, 0)
for i in range(len(f)-1): f[i] += f[i+1]
a = nextPrime(len(f))
b = nextPrime(a)
g, h = [[_ for i in range(x) for _ in f] for x in [a, b]]
c = nextPrime(len(f) >> 2)
for _ in [g, h]:
    for __ in range(c): _.insert(0, 0)
    for i in range(len(_) -  c): _[i] += _[i+c]
g, h = [int(''.join([str(_) for _ in __]), 5) for __ in [g, h]]
for _ in [g, h]:
    if _ == g:
        fname = 'g'
    else:
        fname = 'h'
    of = open(f'{fname}.enc', 'wb')
    of.write(long_to_bytes(_))
    of.close()

Bài này không dùng biến chữ để chạy loop và dùng dấu gạch dưới của python nên lúc đầu mình thấy hơi rắc rối.

Đầu tiên flag được chuyển sang dạng nhị phân và thêm 1 bit “0” ở đầu được dãy . Kế tiếp với mỗi thì .

Kế tiếp 2 số được tạo là 2 số nguyên tố kế tiếp tính từ là độ dài . là 2 list tạo ra từ việc lặp lần. Như vậy độ dài của và độ dài của

Kế tiếp là số nguyên tố kế tiếp tính từ . Thêm bit “0” vào đầu và thực hiện với . Làm tương tự với

Cuối cùng là chuyển sang số int base 5 và viết lên file dưới dạng byte. Nên đầu tiên mình sẽ làm ngược lại và tìm được , sau đó mình bruteforce để tìm , và xem thử bộ nào thỏa .

Sau đó là làm ngược lại quá trình, với thì . Tương tự với . Có thể kiểm chứng cách đúng nếu đầu có đúng số 0 :))

Giờ thì, lấy số đầu của và tiếp tục làm ngược lại sẽ ra các bit của flag.

Flag: CCTF{_how_finD_7h1s_1z_s3cr3T?!}

Maid

#!/usr/bin/python3
from Crypto.Util.number import *
from gmpy2 import *
from secret import *
from flag import flag
global nbit
nbit = 1024
def keygen(nbit):
    while True:
        p, q = [getStrongPrime(nbit) for _ in '01']
        if p % 4 == q % 4 == 3:
            return (p**2)*q, p
def encrypt(m, pubkey):
    if GCD(m, pubkey) != 1 or m >= 2**(2*nbit - 2):
        return None
    return pow(m, 2, pubkey)
def flag_encrypt(flag, p, q):
    m = bytes_to_long(flag)
    assert m < p * q
    return pow(m, 65537, p * q)
def die(*args):
    pr(*args)
    quit()
def pr(*args):
    s = " ".join(map(str, args))
    sys.stdout.write(s + "\n")
    sys.stdout.flush()
def sc():
    return sys.stdin.readline().strip()
def main():
    border = "+"
    pr(border*72)
    pr(border, "  hi all, welcome to Rooney Oracle, you can encrypt and decrypt any ", border)
    pr(border, "  message in this oracle, but the flag is still encrypted, Rooney   ", border)
    pr(border, "  asked me to find the encrypted flag, I'm trying now, please help! ", border)
    pr(border*72)
    pubkey, privkey = keygen(nbit)
    p, q = privkey, pubkey // (privkey ** 2)
    while True:
        pr("| Options: \n|\t[E]ncrypt message \n|\t[D]ecrypt ciphertext \n|\t[S]how encrypted flag \n|\t[Q]uit")
        ans = sc().lower()
        if ans == 'e':
            pr("| Send the message to encrypt: ")
            msg = sc()
            try:
                msg = int(msg)
            except:
                die("| your message is not integer!!")
            pr(f"| encrypt(msg, pubkey) = {encrypt(msg, pubkey)} ")
        elif ans == 'd':
            pr("| Send the ciphertext to decrypt: ")
            enc = sc()
            try:
                enc = int(enc)
            except:
                die("| your message is not integer!!")
            pr(f"| decrypt(enc, privkey) = {decrypt(enc, privkey)} ")
        elif ans == 's': 
            pr(f'| enc = {flag_encrypt(flag, p, q)}')
        elif ans == 'q':
            die("Quitting ...")
        else:
            die("Bye ...")
if __name__ == '__main__':
    main()

Ở bài này server cung cấp cho mình các chứng năng sau:

Key là 1 cặp khóa công khai-bí mật (pubkey,privkey), trong đó còn với là 2 số nguyên tố 1024 bit và đồng dư 3 modulo 4. Hàm encrypt thực hiện mã hóa số bằng cách trả về . Còn hàm decrypt thực hiện giải mã chỉ cần privkey.

Kì cục …………..

Thế quái nào …………..

encrypt cần cả còn decrypt chỉ cần ?

Thật ra là vì nếu thì , như vậy giải thích cho việc không được vượt quá 2048-2 bit và việc giải mã chỉ cần . Như vậy cách attack của mình như sau:

Flag: CCTF{___Ra8!N_H_Cryp705YsT3M__\}

Improve

#!/usr/bin/env python3
from Crypto.Util.number import *
from gmpy2 import gcd
from random import randint
import sys, hashlib
from flag import flag
def lcm(a, b):
    return (a * b) // gcd(a,b)
def gen_params(nbit):
    p, q = [getPrime(nbit) for _ in range(2)]
    n, f, g = p * q, lcm(p-1, q-1), p + q
    e = pow(g, f, n**2)
    u = divmod(e-1, n)[0]
    v = inverse(u, n)
    params = int(n), int(f), int(v)
    return params
def improved(m, params):
    n, f, v = params
    if 1 < m < n**2 - 1:
        e = pow(m, f, n**2)
        u = divmod(e-1, n)[0]
        L = divmod(u*v, n)[1]
    H = hashlib.sha1(str(L).encode('utf-8')).hexdigest()
    return H
def die(*args):
    pr(*args)
    quit()
def pr(*args):
    s = " ".join(map(str, args))
    sys.stdout.write(s + "\n")
    sys.stdout.flush()
def sc():
    return sys.stdin.readline().strip()
def main():
    border = "+"
    pr(border*72)
    pr(border, " hi talented cryptographers! Your mission is to find hash collision ", border)
    pr(border, " in the given hash function based on famous cryptographic algorithm ", border)
    pr(border, " see the source code and get the flag! Its improved version :)      ", border)
    pr(border*72)
    nbit = 512
    params = gen_params(nbit)
    n = params[0]
    while True:
        pr("| Options: \n|\t[R]eport collision! \n|\t[T]ry hash \n|\t[G]et parameters \n|\t[Q]uit")
        ans = sc().lower()
        if ans == 'r':
            pr("| please send the messages split by comma: ")
            m = sc()
            try:
                m_1, m_2 = m.split(',')
                m_1, m_2 = int(m_1), int(m_2)
            except:
                die("| Sorry! your input is invalid, Bye!!")
                # fix the bug :P
            if m_1 % n != 0 and m_2 % n != 0 and m_1 != m_2 and 1 < m_1 < n**2-1 and 1 < m_2 < n**2-1 and improved(m_1, params) == improved(m_2, params):
                die(f"| Congrats! You find the collision!! the flag is: {flag}")
            else:
                die("| Sorry! your input is not correct!!")
        elif ans == 't':
            pr("| Please send your message to get the hash: ")
            m = sc()
            try:
                m = int(m)
                pr(f"improved(m) = {improved(m, params)}")
            except:
                die("| Sorry! your input is invalid, Bye!!") 
        elif ans == 'g':
            pr('| Parameters =', params)
        elif ans == 'q':
            die("Quitting ...")
        else:
            die("Bye ...")
if __name__ == '__main__':
    main()

Ở bài này khá có khá nhiều thứ linh tinh nhưng chung quy lại là mình cần nhập vào 2 số sao cho kết quả hàm improve với 2 số này là giống nhau.

Các tham số sẽ là làm chặn trên cho 2 số nhập vào (không vượt quá , có tính chất quan trọng là luôn chẵn, đây là tiền đề để mình giải bài này.

Hàm improve mình để ý rằng được tạo ra sau vài biến đổi từ , mà mình cần 2 số cho cùng , vậy chỉ cần cho ra cùng là xong. Mà như hồi nãy mình có đề cập là luôn chẵn, vậy chỉ cần chọn là xong :))

Flag: CCTF{Phillip_N0W_4pr0b4b1liStiC__aSymM3Tr1C\_AlGOrithM!!}

Onlude

#!/usr/bin/env sage
from sage.all import *
from flag import flag
global p, alphabet
p = 71
alphabet = '=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$!?_{}<>'
flag = flag.lstrip('CCTF{').rstrip('}')
assert len(flag) == 24
def cross(m):
    return alphabet.index(m)
def prepare(msg):
    A = zero_matrix(GF(p), 11, 11)
    for k in range(len(msg)):
        i, j = 5*k // 11, 5*k % 11
        A[i, j] = cross(msg[k])
    return A
def keygen():
    R = random_matrix(GF(p), 11, 11)
    while True:
        S = random_matrix(GF(p), 11, 11)
        if S.rank() == 11:
            _, L, U = S.LU()
            return R, L, U
def encrypt(A, key):
    R, L, U = key
    S = L * U
    X = A + R
    Y = S * X
    E = L.inverse() * Y
    return E
A = prepare(flag)
key = keygen()
R, L, U = key
S = L * U
E = encrypt(A, key)
print(f'E = \n{E}')
print(f'L * U * L = \n{L * U * L}')
print(f'L^(-1) * S^2 * L = \n{L.inverse() * S**2 * L}')
print(f'R^(-1) * S^8 = \n{R.inverse() * S**8}')

Bài này mình giải trước khi hết thời gian 1 tiếng và là bài cuối cùng mình giải được. Hàm prepare chuyển flag thành ma trận , là bộ 3 ma trận , .

Việc mã hóa như sau:

Đề cho mình 4 ma trận:

Lấy nhân với mình có . Khi đó . Vậy là mình có rồi :))

Quay lại , khi đó , nhân bên phải của 2 vế với thì

Quay lại 1 chút, , suy ra

Từ đó mình dễ dàng tìm lại được

Thực hiện tương tự hàm prepare mình có được flag

Flag: CCTF{LU__D3c0mpO517Ion__4L90?}

Writeup đến đây là hết, cám ơn các bạn đã đọc. Source code của mình ở đây

TIN LIÊN QUAN
The Wanna.One Cyber Security Club shares writeup of some solved Challenges with the purpose of academic exchanges. We always welcome and look forward to comments from any of you via email: wannaone.uit@gmail.com FWORD CTF 2021: https://ctftime.org/event/1405 Sat, 28 Aug. 2021, 00:00 ICT — Sun, 29 Aug. 2021, 12:00 ICT Author:...
CLB An toàn Thông tin Wanna.One chia sẻ một số Challenges giải được và việc chia sẻ writeup nhằm mục đích giao lưu học thuật. Mọi đóng-góp ý-kiến bọn mình luôn-luôn tiếp nhận qua mail: wannaone.uit@gmail.com hoặc inseclab@uit.edu.vn và fanpage: fb.com/inseclab. Mochi Nishi vaudeville Description Info: The Dramatis Personae invite...
CLB An toàn Thông tin Wanna.One chia sẻ một số Challenges giải được và việc chia sẻ writeup nhằm mục đích giao lưu học thuật. Mọi đóng-góp ý-kiến bọn mình luôn-luôn tiếp nhận qua mail: wannaone.uit@gmail.com RE Mochi Nishi foliage Challenge File: foliage Solve: Bài này mình sẽ chi tiết...