前言
cloudflare的5s盾防护,首推模拟浏览器,这里是用的是补环境过的,整个下来要发十多个请求,真心不如浏览器来的省心高效。分析5s盾主要是为了完善纯python补环境框架。不多说开干!
目标网站
我收集了下面三个5s盾的网站,第一个不需要点击,后面两个大概率需要模拟一下点击,才能获取到目标cookie
aHR0cHM6Ly9wYXN0ZWJpbi5jb20vbG9naW4=aHR0cHM6Ly9zdGVhbWRiLmluZm8vaHR0cHM6Ly9zaW1wbGUucmlwbGV5LmNvbS5wZS8=
目标
获取到cf_clearance的cookie值
结果展示
懒得截图直接看分析
相关环境准备
python311的环境,curl-cffi发包,应对tls指纹相关的检测
请求流程分析
0x0
请求目标网址xxx.com(后面目标网址都以xxx.com指代)后,得到一个403的响应,但是响应内容里面是有html结构。浏览器渲染改403的页面,里面有个script标签,执行script标签内的js代码,js代码内容大致如下:
- 生成
window._cf_chl_opt字典,里面主要存储了很多重要数据 - 执行
history.replaceState(null, null, '/login?__cf_chl_rt_tk=23uj.bH4Nck601eNWyK6_zJ8cpAWIT68s1dHuhw_UbU-1731480684-1.0.1.1-UcADOZffDXKvhHujlLxCshNoErbCSaRestb.ZxPjrqQ')方法,replaceState方法的作用不详说,这里的效果相当于这段代码location.href='/login?__cf_chl_rt_tk=23uj.bH4Nck601eNWyK6_zJ8cpAWIT68s1dHuhw_UbU-1731480684-1.0.1.1-UcADOZffDXKvhHujlLxCshNoErbCSaRestb.ZxPjrqQ' - 调用
document.createElement("script")创建一个新的script标签,并为这个标签设置src为/cdn-cgi/challenge-platform/h/b/orchestrate/chl_page/v1?ray=8e1cd5438a57d6cf,同时为这个新script标签设置一个onload事件HTMLScriptElement.onload = function() {history.replaceState(null, null, ogU);},然后将这个新script标签添加到head标签内。
到此为止第一个请求分析完毕。
0x1
下载上面所说的script新标签,并执行里面的js代码,执行完后记得触发一下上述的onload事件,会触发执行history.replaceState(null, null, '/login'),将location.href换回去。js代码执行时会设置一个delay为1000的Interval事件(不用触发),和一个delay为0的Timeout事件,触发一下,该Timeout执行后,会触发一顿dom操作如:创建标签啊,标签设置属性啊,添加或者插入啥的,同时又会生成一系列Timeout事件,其中delay为100的留意一下(很重要,下面在提他的作用),除此之外又会创建一个src为https://challenges.cloudflare.com/turnstile/v0/b/22755d9a86c9/api.js?onload=clJo2&render=explicit的script标签添加到head里面,并为该标签设置属性HTMLScriptElement.setAttribute('crossorigin', 'anonymous')让其能够跨域。至止第二个请求分析完毕。
0x2
如何触发第一次的Post请求?
执行上面所说的delay为100的setTimeout事件,将触发parent页面的第一次的xhr请求(将这403的页面称为parent是因为后面会创建iframe页面,这里做个区分):
getter: Window.XMLHttpRequest -> function XMLHttpRequest() { [native code] }
construct: new XMLHttpRequest()
getter: XMLHttpRequest.open -> function open() { [native code] }
method: XMLHttpRequest.open('POST', '/cdn-cgi/challenge-platform/h/b/flow/ov1/263744831:1731479402:t7vrxLfwsC1PfYyU3KUsER_IR8gBFaakbotZuJLXxUw/8e1cd5438a57d6cf/KWSv3hmMqzGIKo9lp9DBn6lb30w_O7ja7V51RP518c0-1731480684-1.2.1.1-CMMeN20jmRkStAUq1xnL6p9LZ_nHUtjZtJS_rPvzlSBEv8YHToc9gRtY8bqEqhGz', True)
setter: XMLHttpRequest.timeout = 2500
setter: XMLHttpRequest.ontimeout = function(){h()}
getter: XMLHttpRequest.setRequestHeader -> function setRequestHeader() { [native code] }
method: XMLHttpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
getter: XMLHttpRequest.setRequestHeader -> function setRequestHeader() { [native code] }
method: XMLHttpRequest.setRequestHeader('CF-Challenge', 'KWSv3hmMqzGIKo9lp9DBn6lb30w_O7ja7V51RP518c0-1731480684-1.2.1.1-CMMeN20jmRkStAUq1xnL6p9LZ_nHUtjZtJS_rPvzlSBEv8YHToc9gRtY8bqEqhGz')
setter: XMLHttpRequest.onreadystatechange = function(ha,l,C,m,n,o,s,v,x){if(ha=h7,l={'PrrAQ...
method: XMLHttpRequest.send('v_8e1cd5438a57d6cf=klybcbwb...rr',)
发送该请求并触发xhr的onreadystatechange事件,onreadystatechange会将响应的内容(应该时一段js代码)解密并执行,会为window添加一个message事件(为了后面与iframe跨域通信)。到此第三个请求分析完毕。
0x3
上面提到的跨域的script标签,下载下来并执行其内容,执行完毕后又会设置两个delay为0的Timeout事件,触发这两个Timeout事件,其中一个会创建iframe标签并设置src为https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/b/turnstile/if/ov2/av0/rcv0/0/66aix/0x4AAAAAAADnOjc0PNeA8qVm/light/fbE/normal/auto/,大致代码如下:
method: HTMLDocument.createElement('iframe',) -> [object HTMLIFrameElement]
getter: Window.document -> [object HTMLDocument]
getter: HTMLDocument.createElement -> function createElement() { [native code] }
method: HTMLDocument.createElement('div',) -> [object HTMLDivElement]
getter: HTMLDivElement.attachShadow -> function attachShadow() { [native code] }
method: HTMLDivElement.attachShadow({'mode': 'closed'},) -> [object ShadowRoot]
getter: Window.setInterval -> function setInterval() { [native code] }
getter: HTMLIFrameElement.style -> [object CSSStyleDeclaration]
setter: CSSStyleDeclaration.display = none
getter: HTMLIFrameElement.style -> [object CSSStyleDeclaration]
setter: CSSStyleDeclaration.border = none
getter: HTMLIFrameElement.style -> [object CSSStyleDeclaration]
setter: CSSStyleDeclaration.overflow = hidden
getter: HTMLIFrameElement.setAttribute -> function setAttribute() { [native code] }
getter: Window.URLSearchParams -> function URLSearchParams() { [native code] }
construct: new URLSearchParams() -> undefined
getter: URLSearchParams.size -> 0
method: HTMLIFrameElement.setAttribute('src', 'https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/b/turnstile/if/ov2/av0/rcv0/0/66aix/0x4AAAAAAADnOjc0PNeA8qVm/light/fbE/normal/auto/') -> undefined
setter: HTMLIFrameElement.onerror = function(){if(G){G==null||G(String(Xt.code));return}m("Could not load challenge from challenges.cloudflare.com.",161)}
getter: Window.document -> [object HTMLDocument]
getter: HTMLDocument.featurePolicy -> [object FeaturePolicy]
getter: FeaturePolicy.features -> function features() { [native code] }
method: FeaturePolicy.features() -> ['geolocation', 'ch-ua-full-version-list', ...
getter: HTMLIFrameElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLIFrameElement.setAttribute('allow', 'cross-origin-isolated; fullscreen; autoplay') -> undefined
getter: HTMLIFrameElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLIFrameElement.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-popups') -> undefined
setter: HTMLIFrameElement.id = cf-chl-widget-66aix
setter: HTMLIFrameElement.tabIndex = 0
setter: HTMLIFrameElement.title = Widget containing a Cloudflare security challenge
getter: ShadowRoot.appendChild -> function appendChild() { [native code] }
method: ShadowRoot.appendChild(<pyv8env.env.chrome.v8_html_iframe_element.HTMLIFrameElement object at 0x000001E9A0DE0820>,) -> [object HTMLIFrameElement]
ShadowRoot的作用自己去查,大概是为了样式隔离的,最终会将iframe放到body标签页面里,如果是浏览器的话就会触发iframe页面的下载了。补环境就要自己去触发了。到此第四个请求分析完毕。
0x4
触发下载上面说所的iframe页面的下载(每个iframe的上下文content和golalThis与parent页面是不一样,补环境的时候最好不要和parent页面共用一个上下文),iframe的html页面里面有两个script标签,第一个直接执行标签内的内容,生成window._cf_chl_opt字典,以及添加一个message事件,这个事件的作用是用来跨域通信的(头痛的postMessage要来了),这里主要是为了和parent页面通信,当parent页面发送的消息过来时,会触发该事件(不明白的就去补一下window.postMessage相关的知识点吧):
method: Window.addEventListener('message', function(event) {
var e = event.data;
if (e.source && e.source === 'cloudflare-challenge' && e.event === 'meow' && e.widgetId === window._cf_chl_opt.chlApiWidgetId) {
if(window['parent']){
window['parent'].postMessage({
source: 'cloudflare-challenge',
widgetId: window._cf_chl_opt.chlApiWidgetId,
event: 'food',
seq: e.seq,
}, '*');
}
}
}) -> undefined
第二个script标签要去下载下来执行。到此第五个请求分析完毕。
0x5
下载并执行上文中的iframe的script标签(https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/b/orchestrate/chl_api/v1?ray=8e1cd56e4a005c1d&lang=auto),执行完js代码会为document添加一个DOMContentLoaded:
HTMLDocument.addEventListener('DOMContentLoaded', function(){setTimeout(eZ,0)})
触发执行DOMContentLoaded事件,又会添加一个delay为0的Timeout事件,继续触发执行Timeout事件,又会为window添加一个新的message事件(用于接parent页面的消息),又又又会生成一个新的delay为0的Timeout事件,继续触发执行新的Timeout事件,这个时候就会向parent页面发送一条消息:
getter: Window.parent -> [object Window]
getter: Window.postMessage -> function postMessage() { [native code] }
method: Window.postMessage([object Object], '*') -> undefined
// 等同于下面代码
// window.parent.postMessage([object Object], '*')
实现postMessage功能,让iframe页面和parent页面一顿通信后,这个时候会触发一系列的dom操作,和简单的环境检测,然后iframe页面又又又又会生成一个新的delay为0的Timeout事件,执行Timeout事件,又又又又又会生成一个新的delay为100的Timeout事件,继续执行delay为100的Timeout事件,这个时候会触发iframe页面的第一次的XMLHttpRequest的post请求(和上文提起的xhr请求基本一样,但是这是iframe页面的所有domain不一样)。到此第六个请求分析完毕。
0x6
请求0x5中的XMLHttpRequest为post的请求,并触发执行onreadystatechange事件,这个时候会触发严格的环境检测,比如Object.getOwnPropertyNames, canvas, performance.getEntries()等等,其中有个img的检测如下:
method: HTMLDocument.fn_createElement('img',) -> [object HTMLImageElement]
getter: HTMLImageElement.addEventListener -> function addEventListener() { [native code] }
method: HTMLImageElement.fn_addEventListener('load', function cbL() {
done(element.height, element.width);
}, False) -> undefined
getter: HTMLImageElement.addEventListener -> function addEventListener() { [native code] }
method: HTMLImageElement.fn_addEventListener('error', function cbE() {
done(-1, -1);
}, False) -> undefined
setter: HTMLImageElement.src = /cdn-cgi/challenge-platform/h/b/i/8e1cd56e4a005c1d/1731480693264/eLYHelixWxxIMFU
getter: HTMLImageElement.style -> [object CSSStyleDeclaration]
setter: CSSStyleDeclaration.display = none
getter: ShadowRoot.appendChild -> function appendChild() { [native code] }
method: ShadowRoot.fn_appendChild(<pyv8env.env.chrome.v8_html_image_element.HTMLImageElement object at 0x000001E9A13333A0>,) -> [object HTMLImageElement]
需要下载并触发图片的load事件。
还有一个fetch如下:
getter: Window.fetch -> function fetch() { [native code] }
method: Window.fn_fetch('/cdn-cgi/challenge-platform/h/b/pat/8e1cd56e4a005c1d/1731480693265/7f10baf563748fe791137ce1b5a74b404ad7ff77e9e6f0aa58067196e1167813/E4je9BfVn0VVnkM', {'cache': 'no-cache', 'redirect': 'follow'}) -> [object Promise]
需要真实的去请求这个fetch响应是401。
还有一个iframe的检测,:
method: HTMLDocument.createElement('iframe',) -> [object HTMLIFrameElement]
setter: HTMLIFrameElement.height = 1
setter: HTMLIFrameElement.width = 1
setter: HTMLIFrameElement.onload = function d(){if(c)return;c=!![];var e=[];for(var f=1;f<11;f++){var g=b.contentDocument.getElementById('pr'+f);e.push(g.getClientRects())}window._cf_chl_opt.BmEeC4.removeChild(b);if(10!==e.length){YTDg0();return}FSJw6(JSON.stringify(e)).then(function(h){a.Xkqp8=h,YTDg0()})}
setter: HTMLIFrameElement.srcdoc = <html><head><style>#pr10,#pr8,#pr9{position:absolute;margin-left:15.9099rem}#pr1{border:2.715px solid green;padding:3.98px;margin-left:12.12px}#pr2{border:2px solid purple;font-size:30px;margin-top:200px;-webkit-transform:skewY(23.1753218deg);-moz-transform:skewY(23.1753218deg);-ms-transform:skewY(23.1753218deg);-o-transform:skewY(23.1753218deg);transform:skewY(23.1753218deg)}#pr3{border:2.89px solid orange;font-size:45px;transform:scale(100000000000000000000009999999999999.99,1.89);margin-top:50px}#pr4{border:2px solid silver;transform:matrix(1.11,2.0001,-1.0001,1.009,150,94.4);-webkit-transform:matrix(.95559,2.13329,-.9842,.98423,150,95);-moz-transform:matrix(.66371,1.94587,-.6987,.98423,150,103.238);-ms-transform:matrix(.5478,1.94587,-.7383,.98423,150,100.569);-o-transform:matrix(.4623,1.83523,-.6734,.81231,150,99.324);position:absolute;margin-top:11.1331px;margin-left:12.1212px;padding:4.4545px;left:239.4141px;top:178.5050px}#pr5{border:2pt solid red;margin-left:42.395pt}caption{border:2px solid #8b0000;font-size:20.99px;margin-left:20.8px}#pr6{border:2px solid #00008b;-webkit-transform:perspective(12890px) translateZ(101.5px);-moz-transform:perspective(12890px) translateZ(101.5px);-ms-transform:perspective(12890px) translateZ(101.5px);-o-transform:perspective(12890px) translateZ(101.5px);transform:perspective(12890px) translateZ(101.5px);padding:12px}#pr7{position:absolute;margin-top:-350.552px;margin-left:.9099rem;border:2px solid #deb887}#pr8{margin-top:-150.552px;border:2px solid #f4a460}#pr9{margin-top:-110.552px;border:2px solid orchid}#pr10{margin-top:-315.552px;border:2px solid #40e0d0}</style></head><div id=pr1>Ssss tttt</div><div id=pr2>TTTT tttt</div><div id=pr3>WW  ssss tttt</div><div id=pr4>vvvv sssss ttttt tttt</div><table id=pr5><caption>ttttt cccc tttt<thead><tr><th>tttt hhhh<tbody><tr><td>tttt bbbb</table><div id=pr6>ttttt pppp tttt tttt</div><div id=pr7><select><option>sss ooo</select></div><div id=pr8><details><summary>dddd ssss</summary></details></div><div id=pr9><progress max=100 value=49></progress></div><div id=pr10><button type=button></button></div></html>
getter: ShadowRoot.appendChild -> function appendChild() { [native code] }
method: ShadowRoot.appendChild(<pyv8env.env.chrome.v8_html_iframe_element.HTMLIFrameElement object at 0x000001E9A13445E0>,) -> [object HTMLIFrameElement]
getter: HTMLIFrameElement.contentDocument -> [object HTMLDocument]
getter: HTMLDocument.getElementById -> function getElementById() { [native code] }
method: HTMLDocument.getElementById('pr1',) -> [object HTMLDivElement]
getter: HTMLDivElement.getClientRects -> function getClientRects() { [native code] }
method: HTMLDivElement.getClientRects() -> [object DOMRectList]
getter: HTMLIFrameElement.contentDocument -> [object HTMLDocument]
getter: HTMLDocument.getElementById -> function getElementById() { [native code] }
method: HTMLDocument.getElementById('pr2',) -> [object HTMLDivElement]
getter: HTMLDivElement.getClientRects -> function getClientRects() { [native code] }
method: HTMLDivElement.getClientRects() -> [object DOMRectList]
getter: HTMLIFrameElement.contentDocument -> [object HTMLDocument]
getter: HTMLDocument.getElementById -> function getElementById() { [native code] }
method: HTMLDocument.getElementById('pr3',) -> [object HTMLDivElement]
getter: HTMLDivElement.getClientRects -> function getClientRects() { [native code] }
method: HTMLDivElement.getClientRects() -> [object DOMRectList]
getter: HTMLIFrameElement.contentDocument -> [object HTMLDocument]
getter: HTMLDocument.getElementById -> function getElementById() { [native code] }
method: HTMLDocument.getElementById('pr4',) -> [object HTMLDivElement]
getter: HTMLDivElement.getClientRects -> function getClientRects() { [native code] }
method: HTMLDivElement.getClientRects() -> [object DOMRectList]
getter: HTMLIFrameElement.contentDocument -> [object HTMLDocument]
getter: HTMLDocument.getElementById -> function getElementById() { [native code] }
method: HTMLDocument.getElementById('pr5',) -> [object HTMLUnknownElement]
getter: HTMLUnknownElement.getClientRects -> function getClientRects() { [native code] }
method: HTMLUnknownElement.getClientRects() -> [object DOMRectList]
getter: HTMLIFrameElement.contentDocument -> [object HTMLDocument]
getter: HTMLDocument.getElementById -> function getElementById() { [native code] }
method: HTMLDocument.getElementById('pr6',) -> [object HTMLDivElement]
getter: HTMLDivElement.getClientRects -> function getClientRects() { [native code] }
method: HTMLDivElement.getClientRects() -> [object DOMRectList]
getter: HTMLIFrameElement.contentDocument -> [object HTMLDocument]
getter: HTMLDocument.getElementById -> function getElementById() { [native code] }
method: HTMLDocument.getElementById('pr7',) -> [object HTMLDivElement]
getter: HTMLDivElement.getClientRects -> function getClientRects() { [native code] }
method: HTMLDivElement.getClientRects() -> [object DOMRectList]
getter: HTMLIFrameElement.contentDocument -> [object HTMLDocument]
getter: HTMLDocument.getElementById -> function getElementById() { [native code] }
method: HTMLDocument.getElementById('pr8',) -> [object HTMLDivElement]
getter: HTMLDivElement.getClientRects -> function getClientRects() { [native code] }
method: HTMLDivElement.getClientRects() -> [object DOMRectList]
getter: HTMLIFrameElement.contentDocument -> [object HTMLDocument]
getter: HTMLDocument.getElementById -> function getElementById() { [native code] }
method: HTMLDocument.getElementById('pr9',) -> [object HTMLDivElement]
getter: HTMLDivElement.getClientRects -> function getClientRects() { [native code] }
method: HTMLDivElement.getClientRects() -> [object DOMRectList]
getter: HTMLIFrameElement.contentDocument -> [object HTMLDocument]
getter: HTMLDocument.getElementById -> function getElementById() { [native code] }
method: HTMLDocument.getElementById('pr10',) -> [object HTMLDivElement]
getter: HTMLDivElement.getClientRects -> function getClientRects() { [native code] }
method: HTMLDivElement.getClientRects() -> [object DOMRectList]
getter: ShadowRoot.removeChild -> function removeChild() { [native code] }
method: ShadowRoot.removeChild(<pyv8env.env.chrome.v8_html_iframe_element.HTMLIFrameElement object at 0x000001E9A13445E0>,) -> [object HTMLIFrameElement]
getter: Window.FSJw6 -> function(c,jP,e){e=(jP=gL,{'KPUrU':function(g){return g()},'OqyNr':function(g,h){return g(h)},'pebtL':jP(416),'heDVZ':function(g,h){return g(h)}});try{return e[jP(1053)](gJ,c)}catch(g){return jP(197)!==e[jP(1166)]?e[jP(995)](gH,gI(c)):(c(),e[jP(293)](g),e[jP(293)](h),!![])}}
getter: Window.JSON -> [object JSON]
getter: DOMRectList.0 -> [object DOMRect]
method: DOMRect.toJSON('0',) -> {'x': 20.109375, 'y': 8, 'width': 11.9375, 'height': 53.9375, 'top': 8, 'right': 32.046875, 'bottom': 61.9375, 'left': 20.109375}
getter: DOMRectList.0 -> [object DOMRect]
method: DOMRect.toJSON('0',) -> {'x': 8, 'y': 261.081298828125, 'width': 4, 'height': 85.71237182617188, 'top': 261.081298828125, 'right': 12, 'bottom': 346.7936706542969, 'left': 8}
getter: DOMRectList.0 -> [object DOMRect]
method: DOMRect.toJSON('0',) -> {'x': -3.4028232737618185e+32, 'y': 314.0574951171875, 'width': 6.805646547523637e+32, 'height': 347.760009765625, 'top': 314.0574951171875, 'right': 3.4028232737618185e+32, 'bottom': 661.8175048828125, 'left': -3.4028232737618185e+32}
getter: DOMRectList.0 -> [object DOMRect]
method: DOMRect.toJSON('0',) -> {'x': 354.9369201660156, 'y': 232.12351989746094, 'width': 143.09490966796875, 'height': 201.90919494628906, 'top': 232.12351989746094, 'right': 498.0318298339844, 'bottom': 434.03271484375, 'left': 354.9369201660156}
getter: DOMRectList.0 -> [object DOMRect]
method: DOMRect.toJSON('0',) -> {'x': 64.515625, 'y': 579.9375, 'width': 66.90625, 'height': 183, 'top': 579.9375, 'right': 131.421875, 'bottom': 762.9375, 'left': 64.515625}
getter: DOMRectList.0 -> [object DOMRect]
method: DOMRect.toJSON('0',) -> {'x': 7.888884544372559, 'y': 762.4930419921875, 'width': 28.22222900390625, 'height': 112.888916015625, 'top': 762.4930419921875, 'right': 36.11111354827881, 'bottom': 875.3819580078125, 'left': 7.888884544372559}
getter: DOMRectList.0 -> [object DOMRect]
method: DOMRect.toJSON('0',) -> {'x': 22.546875, 'y': 524.390625, 'width': 74, 'height': 26, 'top': 524.390625, 'right': 96.546875, 'bottom': 550.390625, 'left': 22.546875}
getter: DOMRectList.0 -> [object DOMRect]
method: DOMRect.toJSON('0',) -> {'x': 262.546875, 'y': 724.390625, 'width': 44.9375, 'height': 67, 'top': 724.390625, 'right': 307.484375, 'bottom': 791.390625, 'left': 262.546875}
getter: DOMRectList.0 -> [object DOMRect]
method: DOMRect.toJSON('0',) -> {'x': 262.546875, 'y': 764.390625, 'width': 164, 'height': 25, 'top': 764.390625, 'right': 426.546875, 'bottom': 789.390625, 'left': 262.546875}
getter: DOMRectList.0 -> [object DOMRect]
method: DOMRect.toJSON('0',) -> {'x': 262.546875, 'y': 559.390625, 'width': 20, 'height': 25, 'top': 559.390625, 'right': 282.546875, 'bottom': 584.390625, 'left': 262.546875}
getter: Window.TextEncoder -> function TextEncoder() { [native code] }
construct: new TextEncoder() -> undefined
getter: TextEncoder.encode -> function encode() { [native code] }
method: TextEncoder.encode('[{"0":{"x":20.109375,"y":8,"width":11.9375,"height":53.9375,"top":8,"right":32.046875,"bottom":61.9375,"left":20.109375}},{"0":{"x":8,"y":261.081298828125,"width":4,"height":85.71237182617188,"top":261.081298828125,"right":12,"bottom":346.7936706542969,"left":8}},{"0":{"x":-3.4028232737618185e+32,"y":314.0574951171875,"width":6.805646547523637e+32,"height":347.760009765625,"top":314.0574951171875,"right":3.4028232737618185e+32,"bottom":661.8175048828125,"left":-3.4028232737618185e+32}},{"0":{"x":354.9369201660156,"y":232.12351989746094,"width":143.09490966796875,"height":201.90919494628906,"top":232.12351989746094,"right":498.0318298339844,"bottom":434.03271484375,"left":354.9369201660156}},{"0":{"x":64.515625,"y":579.9375,"width":66.90625,"height":183,"top":579.9375,"right":131.421875,"bottom":762.9375,"left":64.515625}},{"0":{"x":7.888884544372559,"y":762.4930419921875,"width":28.22222900390625,"height":112.888916015625,"top":762.4930419921875,"right":36.11111354827881,"bottom":875.3819580078125,"left":7.888884544372559}},{"0":{"x":22.546875,"y":524.390625,"width":74,"height":26,"top":524.390625,"right":96.546875,"bottom":550.390625,"left":22.546875}},{"0":{"x":262.546875,"y":724.390625,"width":44.9375,"height":67,"top":724.390625,"right":307.484375,"bottom":791.390625,"left":262.546875}},{"0":{"x":262.546875,"y":764.390625,"width":164,"height":25,"top":764.390625,"right":426.546875,"bottom":789.390625,"left":262.546875}},{"0":{"x":262.546875,"y":559.390625,"width":20,"height":25,"top":559.390625,"right":282.546875,"bottom":584.390625,"left":262.546875}}]',) -> Uint8Array[91,...]
getter: Window.crypto -> [object Crypto]
getter: Crypto.subtle -> [object SubtleCrypto]
getter: SubtleCrypto.digest -> function digest() { [native code] }
method: SubtleCrypto.digest('SHA-256', Uint8Array[91,...]) -> [object Promise]
检测标签的getClientRects的渲染值吧并将结果sha256哈希一下,并且添加了一个onload事件。
为什么要单独拎出来这三个检测呢,后面再说。到此第七个请求分析完毕。
0x7
发送 0x6中的fetch请求,补环境的时候让其自动发送和触发,注意构建返回Promise中的Response的status属性为401,ok属性为false。并让v8去自动触发。到此第八个请求分析完毕。
0x8
下载 0x6中的img,下载完成后获取图片的宽高,并设置回img标签的宽高属性。获取图片宽高的python代码我用的是这个:
from PIL import Image
import io
width, height = Image.open(io.BytesIO(res.content)).size
然后触发其load事件。
到此第九个请求分析完毕。
0x9
如何触发iframe页面的第二次xhr为post的请求,将上述环境检测的结果回传给服务器校验呢?就是0x7中提到的img的load和iframe的onload。这两个事件可能是互相嵌套的,怎么说呢,img的load事件里会触发iframe的校验,或者是iframe的onload里触发img校验。两个事件互相触发完毕后会触发iframe页面的第二次XMLHttpRequest为post的请求(和上文提起的xhr请求基本一样)。并触发执行onreadystatechange事件,如果校验通过则会出现下面两个情况:
- 需要点击,这个时候会生成一个
input标签,并为这个标签生成一个点击事件。模拟点击一下触发事件即可。 - 不需要点击,会通过
postMessage和parent页面进行交互,一顿交互之后,parent页面会生成一个xhr请求。
到此第十个请求分析完毕。
0x10
继续分析0x9中需要点击的情况。下面是生成input标签相关的hook日志:
method: HTMLDocument.createElement('input',) -> [object HTMLInputElement]
setter: HTMLInputElement.type = checkbox
getter: HTMLUnknownElement.appendChild -> function appendChild() { [native code] }
method: HTMLUnknownElement.appendChild(<pyv8env.env.chrome.v8_html_input_element.HTMLInputElement object at 0x0000019384FDF3A0>,) -> [object HTMLInputElement]
getter: HTMLDocument.createElement -> function createElement() { [native code] }
method: HTMLDocument.createElement('span',) -> [object HTMLSpanElement]
setter: HTMLSpanElement.className = cb-i
getter: HTMLUnknownElement.appendChild -> function appendChild() { [native code] }
method: HTMLUnknownElement.appendChild(<pyv8env.env.chrome.v8_html_span_element.HTMLSpanElement object at 0x0000019384F99D30>,) -> [object HTMLSpanElement]
getter: HTMLDocument.createElement -> function createElement() { [native code] }
method: HTMLDocument.createElement('span',) -> [object HTMLSpanElement]
setter: HTMLSpanElement.innerHTML = 确认您是真人
setter: HTMLSpanElement.className = cb-lb-t
getter: HTMLUnknownElement.appendChild -> function appendChild() { [native code] }
method: HTMLUnknownElement.appendChild(<pyv8env.env.chrome.v8_html_span_element.HTMLSpanElement object at 0x0000019384F99D90>,) -> [object HTMLSpanElement]
getter: HTMLDivElement.appendChild -> function appendChild() { [native code] }
method: HTMLDivElement.appendChild(<pyv8env.env.chrome.v8_html_unknown_element.HTMLUnknownElement object at 0x0000019384FDF130>,) -> [object HTMLUnknownElement]
getter: ShadowRoot.querySelector -> function querySelector() { [native code] }
method: ShadowRoot.querySelector('#kGtPC2',) -> [object HTMLDivElement]
getter: HTMLDivElement.appendChild -> function appendChild() { [native code] }
method: HTMLDivElement.appendChild(<pyv8env.env.chrome.v8_html_div_element.HTMLDivElement object at 0x0000019384FD7EE0>,) -> [object HTMLDivElement]
getter: HTMLInputElement.click -> function click() { [native code] }
setter: HTMLInputElement.click = function() {
clickTrap = true;
setTimeout(function() {
origClick.call(handle);
}, 2000 * Math.random());
}
getter: HTMLInputElement.click -> function click() { [native code] }
getter: HTMLInputElement.click -> function click() { [native code] }
getter: HTMLInputElement.addEventListener -> function addEventListener() { [native code] }
method: HTMLInputElement.addEventListener('click', function(e) {
var eventData = {};
eventData['activeElement'] = String(document.activeElement);
eventData['clientX'] = String(e['clientX']);
eventData['clientY'] = String(e['clientY']);
eventData['height'] = String(e['height']);
eventData['isPrimary'] = String(e['isPrimary']);
eventData['isTrusted'] = String(e['isTrusted']);
eventData['layerX'] = String(e['layerX']);
eventData['layerY'] = String(e['layerY']);
eventData['movementX'] = String(e['movementX']);
eventData['movementY'] = String(e['movementY']);
eventData['offsetX'] = String(e['offsetX']);
eventData['offsetY'] = String(e['offsetY']);
eventData['pageX'] = String(e['pageX']);
eventData['pageY'] = String(e['pageY']);
eventData['pointerId'] = String(e['pointerId']);
eventData['pointerType'] = String(e['pointerType']);
eventData['pressure'] = String(e['pressure']);
eventData['relatedTarget'] = String(e['relatedTarget']);
eventData['screenX'] = String(e['screenX']);
eventData['screenY'] = String(e['screenY']);
eventData['srcElement'] = String(e['srcElement']);
eventData['tangentialPressure'] = String(e['tangentialPressure']);
eventData['target'] = String(e['target']);
eventData['timeStamp'] = String(e['timeStamp']);
eventData['type'] = String(e['type']);
eventData['width'] = String(e['width']);
eventData['x'] = String(e['x']);
eventData['y'] = String(e['y']);
handle.disabled = true;
handle.setAttribute('aria-checked', 'true');
var cdp = (function() {
var dtoef = 'bPlE';
var errorObject = new Error();
Object.defineProperty(errorObject, 'stack', {
get: function () {
dtoef = 'GftA';
return '';
},
configurable: false,
enumerable: false
});
/* eslint-disable-next-line no-console */
console.debug(errorObject);
return dtoef;
})();
;
chl_ret.avXEY0 = _cf_chl_ctx.hOTh2([ eventData, new Error().stack, cdp, clickTrap, ]);
window.CKFVO1.mwNXs8();
setTimeout(after_clicked, 250);
}) -> undefined
模拟触发点击该click事件,将会生成一个delay为250的Timeout事件,执行该Timeout事件,将会触发iframe页面的第三次xhr为post的请求。向前面一样继续发送xhr请求,并触发执行xhr的onreadystatechange事件,然后就会回到0x9中不需要点击的情况。
到此第十一个请求分析完毕。
0x11
继续分析0x9中不需要点击的情况。通过postMessage和parent页面进行交互,一顿交互之后
,parent页面会生成地二次xhr为post的请求。向前面一样继续发送xhr请求,并触发执行xhr的onreadystatechange事件,这个时候会创建form标签和input标签:
method: HTMLDocument.createElement('form',) -> [object HTMLFormElement]
getter: HTMLFormElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLFormElement.setAttribute('action', '/?__cf_chl_f_tk=sxbg3pFZWNiHeXG_SDaYs.H2Saf1sgII0bpKJQmdkkc-1731495606-1.0.1.1-J8AAAB5zf1KGYSnpyTrZ3P9n3VTOS_qoJK1S0sIFqs8') -> undefined
getter: HTMLFormElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLFormElement.setAttribute('method', 'POST') -> undefined
getter: HTMLFormElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLFormElement.setAttribute('enctype', 'application/x-www-form-urlencoded') -> undefined
getter: Window.document -> [object HTMLDocument]
getter: HTMLDocument.createElement -> function createElement() { [native code] }
method: HTMLDocument.createElement('input',) -> [object HTMLInputElement]
getter: HTMLInputElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLInputElement.setAttribute('type', 'hidden') -> undefined
getter: HTMLInputElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLInputElement.setAttribute('name', 'b4bc64b405e238b0977055e6ef046a2157173f7cb8eaa8060e68e63a9317685c') -> undefined
getter: HTMLInputElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLInputElement.setAttribute('value', 'q2QEKyKyiE6Ku6OHc7jfjAFmFB_CYMCancbxmC_diZQ-1731495606-1.2.1.1-SlA2lZExRhX20DdL5RFiYlsJqIEKjsvjNAkRgFWGAHJkId5RMaajLe33M9Sj.ltIwX2_2GPLOm7jWum2Ri7y0DlSkmCA1do3BKeiqDPtWvongd5SI0K_brUh6MwVCLsIz1qD8vBPdpp1GZmAAEp3Q6MGfOYezz0b_6O6g.QU5m58GRNkSf8K23GTd9ynylREA_boLnfXosc77fNZktkJQVSyylAwp_ZafD5Ivn.kU7T4Ijla4hYYpXKwoXgwDaIpzvZowoCydhrhH.jJeHACcIde7nc.g9N7oVsjvydMGMxBANKIO2V.M83.YFphnrmlL9xrCAzd5XtmGjnnUmhMtIly8ze4C73q3T7MYtGawrex5stcYtKLLgsGExy79DSVAEmGq.3aRlgcmtfdtdtA1VrEJhcJsMr6t7pQB2Wo6kh1V2PsAN08Nd6Q9K.GNbyXXdX1k_5O4i.CB.f.1AA1QBYkEJ4txMa9xwm4k9VhjEJD4lHojlZAQZGdrgz1FTVXN9Qi4mSZn0eGsEDWQdoZD2NWLzL_1.F6UROCzbPjObqr3aTbuvFqB0GndBSXRLI5qYC29_STK1S2PM0GuwnU95cBDcI1JsGQEzcRYih_DiB8fzSP2XA.b.iQhQY6A640Uc2ZOLJwIZPmIWvg.hJjoV2Eci_u_UP0e.s7rcDipbJs4k86wK4NV.58DiAKjA40dNBFQuFP3uOQ5xDZ.BK1_IExQ1MZyznxgsXRjakw358awcDfd3uYoCWR6tPJW3mNZUGffWnBKjl6ct9kMfv49puWUE9DROCEbZK1Awg4S_pYd_ybbIICpe19K3uS6bSG00dsiyacuS2Rwl5KxU9kegLYR0rENPNh7qbhZda1UIy.f56SJC_crCzRrRnehe6HvcE3Ml8TH4a.CKGqS8dFPeSq.1XIPgly4Z2BOhWMv2Tv55ICDnEVU_H_RpC3nf5zE27Mkm64.t1rmia6nfhUuu6yLTIsO_IWx5f_TFYGcrETfmngvQjYWgsFxYm8GIb.G8VcHXhsV0pHsGmy70fO3SXf6M.0bAczONjs6n.3MG4cQ1nMmL8xXvu.pFUy..hNzNriJXav4vmjDmUBYdz5BSm5AZd0arxCMatdCibvaeVGzx75iBVfl3368JXQNzfsl3rYWURSUL.UGybpnKbaa.otB6jCd6zRXbM1I14y43VdzxH6yTQpDQ2NgLprAYXDU3gt01jijjPljvJPWlQXHZBtNWBge.AVeB.RnMOu8SQuoXti4AB_Mm6g4uPzBxoZ0kr_Ws3jxrWNyyTiLkKiOFu3xEfjSS.pD9pl9iK.Cf3dLfGOnXfFrPZufogGVMp08iPe_6rSELpkYF.sok0iaHZJ8ajlJdXX7htNYT.VjSPm2yIJL9VfA9RZSvZ8adyo4KrRxdCNrVp5HV9ptrSbDgoD3p0lR59S1xEn1A1D9w5EBLXci60ZWipi.DHPmsMJrqruV5TwA146mRHoogQAYxznZOKnH9.askFNi3kWrp11FS.jv20zcntqLupi_cNlpR7DsehGeq_70t4m2iA31FFHMrqsA2ntvOd.3h7laKVHY7hsLeZqYcewhWUfrjmpleMHv63aozF3y22i6nycX8N.AtTySE3R3OA7X3SC8fo4V02t8HR9lOmSg9aJf7U6n8kEqMy2iaGa6DQJMQASZq7sEK45HpcxF2egRYQTu39mLmFs6s1ACsPvbeFKgVIr6j5O9ei4mJKyL_p6pRxv11CkeyFsVUOOlV7AXc83.oSBcNk2uWENDnqUlGAPC6ebI4v.Hl.4M6HRrOOKLsysjrB33zTYXhsSRW1S00ass7cD9zHVBH68q.avQtUP9T12NXuXLmADSP2neaGKFXsSYLO2xQ64MoxFTW31HPWrpNTlj3bjZFAGl0NJRjXDLlw8drZBLEB8sIDicD4tFtRxKWsOT9Uaqti8pNmtz7hGxfrLXoW8EfNzlZRwwQGL70YMgInIZU6MIW7wAYyiRt8FSnjJl9ZUG7_NRZ0KBLqtIhY7XoP4zkrCsEc5o6o.esOl2h74VUd6uh1TZMcA.vMUGtqJeHhyOAmXXCK.RpMAkM_6oytEiBpLZ6_Hc1jboUhoZiDQQUTrYQ6b5_j5nyeK4Y_sKfhDQ.ugoUJzEtOAOCXaYs5E28i.JSJLmXCggSgbzKjntvQqtjlqAZf32E.qJ5oYByZA7bfMarxS7RjCJiJmFFDYwqYo0U_YbWqzH6m1cgMxB9bhwN2chVkQEgIyChdQywF1fYTJqL4mOZoyLSvrdUCGen20Fyf5FjnDUpac_rGMlwy6W87Vc.EM1a6jW12yScqR4Pk2F5DYuqI.olCgy.UoMFgG8a1ACsL6yVuNwF.5JpMjT0dRjhmbr.CRu5FztBEREFaEicGGVn_aSnEJ1XicWpeh6HD7vnihfkSrVrMwzQEEuXdRyGpEnojaqwBfTfSVJsoo9dDZGi0sXanSas10uTPDyiM.MtteQB4yfnmWL3SjvDFS2EsmkOyAffL7hxCkmvsXMHWSzU2gdBvvxAfdH8k3YQL5uj3YyVUV1GCgNSkipROkc7Nn5uDYZyuatmVOVNZwk0PHG14gL_WONFhFksrzx4Jdr.jqddvU7FUCBx22ZxCwtnGrDGuR0z3CxzF4iTvBj1m42B2bJfX0bDltA.SUr_hfT8PV0Lcp') -> undefined
getter: HTMLFormElement.appendChild -> function appendChild() { [native code] }
method: HTMLFormElement.appendChild(<pyv8env.env.chrome.v8_html_input_element.HTMLInputElement object at 0x0000019383A4EB50>,) -> [object HTMLInputElement]
getter: Window.document -> [object HTMLDocument]
getter: HTMLDocument.createElement -> function createElement() { [native code] }
method: HTMLDocument.createElement('input',) -> [object HTMLInputElement]
getter: HTMLInputElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLInputElement.setAttribute('type', 'hidden') -> undefined
getter: HTMLInputElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLInputElement.setAttribute('name', '95b369ebbe1e60997356b98db32240a738703bc55c917180d0c1810bf0ac4693') -> undefined
getter: HTMLInputElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLInputElement.setAttribute('value', 'EaB4WA_fT0EG9JzFFiGkjQDaq7ywYLWbsrrBAkgIOHE-1731495606-1.2.1.1-c2Li2RL6m1OwyyQ0EjZY.XUNGavyEJY1DZKXUm3ITfJcxqhodwjNxS4sil3m3y7dHY8mAyNM_zFDXVfK82eyjHYw6RlBlC9RbVCcVN0GJxwgDyrqHCnuxdLJuKw6l39IpEcz_slXrBNiCjEHElw61h2M9pbSUllydOjl0m24c5yBg8xIbjMbjPXcbShSyOWH0iYQ7xUTGzUX09yl.hbvCi9GyTE1uH3eKwsLAeko00DdvbFX9MQ1Tw_zRaJuHCSXKrY6qjcQ4htygW2kNZFGCsSDiRbV.SVOMQSU4oQhZspIx3hFBY1tnPGnpBphUbp7UoKuZwB54X6dLTqOLMzMjEoTc67qXH0S5piPonqQf95..4uVvImqvmw67HpvvUqNG8O.acQPgUNrgj9cjKKVfchWcHi.5gc6Y6oHQtRCWopQRCobpBdHemTIHuPRUhUdErp4WYPOVdGKspSuUZbig.k_wQf8NgSKG9HiMN0s0EYjOi1.RkWbsqw3kRazQhl6H3bs9xMLxmcr27Ut62F7GldyEihYB5CLeXrrlfMgq_CzOQRUQvfI7JxDL0qVNwdy32dQFYsDqG.VDQiqm01eEEc1aRSi15Wlbf4lvK97j9iGN7LqjGajMMItuitc2vLhOoH978oIciMnDJtroURrRKuO854VB_Y4y8YtZ5gXO6C0cGWVnSAOaPSsdVan3rhNCmWW_0D3JTDbPAQ6c_BOYJ1sIAbJRFkFkXpxHAB5UyILDtAiJBBbDX6iRvjXOmOblz1DwKeMFnd74TQ9pckrDTAJzvnwMOe9AZVpXb_77AwuIr.IgNzjhUDHfxzf1HGl9q0vxiV0LxcFpT1DoyRh7GiFmanzUpCm1DnAfmMd2Rg6Oxuolt_7nlqSE60vSKZ7d60o7Y82Iq2CsNNN7QYxG6y9fipfgTGKZ5frqxpejMxbiyINR6bqs91GZU0FtTrWNxzWKAwskKe77BrmuMs2YuUDmhw5NHcuDtOzkrfVjezM2S.Oq_hgabP8_masy.jO2UlHnyyDUmg2_maKxBPKMEpnSjwhfnjeOwKTpnaNONCxNINLigbonlHIo49vL2hwOgUkXeawthkL0EWdfAwDiRZrW5lzU9akhEchGg8gCl1u60RdFptvcZchmzMDU4dSLYpVOGA3YZEj8o1LgX6QwQm8LEEHJLHPPnTT8aUCjKsz_Afma9_tW_7HYdeWLg9YJfCVQHQQMbUFJvQZ_WTFCQOfILpje0lucaVSmREXj2n7jxAw0NxygMWw4SbssAgNeIJ8PBdJs20wPesFGlzyL0mOPm4GDA9iwQmnPSOULwp.lSK3rPGJgKEKsZEy5fA1Dl3Jt9UArCWFNiCA5MOhzVE10gatOAbR8qlf.f1C1TbSfnIUGdaQelELECj61B6a_TJtjIFw8JXUucXn4y9pqUuMZQUHcWuSHsrQBKgl73cZI2l6U0yUxi.GhDN0AHKJf6HiYHpDa6lRihjr5WaGc744QVBbEKT2J8UeDS248iLXKK7h5H.WYWECKIzt0VG0h9q5LrPlLEpGFlTuGBpvLOYlOoC9UcPRgq7vOi65mU8fhwB0jJeiZt1vyWMOjAthFMzZ6TH3jCc.Y49pEJsbVKLnVO7nB5G7mRb7GSVo876HiNWallouOGEuilcDXvrX4V8TuZbxQ9GSX9m4DRNOHHd6WhBgs4GvrT_RLcETejPFzxiM7NOMGIGVUd5xNWUV4xAi6VCGugOo2p6_A8tPHg_HS7U2eGXyfyWQVt4nxAawPG1VW9FtT751dH2IVGONcqlkYRdGYkpvIpJgXCXCCEjXgG8oKUur.LieqNA6f3u1pCmAem1ofBepSMlSXUJd67ZXY_MPAZJ321xduo_06.ztBO6InkJvg_2EwlrbW4sq7rb0WDYxdoySar5F6UQf87hgPbHXFLyV92Ymvy0lCYVvZMdhFlIW7XX2RFdX_xuuw8y8BTyQ0vSnrtVnpx9nZZIGjotfyA5Fda_JlZX8YBxrTkSiEeqQAIObeZgtUOHSaEiZjcvdmm16uIG76IolYi9wBL7BcoM_SziyPok1Q0g58dB5j9NH5HdadBxUJfa.2Uysj734uoPu5gZZDHs253z2Nfg4WE4uRJgw11yUGTeUaJ2hdbvjj279CfKwLoaJmgYG9BnMC3sx_p7Mh0ORfpVqoaf5RLfT7g55oFn2oHlcrL76qm8rKr548qgaUQBRUd_nEUmo_YdSP8snSfAf5fGPL6kQqmcBgofq9n5u4Y5Eq5XYCJMRj5I_Q7JWIsoMfiTfDpQ_BlIPrW5Dx16vRg_DHvWxgEZOuuENoTITKaMFOIwqaiKHNw3Q9teOFi553qEqkuissLC6XKYZqedRGthkBCdzw6o7AHdECL21Yo7FDQAh1BHxL5UqAqmEzkN.p9CuxSGHNVD7O1EJs9A5B5iQqcOh1P8zn.IgnAj.ONOBRLUAkB17HakMQF3AQ7mIyUyVtb58Yg6m9IwKQAh_0wieDYxUBzeQ6OIhyc5yn6xPGiEHTAQrqNNGiaXpU6RecEkucTzaeXpiBtXWYvZ.7gwaU.3MS16L4ladSsHx3Gb_AvPVbhu4Gj60QfAM_3v0AsGg3RiB5aYV_HfUX.eOGunRdev1lBLpMmdJFMYu3kkKttcsBEVPaRU7T8aNgtIrYE74zQB0h7044c6OJZ2m4Mr5rSQE66q90c9_mPOmDv.VTebldvBmNZDhZGlz2Q9tfhsCnrgHlYxr2I8DxOqS7Vs_1v3YJK3vbWrs4hDqstJsT.E6hiDsfRbtQQsRMCQ') -> undefined
getter: HTMLFormElement.appendChild -> function appendChild() { [native code] }
method: HTMLFormElement.appendChild(<pyv8env.env.chrome.v8_html_input_element.HTMLInputElement object at 0x0000019383A4E220>,) -> [object HTMLInputElement]
getter: Window.document -> [object HTMLDocument]
getter: HTMLDocument.createElement -> function createElement() { [native code] }
method: HTMLDocument.createElement('input',) -> [object HTMLInputElement]
getter: HTMLInputElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLInputElement.setAttribute('type', 'hidden') -> undefined
getter: HTMLInputElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLInputElement.setAttribute('name', 'cd2a2caa3e86ede0921e936bce124af04236f02774aaa659451f1813fd5b3dec') -> undefined
getter: HTMLInputElement.setAttribute -> function setAttribute() { [native code] }
method: HTMLInputElement.setAttribute('value', 'xt2DacRqHI5Zos2bOfg4v868WBGbXMuUX52bSNBPwVM-1731495632-1.1.1.1-FToe.maKf65ZgPzoC1vN2yAmTCHSmE5maaXBcvT3c4QGptIP2ADRQaME0Fktkx2CGDgc5j_X5_2ExUi1Wj_tYXuoLyv3JJVihGWLSpcp6MFa6_sNTz5rlVwpL45Kx8yKma2PstLpl2F_VXXGOBhR_vTlJLfv8O8z_BPEZsPa3gCKnM5zXDg4Vkk4x8rQYqwt') -> undefined
method: HTMLFormElement.appendChild(<pyv8env.env.chrome.v8_html_input_element.HTMLInputElement object at 0x0000019383A4E4C0>,) -> [object HTMLInputElement]
getter: HTMLBodyElement.appendChild -> function appendChild() { [native code] }
method: HTMLBodyElement.appendChild(<pyv8env.env.chrome.v8_html_form_element.HTMLFormElement object at 0x0000019384A20B20>,) -> [object HTMLFormElement]
getter: HTMLFormElement.submit -> function submit() { [native code] }
method: HTMLFormElement.submit() -> undefined
这里会触发一个form表单请求。
到此第十二个请求分析完毕。
0x11
最后模拟发送上述的表单请求。大概代码如下:
data = {
'b4bc64b405e238b0977055e6ef046a2157173f7cb8eaa8060e68e63a9317685c': 'q2QEKyKyiE6Ku6OHc7jfjAFmFB_CYMCancbxmC_diZQ-1731495606-1.2.1.1-Sl...',
'95b369ebbe1e60997356b98db32240a738703bc55c917180d0c1810bf0ac4693': 'EaB4WA_fT0EG9JzFFiGkjQDaq7ywYLWbsrrBAkgIOHE-1731495606-1.2.1.1-c2Li2RL...',
'cd2a2caa3e86ede0921e936bce124af04236f02774aaa659451f1813fd5b3dec': 'xt2DacRqHI5Zos2bOfg4v868WBGbXMuUX52bSNBPwVM-1731495632-1.1.1.1-FToe.maKf...'
}
action = '/?__cf_chl_f_tk=sxbg3pFZWNiHeXG_SDaYs.H2Saf1sgII0bpKJQmdkkc-1731495606-1.0.1.1-J8AAAB5zf1KGYSnpyTrZ3P9n3VTOS_qoJK1S0sIFqs8'
res = self.s.post(
"https://xxx.com",
data=data,
headers={
# ...
"content-type": "application/x-www-form-urlencoded",
"origin": "https://xxx.com",
# 必须带上并且要字符替换一下
"referer": f"https://xxx.com{action}".replace("__cf_chl_f_tk", "__cf_chl_tk"),
# ...
}
)
print(res.headers) # cf_clearance就在响应头的set-cookie中
到此第十三个请求分析完毕。
检测环境分析
人都麻了,下次再说吧
总结
13个请求才能拿到目标cookie,滚**的,模拟浏览器他是臭的吗?指纹浏览器他不香吗?
打赏码
如果觉得文章不错,就请我抽个华子吧!!!