1.3 任意文件读取漏洞
所谓文件读取漏洞,就是攻击者通过一些手段可以读取服务器上开发者不允许读到的文件。从整个攻击过程来看,它常常作为资产信息搜集的一种强力的补充手段,服务器的各种配置文件、文件形式存储的密钥、服务器信息(包括正在执行的进程信息)、历史命令、网络信息、应用源码及二进制程序都在这个漏洞触发点被攻击者窥探。
文件读取漏洞常常意味着被攻击者的服务器即将被攻击者彻底控制。当然,如果服务器严格按照标准的安全规范进行部署,即使应用中存在可利用的文件读取漏洞,攻击者也很难拿到有价值的信息。文件读取漏洞在每种可部署Web应用的程序语言中几乎都存在。当然,此处的“存在”本质上不是语言本身的问题,而是开发者在进行开发时由于对意外情况考虑不足所产生的疏漏。
通常来讲,Web应用框架或中间件的开发者十分在意代码的可复用性,因此对一些API接口的定义都十分开放,以求尽可能地给二次开发者最大的自由。而真实情况下,许多开发人员在进行二次开发时过于信任Web应用框架或中间件底层所实现的安全机制,在未仔细了解应用框架及中间件对应的安全机制的情况下,便轻率地依据简单的API文档进行开发,不巧的是,Web应用框架或中间件的开发者可能未在文档中标注出API函数的具体实现原理和可接受参数的范围、可预料到的安全问题等。
业界公认的代码库通常被称为“轮子”,程序可以通过使用这些“轮子”极大地减少重复工作量。如果“轮子”中存在漏洞,在“轮子”代码被程序员多次迭代复用的同时,漏洞也将一级一级地传递,而随着对底层“轮子”代码的不断引用,存在于“轮子”代码中的安全隐患对于处在“调用链”顶端的开发者而言几乎接近透明。
对于挖掘Web应用框架漏洞的安全人员来说,能否耐心对这条“调用链”逆向追根溯源也是一个十分严峻的挑战。
另外,有一种任意文件读取漏洞是开发者通过代码无法控制的,这种情况的漏洞常常由Web Server自身的问题或不安全的服务器配置导致。Web Server运行的基本机制是从服务器中读取代码或资源文件,再把代码类文件传送给解释器或CGI程序执行,然后将执行的结果和资源文件反馈给客户端用户,而存在于其中的众多文件操作很可能被攻击者干预,进而造成诸如非预期读取文件、错误地把代码类文件当作资源文件等情况的发生。
1.3.1 文件读取漏洞常见触发点
1.3.1.1 Web语言
不同的Web语言,其文件读取漏洞的触发点也会存在差异,本小节以读取不同Web文件漏洞为例进行介绍,具体的漏洞场景请读者自行查阅,在此不再赘述。
1.PHP
PHP标准函数中有关文件读的部分不再详细介绍,这些函数包括但可能不限于:file_get_contents()、file()、fopen()函数(及其文件指针操作函数fread()、fgets()等),与文件包含相关的函数(include()、require()、include_once()、require_once()等),以及通过PHP读文件的执行系统命令(system()、exec()等)。这些函数在PHP应用中十分常见,所以在整个PHP代码审计的过程中,这些函数会被审计人员重点关注。
这里有些读者或许有疑问,既然这些函数这么危险,为什么开发者还要将动态输入的数据作为参数传递给它们呢?因为现在PHP开发技术越来越倾向于单入口、多层级、多通道的模式,其中涉及PHP文件之间的调用密集且频繁。开发者为了写出一个高复用性的文件调用函数,就需要将一些动态的信息传入(如可变的部分文件名)那些函数(见图1-3-1),如果在程序入口处没有利用switch等分支语句对这些动态输入的数据加以控制,攻击者就很容易注入恶意的路径,从而实现任意文件读取甚至任意文件包含。
图1-3-1
除了上面提到的标准库函数,很多常见的PHP扩展也提供了一些可以读取文件的函数。例如,php-curl扩展(文件内容作为HTTP body)涉及文件存取的库(如数据库相关扩展、图片相关扩展)、XML模块造成的XXE等。这些通过外部库函数进行任意文件读取的CTF题目不是很多,后续章节会对涉及的题目进行实例分析。
与其他语言不同,PHP向用户提供的指定待打开文件的方式不是简简单单的一个路径,而是一个文件流。我们可以将其简单理解成PHP提供的一套协议。例如,在浏览器中输入http://host:port/xxx后,就能通过HTTP请求到远程服务器上对应的文件,而在PHP中有很多功能不同但形式相似的协议,统称为Wrapper,其中最具特色的协议便是php://协议,更有趣的是,PHP提供了接口供开发者编写自定义的wrapper(stream_wrapper_register)。
除了Wrapper,PHP中另一个具有特色的机制是Filter,其作用是对目前的Wrapper进行一定的处理(如把当前文件流的内容全部变为大写)。
对于自定义的Wrapper而言,Filter需要开发者通过stream_filter_register进行注册。而PHP内置的一些Wrapper会自带一些Filter,如php://协议存在图1-3-2中所示类型的Filter。
图1-3-2
PHP的Filter特性给我们进行任意文件读取提供了很多便利。假设服务端include函数的路径参数可控,正常情况下它会将目标文件当作PHP文件去解析,如果解析的文件中存在“<?php”等PHP的相关标签,那么标签中的内容会被作为PHP代码执行。
我们如果直接将这种含有PHP代码的文件的文件名传入include函数,那么由于PHP代码被执行而无法通过可视文本的形式泄露。但这时可以通过使用Filter避免这种情况的发生。
例如,比较常见的Base64相关的Filter可将文件流编码成Base64的形式,这样读取的文件内容中就不会存在PHP标签。而更严重的是,如果服务端开启了远程文件包含选项allow_url_include,我们就可以直接执行远程PHP代码。
当然,这些PHP默认携带的Wrapper和Filter都可以通过php.ini禁用,读者在实际遇到时要具体分析,建议阅读PHP有关Wrapper和Filter的源代码,会更加深入理解相关内容。
在遇到的有关PHP文件包含的实际问题中,我们可能遇到三种情况:①文件路径前面可控,后面不可控;②文件路径后面可控,前面不可控;③文件路径中间可控。
对于第一种情况,在较低的PHP版本及容器版本中可以使用“\x00”截断,对应的URL编码是“%00”。当服务端存在文件上传功能时,也可以尝试利用zip或phar协议直接进行文件包含进而执行PHP代码。
对于第二种情况,我们可以通过符号“../”进行目录穿越来直接读取文件,但这种情况下无法使用Wrapper。如果服务端是利用include等文件包含类的函数,我们将无法读取PHP文件中的PHP代码。
第三种情况与第一种情况相似,但是无法利用Wrapper进行文件包含。
2.Python
与PHP不同的是,Python的Web应用更多地倾向于通过其自身的模块启动服务,同时搭配中间件、代理服务将整个Web应用呈现给用户。用户和Web应用交互的过程本身就包含对服务器资源文件的请求,所以容易出现非预期读取文件的情况。因此,我们看到的层出不穷的Python某框架任意文件读取漏洞也是因为缺乏统一的资源文件交互的标准。
漏洞经常出现在框架请求静态资源文件部分,也就是最后读取文件内容的open函数,但直接导致漏洞的成因往往是框架开发者忽略了Python函数的feature,如os.path.join()函数:
很多开发者通过判断用户传入的路径不包含“.”来保证用户在读取资源时不会发生目录穿越,随后将用户的输入代入os.path.join的第二个参数,但是如果用户传入“/”,则依然可以穿越到根目录,进而导致任意文件读取。这是一个值得我们注意并深思的地方。
除了python框架容易出这种问题,很多涉及文件操作的应用也很有可能因为滥用open函数、模板的不当渲染导致任意文件读取。比如,将用户输入的某些数据作为文件名的一部分(常见于认证服务或者日志服务)存储在服务器中,在取文件内容的部分也通过将经过处理的用户输入数据作为索引去查找相关文件,这就给了攻击者一个进行目录穿越的途径。
例如,CTF线上比赛中,Python开发者调用不安全的解压模块进行压缩文件解压,而导致文件解压后可进行目录穿越。当然,解压文件时的目录穿越的危害是覆写服务器已有文件。
另一种情况是攻击者构造软链接放入压缩包,解压后的内容会直接指向服务器相应文件,攻击者访问解压后的链接文件会返回链接指向文件的相应内容。这将在后面章节中详细分析。与PHP相同,Python的一些模块可能存在XXE读文件的情况。
此外,Python的模板注入、反序列化等漏洞都可造成一定程度的任意文件读取,当然,其最大危害仍然是导致任意命令执行。
3.Java
除了Java本身的文件读取函数FileInputStream、XXE导致的文件读取,Java的一些模块也支持“file://”协议,这是Java应用中出现任意文件读取最多的地方,如Spring Cloud Config Server路径穿越与任意文件读取漏洞(CVE-2019-3799)、Jenkins任意文件读取漏洞(CVE-2018-1999002)等。
4.Ruby
在CTF线上比赛中,Ruby的任意文件读取漏洞通常与Rails框架相关。到目前为止,我们已知的通用漏洞为Ruby On Rails远程代码执行漏洞(CVE-2016-0752)、Ruby On Rails路径穿越与任意文件读取漏洞(CVE-2018-3760)、Ruby On Rails路径穿越与任意文件读取漏洞(CVE-2019-5418)。笔者在CTF竞赛中就曾遇到Ruby On Rails远程代码执行漏洞(CVE-2016-0752)的利用。
5.Node
目前,已知Node.js的express模块曾存在任意文件读取漏洞(CVE-2017-14849),但笔者还未遇到相关CTF赛题。CTF中Node的文件读取漏洞通常为模板注入、代码注入等情况。
1.3.1.2 中间件/服务器相关
不同的中间件/服务器同样可能存在文件读取漏洞,本节以曾经出现的不同中间件/服务器上的文件读取漏洞为例来介绍。具体的漏洞场景请读者自行查阅,在此不再赘述。
1.Nginx错误配置
Nginx错误配置导致的文件读取漏洞在CTF线上比赛中经常出现,尤其是经常搭配Python-Web应用一起出现。这是因为Nginx一般被视为Python-Web反向代理的最佳实现。然而它的配置文件如果配置错误,就容易造成严重问题。例如:
如果配置文件中包含上面这段内容,很可能是运维或者开发人员想让用户可以访问static目录(一般是静态资源目录)。但是,如果用户请求的Web路径是/static../,拼接到alias上就变成了/home/myapp/static/../,此时便会产生目录穿越漏洞,并且穿越到了myapp目录。这时,攻击者可以任意下载Python源代码和字节码文件。注意:漏洞的成因是location最后没有加“/”限制,Nginx匹配到路径static后,把其后面的内容拼接到alias,如果传入的是/static../,Nginx并不认为这是跨目录,而是把它当作整个目录名,所以不会对它进行跨目录相关处理。
2.数据库
可以进行文件读取操作的数据库很多,这里以MySQL为例来进行说明。
MySQL的load_file()函数可以进行文件读取,但是load_file()函数读取文件首先需要数据库配置FILE权限(数据库root用户一般都有),其次需要执行load_file()函数的MySQL用户/用户组对于目标文件具有可读权限(很多配置文件都是所有组/用户可读),主流Linux系统还需要Apparmor配置目录白名单(默认白名单限制在MySQL相关的目录下),可谓“一波三折”。即使这么严格的利用条件,我们还是经常可以在CTF线上比赛中遇到相关的文件读取题。
还有一种方式读取文件,但是与load_file()文件读取函数不同,这种方式需要执行完整的SQL语句,即load data infile。同样,这种方式需要FILE权限,不过比较少见,因为除了SSRF攻击MySQL这种特殊情形,很少有可以直接执行整条非基本SQL语句(除了SELECT/UPDATE/INSERT)的机会。
3.软链接
bash命令ln-s可以创建一个指向指定文件的软链接文件,然后将这个软链接文件上传至服务器,当我们再次请求访问这个链接文件时,实际上是请求在服务端它指向的文件。
4.FFmpeg
2017年6月,FFmpeg被爆出存在任意文件读取漏洞。同年的全国大学生信息安全竞赛实践赛(CISCN)就利用这个漏洞出了一道CTF线上题目(相关题解可以参考https://www.cnblogs.com/iamstudy/articles/2017_quanguo_ctf_web_writeup.html)。
5.Docker-API
Docker-API可以控制Docker的行为,一般来说,Docker-API通过UNIX Socket通信,也可以通过HTTP直接通信。当我们遇见SSRF漏洞时,尤其是可以通过SSRF漏洞进行UNIX Socket通信的时候,就可以通过操纵Docker-API把本地文件载入Docker新容器进行读取(利用Docker的ADD、COPY操作),从而形成一种另类的任意文件读取。
1.3.1.3 客户端相关
客户端也存在文件读取漏洞,大多是基于XSS漏洞读取本地文件。
1.浏览器/Flash XSS
一般来说,很多浏览器会禁止JavaScript代码读取本地文件的相关操作,如请求一个远程网站,如果它的JavaScript代码中使用了File协议读取客户的本地文件,那么此时会由于同源策略导致读取失败。但在浏览器的发展过程中存在着一些操作可以绕过这些措施,如Safari浏览器在2017年8月被爆出存在一个客户端的本地文件读取漏洞。
2.MarkDown语法解析器XSS
与XSS相似,Markdown解析器也具有一定的解析JavaScript的能力。但是这些解析器大多没有像浏览器一样对本地文件读取的操作进行限制,很少有与同源策略类似的防护措施。
1.3.2 文件读取漏洞常见读取路径
1.3.2.1 Linux
1.flag名称(相对路径)
比赛过程中,有时fuzz一下flag名称便可以得到答案。注意以下文件名和后缀名,请读者根据题目及环境自行发挥。
2.服务器信息(绝对路径)
下面列出CTF线上比赛常见的部分需知目录和文件。建议读者在阅读本书后亲自翻看这些目录,对于未列出的文件也建议了解一二。
(1)/etc目录
/etc目录下多是各种应用或系统配置文件,所以其下的文件是进行文件读取的首要目标。
(2)/etc/passwd
/etc/passwd文件是Linux系统保存用户信息及其工作目录的文件,权限是所有用户/组可读,一般被用作Linux系统下文件读取漏洞存在性判断的基准。读到这个文件我们就可以知道系统存在哪些用户、他们所属的组是什么、工作目录是什么。
(3)/etc/shadow
/etc/shadow是Linux系统保存用户信息及(可能存在)密码(hash)的文件,权限是root用户可读写、shadow组可读。所以一般情况下,这个文件是不可读的。
(4)/etc/apache2/*
/etc/apache2/*是Apache配置文件,可以获知Web目录、服务端口等信息。CTF有些题目需要参赛者确认Web路径。
(5)/etc/nginx/*
/etc/nginx/*是Nginx配置文件(Ubuntu等系统),可以获知Web目录、服务端口等信息。
(6)/etc/apparmor(.d)/*
/etc/apparmor(.d)/*是Apparmor配置文件,可以获知各应用系统调用的白名单、黑名单。例如,通过读配置文件查看MySQL是否禁止了系统调用,从而确定是否可以使用UDF(User Defined Functions)执行系统命令。
(7)/etc/(cron.d/*|crontab)
/etc/(cron.d/*|crontab)是定时任务文件。有些CTF题目会设置一些定时任务,读取这些配置文件就可以发现隐藏的目录或其他文件。
(8)/etc/environment
/etc/environment是环境变量配置文件之一。环境变量可能存在大量目录信息的泄露,甚至可能出现secret key泄露的情况。
(9)/etc/hostname
/etc/hostname表示主机名。
(10)/etc/hosts
/etc/hosts是主机名查询静态表,包含指定域名解析IP的成对信息。通过这个文件,参赛者可以探测网卡信息和内网IP/域名。
(11)/etc/issue
/etc/issue指明系统版本。
(12)/etc/mysql/*
/etc/mysql/*是MySQL配置文件。
(13)/etc/php/*
/etc/php/*是PHP配置文件。
(14)/proc目录
/proc目录通常存储着进程动态运行的各种信息,本质上是一种虚拟目录。注意:如果查看非当前进程的信息,pid是可以进行暴力破解的,如果要查看当前进程,只需/proc/self/代替/proc/[pid]/即可。
对应目录下的cmdline可读出比较敏感的信息,如使用mysql-uxxx-pxxxx登录MySQL,会在cmdline中显示明文密码:
有时我们无法获取当前应用所在的目录,通过cwd命令可以直接跳转到当前目录:
环境变量中可能存在secret_key,这时也可以通过environ进行读取:
(15)其他目录
Nginx配置文件可能存在其他路径:
日志文件:
Apache默认Web根目录:
PHP session目录:
用户目录:
[pid]指向进程所对应的可执行文件。有时我们想读取当前应用的可执行文件再进行分析,但在实际利用时可能存在一些安全措施阻止我们去读可执行文件,这时可以尝试读取/proc/self/exe。例如:
1.3.2.2 Windows
Windows系统下的Web应用任意文件读取漏洞在CTF赛题中并不常见,但是Windows与PHP搭配使用时存在一个问题:可以使用“<”等符号作为通配符,从而在不知道完整文件名的情况下进行文件读取,这部分内容会在下面的例题中详细介绍。
1.3.3 文件读取漏洞例题
根据大量相关CTF真题的整理,本节介绍文件读取漏洞的实战,希望参赛者在阅读后仔细总结,熟练掌握,对日后解题会有很大帮助。
1.3.3.1 兵者多诡(HCTF 2016)
【题目简介】在home.php中存在一处include函数导致的文件包含漏洞,传至include函数的路径参数前半部分攻击者可控,后半部分内容确定,不可控部分是后缀的.php。
在upload.php处存在文件上传功能,但上传至服务器的文件名不可控。
【题目难度】中等。
【知识点】php://协议的Filter利用;通过zip://协议进行文件包含。
【解题思路】打开题目,发现首页只有一个上传表单,先上传一个正常文件进行测试。通过对上传的数据进行抓包,发现POST的数据传输到了“?fp=upload”,接着跟随数据跳转,会发现结果跳转到“?fp=show&imagekey=xxx”。
从这里开始,参赛经验程度不同的参赛者的思考方向会产生差异。
(1)第一步
新手:继续测试文件上传的功能。
有经验的参赛者:看到fp参数,会联想到file pointer,即fp的值可能与文件相关。
(2)第二步
接下来的差异会在第一步的基础上继续扩大。
新手玩家:这个文件上传的防护机制到底该怎样绕过?
有经验的参赛者:直接访问show.php、upload.php,或者想办法寻找文件中名含有show、upload等特殊含义的PHP文件,或者把show/upload改成其他已知文件"home"。
更有经验的参赛者:将fp参数的内容改为“./show”“../html/show”等。我们无法得知文件包含的目标文件具体路径是什么,如果是一个很奇怪的路径,就无法找到其原始PHP文件,这时“./show”形式能很好地解决这个困难,进而轻松地判断这里是否存在任意文件包含漏洞。
(3)第三步
新手:这道题一定需要0day才能绕过防护,我可以放弃了。
有经验的参赛者:根据直接访问“show.php/upload.php”和“?fp=home”的结果,判断这里是一个include文件包含。利用Filter机制,构造形如“php://filter/convert.base64-encode/resource=xxx”的攻击数据读取文件,拿到各种文件的源码;利用zip://协议,搭配上传的Zip文件,包含一个压缩的Webshell文件;再通过zip://协议调用压缩包中的Webshell,访问这个Webshell的链接为
【总结】①题目首先考查了选手对于黑盒测试任意文件读取/包含漏洞的能力,每个人都有自己独有的测试思路,上面所写的思路仅供参考。在进行黑盒测试时,我们要善于捕获参数中的关键词,并且具有一定的联想能力。
②考查了参赛者对Filter的利用,如php://filter/convert.Base64-encode(将文件流通过Base64进行编码)。
③考查了选手对zip://协议的利用:将文件流视为一个Zip文件流,同时通过“#”(%23)选出压缩包内指定文件的文件流。
读者可能不太理解第③点,下面具体说明。我们上传一个Zip文件至服务器,当通过zip://协议解析这个压缩文件时,会自动将这个Zip文件按照压缩时的文件结构进行解析,然后通过“#(对应URL编码%23)+文件名”的方式对Zip内部所压缩的文件进行索引(如上面的例子就是内部存储了个名为1.php的文件)。这时整个文件流被定位到1.php的文件流,所以include实际包含的内容是1.php的内容,具体解析流程见图1-3-3。
图1-3-3
1.3.3.2 PWNHUB-Classroom
【题目简介】使用Django框架开发,并通过不安全的方式配置静态资源目录。
【题目难度】中等。
【知识点】Python(Django)静态资源逻辑配置错误导致的文件读取漏洞;Pyc字节码文件反编译;Django框架ORM注入。
【解题思路】第一个漏洞:代码先匹配到用户传入的URL路径static/后的内容,再将这个内容传入os.path.join,与一些系统内定的目录拼接后形成一个绝对路径,然后进行后缀名检查,通过检查,该绝对路径将传入open()函数,读取文件内容并返回用户。
第二个漏洞:views.py的类LoginView中。可以看到,将用户传入的JSON数据加载后,加载得到的数据直接被代入了x.objects.filter(Django ORM原生函数)。
先打开题目,看到HTTP返回头部中显示的Server信息:
我们可以得知题目是使用Python的Django框架开发的,当遇到Python题目没有给源码的情况时,可以第一时间尝试是否存在目录穿越相关的漏洞(可能是Nginx不安全配置或Python框架静态资源目录不安全配置),这里使用“/etc/passwd”作为文件读取的探针,请求的路径为:
可以发现任意文件读取漏洞的确存在,但在随后尝试读取Python源代码文件时发现禁用了几个常见的后缀名,包括Python后缀名、配置文件后缀名、Sqlite后缀名、YML文件后缀名:
在Python 3中运行Python文件时,对于运行的模块会进行缓存,并存放在__pycache__目录下,其中pyc字节码文件的命名规则为:
__pycache__/views.cpython-34.pyc是一个文件名的示例。这里其实考查的是对Python的了解和Django目录结构的认知。
将请求的文件路径更换为符合上面规则的路径:
成功地读取了PYC字节码文件。继续读取所有剩余的PYC文件,再反编译PYC字节码文件获取源代码。通过对获得的源码进行审计,我们发现存在ORM注入漏洞,继续利用该注入漏洞便可得到flag内容,见图1-3-4。
图1-3-4
【总结】①参赛者要通过HTTP头中的指纹信息判断题目的相关环境。当然,这里可能涉及一些经验和技巧,需要通过大量的实践积累。
②熟悉题目所用的环境和Web应用框架。即使参赛者刚开始时不熟悉,也要快速搭建并学习该环境、框架的特性,或者翻看查阅手册。注意:快速搭建环境并学习特性是CTF参赛者进行Web比赛的基本素养。
③黑盒测试出目录穿越漏洞,进而进行任意文件读取。
④源代码审计,根据②所述,了解框架特性后,通过ORM注入获得flag。
1.3.3.3 Show me the shell I(TCTF/0CTF 2018 Final)
【题目简介】题目的漏洞很明显,UpdateHead方法就是更新头像功能,用户传入的URL的协议可以为File协议,进而在Download方法中触发URL组件的任意文件读取漏洞。
【题目难度】简单。
【知识点】Java URL组件通过File协议列出目录结构,进而读取文件内容。
【解题思路】对Java class字节码文件进行反编译(JD);通过代码审计,发现源码中存在的漏洞
【总结】参赛者要积累一定的经验,了解URL组件可使用的协议,赛后分享见图1-3-5。
图1-3-5
1.3.3.4 BabyIntranet I(SCTF 2018)
【题目简介】本题采用了Rails框架进行开发,存在Ruby On Rails远程代码执行漏洞(CVE-2016-0752),可以被任意读取文件(该漏洞其实质是动态文件渲染)。
通过读取源码发现,该应用程序使用了Rails的Cookie-Serialize模块,通过读取应用的密钥,构造恶意反序列化数据,进而执行恶意代码。
【题目难度】中等。
【知识点】Ruby On Rails框架任意文件读取漏洞;Rails cookies反序列化。
【解题思路】对应用进行指纹探测,通过指纹信息发现是通过Rails框架开发的应用,接着可以在HTML源码中发现链接/layouts/c3JjX21w,对软链接后面的部分进行Base64解码,发现内容是src_ip。查阅Rails有关漏洞发现动态模板渲染漏洞(CVE-2016-0752),将../../../../../../etc/passwd编码成Base64放在layouts后,成功返回/etc/passwd文件的内容。
尝试渲染日志文件(../log/development.log)直接进行代码执行失败,发现没权限渲染这个文件,接着读取所有可读的代码或配置文件,发现使用了cookies_serializer模块。尝试读取当前用户环境变量发现没权限,于是尝试读取/proc/self/environ,获取到密钥后,使用metasploit中相应的Ruby反序列化攻击模块直接攻击。
【总结】①通过Ruby On Rails远程代码执行漏洞(CVE-2016-0752)进行任意文件读取(出题人对漏洞代码进行了一定程度的修改,使用了Base64编码),见图1-3-6。
图1-3-6
②服务器禁止了Log日志的读取权限,因此不能直接通过渲染日志完成getshell。通过读取源码,我们可以发现应用中使用了Rails的Cookie-Serialize模块。整个模块的处理机制是将真正的session_data序列化后通过AES-CBC模式加密,再用Base64编码2次,处理流程见图1-3-7。
图1-3-7
从服务器返回的Set-Cookie也能印证这一点,见图1-3-8。
图1-3-8
我们可以通过任意文件读取漏洞获取/proc/self/environ的环境变量,找到AES加密所使用的secret_key,接着借助secret_key伪造序列化数据。这样,当服务端反序列化时,就会触发漏洞执行恶意代码,见图1-3-9。
图1-3-9
1.3.3.5 SimpleVN(BCTF 2018)
【题目简介】题目的功能主要分为如下两点。
(1)用户可以设置一个模板用来被渲染,但是这个模板设置有一定的限制,只能使用“.”和字母、数字。另外,渲染模板的功能只允许127.0.0.1(本地)请求。
(2)题目中存在一个代理请求的服务,用户输入URL并提交,后端会启动Chrome浏览器去请求这个URL,并把请求页面截图,反馈给用户。当然,用户提交的URL也有一定限制,必须是本地配置的HOST(127.0.0.1)。这里存在一个问题,就是我们传入File协议的URL中的HOST部分是空的,所以也可以绕过这个检查。
【题目难度】中等。
【知识点】浏览器协议支持及view-source的利用;Node模板注入;HTTP Request Header:Range。
【解题思路】通过审计源码,发现模板注入漏洞和服务端浏览器请求规则,同时找到了解题方向:获取flag的路径,并读取flag的内容。
通过模板注入process.env.FLAGFILENAME获取flag文件名,获取整个Node应用所在目录process.env.PWD,使用view-source:输出被解析成HTML标签的结果,见图1-3-10。
图1-3-10
使用file://+绝对路径读取config.js中的FLAG_PATH,见图1-3-11。
读取flag内容,使用HTTP请求头的Range来控制输出的开始字节和结束字节。题目中的flag文件内容很多,直接请求无法输出真正flag的部分,需要从中间截断开始输出,见图1-3-12。
图1-3-11
图1-3-12
【总结】①题目中的任意文件读取其实与Node并无太大关系,实质上是利用浏览器支持的协议,属于比较新颖的题目。
②读取文件的原则是按需读取而不盲目读取,盲目读取文件内容会浪费时间。
③同样使用浏览器特性有关的题目还有同场比赛的SEAFARING2,通过SSRF漏洞攻击selenium server,控制浏览器请求file:///读取本地文件。读者如果感兴趣可以搜寻这道题。
1.3.3.6 Translate(Google CTF 2018)
【题目简介】根据题目返回的{{userQuery}},我们容易想到试一下模板注入,使用数学表达式{{3*3}}进行测试。
通过{{this.$parent.$parent.window.angular.module('demo')._invokeQueue[3][2][1]}}读取部分代码,发现使用了i18n.template渲染模板,通过i18n.template('./flag.txt')读取flag。
【题目难度】中等。
【知识点】Node模板注入;i18n.template读flag。
【解题思路】先发现模板注入,利用模板注入搜集信息,在已有信息的基础上,利用模板注入,调用可读文件的函数进行文件读取。
【总结】涉及Node模板注入的知识,需要参赛者对其机制有所了解;模板注入转换成文件读取漏洞。
1.3.3.7 看番就能拿Flag(PWNHUB)
【题目简介】扫描子域名,发现有一个站点记录了题目搭建过程(blog.loli.network)。
发现Nginx配置文件如下:
构造目录穿越后,在上级目录发现了Aria2的配置文件,见图1-3-12。
图1-3-12
同时发现在题目的6800端口开放了Aria2服务。
【题目难度】中等。
【知识点】Nginx错误配置导致目录穿越;Aria2任意文件写入漏洞。
【解题思路】先进行必要的信息搜集,包括目录、子域名等。在测试的过程中发现Nginx配置错误(依据前面的信息搜集到Nginx配置文件,也可以进行黑盒测试。黑盒测试很重要的就是对Nginx的特性及可能存在的漏洞很了解。这也可以节省我们信息搜集所需要的时间,直接切入第二个漏洞点)。利用Ngnix目录穿越获取Aria2配置文件,拿到rpc-secret。再借助Aria2任意文件写入漏洞,Aria2的API需要token也就是rpc-secret才可以调用,前面获取的rpc-secret便能起作用了。
调用api配置allowoverwrite为true:
然后调用API下载远程文件,覆盖本地任意文件(这里直接覆盖SSH公钥),SSH登录获取flag。
1.3.3.8 2013那年(PWNHUB)
【题目简介】(1)发现存在.DS_Store文件,见图1-3-13。
图1-3-13
(2).DS_Store文件泄露当前目录结构,通过分析.DS_Store文件发现存在upload、pwnhub等目录。
(3)pwnhub目录在Nginx文件里被配置成禁止访问(比赛中前期无法拿到Nginx配置文件,只能通过HTTP code 403来判断),配置内容如下:
(4)pwnhub存在隐藏的同级目录,其下的index.php文件可以上传TAR压缩包,且调用了Python脚本自动解压上传的压缩包,同时返回压缩包中文件后缀名为.cfg的文件内容。
(5)通过分析Linux的crontab定时任务,发现存在一个定时任务:
(6)cron_run.sh所执行的是发送邮件的Python脚本,其中泄露了邮箱账号、密码。
(7)通过泄漏的邮箱信息登录,在邮箱中继续发现泄露的VPN账号密码,见图1-3-14。
(8)通过VPN登录内网,发现内网存在一个以Nginx为容器并且可读flag的应用,但是访问该应用会发现只显示Oh Hacked,而没有其他输出。同一IP下其他端口存在一个以Apache为容器的Discuz!X 3.4应用。
图1-3-14
【题目难度】中等。
【知识点】Nginx存在漏洞导致未授权访问目录,进而导致文件读取漏洞;构造存在软链接文件的压缩包,上传压缩包读取文件;Discuz!X 3.4任意文件删除漏洞。
【解题思路】扫描目录发现.DS_Store(MacOS下默认会自动生成的文件,主要作用为记录目录下的文件摆放位置,所以里面会存有文件名等信息),解析.DS_Store文件发现当前目录下的所有目录和文件。
发现upload目录名最后多了一个空格,想到可利用Nginx解析漏洞(CVE-2013-4547)绕过pwnhub目录的权限限制。原理是通过Nginx解析漏洞,让Nginx配置文件中的正则表达式/pwnhub匹配失败,见图1-3-15。
图1-3-15
在/pwnhub目录下存在一个同级目录,其中存在PHP文件。请求该PHP文件,发现存在一个上传表单,见图1-3-16。
图1-3-16
通过该PHP文件上传TAR格式的压缩包文件,发现应用会将上传的压缩包自动解压(tarfile.open),于是可以先在本地通过命令ln-s构造好软链接文件,修改文件名为xxx.cfg,再利用tar命令压缩。上传该TAR压缩包后会将链接指向文件内容进行输出,见图1-3-17。
图1-3-17
读取/etc/crontab发现,在crontab中启动了一个奇怪的定时任务:
读取crontab中调用的sh脚本,发现内部运行了一个Python脚本;接着读取该Python脚本获得泄露的邮箱账号和密码,登录这个邮箱,获取泄露的VPN账号和密码,见图1-3-18。
成功连接VPN后,对VPN所属内网进行扫描,发现部署的Discuz!X 3.4应用和读flag的应用。依据题目简介中所叙述的内容进行猜测,需要删除safe.php才能读到flag,于是利用Discuz!X 3.4任意文件删除漏洞删除safe.php,见图1-3-19。
【总结】①题目流程较长,参赛人员应有清晰的思路。
②除了Nginx因配置内容设置不当导致的目录穿越,其自身也存在历史漏洞可以进行信息泄露。
图1-3-18
通过构造软链接实现文件读取的题目还有很多,如34c3CTF的extract0r,这里不详细介绍,解题思路见图1-3-20。
图1-3-19
图1-3-20
1.3.3.9 Comment(网鼎杯2018线上赛)
【题目简介】开始是个登录页面,见图1-3-21。在题目网站中发现存在.git目录,通过GitHack工具可以还原出程序的源代码,对还原出的源代码进行审计,发现存在二次注入,见图1-3-22。
图1-3-22
图1-3-22
【题目难度】中等。
【知识点】.git目录未删除导致的源码泄露;二次注入(MySQL);通过注入漏洞(load_file)读取文件内容(.bash_history->.DS_Store->flag)。
【解题思路】打开BurpSuite对登录的流量进行抓包,使用BurpSuite自带的Intruder模块爆破密码后3字节,爆破的参数设置见图1-3-23。
图1-3-23
通过git目录泄露还原出应用源代码,通过审计源码发现SQL注入(二次注入),对注入漏洞进行利用,但是发现数据库中没有flag;尝试使用load_file读取/etc/passwd文件内容,成功,则记录用户名www及其workdir:/home/www/;读取/home/www/.bash_history,发现服务器的历史命令:
根据.bash_history文件内容的提示,读取/tmp/.DS_Store,发现并读取flag文件flag_8946e1ff1ee3e40f.php(注意这里需要将load_file结果进行编码,如使用MySQL的hex函数)。
【总结】本题是一个典型的文件读取利用链,在能利用MySQL注入后,需要通过.bash_history泄露更多的目录信息,然后利用搜集到的信息再次读取。
1.3.3.10 方舟计划(CISCN 2017)
【题目简介】题目存在注册、登录的功能。使用管理员账号登录后可上传AVI文件,并且将上传的AVI文件自动转换成MP4文件。
【题目难度】简单。
【知识点】使用内联注释绕过SQL注入WAF;FFMPEG任意文件读取。
【解题思路】遇到存在登录及注册功能并且普通注册用户登录系统后无功能的CTF Web题目时,先尝试注入,通过黑盒测试,发现注册阶段存在INSERT注入漏洞,在深入利用时会发现存在WAF,接着使用内联注释绕过WAF(/*!50001select*/),见图1-3-24。
图1-3-24
通过该注入漏洞继续获取数据,可以得到管理员账号、加密后的密码、加密所用密钥(secret_key),通过AES解密获取明文密码。
利用注入得到的用户名和密码登录管理员账号,发现在管理员页面存在一个视频格式转化的功能,猜测题目的考查内容是FFMPEG的任意文件读取漏洞。
利用已知的exploit脚本生成恶意AVI文件并上传,下载转化后的视频,播放视频可发现能成功读取到文件内容(/etc/passwd),见图1-3-25。
图1-3-25
根据/etc/passwd的文件内容,发现存在名为s0m3b0dy的用户,猜测flag在其用户目录下,即/home/s0m3b0dy/flag(.txt);继续通过FFMPEG文件读取漏洞读取flag,发现成功获得flag,见图1-3-26。
图1-3-26
【总结】①本题使用了一个比较典型的绕过SQL注入WAF的方法(内联注释)。
②本题紧跟热点漏洞,且读文件的效果比较新颖、有趣。FFMPEG任意文件读取漏洞的原理主要是HLS(HTTP Live Streaming)协议支持File协议,导致可以读取文件到视频中。
另一个比较有特色的文件读取呈现效果的比赛是2018年南京邮电大学校赛,题目使用PHP动态生成图片,在利用时可将文件读取漏洞读到的文件内容贴合到图片上,见图1-3-27。
图1-3-27
1.3.3.11 PrintMD(RealWorldCTF 2018线上赛)
【题目简介】题目提供的功能可将在线编辑器Markdown(hackmd)的内容渲染成可打印的形式。渲染方式分为客户端本地渲染、服务端远程渲染。
客户端可以进行本地调试,服务端远程渲染部分的代码如下:
服务端配备Docker环境,并且启动了Docker服务。
flag在服务器上的路径为/flag。
【题目难度】难。
【知识点】JavaScript对象污染;axios SSRF(UNIX Socket)攻击Docker API读取本地文件。
【解题思路】审计客户端被Webpack混淆的代码,找到应用中与服务端通信相关的逻辑,对混淆过的代码进行反混淆。得到的源代码如下:
接着利用HTTP参数污染可以绕过startsWith的限制,同时对req.body.url(服务端)进行对象污染,使服务端axios在请求时被传入socketPath及url等参数。再通过SSRF漏洞攻击Docker API,将/flag拉入Docker容器,调用Docker API读取Docker内文件。
具体的攻击流程如下。
①拉取轻量级镜像docker pull alpine:latest=>:
②创建容器docker create-v/flag:/flagindocker alpine--entrypoint "/bin/sh"--name ctf alpine:latest=>:
启动容器docker start ctf:
读取Docker的文件archive:
【总结】题目考查的点十分细腻、新颖,由于axios不支持File协议,因此需要参赛者利用SSRF控制服务端的其他应用来进行文件读取。
类似axios模块这样可以进行UNIX Socket通信的还有curl组件。
1.3.3.12 粗心的佳佳(PWNHUB)
【题目简介】入口提供了一个Drupal前台,通过搜集信息,发现服务器的23端口开了FTP服务,并且FTP服务存在弱口令,使用弱口令登录FTP后在FTP目录下发现存在Drupal插件源码,并且Drupal插件中存在SQL注入漏洞,同时在内网中存在一台Windows计算机,开启了80端口(Web服务)。
【题目难度】中等。
【知识点】Padding Oracle Attack;Drupal 8.x反序列化漏洞;Windows PHP本地文件包含/读取的特殊利用技巧。
【解题思路】根据题目提示,对FTP登录口令进行暴力破解,发现FTP存在弱口令登录,通过FTP服务可以下载Drupal插件源码。
通过对下载到的插件源码进行审计,发现存在SQL注入漏洞,但是用户的输入需要通过AES-CBC模式解密,才会被代入SQL语句。
通过审计加密的流程,发现可以通过padding oracle attack伪造SQL注入语句的密文,见图1-3-28,继续利用SQL注入漏洞注入得到用户的邮箱和邮箱密码,见图1-3-29。
图1-3-28
图1-3-29
利用注入得到的邮箱信息进行登录,在邮箱中得到泄露的在线文档地址,打开后恢复历史版本,发现admin密码。利用恢复得到的admin密码登录Drupal后台,结合后台的信息判断出Drupal对应的版本,发现存在反序列化漏洞。构造反序列化payload进行Getshell,phpinfo函数的执行结果见图1-3-30。
图1-3-30
Getshell后,对服务器所在的内网进行扫描,发现存在Windows主机并且开启了Web服务,经过简单测试,发现任意文件包含漏洞。
测试文件包含的漏洞会发现存在一定的WAF,即不能输入正常上传的文件名,使用“<”作为文件名通配符绕过WAF,如“123333<.txt”。
【总结】Padding Oracle Attack是Web中常见的Web安全结合密码学的攻击方式,需要熟练掌握,相关细节读者可参考本书第3章第3节。
Windows PHP文件包含/读取可以使用通配符,当我们不知道目录下的文件名或WAF设置了一定的规则进行拦截时,就可以利用通配符的技巧进行文件读取。具体对应正则通配符规则如下:Windows下,“>”相当于正则通配符的“?”,“<”相当于“*”,“"”相当于“.”。
1.3.3.13 教育机构(强网杯2018线上赛)
【题目简介】题目存在一个评论框,评论框支持XML语法,可造成XXE;配置文件中存放着一半flag;内网存在一个Web服务。
【题目难度】中等。
【知识点】利用XXE漏洞读取文件,进行SSRF攻击。
【解题思路】通过对网站应用目录进行扫描,发现网站的.idea/workspace.xml泄露,在workspace.xml的内容中有一段XML调用实体的变量被注释。而题目只有comment一个输入点,于是测试是否存在XXE漏洞(输入XML头部“<?xml version="1.0"encoding="utf-8"?>”,可观察到返回包存在报错),见图1-3-31。
通过相应内容中报错显示的simplexml_load_string函数,基本确认了XXE漏洞的存在,接着尝试构造远程实体调用实现Blind XXE的利用。构造的利用数据如下:
图1-3-31
根据测试XXE是否存在时的报错内容可以发现Web目录位置,利用XXE漏洞读取Web应用的源码,发现在config.php文件中存在着一半的flag内容。
然后在本机寻找另一半flag,以失败告终。猜测另一半的flag内容在内网中,于是依次读取/etc/host、/proc/net/arp,发现存在内网IP:192.168.223.18。
利用XXE漏洞访问192.168.223.18的80端口(也可以进行端口扫描,这里直接猜测常见端口),发现192.168.223.18主机存在Web服务且存在SQL注入。利用盲注注入获得flag的另一半。
【总结】本题考查的是PHP XXE漏洞的文件读取利用方法,不同语言的XML扩展支持的协议可能不同。PHP十分有特色地保留了PHP协议,所以可以用Base64这个Filter编码读取到的文件内容,避免由于“&”“<”等特殊字符截断Blind XXE,导致漏洞利用失败。
1.3.3.14 Magic Tunnel(RealworldCTF 2018线下赛)
【题目简介】使用Django框架搭建Web服务,会使用pycurl去请求用户传入的链接。
请求链接部分的源码如下:
【题目难度】较难。
【知识点】通过SSRF漏洞对uwsgi进行攻击。
【解题思路】通过文件读取漏洞去读取file:///proc/mounts文件,可以看到Docker目录挂载情况,见图1-3-32。
图1-3-32
在成功找到目录后,就可以通过文件读取漏洞读取整个应用的源代码,通过服务器的server.sh文件的内容,可知Web应用使用uwsgi启动(也可以通过读取/proc/self/cmdline获知这些信息)。server.sh文件的内容如下:
通过SSRF漏洞,利用Gopher协议攻击uwsgi(注入SCRIPT_NAME运行恶意Python脚本或直接使用EXEC执行系统命令)。
【总结】本题需要通过File协议进行任意文件读取,完成对服务器的信息搜集,即通过/proc/mounts泄露应用路径,从而获知如何进行下一步的文件读取。
1.3.3.15 Can you find me?(WHUCTF 2019,武汉大学校赛)
【题目简介】题目中存在一处较明显的文件包含漏洞,但是已知信息是flag在相对路径../../flag处,并且在利用文件包含漏洞时发现存在WAF,禁止进行相对路径跳转。
【题目难度】简单。
【知识点】PHP文件包含漏洞。
【解题思路】通过读取Apache配置文件找到Web目录,见图1-3-33。
图1-3-33
已知Web目录后,可直接通过Web目录构造flag文件的绝对路径,绕过相对路径的限制,读取flag,见图1-3-34。
图1-3-34
【总结】这是一道经典的文件读取类型的题目,主要考查参赛者对于Web配置文件信息搜集的能力,需要通过读取Apache配置文件发现Web目录,通过构造绝对路径,绕过相对路径的限制,完成flag文件的读取。