question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

X-Net-Sync-Term Header Fixed !!

See original GitHub issue

I would like to share the method used to capture the “X-Net-Sync-Term” header of the HTTP request. Currently the Bet365 index page does not have “boot.nsu (str1, str2)”, they have changed the way the website is displayed.

Encrypted initial token: image

Method used to capture: [Javascript]

let generate = (param) => {
	let arr;
	
	if(typeof param == 'string')
		arr = eval('[' + param.split('var a=[')[1].split('];')[0] + ']');
	else if(Array.isArray(param))
		arr = param
	else
		return false
		
	let n = arr[397];
	
	let q = arr[158] + '.' + arr[375] + arr[182] + arr[294];

	let parts = q.split('.')

	let compressed = decodeURIComponent(parts[0])
	
	let decompress = function(o) {
		o = decodeURIComponent(o);

		let s = +atob(n) * -1;
		
		s = s % 64;

		let r = '';
		
		for (var t = 0; t < o.length; t++) {
			var u = o.charCodeAt(t)
			  , v = String.fromCharCode((u + s) % 256);
			  
			r += v;
		}
		
		return r;
	}
		
	return decompress(compressed) + '.' + parts[1];
}

The parameter can be the entire HTML returned by the Bet365 website, or an array, if you choose to pass an array, the array must be the one shown in the image.

Ps: The above function will return the token (encrypted) of the page, which in this case is: idS4bd==.KavFYZJwIEwXZ1nkv6zdXI/FqYJYQiHNxQDhvhnLP1E= with this token, you will need to decode

Method used to decode or encode (encode only to explication) function:

class Bet365 {
    mapLen = 64;
    
	charMap = [["A", "d"], ["B", "e"], ["C", "f"], ["D", "g"], ["E", "h"],
        ["F", "i"], ["G", "j"], ["H", "k"], ["I", "l"], ["J", "m"], ["K", "n"], ["L", "o"],
        ["M", "p"], ["N", "q"], ["O", "r"], ["P", "s"], ["Q", "t"], ["R", "u"], ["S", "v"],
        ["T", "w"], ["U", "x"], ["V", "y"], ["W", "z"], ["X", "a"], ["Y", "b"], ["Z", "c"],
        ["a", "Q"], ["b", "R"], ["c", "S"], ["d", "T"], ["e", "U"], ["f", "V"], ["g", "W"],
        ["h", "X"], ["i", "Y"], ["j", "Z"], ["k", "A"], ["l", "B"], ["m", "C"], ["n", "D"],
        ["o", "E"], ["p", "F"], ["q", "0"], ["r", "1"], ["s", "2"], ["t", "3"], ["u", "4"],
        ["v", "5"], ["w", "6"], ["x", "7"], ["y", "8"], ["z", "9"], ["0", "G"], ["1", "H"],
        ["2", "I"], ["3", "J"], ["4", "K"], ["5", "L"], ["6", "M"], ["7", "N"], ["8", "O"],
        ["9", "P"], ["\n", ":|~"], ["\r", ""]];

    encrypt( txt ){
        let result = "";

        for( let i = 0; i < txt.length; i++ ){
			let c = txt.substr(i, 1)
			
            for( let j = 0; j < this.mapLen; j++ ){
                if( c == this.charMap[j][0] ){
                    c = this.charMap[j][1];
                    break;
                }
            }
            result += c;
        }
		
        return result;
    }

    decrypt( txt ){
        let result = "";

        for(let i = 0; i < txt.length; i++){
            let c = txt.substr(i, 1)
			
            for( let j = 0; j < this.mapLen; j++ ){
                if( ":" == c && ":|~" == substr( txt, i, 3 ) ){
                    c = "\n";
                    i+=2;
                    break;
                }
                if( c == this.charMap[j][1] ){
                    c = this.charMap[j][0];
                    break;
                }
            }
            result += c;
        }

        return result;
    }
}

let tool = new Bet365

Decrypted token: FAcuYA==.4XSpij3T2oThjrKHSwWAh2/pNi3iaF17UanESEK59ro=

Websocket: image

After sending the token in the initial request, which looks something like this: “time,S{PSTK},D{DecodedToken}”

In this example: {PSTK} = 62E1FE57F3BF449681C3E380BE1D986A000003 {DecodedToken} = FAcuYA==.4XSpij3T2oThjrKHSwWAh2/pNi3iaF17UanESEK59ro=

Importante note:

  1. Sometimes you will receive responses from the WebSocket containing the message: “_SPTBK_D” and “==.”, When you receive this, your requests should be updated to tool.decrypt (received token), example in the image above: tool.decrypt(‘RtA4bd==.qBNfyjxIInIdGMbjt/2ayaTyB8IoL8XKAzJU5uf4D6t=’)

  2. You should always preserve the characters sent on the Websocket, for this reason it is recommended that you intercept messages sent by the websocket through Base64, an example: The initial request is: atob(“IwNQAV9fdGltZSxTX1BTVEssRF9ERUNPREVEX1RPS0VOAA==”)

image

With this I have the intact and safe initial message, and only need to execute:

let initReq = atob("IwNQAV9fdGltZSxTX1BTVEssRF9ERUNPREVEX1RPS0VOAA==")

initReq = initReq.replace('PSTK', PSTK)
initReq = initReq.replace('DECODED_TOKEN', DecodedToken)

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:1
  • Comments:19

github_iconTop GitHub Comments

4reactions
incapdnscommented, Mar 1, 2021

Important: Domjs new JSDOM (‘’ ", {url: ‘https://www.bet365.com’}) is not loading Bet365, just simulating window.origin and window.referer to be www.bet365.com.

JSDOM is also not a headless browser, it is lighter than a headless browser, as it only simulates the DOM elements like “document.create” or “HTMLAnchorElement.prototype” through the 100% javascript code implementation.

Note: You can also use this code without NodeJS directly in the browser when creating a page like “test.html” and using the “<script>” located in Pastebin

1reaction
incapdnscommented, Mar 1, 2021

Put the code (pastebin) in file “code.js”, and use this in NodeJS:

const jsdom = require("jsdom")
const { JSDOM } = jsdom

const code = fs.readFileSync('./code.js').toString()

let dom =  new JSDOM('', { 
	pretendToBeVisual: false, 
	runScripts: "outside-only",
	url: "https://www.bet365.com/",
	referrer: "https://www.bet365.com/",
})
dom.window.eval(code)
dom.window.generate(bet365).then(console.log)

Note: You don’t need to recreate the “dom” instance to reuse the “generate” function, just use it normally, if you need to extract the token from several Bet365 (example: Several F5 tokens), just call the function:

window.window.generate(Bet365HTML).then(token => {
    console.log ('The token is:', token)
})

The generating time is quite short, around 1 ~ 5 milliseconds *(ms)

Read more comments on GitHub >

github_iconTop Results From Across the Web

position fixed header in html - Stack Overflow
I need to place the container div right below the header. As the header height is dynamic, I can't use the fixed value...
Read more >
How To Create a Fixed Header - Duda Blog
A fixed header (also known as a sticky header) is a smart navigation tool that causes the header of a website to remain...
Read more >
Fixed Headers, On-Page Links, and Overlapping Content, Oh ...
Let's take a basic on-page link: <a href="#section-two">Section Two</a>. When clicked, the browser will scroll itself to the element with ...
Read more >
How to Enable FIxed & Sticky Header with Kicker WordPress ...
In this video you will learn how you can easily enable fixed sticky headers with Kicker WordPress Theme. You can do this for...
Read more >
CSS Fixed Headers - YouTube
This is a small tutorial on how to modify your css headers to allow them to be fixed. Fixed headers allows you to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found