LINE CTF 2024 - hacklolo
๋ชฉ์ฐจ
0x00. Introduction
C++๋ก ๋ง๋ค์ด์ง ๋ฐ์ด๋๋ฆฌ๋ก ๋ถ์ํ๋๋ฐ์ ์๋นํ ๊น๋ค๋ก์ ๋ค.
Structure
;
;
C++์์ basic_string ๊ฐ์ฒด๊ฐ ๊ฐ์ง๋ ํน์ฑ ๋๋ฌธ์ธ์ง ๋ฌธ์์ด์ ๊ทธ๋ฅ ์ ์ฅํ์ง ์๊ณ id๋ฅผ ์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ ์ฅํ๋ค.
id_ptr: ๋ฌธ์์ด์ด ์ ์ฅ๋ ์ฃผ์id_size: ๋ฌธ์์ด์ ๊ธธ์ดid[8]: ๊ธธ์ด 8๊น์ง์ ๋ฌธ์์ด์ ์ฌ๊ธฐ์ ์ ์ฅํ๊ณ ๋ ๊ธด ๋ฌธ์์ด์ ๋ค๋ฅธ ์์ญ์ ํ ๋น๋ฐ์ ์ ์ฅid_end: ์ฐ์ด์ง ์๋ ์์ญ์ผ๋ก chunk ๊ด๋ จ ๋ฐ์ดํฐ๋ก ์ถ์
0x01. Vulnerability
Improper Check
__int64 __fastcall
used_db์๋ ์ด 32๊ฐ์ user๋ฅผ ์ ์ฅํ ์ ์๋ ๊ณต๊ฐ์ด ์๋๋ฐ login_790E()์์ user๋ฅผ ํ์ธํ๋ ๋ฒ์๋ 33๊ฐ์ด๋ค. ๋๋ฌธ์ user_list[32] ์ดํ ์์ญ์ด ๋ ํ๋์ user๋ก ์ธ์๋๋ฉฐ ๋ค์๊ณผ ๊ฐ์ด ์์ญ์ด ๊ฒน์ณ์ง๋ค.
after user_list | user |
|---|---|
| user *user_list_ptr | char *pw_ptr |
| _QWORD count | _QWORD pw_size |
| _QWORD login_try | char pw[8] |
| _QWORD is_login | _QWORD end_pw |
| char *welcome_ptr | char *id_ptr |
| _QWORD welcome_size | _QWORD id_size |
| char welcome[8] | char id[8] |
| _QWORD canary | _QWORD end_id |
| user *current_user | char *email_ptr |
| _QWORD login_success | _QWORD email_size |
| char *jwt_key | char email[8] |
| _QWORD jwt_key_size | _QWORD end_email |
| _QWORD jwt_key_end |
๋ฐ๋ผ์ ๋ฐ์ด๋๋ฆฌ ์คํ ์ ์ถ๋ ฅ๋๋ "Welcome!"์ด id์ธ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ์ด ๊ฐ๋ฅํ๋ค.
JWT Counterfeit
join์ ์์ฑ๋๋ coupon์ HS256์ผ๋ก ์์ฑํ JWT ๊ฐ์ผ๋ก, siganture ๋ถ๋ถ์ HMAC-SHA256์ ์ด์ฉํด ์์ฑ๋๋ค. ์ด ๋ ์ถ๋ ฅ๊ฐ์ด 256๋นํธ(32๋ฐ์ดํธ)์ด๊ณ ์ด ๊ฐ์ base64URL์ผ๋ก ์ธ์ฝ๋ฉํ๋ค. ์ธ์ฝ๋ฉ ๊ณผ์ ์์ base64๊ฐ 3๋ฐ์ดํธ ๋จ์๋ก ์ธ์ฝ๋ฉ์ ํ๋ฏ๋ก padding(=)์ด ๋ถ๊ฒ ๋๋ค.

