|
本帖最后由 op351 于 2024-1-4 14:23 编辑
1.wireshark抓包 论坛教程很多 不再赘述
2.
在抓完包以后 我们可以尝试过滤udp流量 发现没有
没错 云南电信默认不使用组播技术 而使用单播。
好处当然是机顶盒随便插哪儿都能用啦,不管你家有几级路由,只要能联网的网口,怼上机顶盒就能看。
3.
那么我们就来看看单播是如何获取的
技术实现上使用python来编写脚本
按照惯例 我们先查找CTCGetAuthInfo方法 可以发现如下请求
- GET /yniptv/register?UserID=xxxx&Action=Login HTTP/1.1
- Host: 112.115.0.132:11888
- Accept-Encoding: deflate, gzip
- Connection: Keep-Alive
- Proxy-Connection: Keep-Alive
- Accept-Language: zh-CN,en-US;q=0.8
- User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.0 (KHTML, like Gecko)
- Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
- HTTP/1.1 200
- Server: nginx
- Date:
- Content-Type: text/html;charset=UTF-8
- Content-Length: xxx
- Connection: keep-alive
- Set-Cookie: JSESSIONID=xxxx; Path=/yniptv; HttpOnly
- <html> <head><script language='javascript'>function DoAuth(){document.authform.Authenticator.value=Authentication.CTCGetAuthInfo('xxxxxxxxx');document.authform.submit();}
复制代码 那么在yniptv/register中我们就获取到了CTCGetAuthInfo的值
对应的py代码如下
- url = "http://112.115.0.132:11888/yniptv/register?UserID=xxxxx&Action=Login"
- payload = {}
- headers = {
- 'User-Agent': 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.0 (KHTML, like Gecko)'
- }
- ctcResponse = requests.request("GET", url, headers=headers, data=payload)
- ctcResult = ctcResponse.text
- ctcmatch = re.findall("CTCGetAuthInfo\('(.*)'\)",ctcResult)
- ctc = ctcmatch[0]
复制代码 那么接下来就是加密生成Authenticator的值,机顶盒的password值获取方法和我之前的帖子江苏电信IPTV回看地址探究 (技术分析)中一样,这里不再赘述,但我推荐直接爆破。
Authenticator的生成,py代码如下
- key = "机顶盒的password值".encode("utf-8")
- text = "99999$"+ctc+"$iptv账号$机顶盒序列号$机顶盒ip地址$机顶盒MAC值$$CTC"
- crypter = DES.new(key, DES.MODE_ECB)
- Authenticator = crypter.encrypt(pkcs7_padding(text.encode("utf-8"))).hex().upper()
复制代码 Authenticator生成以后,还是/yniptv/register 但method变为post- POST /yniptv/register HTTP/1.1
- Host: 112.115.0.132:11888
- Accept-Encoding: deflate, gzip
- Cookie: JSESSIONID=xxxx
- Connection: Keep-Alive
- Proxy-Connection: Keep-Alive
- Origin: http://112.115.0.132:11888
- Accept-Language: zh-CN,en-US;q=0.8
- User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.0 (KHTML, like Gecko)
- Content-Type: application/x-www-form-urlencoded
- Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
- Referer: http://112.115.0.132:11888/yniptv/register?UserID=xxxxx&Action=Login
- Content-Length: xxx
- UserID=xxxxxxxx&Authenticator=xxxxxxxxxxxxxxxxx
复制代码 py代码实现如下
- url = "http://112.115.0.132:11888/yniptv/register"
- payload = 'UserID=xxxx&Authenticator='+Authenticator
- headers = {
- 'Origin': 'http://112.115.0.132:11888',
- 'User-Agent': 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.0 (KHTML, like Gecko)',
- 'Content-Type': 'application/x-www-form-urlencoded',
- 'Referer': 'http://112.115.0.132:11888/yniptv/register?UserID=xxxxx&Action=Login'
- }
- registerResponse = requests.request("POST", url, headers=headers, data=payload)
- registerResult = registerResponse.text
- UserTokenMatch = re.findall("'UserToken','(\d*)'", registerResult)
- UserToken = UserTokenMatch[0]
- EncryptedUserTokenMatch = re.findall("'EncryptedUserToken','((\d|[A-Z])*)'", registerResult)
- EncryptedUserToken = EncryptedUserTokenMatch[0][0]
复制代码 这一步我们剥离两个数值UserToken 和EncryptedUserToken
接下来开始鉴权,包数据如下
- GET /EpgAuth?userToken=xxxx&stbNo=xxxx&userID=xxxxx&isNew=1&encryptedUserToken=xxxxx&areaNode=pe001&refreshTimeRandom=xxxxxxHTTP/1.1
- Host: 106.57.175.22:78
- Accept: */*
- Accept-Encoding: deflate, gzip
- Connection: Keep-Alive
- Proxy-Connection: Keep-Alive
- Accept-Language: zh-CN,en-US;q=0.8
- User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.0 (KHTML, like Gecko)
- Referer: http://106.57.175.22:78/iptv/ppthdplay/scrollcpapps/index/index.html
- HTTP/1.1 200 OK
- Date:
- Content-Type: text/plain;charset=UTF-8
- Content-Length: xxx
- Connection: keep-alive
- Expires:
- Cache-Control: no-cache
- X-XSS-Protection: 1; mode=block
- Pragma: no-cache
- X-Frame-Options: DENY
- X-Content-Type-Options: nosniff
- Cache-Control: no-cache
- Cache-Control: private
- {"description":"鉴权成功","epgGroupNMB":"xxxx","mac":"xxxxx","products":"xxxx","result":"0","stbID":"xxxx","tokenExpireTime":"","userGroupNMB":"xxx","userId":"xxx"}
复制代码 这一步中我们需要剥离products参数,py代码如下
- url = "http://106.57.175.22:78/EpgAuth?userToken="+UserToken+"&stbNo=xxxx&userID=xxxxx&isNew=1&encryptedUserToken="+EncryptedUserToken+"&areaNode=pe001&refreshTimeRandom=xxxx"
- payload = {}
- headers = {
- 'User-Agent': 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.0 (KHTML, like Gecko)',
- 'Referer': 'http://106.57.175.22:78/iptv/ppthdplay/scrollcpapps/index/index.html'
- }
- authResponse = requests.request("GET", url, headers=headers, data=payload)
- authResult = authResponse.text
- authJson = json.loads(authResult)
- products = authJson['products']
复制代码 下一步为获取频道信息,包如下
- POST /Channels HTTP/1.1
- Host: 106.57.175.22:78
- Accept-Encoding: deflate, gzip
- Cookie: dataCollectCache=%5B%5D; products=xxx
- Connection: Keep-Alive
- Proxy-Connection: Keep-Alive
- Origin: http://106.57.175.22:78
- Accept-Language: zh-CN,en-US;q=0.8
- X-Requested-With: XMLHttpRequest
- User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.0 (KHTML, like Gecko)
- Content-Type: application/x-www-form-urlencoded; charset=UTF-8
- Accept: application/json, text/javascript, */*; q=0.01
- Referer: http://106.57.175.22:78/iptv/ppthdplay/scrollcpapps/index/specialSubject/PPT_BootAd/advertisePlay.html
- Content-Length: xxxx
- Expect: 100-continue
- channellistStr=xxxx
复制代码 py实现如下
- url = "http://106.57.175.22:78/Channels"
- payload = "channellistStr=xxx&userToken="+UserToken+"&userID=xxxx&isNew=1&isAntiTheftChain=false&encryptedUserToken="+EncryptedUserToken
- headers = {
- 'Cookie': 'dataCollectCache=[];products='+products,
- 'Origin': 'http://106.57.175.22:78',
- 'X-Requested-With': 'XMLHttpRequest',
- 'User-Agent': 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.0 (KHTML, like Gecko)',
- 'Referer': 'http://106.57.175.22:78/iptv/ppthdplay/scrollcpapps/index/specialSubject/PPT_BootAd/advertisePlay.html',
- 'Expect': '100-continue',
- 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
- }
- channelsInfoResponse = requests.request("POST", url, headers=headers, data=payload)
- channelsInfoResult = channelsInfoResponse.text
- channelsInfoJson = json.loads(channelsInfoResult)
- channelGroups = channelsInfoJson['channelGroups']
- channelsInfo = []
- for group in channelGroups:
- channels = group['channels']
- for channel in channels:
- channelTemp = {
- 'channelCode': channel['channelCode'],
- 'channelName': channel['channelName'],
- 'groupName': channel['groupName']
- }
- channelsInfo.append(channelTemp)
复制代码 这一步剥离了频道code,频道名和分组
接下来是获取单播的url,包如下
- POST /EPG/jsp/getChannelPlayUrl?stbNo=xxxxx&userToken=xxxx&userID=xxxx&isNew=1&encryptedUserToken=xxxxx&refreshTimeRandom=xxxxx&areaNode=pe001 HTTP/1.1
- Host: 106.57.175.22:78
- Accept-Encoding: deflate, gzip
- Cookie: dataCollectCache=%5B%5D; products=xxxx
- Connection: Keep-Alive
- Proxy-Connection: Keep-Alive
- Origin: http://106.57.175.22:78
- Accept-Language: zh-CN,en-US;q=0.8
- X-Requested-With: XMLHttpRequest
- User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.0 (KHTML, like Gecko)
- Content-Type: application/x-www-form-urlencoded; charset=UTF-8
- Accept: application/json, text/javascript, */*; q=0.01
- Referer: http://106.57.175.22:78/iptv/ppthdplay/scrollcpapps/index/specialSubject/PPT_BootAd/advertisePlay.html
- Content-Length: xxx
- Expect: 100-continue
- {"codes":
复制代码 py实现如下
- url = "http://106.57.175.22:78/EPG/jsp/getChannelPlayUrl?stbNo=xxxx&userToken="+UserToken+"&userID=xxx&isNew=1&encryptedUserToken="+EncryptedUserToken+"&
- refreshTimeRandom=xxx&areaNode=pe001"
- payload = "{"codes"xxxxxxx"<div>headers = {</div> 'Origin': 'http://106.57.175.22:78',
- 'Cookie': 'dataCollectCache=[];products='+products,
- 'X-Requested-With': 'XMLHttpRequest',
- 'User-Agent': 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.0 (KHTML, like Gecko)',
- 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
- 'Referer': 'http://106.57.175.22:78/iptv/ppthdplay/scrollcpapps/index/specialSubject/PPT_BootAd/advertisePlay.html',
- 'Expect': '100-continue'
- }
- channelUrlResponse = requests.request("POST", url, headers=headers, data=payload)
- channelUrlResult = channelUrlResponse.text
- channelUrlJson = json.loads(channelUrlResult)
- channels = channelUrlJson['contentURL']
- m3uList = []
- for channel in channels:
- channelCode = channel['code']
- channelName = ''
- channelGroup = ''
- for ch in channelsInfo:
- if ch['channelCode'] == channelCode:
- channelName = ch['channelName']
- channelGroup = ch['groupName']
- playUrl = channel['url']['playURL']
- m3uList.append({
- 'channelName': channelName,
- 'playUrl' :playUrl,
- 'channelGroup': channelGroup
- })
复制代码 在获取到播放url之后,和之前的channel基本信息组合,输出m3u数组对象
最后一步
输出m3u文件,也可按需输出txt等格式
- with open('./test.m3u', 'w', encoding="utf-8") as testm3u:
- if len(m3uList) > 0:
- testm3u.write("#EXTM3U\n")
- for item in m3uList:
- if item['channelName'] != "":
- testm3u.write("#EXTINF:-1 group-title="+'"'+item['channelGroup']+'"'+","+item['channelName']+ "\n")
- testm3u.write(item['playUrl'] + "\n")
复制代码
2024.1.4 补充
在获取usertoken的同时需要获取JSESSIONID,代码如下
- JSESSIONID = registerResponse.cookies.get("JSESSIONID")
复制代码 上文中的106.57.175.22:78为动态值,估计是负载均衡导致每次的ip都不一样
更新方法如下
- url = "http://112.115.0.132:11888/yniptv/register?Action=getchannellist"
- payload = {}
- headers = {
- 'Cookie': 'JSESSIONID='+JSESSIONID+'; UserToken='+UserToken+';',
- 'User-Agent': 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.0 (KHTML, like Gecko)',
- 'Referer': 'http://112.115.0.132:11888/yniptv/register'
- }
- response = requests.request("GET", url, headers=headers, data=payload)
- slbipmatch = re.findall('document.location="http:\/\/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}).*', response.text)
- slbip = slbipmatch[0]
复制代码 将所有106.57.175.22:78替换为剥离的slbip即可
请不要胡乱输入以及粘贴、复制等方式灌水
请尊重作者、并共同维护网站的正常阅读,否则账户将会被限制发帖、回帖,并且积分可能会被清零,站内短信以及阅读权限等都会受到影响,谢谢。
具体限制方式:https://www.right.com.cn/forum/thread-8307840-1-1.html
|
|