哈希长度扩展攻击 以及一种奇葩解法
已将该题收录至Code-Audit-Challenges-python:1
Task
|
|
页面打开如下:
Solution
题目提供了源码,如下:
server.py:
还有hash.py,鉴于太长,这里就不贴出来了,可以见这:Code-Audit-Challenges-python:1
看一下server.py的流程,分为三个路由:
- 根路径,会重定向到login
- login页面,登陆后能拿到flag。
- logout页面
流程分析
接下来细看login()
,这里会啰嗦点尽量把整个流程解释清楚(其实都是废话)。
当我们在表单中输入用户名并提交后,server.py通过str(request.form.get('username'))
获取用户名并保存到变量username中。
接下来,如果在cookie中能获取到data和user字段,则接收并进行base64解码后去掉两边的空格之后存放到对应的变量data和user中:
其中strip()的作用是去掉字符串头尾指定的字符,默认为空格。
接下来通过join操作,得到一个变量temp,其组成为key|username|user
,其中username和user即前面提到的。而这个key是通过下面的语句定义的:
也就是说,变量key是未知的。
继续,截取server.py的代码如下:
会进行一个data与SLHA1(temp)的比较,其中SLHA1(temp)的具体实现在hash.py)中。如果比较相等且字符串admin
在变量user中,则得到flag。注意这里是用in
操作符,所以如下的情况是真的:
如果比较不等,则会进行一个set_cookie操作,即我们会接受到以下的cookie:
如果在cookie中不能能获取到data和user字段,它会执行下面的代码:
也是有一个set_cookie操作,我们会得到以下的cookie:
这里括号中的'user'
是指定的字符串,跟前面我们通过cookie传入得到的user变量是不一样的。
接下来看看SLHA1函数,这个是模仿了SHA1加密,对一些参数等做了修改,但本质上是基于Merkle–Damgård construction。所以我可以尝试一下哈希长度扩展攻击。
法一:哈希长度扩展攻击
基本的思路如下:
- 先获取到cookie,其中data=SLHA1(key|xxx),user=base64encode(‘user’)
- 基于第一步,通过哈希长度扩展攻击,得到SLHA1(key|xxx。。。admin)。
- 构造data,user字段,发送cookie,使之满足
data == SLHA1(temp).digest()
第一步获取cookie:
几个已知的参数如下:
data由服务器端经过SLHA1("xxxx|chybeta|user")
加密得到,括号里的都是字符串不是变量,xxxx表示key。
第二步,进行哈希长度扩展攻击。先看看目标,注意以下代码:
要构造出SLHA1("xxxx|chybeta|user"+padding+"admin")
,并将其设置为data。同时设置cookie中的user为base64encode(“user”+padding+”admin”)。即:
这样服务器端的流程约莫如下:
- 保持post传入的username仍为”chybeta”
- data = str(request.cookies.get(‘data’)).decode(‘base64’).strip() 得到 data = SLHA1(“xxxx|chybeta|user”+padding+”admin”)
- user = str(request.cookies.get(‘user’)).decode(‘base64’).strip() 得到 user = “user”+padding+”admin”
- temp = ‘|’.join([key,username,user]) 得到 temp = “xxxx|chybeta|user”+padding+”admin”
- 判断 SLHA1(“xxxx|chybeta|user”+padding+”admin”) == SLHA1(“xxxx|chybeta|user”+padding+”admin”)
因为出题者自己写了SLHA1,所以现成的工具是不行的。对照SHA1加密算法,我们写一个对SLHA1的长度扩展攻击算法。
上面这图是SHA1加密算法的流程:首先有原始register值,然后将hash的字符串分组等初始化操作后进行复杂的数学运算,同时会生成新的register的值,供下一个chunk进行加密使用。
在hash.py中,SLHA1算法的原始register值有6个:a,b,c,d,e,f。它们在每个chunk加密后会被更新,以参与下一个chunk的加密。可以通过self._h
进行赋值来直接指定SLHA1算法的register值。
对一个字符串进行SLHA1算法加密,可以通过调用update()来进行.
对加密字符串的初始化操作如下:
message是要进行加密的字符串。它会先加上一个字节\xfd
,之后再加上一堆的\xab
,使得chunk的长度能满足整除64后余数为56。之后添上8个字节的长度描述符。接下去从h = _process_chunk...
开始是对最后一个chunk的加密处理。
由于要进行padding,我们需要知道原本xxxx|chybeta
的长度,但xxx
是未知的,这个可以爆破解决。
借用一下人家的脚本:
PS: 其实今天早上(17/9/29)自己也写了一个脚本,但有些问题,准备过会再调试一下。然后下课后,TT && GG:
网站居然下线了woc。。。。。
法二:剑走偏锋:)
这个算是非预期解。毕竟这题名字叫Extend me,明显就是考哈希长度扩展攻击。不过这个非预期解法也蛮好玩的。
先通过post参数,设置username为 “chybeta|admin”。接着服务器进行加密 SLHA1(“xxxx|chybeta|admin|user”),这里的xxxx是指key,后面的user是服务器端默认的,中间的“chybeta|admin”即为变量username,这个加密过程对应:
第二步,更改cookie中的user字段:
Cookie的data字段保持不变。post进的username改为”chybeta”
接下来仔细看一下关键验证代码: