Các bài rev ở đây thường không có description :D
Chạy file:
Code trong IDA (đã được rename function và biến):
Như ta có thể thấy, chương trình nhận vào input 4 kí tự nếu lớn hơn thì xuất ra "too long" và exit.
Còn đây là bên trong susfunction:
Function này khá là rối, mình không chắc cái này có thể dịch ngược hoàn toàn, tuy nhiên dựa vào length của input khá ít nên mình có thể dễ dàng solve bằng bruteforce:
from subprocess import *
import struct
import string
import requests
from concurrent.futures import ThreadPoolExecutor
n = 0
m = string.printable
m = string.ascii_letters
x = []
for i in m:
for j in m:
for k in m:
for l in m:
x.append((i+j+k+l).encode())
def func(user_input):
p = Popen([r'gues.exe', 'f'], stdout = PIPE, stdin = PIPE, stderr = STDOUT)
p.stdin.write(user_input)
testresult = p.communicate()[0]
return testresult
def check(x):
for i in x:
if chr(i) not in string.printable:
return False
return True
n = 0
for ui in x:
res = func(ui)
if b'C{' in res:
print(res,ui)
n+=1
Vì mình code bài này khá vội nên là như mì ăn liền vậy, code không clean mọi người thông cảm:V
Ban đầu có thể nói là brute khá lâu, nhma thay vì dùng string.printable
thì mình chuyển sang string.ascii_letters
và đây là kết quả:
Flag: "KCSC{brut6_n6rv6r_die}
Như cái tên bài thì bài này mix giữa C# và C++.
Đầu tiên mình dùng Die để detect:
Do là file là C# obfuscated nên mình đã dùng tool để deobfuscate trước, cụ thể là de4dot:
Có được file Mix-cleaned.exe, load nó bằng dnspy và đây là hàm main:
Đa số các hàm đều là built-in function ví dụ như smethod_17()
chỉ đơn giản là compare 2 buffer,…
Ref Flagenc, mình có được flag_encrypted:
Về input của mình chỉ đơn giản là chuyển thành bytes, sau đó encrypt bởi hàm enc()
và đem so sánh với flagenc.
Mình thử debug và stepinto enc
tuy nhiên không có kết quả là mấy.
Tuy nhiên, tên bài là Mix mình nghĩ vẫn còn code đâu đó, cụ thể là C++, thử load vào IDA bằng IDA:
Sau khi xem string thì mình thấy có 1 thứ rất khả nghi, đó là "expand 64-byte k"
Mình nhận ra đây rất có thể là Salsa20 hoặc là ChaCha20, còn đây là hàm enc
mà mình tìm được:
Như đã thấy, ta có 32 bytes của key nằm ở v9 và nonce là 8 bytes nằm ở v9[4]. Sau khi xem hàm sub_140001F10
thì mình khá chắc chắn là đây là chacha20.
Sau đó mình thử viết script (có salsa 20 bởi vì lúc viết script mình chạy không ra, nghi ngờ là do mình đoán sai):
from pwn import *
from Crypto.Cipher import Salsa20,ChaCha20,ChaCha20_Poly1305
flag_enc = bytes([143,124,41,217,251,185,171,26,74,83,173,236,169,239,22,115,128,248,92,93])
print(flag_enc,flag_enc.hex())
def ls2bytes(ls):
return b"".join([bytes.fromhex(x)[::-1] for x in ls])
secret = [0]*7
secret[0] = "43604259"
secret[1] = "45724033"
secret[2] = "1763427E"
secret[3] = "5B725F70"
secret[4] = "507D527F"
secret[5] = "193D1976"
secret[6] = "3713371337133713"
nonce = [0]*2
nonce[0] = "03010200"
nonce[1] = "11FF0005"
secret = ls2bytes(secret)
nonce = ls2bytes(nonce)
print(secret.hex(),nonce.hex())
new_secret = []
for i in range(0,32,2):
new_secret.append(secret[i]^0x13)
new_secret.append(secret[i+1]^0x37)
new_secret = bytes(new_secret)[:32] #+b'\x00'*32
print(new_secret,nonce)
cipher = cipher = Salsa20.new(key=new_secret, nonce=nonce)
plaintext = cipher.decrypt(flag_enc)
print("Salsa:",plaintext)
cipher = cipher = ChaCha20.new(key=new_secret, nonce=nonce)
plaintext = cipher.decrypt(flag_enc)
print("Chacha:",plaintext)
Tuy nhiên cả 2 plaintext đều không phải flag. Mình cũng không hiểu tại sao, có thể là do đoạn "expand 64 byte k" (thường là 32).
Do đó vi tính chất đối xứng, nên mình quyết định debug và patch input của mình thành flagenc => enc(flagenc) = flag
.
Đoạn này đổi string lại thành bytes của flagenc.
Sau đó dựa theo địa chỉ cùa ptr để tìm ra vị trí của nó trên memory:
Lúc đầu mình làm không ra, tuy nhiên mình phát hiện patch sai 1 bytes,
Đoạn …73 3F F8… nếu đúng như flagenc thì phải là …73 80 F8…
Ta chỉ cần sửa đoạn này lại, hoặc từ đầu có thể patch bytes thẳng vào memory(cách này hay hơn :V), đặt breakpoint ngay chổ so sánh và tìm flag trên memory:
Flag: "KCSC{h3Ll0_fR0M_c##}"