史高治

新随笔 联系 管理

EgのExcelHome上传附件:

类MultipartEncoder:
 
2参boundary的-及字母数字的数量同Content-Type的bdr,而postData中各键首行的boundary则在开头补了俩-:其__init__内有句self.boundary = '--{0}'.format(self.boundary_value)。
postData中各键值对的结构:--boundary行、……key行、[文件流独有的Content-Type行]、空行、value行。列完各键值对,postData最后以--boundary--行结尾。
 
默认方法.to_string(),能如F12界面所示的postData那样显示。上传的文件名不能有中文,如F12下看到的是filename="测.rar",mpe却会给处理为filename*=utf-8''%E6%B5%8B.rar而上传失败,故而要么文件名无中文,要么m.to_string()后再作替换。
*********************分割线*********************
import os,random,string,requests
from fake_useragent import UserAgent as ua
from requests_toolbelt import MultipartEncoder
from tkinter.filedialog import askopenfilenames as ofn
 
def data参数法(fileData):
    postData={'uid':uid,'hash':hash,'Filedata':fileData}
    boundary='-'*10+''.join(random.choices(string.ascii_letters+string.digits,k=30))
    m=MultipartEncoder(postData,boundary)
    headers['Content-Type']=m.content_type
    print(requests.post(url,m,headers=headers).text)
 
def files参数法(fileData):
    #files参数的模式{k:(fileName,v,对应的Content-Type),},若v非文件流则(*)的首尾可为空
    #files={'uid':(None,uid),'hash':(None,hash),'Filedata':fileData}
    #r=requests.post(url,files=files,headers=headers)
    r=requests.post(url,{'uid':uid,'hash':hash},files={'Filedata':fileData},headers=headers)
    print(r.text)
 
if __name__ == '__main__':
    url='http://club.excelhome.net/misc.php?mod=swfupload&fid=2&action=swfupload&operation=upload'
    headers={'User-Agent':ua().random}
    uid='24810??'   #本例postData中的uid,hash,Filedata为必需键;??为我的学号-1
    hash='8dfae1d86bfc714ec489e6518094d2b2'
    filesName=ofn(initialdir=os.path.dirname(__file__),title='选择上传的各文件,路径不能有中文')
    for fileName in filesName:
        with open(fileName,'rb') as f:
            fileData=(os.path.basename(fileName),f)  #末项'application/octet-stream'等CT的值可不写
            #data参数法(fileData)
            files参数法(fileData)
 
出现7位数字为成功,到论坛如下的发帖界面,可看到"未使用的附件"的提示:
http://club.excelhome.net/forum.php?mod=post&action=newthread&fid=2。
****************************************分割线****************************************
Egの登录知呼:
 
import requests,time,execjs,json,random,string
from parsel import Selector
from requests_toolbelt import MultipartEncoder
 
def getData(username,password,captcha=''):
    client_id='c3cef7c66a1843f8b3a9e6a1e3160e20'
    timestamp=int(time.time()*1000)
    with open('D:/signature.js','r',encoding='utf8') as f:
        text=f.read()
    signature=execjs.compile(text).call('run',client_id,timestamp)
    data={'username':username,'password':password,'captcha':captcha,
          'client_id':client_id,'grant_type':'password','timestamp':str(timestamp),
        'source':'com.zhihu.web','signature':signature}
    return data
 
def getHeaders():
    headers=originalHeaders
    response=Selector(s.get(indexUrl,headers=headers).text)
    jsons=response.css('div#data::attr(data-state)').extract_first()
    jsons=json.loads(jsons)['token']
    xudid,xsrf=jsons['xUDID'],jsons['xsrf']
    headers.update({'x-udid':xudid,'x-xsrftoken':xsrf,
        'Referer':indexUrl+'signup?next=%2F',
        'authorization':'oauth c3cef7c66a1843f8b3a9e6a1e3160e20'})
    return headers
 
def checkCaptcha(headers,cn=True):
    captchaUrl=indexUrl+'api/v3/oauth/captcha?lang='+('cn' if cn else 'en')
    headers.pop('x-xsrftoken')
    s.get(captchaUrl,headers=headers)
 
def login(username,password):
    headers=getHeaders()
    checkCaptcha(headers)   #无论拦路虎是否跳出,中途路过都得打个招呼
    postData=getData(username,password)
    boundary='-'*27+''.join(random.choices(string.digits,k=11))
    m=MultipartEncoder(postData,boundary)
    headers['Content-Type']=m.content_type
    s.post(indexUrl+'api/v3/oauth/sign_in',m,headers=headers)
    s.headers=originalHeaders
    response=s.get(indexUrl+'settings/profile').text
    print(response)
    if '个性域名'in response:
        print(response,'登录成功',sep='\n\n')
 
if __name__=='__main__':
    s=requests.Session()
    indexUrl='https://www.zhihu.com/'
    originalHeaders={'User-Agent':'Mozilla/5.0 Firefox/57.0 Chrome/64.0'}
    username='+86'+'手机号'
    password='密码'
    login(username,password)
*********************分割线*********************
D:/signature.js:
 
………………截取自js文件的a函数及在同一个父函数块下的众兄弟函数………………
 
function run(client_id,timestamp) {
    r = new a("SHA-1", "TEXT");
    r.setHMACKey("d1b964811afb40118a12068ff74a12f4", "TEXT");
    r.update('password');  //grantType:e,postData中已知grantType为'password'
    r.update(client_id);  //clientId:i.a,i.a同样讨巧取自postData的clientId,不再在js摸索
    r.update("com.zhihu.web");
    r.update(String(timestamp));
    return r.getHMAC("HEX")
}
 
js解析历程:
 
①:定位到postData参数signature的出处:function r(e,t){var n=Date.now(),r=new a.a("SHA-1","TEXT");return r.setHMACKey("d1b964811afb40118a12068ff74a12f4","TEXT"),r.update(e),r.update(i.a),r.update("com.zhihu.web"),r.update(String(n)),s({clientId:i.a,grantType:e,timestamp:n,source:"com.zhihu.web",signature:r.getHMAC("HEX")},t)}。 
 
②:测试发现末行的s({k:v,},t)并没对各键值对再做加工,可忽略s(*),然后改装为上文的run函数。形参t没被r引用故不管它,e没精力探索了,因其又是s({})的grantType的value,而比较几次抓包所得的401验证Session的postData,发现grantType是固定的,clientId也是,于是就取巧把它俩各自对应的e、i.a直接给出,用于r.update(*)。
 
③:r来自函数名a,并且用到了a的3个子函数setHMACKey、update、getHMAC。用便搜的EditPlus打开js文件:任搜个子函数,如搜function getHMAC或getHMAC=function或{key:"getHMAC",value:function(){。光标定位至此,再搜上一个function a或a=function或{key:"a",value:function(){,这样就找到a的开头,上文的js可不理了。把a函数头至js文件尾格式化下,格式化后光标移至文首搜^},即第1个出现在行首的},就是a函数的结尾。
 
④:把a的函数块及改装的run函数块贴到Console回车,最后执行run('hello',666),然而报错缺参数。看来只有a的函数块不行,于是范围先扩大为a的父函数块。本例a的上1行恰好就是其父的function头故不必搜头了,取父头至js文件尾再格式化,然后搜^},得a父的function块。取出父(*){…}的…函数正文,删除最后几句不明所以且惹错的void 0 !==(){…}.call()…,末尾的var那几行没用到也可不要,然后和run的function块、run('hello',666)先后在Console回车,出结果了。
posted on 2017-10-19 17:47  史高治  阅读(376)  评论(0编辑  收藏  举报