[0CTF 2016]piapiapia之愚见

今天在buuctf上尝试了一下[0CTF 2016]piapiapia之愚见这个题目,点进去之后是登录界面和一张猫的动图,进行了爆破和简单的注入尝试,扫描了一下目录,一无所获。

在网上看了看大佬的wp,发现有www.zip源码泄露(个人认为严格意义上不算泄露),不同扫描器内的字典也不一样,据说能在本题中扫描出来的有dirmap、dirsearch、nikto,我偷懒直接将源码下载下来进行审计。

代码量并不大,比较友好,按照所学,先看config.php,再是class.php,


config.php

我们要有一个意识:这是我们下载下来的源码,并非真正的服务端运行的源码,本地搭建做题环境时要改成自己的用户名、密码之类,在服务端docker的主机里,$flag变量应该存的就是我们要的flag。

继续审计代码,我们可以发现在class.php中有本题关键的两个类和相关函数,其中的函数写的较为全面(增改查都涉及)、认真(变量有单引号保护且过滤了单引号和一些关键词),若想注入恐怕需要费点功夫,其余的php文件亮点不多、比较平常,但还有三个点需要注意:

一是update.php里有一个序列化操作,与之对应的有一个反序列化操作,在注入可能不好用的情况下,这很有可能是本题的关键;


update.php 此处的serialize($profile)将会存入数据库


profile.php 此处从数据库中取出序列化的$profile

二是update.php里对传入的变量做了简单的检查,


这里比较有意思的是,前两个是没有按相应规则匹配到文本则执行die()函数,也就是说无论preg_match()返回值为0或null或false皆会die出,而第三个检查则不是这样,是如果匹配到非字母数字或nickname长度大于10则die出,这里我们就可以操作了,控制nickname为一个数组,这样的话两个判断条件为false或NULL,故不会die出。



可以想象这是出题人故意设计的,否则为什么不接着前两个if判断的格式写。由此看来,nickname为我们可以较为完全的控制、利用的变量。

三是有profile.php的功能是展示文件,说是展示,实为读取,


刚才我们在config.php里想到要读取服务端上config.php的源码,而这里是整个题目里唯一的可以读取文件的点。

现在我们有个大体思路了,update.php中有一个$profile数组变量,这个数组里有$phone, $email, $nickname, $photo几个变量,序列化后以profile字段存入数据库,而我们如果能控制photo变量为"config.php",则能在访问profile.php时获得base64编码之后的config.php源码。

下面问题来了,怎么控制$photo?


update.php中的文件上传为$photo变量唯一的来源,无法实际利用,到了这里如果不知道本题想考的知识点——PHP序列化长度变化导致字符逃逸,我们就可以放弃了。

阅读了诸位大佬的wp后(没办法,太菜了),再经过动手实践,我对这个知识点有了一定的理解,和大家分享一下。

大佬说:看过PHP的底层代码后,发现PHP反序列化中值的字符读取多少其实是由表示长度的数字控制的,而且只要整个字符串的前一部分能够成功反序列化,这个字符串后面剩下的一部分将会被丢弃,举个例子:





这样很正常,下面我们引出知识点。



我们可以看到,原来的字符串Northind内被填充了几个字符串,先是 """ 三个双引号,再是正常结尾时需要有的 ";} 三个字符,在PHP进行反序列化时,由字符串初始位置向后读取8个字符,即使遇到字符串分解符单双引号也会继续向下读,此处读取到 North""" ,而后遇到了正常的结束符,达成了正常反序列化的条件,反序列化结束,后面的 ind";}  几个字符均被丢弃。

借用大佬的一个例子(https://www.cnblogs.com/litlife/p/11690918.html),简单分享一下这个知识点的应用



这里的username我们可控,bad_str函数会把反序列化后的字符串中的单引号替换“no”,我们做个分析,尝试着修改该用户的签名,用到的当然是本题的知识点,


我们要记住一点,我们的字符串是在某变量被反序列化得到的字符串受某函数的所谓过滤处理后得到的,而且经过处理之后,字符串的某一部分会加长,但描述其长度的数字没有改变(该数字由反序列化时变量的属性决定),就有可能导致PHP在按该数字读取相应长度字符串后,本来属于该字符串的内容逃逸出了该字符串的管辖范围,轻则反序列化失败,重则自成一家成为一个独立于原字符串的变量,若是这个独立出来的变量末尾是个 ";} ,则可能会导致反序列化成功结束,后面的内容也就被丢弃了。此处能逃逸的字符串的长度由经过滤后字符串增加的长度决定,如上图第四个语句,@号内就是我们要逃逸出来的字符串,长度为33,百分号内为我们输入的username变量,要想让@号内的字符串逃逸,就需要原来的字符串增长33,这样的话@号内的字符串被挤出,username的正常部分和增长的部分正好被PHP解析为一整个变量,@号内的内容就被解析为一个独立的变量,而且因为它的最后有 ";} ,使反序列化成功结束。

