-
-
Plaid CTF 2016 – Tonnerre解题思路
-
发表于: 2016-4-23 20:01 1587
-
新闻链接:http://www.freebuf.com/articles/web/102285.html
新闻时间:2016-04-23
新闻正文:
描述
首先我们确信搭载tonnerre.pwning.xxx:8560的服务器是完全安全的,后面我们可以访问该网站。怎么搞呢?
我们有了一个大胆的想法….他们会不会将用户数据和网页内容存储在同一个数据库呢?
细节
分值: 200
分类: 加密
验证: 119
解决方案
这个Web登录表单存在一个简单的SQL注入,运行sqlmap就可以直接获取tonnerre数据库中的users表单:只有一个用户get_flag 以及两个值:
salt, 一个随机的127字节字符串
verifier, 一个随机的145字节字符串
web.png
creds.png
这两个值都使用到基于公钥的认证协议,远程协议类似于SRP(安全远程密码协议),其服务端是由Python实现的。
下面包含我们注释的代码就是其中一部分有趣的地方:
N = ... # a 1024-bit prime number, the group modulus
g = ... # a 671-bit number, a group generator
...
# generates a key pair
random_server = random.randint(2, N-3)
public_server = pow(g, random_server, N)
# mask the public key with the verifier
residue = (public_server + permitted_users[username][1]) % N
# send salt and masked pubkey
req.sendall(tostr(permitted_users[username][0]) + '\n')
req.sendall(tostr(residue) + '\n')
# compute the session key,
# masking the client pubkey with the verifier
# raising to the server's secret exponent
# hashign the whole thing using SHA-256
session_secret = (public_client * permitted_users[username][1]) % N
session_secret = pow(session_secret, random_server, N)
session_key = H(tostr(session_secret))
# receive a proof from the client..
proof = req.recv(512).strip('\n')
# ..should be a hash of the server's masked pubkey and session key
if (proof != H(tostr(residue) + session_key)):
req.sendall('Sorry, not permitted.\n')
req.close()
return
# this is useless for the challenge
our_verifier = H(tostr(public_client) + session_key)
req.sendall(our_verifier + '\n')
# send us the flag!
req.sendall('Congratulations! The flag is ' + flag + '\n')
req.close()
现在我们就调用服务器端的(s, S)密钥对,以及客户端的(c, C)密钥对。类似于g^s=S 以及 g^c=C.
他看起来像是客户端接收服务端的Diffie-Hellman算法公钥(使用verifier后得知),另一方面共享密钥为:
(C * verifier)^s = g^(cs) * verifier^s
由于客户端并不知道服务端的private exponent s,所以我们不能确定共享密钥,问题出在哪儿呢?
其中的诀窍便是public_client不应该是客户端公钥C,而是C乘以verifier的倒数。使用标准模块的反序算法,我们可以计算出verifier的主要逆模N。
我们可以用下面的程序进行身份验证(同样,我们仅向您展示精彩部分)
random_client = random.randint(2, N-2)
public_client = pow(g, random_client, N)
invver = modinv(verifier, N)
public_client2 = invver * public_client % N
if ((public_client2 * verifier) % N) == public_client:
print 'verifier verified'
s.sendall(tostr(public_client2) + '\n')
# get salt and server pubkey
salt = int(s.recv(512).strip('\n'), 16) % N
residue = int(s.recv(512).strip('\n'), 16) % N
public_server = (residue - verifier + N) % N
session_secret = pow(public_server, random_client, N)
session_key = H(tostr(session_secret))
proof = H(tostr(residue) + session_key)
s.sendall(proof + '\n')
time.sleep(0.5)
r = s.recv(512).strip('\n')
print r
获得结果
python tonnerre_solve.py
Welcome to the Tonnerre Authentication System!
verifier verified
ca787059bc572bc7902c91d2a168226a32052518073f4c32948ff02826e6be22
Congratulations! The flag is PCTF{SrP_v1_BeSt_sRp_c0nf1rm3d}
*原文链接:duksctf,鸢尾编译,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)
新闻时间:2016-04-23
新闻正文:
描述
首先我们确信搭载tonnerre.pwning.xxx:8560的服务器是完全安全的,后面我们可以访问该网站。怎么搞呢?
我们有了一个大胆的想法….他们会不会将用户数据和网页内容存储在同一个数据库呢?
细节
分值: 200
分类: 加密
验证: 119
解决方案
这个Web登录表单存在一个简单的SQL注入,运行sqlmap就可以直接获取tonnerre数据库中的users表单:只有一个用户get_flag 以及两个值:
salt, 一个随机的127字节字符串
verifier, 一个随机的145字节字符串
web.png
creds.png
这两个值都使用到基于公钥的认证协议,远程协议类似于SRP(安全远程密码协议),其服务端是由Python实现的。
下面包含我们注释的代码就是其中一部分有趣的地方:
N = ... # a 1024-bit prime number, the group modulus
g = ... # a 671-bit number, a group generator
...
# generates a key pair
random_server = random.randint(2, N-3)
public_server = pow(g, random_server, N)
# mask the public key with the verifier
residue = (public_server + permitted_users[username][1]) % N
# send salt and masked pubkey
req.sendall(tostr(permitted_users[username][0]) + '\n')
req.sendall(tostr(residue) + '\n')
# compute the session key,
# masking the client pubkey with the verifier
# raising to the server's secret exponent
# hashign the whole thing using SHA-256
session_secret = (public_client * permitted_users[username][1]) % N
session_secret = pow(session_secret, random_server, N)
session_key = H(tostr(session_secret))
# receive a proof from the client..
proof = req.recv(512).strip('\n')
# ..should be a hash of the server's masked pubkey and session key
if (proof != H(tostr(residue) + session_key)):
req.sendall('Sorry, not permitted.\n')
req.close()
return
# this is useless for the challenge
our_verifier = H(tostr(public_client) + session_key)
req.sendall(our_verifier + '\n')
# send us the flag!
req.sendall('Congratulations! The flag is ' + flag + '\n')
req.close()
现在我们就调用服务器端的(s, S)密钥对,以及客户端的(c, C)密钥对。类似于g^s=S 以及 g^c=C.
他看起来像是客户端接收服务端的Diffie-Hellman算法公钥(使用verifier后得知),另一方面共享密钥为:
(C * verifier)^s = g^(cs) * verifier^s
由于客户端并不知道服务端的private exponent s,所以我们不能确定共享密钥,问题出在哪儿呢?
其中的诀窍便是public_client不应该是客户端公钥C,而是C乘以verifier的倒数。使用标准模块的反序算法,我们可以计算出verifier的主要逆模N。
我们可以用下面的程序进行身份验证(同样,我们仅向您展示精彩部分)
random_client = random.randint(2, N-2)
public_client = pow(g, random_client, N)
invver = modinv(verifier, N)
public_client2 = invver * public_client % N
if ((public_client2 * verifier) % N) == public_client:
print 'verifier verified'
s.sendall(tostr(public_client2) + '\n')
# get salt and server pubkey
salt = int(s.recv(512).strip('\n'), 16) % N
residue = int(s.recv(512).strip('\n'), 16) % N
public_server = (residue - verifier + N) % N
session_secret = pow(public_server, random_client, N)
session_key = H(tostr(session_secret))
proof = H(tostr(residue) + session_key)
s.sendall(proof + '\n')
time.sleep(0.5)
r = s.recv(512).strip('\n')
print r
获得结果
python tonnerre_solve.py
Welcome to the Tonnerre Authentication System!
verifier verified
ca787059bc572bc7902c91d2a168226a32052518073f4c32948ff02826e6be22
Congratulations! The flag is PCTF{SrP_v1_BeSt_sRp_c0nf1rm3d}
*原文链接:duksctf,鸢尾编译,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)
赞赏
他的文章
- [分享]简单后门分析 5555
- [分享]cve-2012-0158两种poc分析 7905
- [求助]windows逆向实习 5441
- [分享]堆溢出研究三 8596
- [分享]堆溢出研究二 9227
看原图
赞赏
雪币:
留言: