挖洞遇到验证码那些事
发布日期:2024-05-19 浏览次数: 专利申请、商标注册、软件著作权、资质办理快速响应热线:4006-054-001 微信:15998557370
# 前言 平台:aHR0cHM6Ly93d3cudnVsYm94LmNvbS8=公益SRC 厂商:zay7qMuz 链接:aHR0cHM6Ly91cGFzcy4xMGpxa2EuY29tLmNuL2xvZ2lu 文章搭配视频地址:挖洞遇到验证码那些事 # 正文 输入手机号码与账号密码登录的接口都有滑块。区别在于账号密码登录的时候有个加盐密码。流程比手机号码的接口复杂一下,为了省时间。此文章便是根据手机号码的接口去写的,毕竟咱的目的是过滑块嘛。 ## 发包逻辑分析 每次刷新验证码,都会发四个数据包下来。第一个数据包用于请求图片。图片链接的拼接就是urlParams加上imgs的值。 第三个数据包是背景图 第四个数据包是缺口图片 正确拼接验证码,短信验证码发送成功 captcha_signature在刷新验证码发下来的数据包里面的sign参数。 captcha_phrase和captcha_ticket在getTicket接口从服务器返回回来的,captcha_phrase是缺口,如果缺口对齐失败的话captcha_ticket是获取不到的。所以得先把getTicket接口的参数补齐拿到ticket。 getTicket的前五个参数直接从getPreHandle接口返回的urlParams获取。 phrase直接用搜索大法就能搜到关键位置 phrase: (x) + ";" + inity + ";" + opt.width + ";" + opt.height x是缺口识别的x轴,opt.width和opt.height是固定的值 inity也是直接在js文件一搜就能拿到他的关键代码。data.data.inity在getPreHandle接口里面的inity。这段代码就是取那个inity相除相乘再拼接到phrase里头 inity = (data.data.inity / 195 * opt.height); x直接就是缺口识别然后减去15(因为图片实际大小跟他在网页上面的大小不一样),懒得缩小了。因为通过训练相同的图片跟缺口其x就相差15,直接减更方便(懒人做法) 图片缺口识别代码: def detect_captcha_gap(bg, tp): ''' bg: 背景图片 tp: 缺口图片 return:空缺距背景图左边的距离 ''' # 读取背景图片和缺口图片 bg_img = cv2.imread(bg) # 背景图片 tp_img = cv2.imread(tp) # 缺口图片 # 识别图片边缘 bg_edge = cv2.Canny(bg_img, 100, 200) tp_edge = cv2.Canny(tp_img, 100, 200) # 转换图片格式 bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB) tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB) # cv2.imwrite("bg_style.png",bg_pic) # 保存背景轮廓提取 # cv2.imwrite("slide_style.png",tp_pic) # 保存滑块背景提取 # 缺口匹配 res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # 寻找最优匹配 th, tw = tp_pic.shape[:2] tl = max_loc # 左上角点的坐标 # 返回缺口的左上角X坐标 br = (tl[0] + tw, tl[1] + th) # 右下角点的坐标 cv2.rectangle(bg_img, tl, br, (0, 0, 255), 2) # 绘制矩形 cv2.imwrite("result_new.png", bg_img) # 保存在本地 # 返回缺口的左上角X坐标 return tl[0] x = detect_captcha_gap("bg.jpg","tp.jpg")-15 mobile加密就是一个rsa加密,没有任何混淆跟难点。 验证码校验接口还有个hexin-v参数 hexin-v硬扣 校验验证码的数据包里面有个加密的header参数hexin-v,他跟cookie的v是一模一样的。有两种方法可以找到关键加密位置,第一种是headers hook,第二种是cookie hook。 cookie hook代码: (function () { 'use strict'; var cookieTemp = ""; Object.defineProperty(document, 'cookie', { set: function (val) { console.log('Hook捕获到cookie设置->', val); if (val.indexOf('v') != -1) { debugger; } cookieTemp = val; return val; }, get: function () { return cookieTemp; } });})(); 在控制台输入hook的代码 断点断了下来。回溯堆栈找到关键代码加密的地方 w函数便是设置cookie的函数,r就是v加密生成返回的值。那么qn.update()就是v生成的函数了。把断点下到qn.update()那一行然后刷新。由于这个网站的js文件是动态生成的,所以需要重新进入新的js文件在qn.update()那一行重新下个断点刷新。 断点断下之后进入qn.update()看看里面写了啥 进入到qn.update()函数内部可以看出他返回了另外一个函数的返回值。 把断点断到R函数这一行进入到R函数内部。 R函数往E对象里面压入一堆值。找找E在哪里生成的。 E对象是在b函数里面被赋值的,但因作用域的原因,他并不是在这里声明的,E声明的地方还得往上面去找。 在945行找到E声明的地方,同时也发现了这一段大的函数是一个自执行的函数。 开始扣代码,就只扣需要的代码,R()是v加密后的值,R函数里面有E对象,E对象是在b函数里面被实例化的。b函数也扣下来,b函数里面调用了C函数。C函数也一并扣下来。因为E对象是全局作用域,其声明的代码在几个函数的外面。 var o = r[40], i = r[37], u = e[26], c = e[121], s = parseInt(Kn(n[80], e[122], t[135]), t[67]), f = n[94], v = r[59], l = e[74], p = n[53], d = parseInt(t[29], t[62]), h = parseInt(n[68], n[134]), g = n[135], m = parseInt(e[123], n[51]), w = parseInt(n[136], e[58]), I = parseInt(e[124], t[136]), _ = parseInt(e[125], e[79]), y = parseInt(n[137], n[134]), A = parseInt(e[126], t[67]), E; function C() { var r = Wn.getCookie(On) || $n.get(Pn); if (r && r[t[59]] == parseInt(n[138], t[62])) { var e = Qn.decode(r); if (e && (E.decodeBuffer(e), E[o] != n[29])) return } E[o] = Gn.random() } function b() { var t = e[31] , a = parseInt(e[127], e[26]) , o = r[52] , u = parseInt(e[128], e[26]); E = new Un([u, u, u, u, t, t, t, o, a, a, a, a, a, a, a, u, a, t]), E[i] = Gn.serverTimeNow(), C(), E[_] = Dn, E[A] = xn, E[y] = n[29], E[c] = Gn.strhash(navigator.userAgent), E[w] = Yn.getBrowserFeature(), E[s] = Yn.getPlatform(), E[f] = Yn.getBrowserIndex(), E[v] = Yn.getPluginNum() } function R() { var n = Y; E[y]++, E[i] = Gn.serverTimeNow(), E[u] = Gn.timeNow(), E[_] = Dn, E[l] = Jn.getMouseMove(), n = q, E[p] = Jn.getMouseClick(), E[d] = Jn.getMouseWhell(), E[h] = Jn.getKeyDown(), E[g] = Jn.getClickPos().x, E[m] = Jn.getClickPos().y; var t = E.toBuffer(); return Qn.encode(t) } console.log(R()) 代码运行报错,r未定义。那么e,t,n是否也是未定义。在浏览器运行一下看看是什么呢 在控制台打印r,e,t,n。发现他们都是大数组。直接扣下来就行了 var n=["xi", "n-", "v", "ai", ".", "get", "kie", "; d", "x1c)Awx1b", "3", "ced", "strT", "rigi", "]V8a", "w", "l", Array, "Map", Function, 58, "ttpR", "Feb 2050", "fZ,x19", "x15x18;", "", 9527, 256, String, "head", 0, 1, "al", "Coo", 92, 81, !1, window, "[X9^QR", "TR8", "u250cu252c", "localStorage", "d", "___", "documentElement", "addBehavior", '', "frames", "base_fileds", "ZKx1f", "f", "ode", 2, 16, 8, "14", "3f", 30, "ZV%Px0ex03x12P[X2P", "ned", "r", "e", ")^]a", 86, "le", "u2559u253e", "^{", "th", / /g, "10", RegExp, '^".*"