๊ธ€ ์ž‘์„ฑ์ž: heogi

# Baby Simple GoCurl


๋ฌธ์ œ ํŽ˜์ด์ง€์— ์ ‘์†ํ•˜๋ฉด URL, Header Key, Header Value๋ฅผ ์„ค์ •ํ•˜์—ฌ Curl ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด ์กด์žฌํ•œ๋‹ค. ์ƒ๋‹จ์—๋Š” ํ˜„์žฌ ๋‚ด๊ฐ€ ํ• ๋‹น๋ฐ›์€ IP์ฃผ์†Œ๊ฐ€ ํ‘œ๊ธฐ๋˜๊ฒŒ ๋˜์–ด์žˆ๋‹ค.

https://www.naver.com , test, test๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ์•„๋ž˜ ์ฒ˜๋Ÿผ Response๊ฐ€ ๋‚˜ํƒ€๋‚œ๋‹ค.

  • GET /flag/
r.GET("/flag/", func(c *gin.Context) {
		reqIP := strings.Split(c.Request.RemoteAddr, ":")[0]

		log.Println("[+] IP : " + reqIP)
		if reqIP == "127.0.0.1" {
			c.JSON(http.StatusOK, gin.H{
				"message": flag,
			})
			return
		}

		c.JSON(http.StatusBadRequest, gin.H{
			"message": "You are a Guest, This is only for Host",
		})
	})
  • GET /curl/
r.GET("/curl/", func(c *gin.Context) {
	client := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return redirectChecker(req, via)
		},
	}

	reqUrl := strings.ToLower(c.Query("url"))
	reqHeaderKey := c.Query("header_key")
	reqHeaderValue := c.Query("header_value")
	reqIP := strings.Split(c.Request.RemoteAddr, ":")[0]
	fmt.Println("[+] " + reqUrl + ", " + reqIP + ", " + reqHeaderKey + ", " + reqHeaderValue)

	if c.ClientIP() != "127.0.0.1" && (strings.Contains(reqUrl, "flag") || strings.Contains(reqUrl, "curl") || strings.Contains(reqUrl, "%")) {
		c.JSON(http.StatusBadRequest, gin.H{"message": "Something wrong"})
		return
	}

	req, err := http.NewRequest("GET", reqUrl, nil)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"message": "Something wrong"})
		return
	}

	if reqHeaderKey != "" || reqHeaderValue != "" {
		req.Header.Set(reqHeaderKey, reqHeaderValue)
	}

	resp, err := client.Do(req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"message": "Something wrong"})
		return
	}

	defer resp.Body.Close()

	bodyText, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"message": "Something wrong"})
		return
	}
	statusText := resp.Status

	c.JSON(http.StatusOK, gin.H{
		"body":   string(bodyText),
		"status": statusText,
	})
})

์ฒซ ๋ฒˆ์งธ ์กฐ๊ฑด์„ ๋ณด๋ฉด c.ClientIP()๊ฐ€ 127.0.0.1์ด ์•„๋‹ˆ๊ณ , requrl ํŒŒ๋ผ๋ฏธํ„ฐ์— flag, curl, %์˜ ๋ฌธ์ž์—ด์ด ํฌํ•จ๋˜์–ด์žˆ์œผ๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋˜์–ด์žˆ๋‹ค.

ํ•ด๋‹น ๋ถ€๋ถ„์„ ๋งŒ์กฑ์‹œ์ผœ ์„œ๋ฒ„์—์„œ(127.0.0.1) ์ง์ ‘ GET /flag ๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ์žก๊ณ  ์ง„ํ–‰ํ•œ๋‹ค.

  1. GET /flag ์—์„œ ํ™•์ธํ•˜๋Š” IP flag ํ•จ์ˆ˜์—์„œ ํ™•์ธํ•˜๋Š” IP๋Š” RemoteAddr() ์ด๋‹ค. ํ•ด๋‹น IP๋Š” ์š”์ฒญํ•œ Client์˜ IP๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
  2. GET /curl ์—์„œ ํ™•์ธํ•˜๋Š” IP curl ํ•จ์ˆ˜์—์„œ ํ™•์ธํ•˜๋Š” IP๋Š” Go์˜ c.ClientIP() ์ด๋‹ค. ํ•ด๋‹น IP๋Š” Document์— ๋”ฐ๋ฅด๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” IP์ธ์ง€ ํ™•์ธํ•œ๊ณ  ์‹ ๋ขฐ ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด X-Fowarded-For๋‚˜ X-Real-IP ํ—ค๋”๋ฅผ ์ฐธ์กฐํ•˜๊ณ , ๊ตฌ๋ฌธ์ ์œผ๋กœ ์œ ํšจํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์‹ ๋ขฐ์„ฑ์ด ์—†๋‹ค๋ฉด ์›๊ฒฉ Client IP์ธ RemoteAddr์„ ์ฐธ์กฐํ•œ๋‹ค.

์ฐธ๊ณ  : https://github.com/gin-gonic/gin/blob/v1.9.0/context.go#L771

Request์— X-Fowarded-For ํ—ค๋”๋ฅผ ๋‹ด์•„์„œ ์š”์ฒญ์„ ๋ณด๋‚ด๋ณด๋ฉด ์•„๋ž˜ ์ฒ˜๋Ÿผ c.ClientIP()์—์˜ํ•ด ์ถœ๋ ฅ๋˜๋Š” IP๊ฐ€ ๋ณ€์กฐ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.


GET /curl/ ํ•จ์ˆ˜์˜ IP ์ฒดํฌ๋Š” ์šฐํšŒ๊ฐ€ ๋˜์–ด ์ด์ œ requrl์— flag ๋ฌธ์ž์—ด์„ ํฌํ•จํ•˜์—ฌ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿผ ์ด์ œ ์„œ๋ฒ„์—์„œ ์ง์ ‘ localhost๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๊ฒŒ๋˜๋ฉด GET /flag์—์„œ ์ฒดํฌํ•˜๋Š” IP ์กฐ๊ฑด์ธ 127.0.0.1๋„ ๋งŒ์กฑํ•  ์ˆ˜ ์žˆ๋‹ค.

  • GIN ์„œ๋น„์Šค์˜ Default Port๊ฐ€ 8080์ด๋‹ค.

'๐Ÿ›ก๏ธCTF > LineCTF' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

LineCTF(2023) - Adult Simple GoCurl  (0) 2023.08.13
LineCTF 2022 - memo drive  (0) 2022.04.13
LineCTF 2022 - gotm  (0) 2022.03.29