๊ทธ๋ฐ๋ฐ ์ฌ์ค = ๋ฟ๋ง ์๋๋ผ ๋ง์ง๋ง ๋ฐ์ดํธ์ ๋ง์ง๋ง ๋ ๋นํธ๊น์ง 00์ผ๋ก padding์ด ๋ถ๋๋ค. ๋ฐ๋ผ์ ๋์ฝ๋ฉ ๊ณผ์ ์์ ๋ง์ง๋ง ๋ฐ์ดํธ์ ๋ง์ง๋ง ๋ ๋นํธ๋ ์๋ณธ ๋ฐ์ดํฐ์ ์ํฅ์ ๋ฏธ์น์ง ๋ชปํ๋ค.
๋ฐ๊ฟ ๋งํ๋ฉด ๋ง์ง๋ง ๋ฐ์ดํธ์ ๋ง์ง๋ง ๋ ๋นํธ์ 00, 01, 10, 11 ๋ท ์ค ์๋ฌด๊ฑฐ๋ ๋ค์ด๊ฐ๋ ๊ฐ์ ๊ฐ์ผ๋ก ๋์ฝ๋ฉ๋๋ค. ๋์ฝ๋ฉ ๊ฐ์ด ๊ฐ๋ค๋ฉด coupon ๊ฐ์์ ํ ๋นํธ์ฉ ๊ฐ์ ์ฆ๊ฐ์์ผ๋ ์๋ช
๊ฒ์ฆ์ ํต๊ณผํ๊ธฐ ๋๋ฌธ์ ์ฌ๋ฌ๋ฒ coupon์ ๋ฑ๋กํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ค.
JWS์ ๊ตฌํ ์ ๋ฐ์ํ๋ ๋ฌธ์ ๋ก ์ด๋ป๊ฒ ์จ๋จน์ ์ ์์์ง ๋ชจ๋ฅด๊ฒ ์ง๋ง ๋ค๋ฅธ ๊ณณ์์๋ ์ฌ์ฉํ ์ ์์ ๊ฒ ๊ฐ๋ค.
0x02. Exploit
Memory Leak
user_db->user_list[32] ์ดํ์ ์์ญ(Welcome! ๊ณ์ )์ ๋ฉ๋ชจ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ๋ค.
# Welcome!
pw_ptr๋ฅผ ์๋ฏธํ๋ ์์ญ์๋ user_list์ ์์ ์ฃผ์์ธ 0x7fffffffdf60๊ฐ ๋ด๊ฒจ์๊ณ , pw_size๋ฅผ ์๋ฏธํ๋ ์์ญ์๋ ๊ณ์ ์ ๊ฐ์๋ฅผ ์๋ฏธํ๋ count๊ฐ ๋ด๊ฒจ์๋ค.
ํ์ฌ count๋ main() ์ด๋ฐ๋ถ์ ํธ์ถ๋๋ setup_admin_7D3A()์์ admin ๊ณ์ ์ ์ถ๊ฐํ๋ฉด์ 1์ด ๋์ด์๋ค. ๋ฐ๋ผ์ Welcome! ๊ณ์ ์ ๋น๋ฐ๋ฒํธ๋ 0x7fffffffdf60์ ์ ์ฅ๋ 1๋ฐ์ดํธ์ด๋ค.
์ด๋ฅผ ์ด์ฉํด user๋ฅผ ๋๋ ค๊ฐ๋ฉฐ 1๋ฐ์ดํธ์ฉ ๋น๋ฐ๋ฒํธ๋ฅผ brute forcingํ์ฌ memory leak์ด ๊ฐ๋ฅํ๋ค.
# admin
0x7fffffffdf60์ ๋ค์ ๋งํ๋ฉด user_list[0]์ด๊ณ ์ต์ด์ ๊ณ์ ์ธ admin์ ์ ๋ณด๊ฐ ์ ์ฅ๋์ด์๋ค. count๋ ์ต๋ 32๊น์ง ์ฆ๊ฐ์ํฌ ์ ์์ผ๋ฏ๋ก ์ต๋ 32๋ฐ์ดํธ๊น์ง leak์ด ๊ฐ๋ฅํ์ง๋ง, ๋ง์ง๋ง 8๋ฐ์ดํธ๋ basic_string์ ๊ธฐํ ๋ฐ์ดํฐ์ด๋ฏ๋ก ์ด 26๋ฐ์ดํธ๋ง leak์ ์๋ํ๋ค.
์ด๋ฅผ ํตํด stack ์ฃผ์์ admin์ pw๋ฅผ ํ๋ํ ์ ์๋ค.
=
continue
=
+=
break
=
return
\t, \n ๋ฑ์ ์๋ฏธํ๋ ๊ฐ๋ค์ ์
์ถ๋ ฅ์ leak์ด ๋ถ๊ฐ๋ฅํ์ง๋ง ์์ฃผ ๋ฐ์ํ๋ ๋ฌธ์ ๋ ์๋ ๊ฒ ๊ฐ๋ค.
Win Game
๋ก๊ทธ์ธ์ ํ๋ฉด Play Game, Apply Coupon, Coupon usage history, Change PW, Print Information์ค ํ๋๋ฅผ ํ ์ ์๋ค.
์ด ์ค Change PW์ Print Information์ Play Game์์ ๋ณด์ค๋ฅผ ์ฐ๋ฌ๋จ๋ฆฌ๊ณ regular member๊ฐ ๋์ด์ผ ์ฌ์ฉํ ์ ์๋ ๋ฉ๋ด์ด๋ค.
๋ฌธ์ ๋ฅผ ํ ๋๋ ๋ค์ ๋จ๊ณ๋ก ๋์ด๊ฐ๊ธฐ ์ํด ์ผ๋จ ๊ฒ์์ ๊นผ๋๋ฐ ์ง๊ธ์ฒ๋ผ ๋จผ์ exploit ์๋๋ฆฌ์ค๋ฅผ ์ธ์์ ๋ชฉ์ ์ ๊ฐ์ง๊ณ ์งํํ๋ ์ต๊ด์ ๋ค์ฌ์ผ๊ฒ ๋ค.
OOB ์ทจ์ฝ์ ์ ์ด์ฉํด์ Welcome! ๊ณ์ ์ผ๋ก ๊ฒ์์ ๊นจ๊ณ Change PW๋ฅผ ํธ์ถํ๋ฉด pw_ptr์ด ๊ฐ๋ฆฌํค๋ ๊ณณ์ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ค. Welcome!->pw_ptr์ admin->pw_ptr์ด ์ ์ฅ๋ ์ฃผ์๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์์ผ๋ฏ๋ก, admin->pw_ptr์ ์ํ๋ ์ฃผ์๋ก ๋ฐ๊ฟ๋๊ณ admin์ผ๋ก ๋ก๊ทธ์ธํด์ ๋ค์ Change PW๋ฅผ ํธ์ถํ๋ฉด ์์ ์ค์ ํ ์ํ๋ ์ฃผ์์ ๋ฐ์ดํฐ๋ฅผ ์ธ ์ ์๋ AAW๋ฅผ ํ๋ํ ์ ์๋ค.
๋ค๋ง ์์ ํ AAW๋ ์๋ ๊ฒ์ด admin->pw_ptr์ ๋ฐ๊พธ๋ ์๊ฐ admin์ผ๋ก ๋ก๊ทธ์ธ์ ํ๊ธฐ ์ํด ํ์ํ ๋น๋ฐ๋ฒํธ๊ฐ ๋ฐ๋๋ค. ๋ฐ๋ผ์ ๋ฐ์ดํฐ๋ฅผ ์ธ ์ฃผ์์ ์ ์ฅ๋ ๊ฐ์ ์๊ณ ์์ด์ผ ํ๋๋ฐ, ์ง๊ธ ์๊ฐํด๋ณด๋ Welcome!์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ฐ๊ฟ ๋ admin->pw_size๊น์ง 1๋ก ๋ฐ๊ฟ์ brute forcing์ ํด๋ ๊ด์ฐฎ์ ๊ฒ ๊ฐ๋ค.
์๋ฌดํผ ๊ฒ์์ ๋๋ฅผ ๋ฐ๋ผ์ค๋ Enemy๋ฅผ ํผํด Item์ ํ๋ํด์ Attack๊ณผ Defense๋ฅผ ์ฌ๋ฆฐ ๋ค Enemy์ ์ธ์์ผ ํ๋๋ฐ Item์ ๋ค ๋จน์ด๋ Enemy๋ฅผ ์ด๊ธธ ์ ์๋ค.
์ด ๋ ๊ฐ์
์ ๋ฐ๊ธ๋๋ coupon์ ์ด์ฉํ๋ฉด Attack์ด ๋ ๋ฐฐ๊ฐ ๋๋ฏ๋ก JWT counterfeit ์ทจ์ฝ์ ์ ์ด์ฉํด ์ด ๋ค๊ฐ์ coupon์ ์ด์ฉํ๋ฉด Enemy๋ฅผ ์ด๊ธธ ์ ์๋ค.
๋ฌธ์ ๋ ์์ ํ AAW๋ฅผ ์ป๊ธฐ ์ํด Welcome! ๊ณ์ ์ด regular member๊ฐ ๋์ด์ผํ๋๋ฐ Welcome! ๊ณ์ ์ ๊ฐ์
๋ ๊ณ์ ์ด ์๋๋ค๋ณด๋ ๋ฐ๊ธ๋ coupon์ด ์๋ค.
__int64 __fastcall
๋คํํ join_8A4A()์ ๋ณด๋ฉด id๊ฐ ์ค๋ณต๋์๋์ง๋ฅผ user_list๋ฅผ count๊น์ง๋ง ๋๋ฉด์ ํ์ธํ๊ธฐ ๋๋ฌธ์ Welcome!์ด๋ผ๋ ๊ณ์ ์ ์์ฑํ ์ ์๋ค. ๋ํ login_790E()์์๋ id๋ง ๋ง๊ณ pw๊ฐ ๋ค๋ฅผ ๊ฒฝ์ฐ ๊ทธ๋ฅ ๋ค์ ๋ฃจํ๋ก ๋์ด๊ฐ๊ธฐ ๋๋ฌธ์ ๊ฐ์
์ดํ์๋ 33๋ฒ์งธ Welcome! ๊ณ์ ์ ๋ก๊ทธ์ธ์ด ๊ฐ๋ฅํ๋ค.
๋ง์ง๋ง์ ์์ฑํ Welcome! ๊ณ์ ์ coupon์ 33๋ฒ์งธ Welcome! ๊ณ์ ์ด ์ฌ์ฉํ ์ ์๋๊ฐ์ธ๋ฐ ๋๋ฒ๊ฑฐ์์ secret key๋ฅผ ํ์ธํด jwt.io์์ ๋ด์ฉ์ ํ์ธํ ๊ฒฐ๊ณผ ๋ค์๊ณผ ๊ฐ์ด userid๊ฐ ๊ฐ๊ธฐ ๋๋ฌธ์ 33๋ฒ์งธ Welcome! ๊ณ์ ์์ coupon์ ์ฌ์ฉํ ์ ์์๋ค.

