SECUINSIDE CTF 2013 - lockd
๋ชฉ์ฐจ
0x00. Introduction
)
0x01. Vulnerability
Buffer Overflow
int
main()์ ํต์ฌ์ ์ธ lock(), unlock() ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ floor_804A4C0, room_804A0A0 ๊ฐ์ ๋ฒ์์ ๋ง๊ฒ ์
๋ ฅํ๊ณ , read_password_8048A7D()์ ๊ฒฐ๊ณผ๊ฐ True์ฌ์ผ ํ๋ค.
int
์ด ๋ 20๋ฐ์ดํธ์ง๋ฆฌ buf์ 40๋ฐ์ดํธ๋งํผ ์
๋ ฅ์ ๋ฐ๊ธฐ ๋๋ฌธ์ ์ง์ญ๋ณ์ password๋ฅผ ๋ฎ์ ์ ์๋ค.
FSB in syslog
int
password leak์ ์ฑ๊ณตํ๋ฉด lock()๊ณผ unlock()์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๋ค.
์ด ์ค์์ syslog()์ ๋ํด์ ์์ธํ๊ฒ ์ดํด๋ณด๋ฉด,
void ;
๋ ๋ฒ์งธ ์ธ์ format์ format string์ผ๋ก, Linux manual page์์๋ ๊ด๋ จ ๋ด์ฉ์ ํ์ธํ ์ ์๋ค.
Never pass a string with user-supplied data as a format, use the following instead:
syslog(priority, "%s", string);
๊ทธ๋ฐ๋ฐ lock()์์๋ syslog(13, fmt_0804A0C0); ํ์์ผ๋ก ์ฌ์ฉํ๊ณ ์๊ธฐ ๋๋ฌธ์ fmt_0804A0C0์ format string์ ๋ฃ์ด์ฃผ๋ฉด FSB๊ฐ ๋ฐ์ํ๋ค.
๋คํํ name_804A2C0๋ฅผ ํตํด fmt_0804A0C0์ format string์ ์ ๋ฌํ ์ ์์ผ๋ฏ๋ก, ์ทจ์ฝ์ ์ ํ์ฉํ ์ ์๋ค.
0x02. Exploit
Info Leak
int
read_password_8048A7D()๋ฅผ ๋ณด๋ฉด read()์์ 40๋ฐ์ดํธ๋ฅผ ์ฝ์ผ๋ฉฐ ์ง์ญ๋ณ์ password์ ๊ฐ์ ์กฐ์ํ ์ ์์ง๋ง, lock()์ด๋ unlock()์์๋ ์ ์ญ๋ณ์ password_804A0A4์ ๊ฐ๊ณผ ๋น๊ตํ๊ธฐ ๋๋ฌธ์ ์๋ฏธ๊ฐ ์๋ค.
๋์ ๋ค๋ฅธ ๊ณต๊ฒฉ์ด ๊ฐ๋ฅํ๋ฐ, password์ ๋ง์ง๋ง 1๋ฐ์ดํธ๋ฅผ ๋จ๊ฒจ๋๊ณ ์ ๋ถ๋ถ์ buf์ ๊ฐ์ ๊ฐ์ผ๋ก ๋ฎ์ผ๋ฉด 1๋ฐ์ดํธ์ฉ brute forcing์ด ๊ฐ๋ฅํ๋ค.
๋ฐ๋ผ์ ๋ค์๊ณผ ๊ฐ์ด payload๋ฅผ ์์ฑํ๋ค.
=
=
= b *
+=
+=
+= b * 4
+= b *
break
continue
return
FSB
ํ์์ฒ๋ผ FSB๋ฅผ ํ์ฉํ๋ ค๋ฉด payload๋ฅผ %p %p %p %p ... ์ด๋ฐ ์์ผ๋ก ๊ตฌ์ฑํด์ ๋ช ๋ฒ์งธ format string๋ถํฐ $esp๊ฐ ๊ฐ๋ฆฌํค๋ ๋ถ๋ถ์ธ์ง ํ์ธํ๋ค. ํ์ง๋ง syslog()๋ /var/log/syslog์ ๋ก๊ทธ๋ฅผ ๋จ๊ธธ ๋ฟ์ด๋ผ์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์๊ฐ ์์๋ค. ๊ฒฐ๊ตญ %?$n์์ ?๊ฐ์ ๋๋ ค๊ฐ๋ฉฐ ์ธ์ ์ด๋์ ๊ฐ์ด ์จ์ง๋์ง ์์ผ๋ก ํผ์ง์ ํ๋ค.
๊ทธ ๊ฒฐ๊ณผ $esp์์ n๋ฒ์งธ ๋ฉ๋ชจ๋ฆฌ๋ %(n + 2)$n์ผ๋ก ์ ๊ทผํ ์์๋ค๋ ๊ฒ์ ํ์ธํ๋ค.
๋ํ ์ฐ๋ฆฌ๊ฐ ์
๋ ฅํ format string๋ง ์ถ๋ ฅ๋๋ ๊ฒ์ด ์๋๋ผ "LOCK %d-%d by %s" ๋ฌธ์์ด์ %s ๋ถ๋ถ์ format string์ด ๋ค์ด๊ฐ๋ฏ๋ก 0xc๋ฐ์ดํธ๋งํผ ๊ฐ์ด ๋ ์จ์ง๋ค. ๋ฐ๋ผ์ ๋ค์๊ณผ ๊ฐ์ด payload๋ฅผ ์์ฑํ๋ค.
# %n$ -> pointing (n + 2)th dword from esp
=
= 26
์ด์ exploit์ ์ํด syslog()๋ฅผ ํธ์ถํ ๋์ stack์ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
๋ชจ๋ ์ ๋ ฅ์ ์ ์ญ๋ณ์์ ๋ฐ๊ธฐ ๋๋ฌธ์ stack์ ์๋ ๊ฐ์ ์ ์ด์ฉํด์ exploit์ ํด์ผํ๋ค. ์ฒ์์๋ 4๋ฐ์ดํธ๊ฐ ํ๋ฒ์ ์จ์ง๊ฑฐ๋ผ๊ณ ์๊ฐ์ ๋ชปํด์
0xffffddb4์0x00write
0xffffddb4: 0xffffde00
0xffffde00์ 2๋ฐ์ดํธ write (ํ์ 2๋ฐ์ดํธ)
0xffffde00: 0x0000a03c
0xffffddb4์0x02write
0xffffddb4: 0xffffde02
0xffffde00์ 2๋ฐ์ดํธ write (์์ 2๋ฐ์ดํธ)
0xffffde00: 0x0804a03c
0x0804a03c(sprintf got)์ 2๋ฐ์ดํธ write
์ด๋ฐ ์์ผ๋ก exploit์ ์งํํ๋ ค๊ณ ํ์ผ๋, ASLR์ ํค๊ณ ๋๋๊น ์ํฉ์ด ๋ฌ๋ผ์ก๋ค.
ASLR์ด ๊บผ์ง ๊ฒฝ์ฐ 0xffffddb4๊ฐ 0xffffdec4๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์์ด 0xffffde?? ์์ญ์ ์ปจํธ๋กคํ ์ ์๋ ๋ฐ๋ฉด
ASLR์ด ์ผ์ง ๊ฒฝ์ฐ 0xff8ca714๊ฐ 0xff8caec4๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์์ด 0xff8cae?? ์์ญ์ ์ปจํธ๋กคํ ์ ์๋ค.
์ด๋ฌ๋ฉด sprintf()์ got ์ฃผ์๋ฅผ stack์ ์ ๊ตฌ์ฑํด๋๊ณ ์ ์ %?$n์ผ๋ก ์ ๊ทผํ ๋ ? ๊ฐ์ด ์ผ์ ํ์ง ์๋ค๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. ๊ทธ๋ ๊ฒ ํ๋ฅ ์ด์๋ก ํ์ฐธ ๊ณ ์์ ํ๋ค๊ฐ ์๊ฒ ๋ ์ฌ์ค์ด 0x0804a03c๊ฐ ํ ๋ฒ์ ์ฐ์ฌ์ง๋ค๋ ๊ฒ์ธ๋ฐ, ๊ทธ๋ฌ๋ฉด exploit์ด ์๋นํ ๊ฐ๊ฒฐํด์ง๋ค.
0xffffddb4์0x0804a03c(sprintf got) write
- 0xffffddb4: 0x0804a03c
0x0804a03c์0x080485e0(system plt) write
- 0x0804a03c: 0x080485e0
์ฐธ๊ณ ๋ก sprintf()๋ฅผ system()์ผ๋ก ๋ฎ๋ ์์ด๋์ด๋ ์ฒซ ๋ฒ์งธ ์ธ์์ ๋ด๊ฐ ์ปจํธ๋กคํ ์ ์๋ ๊ฐ์ด ๋ค์ด๊ฐ๋ ํจ์๊ฐ sprintf()๋ฐ์ ์์๋ค.
;
if
return -1;
;
์ฒซ ๋ฒ์งธ ์ธ์์ธ fmt_0804A0C0์ password๊ฐ ๋ด๊ฒจ์์ด์ผ ํ๋๋ฐ, ๋คํํ memcmp()๋ฅผ 16๋ฐ์ดํธ๋ง ํ๋ ๋ฐ๋ฉด ์
๋ ฅ์ 20๋ฐ์ดํธ๋ฅผ ๋ฐ์ผ๋ฏ๋ก 4๋ฐ์ดํธ์ ์ฌ์ ๊ณต๊ฐ์ด ์๊ธด๋ค. ๋ฐ๋ผ์ key ๋ค์ ;sh๋ฅผ ๋ฃ์ด์ฃผ๋ฉด GOT overwrite๊ฐ ์ฑ๊ณตํ์ ๋ ๋ค์๊ณผ ๊ฐ์ด ํจ์๊ฐ ์คํ๋๋ค.
// sprintf(fmt_0804A0C0, "./lock UNLOCK %d %d", floor_804A4C0, room_804A0A0);
;
์์ c39f30e348c07297 ๋ถ๋ถ์ ์๋ ๋ช
๋ น์ด๋ฏ๋ก ๋ฌด์๋๊ณ , ๋ค์ ๋ช
๋ น์ธ sh๊ฐ ์คํ๋์ด shell์ ์คํ์ํฌ ์ ์๋ค.
0x03. Payload
= True
=
=
= f
=
return
=
=
= b *
+=
+=
+= b * 4
+= b *
break
continue
return
=
=
=
=
# [+] key : c39f30e348c07297
# key = ''.join(guess_key(s))
# log.success(f"key : {key}")
= b
# %n$ -> pointing (n + 2)th dword from esp
=
= 26
=
= 62