๐Ÿšช Intro

์›น 3๋ฒˆ์งธ ๋ฌธ์ œ ppower ์ž…๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” `prototype pollution` ์„ ํ†ตํ•œ RCE๋ฅผ ํ•˜๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

 

๐Ÿ’ก Analysis - ์ฝ”๋“œ ๋ถ„์„

/answer ํŽ˜์ด์ง€๋กœ GET ๋ฐฉ์‹์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” `req.query` ์— ์ €์žฅ๋˜์—ฌ `merge()` ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด `r` ๋ณ€์ˆ˜์— ์ €์žฅ๋˜๋Š”๋ฐ, `merge()` ํ•จ์ˆ˜๋Š” ์–ด๋– ํ•œ ๊ฒ€์ฆ์—†์ด merge ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ „ํ˜•์ ์ธ prototype pollution ๊ณต๊ฒฉ์—  ์ทจ์•ฝํ•œ ์ฝ”๋“œ ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ, 53๋ฒˆ์งธ ์ค„์—์„œ `config.flagForEveryone` ๊ฐ’์ด ๋ฌด์กฐ๊ฑด false๊ฐ€ ์•„๋‹ˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์•ผ `sendFlag()` ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜์ฃ .

 

 

`sendFlag()` ํ•จ์ˆ˜๋ฅผ ๋ณด๋ฉด, 25๋ฒˆ์งธ ์ค„์—์„œ `childProcess` ๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์‹คํ–‰๋œ ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ, 30๋ฒˆ์งธ ์ค„์—์„œ ๋ฆฌํ„ดํ•˜๊ณ  ์žˆ๋Š” ๊ฐ’์€ 25๋ฒˆ์งธ ์ค„์— ์„ ์–ธ๋œ ๋ณ€์ˆ˜์™€ ๋‹ค๋ฅธ ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค. (๋งˆ์ง€๋ง‰์— g ๋ฌธ์ž ํ•˜๋‚˜๊ฐ€ ๋น ์ ธ์žˆ์Œ...)

์ฆ‰, `config.flagForEveryone` ๊ฐ’์„ prototype pollution ๊ณต๊ฒฉ์„ ํ†ตํ•ด true ๋กœ ๋ฐ”๊พผ๋‹ค๊ณ  ํ•ด๋„ flag ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

 

 

 

 

๐Ÿ’ก Analysis - childProcess.execSync

๋Œ€ํšŒ๊ฐ€ ๋๋‚œ ์ดํ›„ 2๊ฐœ์˜ ํ’€์ด๋ฅผ ๋ณด์•˜๋Š”๋ฐ, ์ด ๋‘˜์˜ ํ’€์ด ๊ณผ์ • ์ค‘ ๊ณตํ†ต์ ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฐ”๋กœ `childProcess.execSync` ํ•จ์ˆ˜์˜ ์ธ์ž๋“ค ์†์„ฑ์„ ์ด์šฉํ•œ ๊ฒƒ์ธ๋ฐ์š”.

 

์ด ํ•จ์ˆ˜์˜ ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ๋ณด๋ฉด, `command`๋Š” ํ•„์ˆ˜์ ์œผ๋กœ ๋„˜๊ฒจ์•ผ ํ•˜๋Š” ์ธ์ž์ด๋ฉฐ, ์‚ฌ์šฉ์ž๋Š” ์„ ํƒ์ ์œผ๋กœ `options` ๊ฐ’์„ ๋„˜๊ฒจ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด `options` ์ธ์ž๋Š” ์•„๋ž˜ ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด, ๋‹ค์–‘ํ•œ ์˜ต์…˜๋“ค์ด ์กด์žฌ ํ•ฉ๋‹ˆ๋‹ค.

https://nodejs.org/api/child_process.html#child_processexecsynccommand-options

 

