以摘要认证(Digest Authentication)方式伪登录某摄像头

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/spenghui/article/details/79028427

本文部分摘自ASP.NET Web API(三):安全验证之使用摘要认证(digest authentication)

密码已知。
分析发现,该摄像头Web登录采用了Digest Authentication的方式。流程如下:
这里写图片描述
下面大致看一下这部分的验证流程:
1. 客户端请求 /api/employees;
2. 服务端返回401未验证的状态,并且在返回的信息中包含了验证方式Digest,realm的值,QOP(quality of protection)只设置成auth,nonce为一串随机值,在下面的请求中会一直使用到,当过了存活期后服务端将刷新生成一个新的nonce值;
3. 客户端接受到请求返回后,将username:realm:password进行HASH运算,假设运算后的值为HA1。又将请求方法和请求的路径/api/employees进行HASH运算,假设运算后的值为HA2。再将HA1:nonce:nc:cnonce:qop:HA2进行HASH运算,得到的值放在response中。这里的cnonce为客户端生成的nonce值,而nc用于统计,假设开始时为00000001,下次请求后就变成了00000002,不一定每次都加1,但是后面请求中的nc值肯定大于前一次请求中的nc值。
4. 服务端收到请求后将验证nonce是否过期,如果过期,那么直接返回401,即第二步的状态。如果没有过期,那么比较nc值,如果比前一次nc值小或者前一次根本没有存储的nc值,那么也将直接返回401状态。如果前面的验证都通过,那么服务端也将按照步骤3中计算最终HASH值的步骤计算出HASH值与客户端的进行比较,然后比较客户端提交过来的HASH值与服务端计算出来的HASH进行比较,不匹配返回401,匹配获取请求的数据并返回状态200。

总结一下:

HA1=MD5(username:realm:password)
HA2=MD5(method:digestURI)
response=MD5(HA1:nonce:nc:cnonce:qop:HA2)

注意:不是所有的摘要认证方式都按上述进行计算,具体可阅读Digest access authentication

伪登录代码:

#!/usr/bin/python

import hashlib
import httplib
import re

ip="the camera 's ip"
port="the camera 's port"
username="your username"
pwd="your password"

conn = httplib.HTTPConnection(ip, port,timeout=10)

# step 1: get nonce from 401 unauthorized response sent by the server
conn.connect()
headers={
"Host": ip+":"+port,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
"Accept-Encoding": "gzip, deflate",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1"
}
conn.request("GET", "http://"+ip+":"+port+"/", "",headers)
res = conn.getresponse().getheader('WWW-Authenticate')
conn.close()
nonce =re.findall(r'nonce="(.*?)"',res)[0]
realm=re.findall(r'realm="(.*?)"',res)[0]
qop=re.findall(r'qop="(.*?)"',res)[0]
opaque=re.findall(r'opaque="(.*?)"',res)[0]

print "login successfully..."

# step 2: GET http://ip:port/upgrade.htm
urI="/upgrade.htm"
method="GET"
nc="00000001"
cnonce="12234dce7db449b5"
# cal HA1
m = hashlib.md5()
m.update(username+":"+realm+":"+pwd)
HA1 = m.hexdigest()
# cal HA2
m = hashlib.md5()
m.update(method+":"+urI)
HA2 = m.hexdigest()
# cal client response
m = hashlib.md5()
m.update(HA1+":"+nonce+":"+nc+":"+cnonce+":"+qop+":"+HA2)
response= m.hexdigest()
# GET http://ip:port/upgrade.htm
headers={
"Host": ip+":"+port,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
"Accept-Encoding": "gzip, deflate",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
"Authorization": 'Digest username="'+username+'", realm="'+realm+'", nonce="'+nonce+'", uri="'+urI+'", algorithm=MD5, response="'+response+'", opaque="'+opaque+'", qop='+qop+', nc='+nc+', cnonce="'+cnonce+'"'
}
conn.connect()
conn.request(method, "http://"+ip+":"+port+urI, "", headers)
res = conn.getresponse()
print res.read()
conn.close()
展开阅读全文

没有更多推荐了,返回首页