1. 整体流程

  1. 访问/geneSign?param=flag.txt拿到md5(secert_key + "flag.txt" + "scan")的值
  2. 利用HashPump进行哈希长度扩展攻击
  3. 访问/De1ta?param=flag.txt,并设置cookie,刷新页面之后得到flag。

Alt text

2. 题目分析

直接访问题目即可拿到题目源代码。可以看到这是一道拿flask框架写的题目。定义的路由有'/''/De1ta''/geneSign'三个
最简单的'/geneSign'路由,作用是调用getSign函数获取哈希值。其中secret_key的值未知,param的值为GET/POST传参获取,action的值为scan。即secret_key未知, param + action已知。

app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
    param = urllib.unquote(request.args.get("param", ""))
    action = "scan"
    return getSign(action, param)

def getSign(action, param):
    return hashlib.md5(secert_key + param + action).hexdigest()

继续分析代码,看到在Task类中有一个checkSign函数,如果getSign函数的返回值与self.sign相等,则返回True

class Task:
    def checkSign(self):
        if (getSign(self.action, self.param) == self.sign):
            return True
        else:
            return False

分析self.sign。路由/De1ta调用了Task这个类,传进去的sign值为sign = urllib.unquote(request.cookies.get("sign"))。也就是说,只有当getSign函数的返回值与cookie里面设置的sign值相等时,才能进入Exec函数中的if语句。

Alt text

分析这个if (self.checkSign())的逻辑可知,如果在action中检测到scan关键字,那么则会创建一个文件,并将对url的请求结果写入result.txt里面。如果在action中检测到read关键字,那么会读取result.txt的请求结果并回显到页面上面。

Alt text

那么现在攻击思路就清楚了。通过hash长度扩展攻击去读取flag.txt文件(题目hint: flag is in ./flag.txt)。通过/geneSign路由获取hash值,输入数据为scan,key的长度由secert_key = os.urandom(16)可知为16 + 8(scanread) = 24。因为还要将数据回显到界面上,所以还需要添加的数据为read。然后就可以获取hashpump生成的值了。
然后访问/De1ta路由,GET传参param值为flag.txt。添加cookie,action=scan%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%e0%00%00%00%00%00%00%00readsign=27527c63ccc5aedc91aaff79265721c7。然后刷新页面获取到flag。

Last modification:December 25th, 2019 at 03:19 pm
给肥宅一点零花钱买可乐叭 (゜-゜)つロ