WEB BUUCTF [De1CTF 2019] SSRF Me
Buuctf have to say is a good site, the game has a lot of problems to reproduce! !
Subject to the source:
#! /usr/bin/env python
#encoding=utf-8
from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json
reload(sys)
sys.setdefaultencoding('latin1')
app = Flask(__name__)
secert_key = os.urandom(16)
class Task:
def __init__(self, action, param, sign, ip):
self.action = action
self.param = param
self.sign = sign
self.sandbox = md5(ip)
if(not os.path.exists(self.sandbox)): #SandBox For Remote_Addr
os.mkdir(self.sandbox)
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
def checkSign(self):
if (getSign(self.action, self.param) == self.sign):
return True
else:
return False
#generate Sign For Action Scan.
@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
param = urllib.unquote(request.args.get("param", ""))
action = "scan"
return getSign(action, param)
@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())
@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
if __name__ == '__main__':
app.debug = False
app.run(host='0.0.0.0')
There is also a topic hint:
audit at the source! The flask python framework, three routes
index to obtain the source code, geneSign called getSign method to generate MD5,
De1ta should be the key of the page! You can see get three parameters, two of which are obtained from a cookie:
action = urllib.unquote(request.cookies.get("action"))
param = urllib.unquote(request.args.get("param", ""))
sign = urllib.unquote(request.cookies.get("sign"))
As a parameter passed to the Task class, and calls the Exec () method in the Task class, which should be the key! !
Analysis of three parameters:
The first parameter is the action of incoming read and scan, the
second argument should be looked at pass a filename,
the third parameter is a sign md5 value,
to follow up the Task Exec ( ) method can be found that there is also a checkSign (), and there called getSign () method, the results were compared with the sign
closer look getSign () method, we found a secert_key is unknown ,,,, ,
after reading the code will have a certain understanding! ! His aim should be to read the contents of flag.txt us in!
So we need to construct parameters! The first argument action should contain read ,, second param filename parameter should be
the most critical is the third argument, because we do not know the value of secert_key, it is not their own encryption, test sites should be here!
Access what geneSign page and pass parameters param = flag.txt get a string of MD5 value: ea25b05cf3918f0728b123883e59f93c
this way we get value md5 (secert_key + flag.txtscan) of! !
Looked and saw that MD5 is a character stitching! ! We will configured param param = flag.txtread parameters
so that we can get the value md5 md5 (secert_key + flag.txtreadscan): the a8bda0fcca126badfc8483ee6b3623cc
re-page access De1ta parameter passing, get flag:
Because we are able to bypass through the string concatenation checkSign ()method! ! So we can get friends ~ ~ flag
In fact, there is a way, is MD5hash length extension attack! ! !
In fact this method is relatively tasteless, but ctf title still possible, that does not appear! ! !
hash length extension attack means for allowing some cryptographic hash function (MD5, SHA1 and the like) contain additional information of attacks
understand the encryption process can be appreciated that extension attack because MD5 encryption is encrypted packet
principle: the Hash the Extension the Length Attack
The above article was very well written! He said very clearly, what is the hash extension attack ,,
here we just use the tool, do not use tools can do, yourself, understand the principle should be able to get yourself out! !
kali installation HashPump:
git clone https://github.com/bwall/HashPump
apt-get install g++ libssl-dev
cd HashPump
make
make install
Operation, and the value obtained md5 string:
e4310fe8dd373052d4e304f725f683f1
scan\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x00\x00\x00\x00read
Parameter passing to give flag: