2019 De1CTF web wp

0x01 SSRF Me

关键词:哈希长度扩展攻击 首先进入网页发现是python源代码,其中发现一些比较重要的路由

@app.route('/') 
def index(): 
    return open("code.txt","r").read() 
def scan(param): 
    socket.setdefaulttimeout(1) 
    try: 
        return urllib.urlopen(param).read()[:50] 
    except: 
        return "Connection Timeout" 
def getSign(action, param): 
    return hashlib.md5(secert_key + param + action).hexdigest() 
def md5(content): 
    return hashlib.md5(content).hexdigest() 
def waf(param): 
    check=param.strip().lower() 
    if check.startswith("gopher") or check.startswith("file"): 
        return True 
    else: 
        return False

index函数打开code.txt展示为主页,getSign函数将随机生成的16位key和param和action拼接最后采用md5加密得到sign,waf屏蔽掉了gopher和file伪协议

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

geneSign路由下可以通过GET方式传入param变量,action固定为scan,调用getSign函数

@app.route('/De1ta',methods=['GET','POST']) 
def challenge(): 
    action = urllib.unquote(request.cookies.get("action")) 
    param = urllib.unquote(request.args.get("param", "")) 
    sign = urllib.unquote(request.cookies.get("sign")) 
    ip = request.remote_addr 
    if(waf(param)): 
        return "No Hacker!!!!" 
    task = Task(action, param, sign, ip) 
    return json.dumps(task.Exec()) 

De1ta路由下通过Cookie传入action和sign值,通过GET方法传入param值,建立Task类的对象task,调用对象task中的Exec方法生成结果

关键函数Exec:

def Exec(self): 
        result = {}
        result['code'] = 500 
        if (self.checkSign()): 
            if "scan" in self.action: 
                tmpfile = open("./%s/result.txt" % self.sandbox, 'w') 
                resp = scan(self.param) 
                if (resp == "Connection Timeout"): 
                    result['data'] = resp 
                else: 
                    print(resp)
                    tmpfile.write(resp) 
                    tmpfile.close() 
                    result['code'] = 200 
            if "read" in self.action:
                f = open("./%s/result.txt" % self.sandbox, 'r') 
                result['code'] = 200 
                result['data'] = f.read() 
        	if result['code'] == 500:
            	result['data'] = "Action Error" 
        else: 
            result['code'] = 500 
            result['msg'] = "Sign Error" 
        return result

类中若checkSignTrue则进入分支,分支中识别action为scan则执行将param代表的文件写入result.txt,而action=read的时候将result.txt中的代码进行读出并打印在页面上。

故我们需要获取flag,则需要获取param=flag.txt并且action=read这种情况下的sign,很明显在代码中并无可能实现,因为在生成sign的时候默认action为scan。因而我们需要采取哈希长度扩展攻击。

知识点:哈希长度扩展攻击 ==> 《白帽子讲web安全》(p275)

  • 哈希长度扩展攻击:

  • md5原理:MD5

  • 衍生出对于已知hash值hash(salt)和salt长度但未知salt值的情况下可以知道hash(salt   padding   append)的值,其中padding为根据salt长度产生的填充,append为任意数据
  • 由于md5在对原始数据进行512bit一组的分组后,采用初始向量(4*32bit)进行加密,每一轮的加密结果(128bit)分割为四组作为下一轮加密的初始向量,因而对于hash(salt),我们通过填充padding从而让hash(salt)成为下一轮加密append的初始向量,从而完成对hash(salt   padding   append)的计算
  • 可以采用工具hashpump

  • 使用方式:CSRF1

  • 其中Key Length指增加data之前的所有内容长度

采用哈希长度扩展攻击,利用hashpump计算出需要填充的字节数,在这个情况下,我们需要操作的变量为action,我们需要将action的scan变为read,因而我们通过哈希长度扩展攻击获得我们所需要的md5值,即sign

最终我们用burpSuite抓包发送请求获取flag

De1CTF1