๋ฐ๋ผ์ ๋ค์๊ณผ ๊ฐ์ด payload๋ฅผ ์์ฑํ๋ค.
# join fake "Welcome!"
=
=
# counterfeit coupon
์ด์ ๊ฒ์์ ๊นจ์ผํ๋๋ฐ ์ฐจํ ๋๋ฒ๊น ์ ์ํด์๋ผ๋ ์๋ํ๋ฅผ ํ๋ ค๊ณ ํ๋๋ฐโฆ ์ฌ๊ธฐ์์ ANSI escape code๋ฅผ ์ฌ์ฉํ ์ ์ถ๋ ฅ๋๋ฌธ์ ์์ฒญ ์ค๋๊ฑธ๋ ธ๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก๋ pyte๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ map ์ ๋ณด๋ฅผ ํ์ฑํด์๊ณ , Item์ ๋จน๋ ์๊ณ ๋ฆฌ์ฆ์ ์ข์๊ฒ ๋ ์ค๋ฅด์ง ์์ ๋ค์๊ณผ ๊ฐ์ ๋จ์ํ ๋ฐฉ์์ ์ฌ์ฉํ๋ค.
- ํ๋ฅ ์ ๋์ด๊ธฐ ์ํด
Enemy์ ํ ์นธ ์ฐจ์ด๊ฐ ๋๋๋ก ์๋ก ์ด๋ - ๋งจ ์ผ์ชฝ ์๋์ผ๋ก ์ด๋ -
(0, 0) - ๋งจ ์ผ์ชฝ ์์ผ๋ก ์ด๋ -
(0, 16) Item์ด ์๋ column์ผ๋ก ์ด๋ -(n, 16)- ๋งจ ์๋๋ก ์ด๋ -
(n, 0) Item์ ๋ค ๋จน์์ผ๋ฉด 7๋ฒ, ๋จ์์ผ๋ฉด 2๋ฒEnemy์ ์ ํฌ
์ด์ ๋ ๋ชจ๋ฅด๊ฒ ๋๋ฐ (0, 16)์ ๊ฐ๋ฉด ๋์ ํ๋ฅ ๋ก Enemy์ ๋ ์นธ ์ฐจ์ด๊ฐ ๋๊ฒ ๋์ด Item์ column์ ๋ณด๊ณ ๋๋ฌด ๊ฐ๊น์ด ๊ณณ์ ์์ผ๋ฉด ๊ทธ๋ฅ ๊ฒ์์ ์ฌ์์ํ๋๊ฒ ๋นจ๋ผ ํด๋น ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ค.
Libc Leak
์์ ํ ๋ฐฉ๋ฒ์ผ๋ก AAW๋ฅผ ์ป๋๋ค ์ณ๋ RIP๋ฅผ ์ด๋๋ก controlํ ์ง๊ฐ ๋ฌธ์ ์ด๋ค. ๋ฐ๋ผ์ libc leak์ด ํ์ํ๋ค๊ณ ํ๋จํ๊ณ , ์ถ๋ ฅ๋ถ๋ฅผ ํ์ธํด๋ณด๋ Print Information์ด ์์๋ค. ์ฌ๊ธฐ์์ email์ ์ถ๋ ฅํด์ฃผ๋๋ฐ email_size๊ฐ Welcome!->login_success ์์ญ๊ณผ ๊ฒน์น๋ค.
๋ฐ๋ผ์ ๋ก๊ทธ์ธ์ ์ฑ๊ณต์์ผ login_success ๊ฐ์ ๋๋ฆฌ๋ฉด memory leak์ด ๊ฐ๋ฅํ ๊ฒ์ผ๋ก ํ๋จํ๋ค.
์ฃผ์ํ ๊ฒ์ C++์ด๋ผ์ ๊ทธ๋ฐ์ง ์ฌ์ฉํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ง์ glibc ์์ญ์ ์ ์ฐพ์ ๊ฐ์ ธ์์ผํ๋ค.
=
=
= - 0x29d90
RIP Control
์ด์ stack ์ฃผ์๋ฅผ ์๊ณ ์์ผ๋ main()์ return address๋ฅผ ๋ฎ์ด์ ROP ๊ฐ์ ฏ๋ค์ ์คํํ ๋ค execve๋ฅผ ์คํํ๊ฒ๋ payload๋ฅผ ์์ฑํ๋ค.
๋ค๋ง main() ์ข
๋ฃ ์ง์ ์ ํธ์ถ๋๋ free_db_24FBA()์์ ๊ฐ user ์ ๋ณด๋ค์ ์ ์ฅํ ๊ฐ์ฒด๋ค์ ํด์ ํ๊ธฐ ๋๋ฌธ์ AAW๋ฅผ ์ํด ๋ฐ๊ฟ๋ admin->pw_ptr์ ์๋ณต์์ผ์ผ ํ๋ค.
__int64 __fastcall
๋ฐ๋ผ์ ๋ค์๊ณผ ๊ฐ์ด paylaod๋ฅผ ์์ฑํ๋ค.
# change admin->pw to point return address of main
= + 0xd98
# overwrite return address
= + 0x2a3e5
= + 0x2be51
= + 0x904a9
=
+=
+=
+=
+=
+=
+=
+=
# restore admin->pw
0x03. Payload
=
=
=
return
return
return
return
=
return True
return False
return
return
return
=
continue
=
+=
break
=
return
= +
= +
= +
=
return
# ํฐ๋ฏธ๋ ํฌ๊ธฐ ์ค์ (24ํ, 80์ด ๋ฑ์ผ๋ก ์ค์ )
=
=
# ํ๋ฉด ์ถ๋ ฅ ํ์ฑ ํ 'I', 'O', 'E' ์์น ์ฐพ๊ธฐ
=
continue
return
=
return
=
=
=
# die if too close
= 0
= 1
break
continue
# go to 0, 0
= * 6
+= * 8
+= * 30
=
# farm items
= * 16
+= *
+= * 16
+= *
=
# fight!
return
= 0x555555554000
=
= f
=
=
=
=
=
=
# memory leak using OOB
=
=
=
# join fake "Welcome!"
=
=
# counterfeit coupon
# win game to be regular member
# libc leak by increasing login_success(email_size)
=
=
= - 0x29d90
# change admin->pw to point return address of main
= + 0xd98
# overwrite return address
= + 0x2a3e5
= + 0x2be51
= + 0x904a9
=
+=
+=
+=
+=
+=
+=
+=
# restore admin->pw
# trigger ret in main
=
=