์œ„ `options` ์ธ์ž๋“ค ์ค‘, `input`๊ณผ `shell` ์ด๋ผ๋Š” ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ์„  `shell` ์˜ต์…˜์— ๋Œ€ํ•œ ์„ค๋ช…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด ์˜ต์…˜์€ ๋ช…๋ น์„ ์‹คํ–‰ํ•  ์‰˜ ์ž…๋‹ˆ๋‹ค. ์ฆ‰, Unix๋Š” ๊ธฐ๋ณธ ์‰˜์ด /bin/sh ์ด default๋กœ ์„ค์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ง€์ •ํ•˜์ง€ ์•Š์•„๋„ ๋ง์ด์ฃ . ๊ทธ๋ž˜์„œ `execSync` ํ•จ์ˆ˜์— ์ฒซ๋ฒˆ์งธ ์ธ์ž์ธ `command` ๊ฐ’์„ ๋„˜๊ฒจ์ฃผ๋ฉด, unix ๊ธฐ์ค€์œผ๋กœ `/bin/sh command` ์ด๋ ‡๊ฒŒ ์‹คํ–‰์ด ๋ฉ๋‹ˆ๋‹ค.

 

๊ทธ ๋‹ค์Œ์œผ๋กœ, `input` ์˜ต์…˜์— ๋Œ€ํ•œ ์„ค๋ช…์ž…๋‹ˆ๋‹ค.

์ด ์˜ต์…˜์€ ์ƒ์„ฑ๋œ ํ”„๋กœ์„ธ์Šค์— stdin์œผ๋กœ ์ „๋‹ฌ๋  ๊ฐ’์ž…๋‹ˆ๋‹ค.

 

์œ„ ๋‘๊ฐ€์ง€ ์˜ต์…˜๊ณผ prototype pollution ๊ณต๊ฒฉ์„ ํ†ตํ•ด RCE๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ์ „์— ์ถ”๊ฐ€๋กœ ์„ค๋ช…ํ•  ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

 

๐Ÿ’ก Analysis - /sbin/debugfs

ํ’€์ด๋ฅผ ๋ณด๋ฉด์„œ ์ด๋Ÿฐ ๊ฒƒ๋„ ์žˆ๊ตฌ๋‚˜... ๋ฅผ ์•Œ๊ฒŒ ๋˜์—ˆ์–ด์š”.

`/sbin/debugfs` ๋Š” ext2/ext3/ext4 ํŒŒ์ผ์‹œ์Šคํ…œ ๋””๋ฒ„๊ฑฐ ํ”„๋กœ๊ทธ๋žจ ์ž…๋‹ˆ๋‹ค.

์ด๋ฅผ ์‹คํ–‰ ํ›„, ์•„๋ž˜ ์‚ฌ์ง„์ฒ˜๋Ÿผ !command ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๋ช…๋ ฌ์–ด๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„ ๋™์ž‘ ๊ณผ์ •์„ ๋ณด๋ฉด, `/sbin/debugfs` ๋ฅผ ์‹คํ–‰ ํ›„ stdin ๋ฐฉ์‹์œผ๋กœ ์ž…๋ ฅ์„ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ์ด์šฉํ•˜์—ฌ RCE๋ฅผ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

 

๐Ÿ’ก Exploit - Prototype Pollution

์šฐ์„ , 52๋ฒˆ์งธ ์ค„์—์„œ if ๋ฌธ ํ†ต๊ณผ๋ฅผ ์œ„ํ•ด ์กฐ๊ฑด์— ๋งž๋Š” ์ธ์ž๋ฅผ ๋„˜๊ฒจ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„, `config.flagForEveryone` ๊ฐ’์„ prototype pollution ์„ ์ด์šฉํ•˜์—ฌ true๋กœ ๋ฐ”๊ฟ”์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ `__proto__` ๋ฅผ ์ด์šฉํ•˜์ง€๋งŒ, ์ตœ์‹  node์—์„œ๋Š” ํ•„ํ„ฐ๋ง ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.(?) 