为了增长33,我们需要username里加入33个单引号,它们会被替换为33个no,使长度增加33,由此以来,上图中x的值也可以确定了,输入的username即为Northind'''''''''''''''''''''''''''''''''";i:1;s:18:"Today is Northind!";},x为它的长度(74),所以我们最后得到的字符串为:

a:2:{i:0;s:74:"Northind'''''''''''''''''''''''''''''''''"(注意最后这里是个双引号);i:1;s:18:"Today is Northind!";};i:1;s:15:"Today is Mondy!";}



我们可以看到,在这个反序列化字符串被过滤后,里面的单引号全部被替换为“no”,使"Northind"+"no"*33的长度之和等于74,配合上我们传入的",满足PHP反序列化的条件之一,后面的";i:1;s:18:"Today is Northind!";}先闭合了一个变量的正确格式,又写入了一个变量正确格式,最后闭合了一个反序列化操作。该挤出的被挤出逃逸了,该丢弃的丢弃了,任务也完毕了。这是我们的分析,接下来实际传个username变量进去看看,


可以发现,成功修改了签名。

下面回到piapiapia这个题,既然要用到反序列化长度逃逸,必然是先把变量序列化,然后进行过滤,在过滤的过程中把某个关键词替换成了长度更长的关键词,导致长度加长,最终引起逃逸,而在class.php中,我们可以看到:


我们只有传入的字符串中有'where'关键字,被替换为'hacker'关键字,才会让长度加一,否则长度不变。在这里眼尖的大佬直接就看出端倪了,而我水平着实有限,不读读大佬的博客是真看不出来。

下面我们来分析piapiapia这个题应该怎样构造字符串,

经过本地调试,我们可以知道,正常情况下,原始的$profile字符串为 (此处已经将nickname以数组类型传参):

a:4:{s:5:"phone";s:11:"66666666666";s:5:"email";s:10:"111@qq.com";s:8:"nickname";a:1:{i:0;s:5:"kendo";}s:5:"photo";s:39:"upload/f3ccdd27d2000e3f9255a7e3e2c48800";}

因为我们想把photo改为config.php,我们目的字符串的前身可知矣(为了看着方便还是把可控部分的双引号改为%):

a:4:{s:5:"phone";s:11:"66666666666";s:5:"email";s:10:"111@qq.com";s:8:"nickname";a:1:{i:0;s:5:%kendo";}s:5:"photo";s:10:"config.php";}%;}s:5:"photo";s:39:"upload/f3ccdd27d2000e3f9255a7e3e2c48800";}

我们要逃逸的部分为";}s:5:"photo";s:10:"config.php";},长度为34,需要在nickname[0]里添加34个where才能被成功逃逸。

我们可以构造构造,并在本地试着反序列化看看能否输出有效信息,


所以我们的目标字符串为:

a:4:{s:5:"phone";s:11:"66666666666";s:5:"email";s:10:"111@qq.com";s:8:%nickname";a:1:{i:0;s:204:"34个where";}s:5:"photo";s:10:"config.php";}%;}s:5:"photo";s:39:"upload/f3ccdd27d2000e3f9255a7e3e2c48800";}

为了方便好看还是将可控部分的双引号改为%,

然后简单的复制了profile的代码和filter函数,建了个PHP文件,



输出中有base64编码的内容,解码即为config.php

结果看来,已经可以成功读取本地的config.php,接下来的内容不难,在docker上访问register.php,注册用户,在update.php里输入一定的字符,抓包,


将nickname那里改为nickname[],(根据直觉这么改就能传数组,实际也确实是这样),再将他的值改为我们构造的字符串中%内部分,



页面有warning是因为我们的nickname为数组类型,但无伤大雅,访问profile.php,查看源代码,



将这个内容base64解码,就能读取服务端的config.php,得到flag。

几点心得体会:

1.扫描器之间也有些差别,有的扫描器确实是扫不出来,这就让我们不得不多备一两个扫描器;

2.还是要多动手,多去实践才能弄懂;

3.先发散找思路,再缩小范围,最后去尝试;

4.我对PHP底层的东西的了解为0,日后有机会一定要多多了解。

大胆应无惧,雄心誓不回

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容

  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,746评论 0 10
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,320评论 0 9
  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,383评论 0 5
  • 常用模块 认识模块 什么是模块 什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文...
    go以恒阅读 1,953评论 0 6
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,424评论 0 17