COMPETITION
ACTIVITY://CLUB-UNION-CTF
K.knock · D-Alpha · CAUtion 동아리 연합 CTF.
동아리 연합 CTF 참여 기록을 정리하는 공간입니다.
01환불해드립니다AI+


- 프롬프트 인젝션b으로 LLM이 print("open('/flag.txt').read()")c 를 생성 — 핵심은 open(...)c을 문자열 리터럴로 감싸게b 만든 것. "계산 표현식 문자열을 그대로 넘겨라"는 프레이밍이 통했습니다.
- 샌드박스b는 그 코드를 실행 → open()c을 실행하지 않고 문자열 open('/flag.txt').read()c만 stdout으로 출력.
- serverb의 eval(stdout)c가 그 문자열을 플래그가 마운트된 server에서b 실행 → 파일 내용을 읽어 응답에 노출.
02Déjà VuCRYPTO+
recon.py
python recon.py
=== BANNER GET / ===
{
"endpoints": {
"/": "this banner",
"/flag_entry": "GET the encrypted admin log entry (nonce, ct, tag)",
"/log": "POST {\"message\": \"...\"} to store & encrypt a log entry"
},
"note": "All entries are encrypted with AES-256-GCM. Nonces are generated per-request for maximum security.",
"service": "SecureVault Logging API v1.3"
}
########## flag_entry 반복 호출 ##########
=== flag_entry #0 ===
{
"ciphertext": "631033e28727a90f484abaab4c25bd3df62350340c5d3005b918098299866091ed0d9b78667c711a058c904e68b0410064bd91c2870a5ce7e0a7c0cd620537f0bfe5640d79faf6b723d6de65de99b4498fcb46ed691307bdac",
"hint": "This is an admin log entry. Same JSON shape as your own logs.",
"nonce": "06ec83523fc0f3a700000000",
"tag": "414507ce43de4663a6c2e9e1bb1a0df7"
}
=== flag_entry #1 ===
{
"ciphertext": "631033e28727a90f484abaab4c25bd3df62350340c5d3005b918098299866091ed0d9b78667c711a058c904e68b0410064bd91c2870a5ce7e0a7c0cd620537f0bfe5640d79faf6b723d6de65de99b4498fcb46ed691307bdac",
"hint": "This is an admin log entry. Same JSON shape as your own logs.",
"nonce": "06ec83523fc0f3a700000000",
"tag": "414507ce43de4663a6c2e9e1bb1a0df7"
}
=== flag_entry #2 ===
{
"ciphertext": "631033e28727a90f484abaab4c25bd3df62350340c5d3005b918098299866091ed0d9b78667c711a058c904e68b0410064bd91c2870a5ce7e0a7c0cd620537f0bfe5640d79faf6b723d6de65de99b4498fcb46ed691307bdac",
"hint": "This is an admin log entry. Same JSON shape as your own logs.",
"nonce": "06ec83523fc0f3a700000000",
"tag": "414507ce43de4663a6c2e9e1bb1a0df7"
}
=== flag_entry #3 ===
{
"ciphertext": "631033e28727a90f484abaab4c25bd3df62350340c5d3005b918098299866091ed0d9b78667c711a058c904e68b0410064bd91c2870a5ce7e0a7c0cd620537f0bfe5640d79faf6b723d6de65de99b4498fcb46ed691307bdac",
"hint": "This is an admin log entry. Same JSON shape as your own logs.",
"nonce": "06ec83523fc0f3a700000000",
"tag": "414507ce43de4663a6c2e9e1bb1a0df7"
}
########## /log 반복 호출 (같은 메시지) ##########
=== log #0 (msg='A'*48) ===
{
"ciphertext": "ee9264bb90fc12d948d7be14224b49232094ba754ca3351147e55bb5f959d94fd54c5613fa7124daff7b5b97ab1d044967c5a6389414d1aeabdecd6d4c13c954b86b73e5a97812abef5fa2291cdd5fae1312ebd49a0f7fb7",
"nonce": "06ec83523fc0f3a700000001",
"stored_entry_preview": "{\"user\":\"guest\",\"role\":\"user\",\"note\":\"...\"}",
"tag": "7afdcaf3cd4fd15afb661acf95bccfc5"
}
=== log #1 (msg='A'*48) ===
{
"ciphertext": "91682bece6ebf3194750ea4f5063962f80e25f322739c35017bd0404a2b7f47ced160c13809b0dc8a07835d0bd57c854d14073f7b433f5255d2a8a9adb5af64554ca018c01a87b59872541be9b41133ffe5b426fdf04cd40",
"nonce": "06ec83523fc0f3a700000002",
"stored_entry_preview": "{\"user\":\"guest\",\"role\":\"user\",\"note\":\"...\"}",
"tag": "03b66ebc46900900d7124cefc6724544"
}
=== log #2 (msg='A'*48) ===
{
"ciphertext": "79f77cb956ec08cf76cac87e3f4e40c13c46b2e8dc7a6a26f531d5cb8a57c2da3b3b130009d924cd7bbdd7184c5a047f61c519810fcb80d39c22f111d77ba70faff3ae99b9a61b006556a8ad90abc837183dd34ba8ca8a2f",
"nonce": "06ec83523fc0f3a700000003",
"stored_entry_preview": "{\"user\":\"guest\",\"role\":\"user\",\"note\":\"...\"}",
"tag": "073bcd0e388697a51567d72c13a2b8c9"
}
=== log #3 (msg='A'*48) ===
{
"ciphertext": "114592ce6feedc5eb0c2fb37f2d5ef426e0bda0a637cd32884d09bf87b285f70c6254d6d37d1ca64f2b742d0f85cb37d4c068af3a349447d032fe6d5dcfb906e576bae87f02e9de901bc9befdc7b33eebee78c4e933e3b64",
"nonce": "06ec83523fc0f3a700000004",
"stored_entry_preview": "{\"user\":\"guest\",\"role\":\"user\",\"note\":\"...\"}",
"tag": "67e7955cb796e3be95073d43459c5fd6"
}
=== log #4 (msg='A'*48) ===
{
"ciphertext": "1f8e27732b57e9668c3482ac4b21df887ed262294031f9b3496a6730a6543570184de6ef11c7f5a731decf22ee3a3c5caf7c7d60615456a180a6a3821cef87022a91203390020a287f380703d27409f0da854764c4819402",
"nonce": "06ec83523fc0f3a700000005",
"stored_entry_preview": "{\"user\":\"guest\",\"role\":\"user\",\"note\":\"...\"}",
"tag": "b276a0509aebaea0b8db12900eaa69b9"
}
=== log #5 (msg='A'*48) ===
{
"ciphertext": "806534383574777bfad0afea52465adb7099685057eeb0fd1617f82a7f70c0576b92e08e723c4ad7028e5fe9486a62c1468d20227a771cc871ecbf7d92f89a74b2123f311832ff7c989d385752d0b480bb05f4e607f40f48",
"nonce": "06ec83523fc0f3a700000006",
"stored_entry_preview": "{\"user\":\"guest\",\"role\":\"user\",\"note\":\"...\"}",
"tag": "d5122e8bad201c3c8cd65c63b204c4b4"
}
########## /log 다양한 메시지 ##########
=== log msg=hello... len=5 ===
{
"ciphertext": "aeb4863b4403fa9e5ac6a93e409142e99ccd26b398ae761e1fc8e606a67fb69596a4ea59e860e8a4cceb1f9ec4",
"nonce": "06ec83523fc0f3a700000007",
"stored_entry_preview": "{\"user\":\"guest\",\"role\":\"user\",\"note\":\"...\"}",
"tag": "23601a5bc2bba882ba0b63448c264fb4"
}
=== log msg=BBBBBBBBBBBB... len=16 ===
{
"ciphertext": "825f77cf97f6087b0a09d717494d1d77ff3a9f2e363f1a19f34ea3dbf981941d73280ae53ac05f47f9cf551c4e8e350bb1bbddc02f089f04",
"nonce": "06ec83523fc0f3a700000008",
"stored_entry_preview": "{\"user\":\"guest\",\"role\":\"user\",\"note\":\"...\"}",
"tag": "3b951f2de2116149a11893a84762a1da"
}
=== log msg=CCCCCCCCCCCC... len=64 ===
{
"ciphertext": "1418c8e0c7f0dc4d649eb6e8cc7d45a4ad3eb7a648ebde0c6b0216609514486673004938d59284d15b1f16cdc8e48b9cfc4662456cf15e27b47aeb51bef5d48fe09fbf9af2ec9c112a854fde4b9c785a9de033563e1102a90d250a0e425c23fe19bc6bcf9f6dd347",
"nonce": "06ec83523fc0f3a700000009",
"stored_entry_preview": "{\"user\":\"guest\",\"role\":\"user\",\"note\":\"...\"}",
"tag": "04bb8cc0f28a501e2cd6c88551f04367"
}
>>> 확인 포인트:
(1) flag_entry의 nonce가 4번 다 같은가? (같으면 flag는 고정 암호문)
(2) /log 응답 nonce들이 서로 같은가? 규칙적으로 증가하나? 완전 랜덤인가?
(3) flag_entry의 nonce와 /log의 nonce 중 겹치는 값이 있나?취약점
배너는 nonce는 per-request로 랜덤 생성, 최대 보안이라 함
실제론 고정 prefix(b06ec83523fc0f3a7bc) + 순차 카운터b
전혀 랜덤이 아니고 완전히 예측 가능 → 그리고 flag는 counter=0b, 우리 로그는 1부터 시작
GCM에서 keystream은 nonce에만 의존, 만약 flag와 같은 nonceb로 우리가 아는 평문을 암호화시킬 수만 있으면?
pt_flag = ct_flag XOR ct_known XOR pt_known→ 키 몰라도 flag 도출
- 새 연결에서 카운터가 0으로 리셋되는지b (연결마다 카운터가 초기화되는 구현이면 새 커넥션 첫 요청이 곧 flag nonce)
- /logbc 본문이 nonce/counter 오버라이드를 받는지b ({"message":...,"counter":0}c 같은 히든 파라미터)
exploit.py
→ python 실행하면?
python exploit.py
flag nonce : 06ec83523fc0f3a700000000
flag counter : 0
flag ct len : 89 bytes
[1] fresh-connection counter reset test
fresh #0: nonce=06ec83523fc0f3a700000008 counter=8
fresh #1: nonce=06ec83523fc0f3a700000009 counter=9
fresh #2: nonce=06ec83523fc0f3a70000000a counter=10
[2] nonce/counter override probes
{'nonce': '06ec83523fc0f3a700000000'}: nonce=06ec83523fc0f3a70000000b
{'nonce': '00000000'}: nonce=06ec83523fc0f3a70000000c
{'iv': '06ec83523fc0f3a700000000'}: nonce=06ec83523fc0f3a70000000d
{'counter': 0}: nonce=06ec83523fc0f3a70000000e
{'ctr': 0}: nonce=06ec83523fc0f3a70000000f
{'n': 0}: nonce=06ec83523fc0f3a700000000
[+] NONCE REUSE via override! FLAG = b'{"user":"admin","role":"root","note":"CTF{tw0_t1me_p4d_str1kes_4g41n_n0nce_re5pect_pls}"}'flag 도출
CTF{tw0_t1me_p4d_str1kes_4g41n_n0nce_re5pect_pls}c