๋”ฐ๋ผ์„œ prototype์„ ์ด์šฉํ•˜์—ฌ pollution์„ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด, flagForEveryone ์˜ ๊ฐ’์„ 1๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

/answer?constructor[prototype][flagForEveryone]=1&answer=It%27s-none-of-your-business

 

๊ทธ ๋‹ค์Œ์œผ๋กœ, `child_process.execSync()` ํ•จ์ˆ˜์— ์‚ฌ์šฉ๋˜๋Š” `shell` ๊ณผ `input` ์„ ์˜ค์—ผ์‹œํ‚ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ payload๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. 

constructor[prototype][shell]=/sbin/debugfs
constructor[prototype][input]=!id

`shell` ์„ `/sbin/debugfs` ๋กœ ์˜ค์—ผ์‹œํ‚ค๋Š” ์ด์œ ๋Š”, `shell`์€ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•  ์‰˜ ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์œผ๋กœ /bin/sh๋กœ ์„ค์ •๋˜์–ด ์žˆ์ง€๋งŒ, `/sbin/debugfs`๋กœ ์˜ค์—ผ์‹œํ‚ค๊ฒŒ ๋˜๋ฉด `/sbin/debugfs command` ์ด๋ ‡๊ฒŒ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์‹ค์ œ ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰ํ•˜๋ฉด ์•„๋ž˜ ์‚ฌ์ง„์ฒ˜๋Ÿผ ls๋ผ๋Š” ํŒŒ์ผ์„ open ํ•˜๋ ค๊ณ  ํ–ˆ์ง€๋งŒ ํŒŒ์ผ์ด ์—†๋‹ค๋Š” ์—๋Ÿฌ๋ฅผ ๋„์šฐ๊ณ  ์ž…๋ ฅ ์ฐฝ์ด ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ž…๋ ฅํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด๋ผ๋ฉด, `child_process.execSync()` ํ•จ์ˆ˜์—์„œ ์•ž์„œ ์„ค๋ช…ํ–ˆ๋˜ `options`์˜ `input` ์˜ต์…˜์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

์˜ˆ๋ฅผ๋“ค์–ด !id ๋ผ๋Š” ๊ฐ’์„ ์ „๋‹ฌํ•˜๋ฉด `child_process.execSync(command)` ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด `/sbin/debugfs command` ๋ช…๋ น์–ด๊ฐ€ ๋™์ž‘ํ•˜๊ณ , ์ด๋•Œ stdin ์œผ๋กœ !id ๋ผ๋Š” ๊ฐ’์ด `/sbin/debugfs` ๋กœ ์ „๋‹ฌ๋˜์–ด ๋ช…๋ น์–ด๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

 

ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰ํ•˜์—ฌ ์ฝ˜์†” ์ฐฝ์„ ๋ณด๋ฉด `id` ๋ช…๋ น์–ด๊ฐ€ ์‹คํ–‰๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (debugfs ๋ช…๋ น์–ด ์—๋Ÿฌ๋„ ๋ณด์ด๋„ค์š”.)

 

๋”ฐ๋ผ์„œ ์ตœ์ข… payload๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. input ๊ฐ’์€ reverse shell ํ˜น์€ ๋‹ค๋ฅธ ๋ช…๋ น์–ด๋ฅผ ๋„ฃ์–ด์„œ ํ•˜๋ฉด RCE๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

/answer?constructor[prototype][flagForEveryone]=1&constructor[prototype][shell]=/sbin/debugfs&constructor[prototype][input]=!id&answer=It%27s-none-of-your-business

 

`WACon{node**pp=rce/*:P*/}`

'CTF' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

DiceCTF 2022 writeup  (0) 2022.07.25
[WACon 2022] yet_another_baby_web  (0) 2022.06.28
[WACon 2022] Kuncษ›lan write up  (0) 2022.06.27
zer0pts ctf 2022 GitFile Explorer write up  (0) 2022.03.27
hayyim CTF 2022 writeup  (0) 2022.02.13