ctf之php反序列化字符串数组逃逸(转自最详细的大佬)2021-9-9

[0CTF 2016]piapiapia WP(详细)



1.打开网站,是个登录框,尝试注入无果.....按道理来说就是注入了啊喂

在这里插入图片描述

2.玄学时间到:::

      目录扫完啥结果没有。在buuctf做题总是这样,御剑线程开1,不管有没有压缩文件,统统扫不到- -但是可以扫出来普通的php文件,dirsearch要加延迟和调线程,不然都是429,可以扫到压缩文件,但是普通的php文件扫不到= =。
在这里插入图片描述
在这里插入图片描述

3.首先御剑发现个注册页面,注册上去看到个上传,测试多次无果。

在这里插入图片描述

4.打开源码
      只有几个php文件,还好,先看config.php敏感文件,看到了flag,后面可能会用到config.php:

在这里插入图片描述

5.然后依次打开其他几个文件,看看有没有什么敏感函数,发现了三处:

profile.php有两处:
unserialize和file_get_contents。
在这里插入图片描述
update.php的serialize在这里插入图片描述

6.反序列化也是为危险函数做贡献的
      所以我们的注意点就在file_get_contents上,应该是让我们通过这个函数去请求config.php文件。看一下参数怎么传过来的:

      1)在profile.php里,它是$profile数组里键名为photo的键值
在这里插入图片描述
      2)$profile又是通过$user的show_profile函数传过来的,而且传过去了$username参数:
在这里插入图片描述
      3)跟进去class.php下,user类里面:在这里插入图片描述
      4)user类继承了mysql类,这里先调用了父类的filter函数。
这里是替换字符串中的单引号和反斜杠为下划线 ,并且替换多个字符串为hacker。
implode函数是表示把数组拼接起来,拼接符是 “|”:
在这里插入图片描述
      5)然后show_profile里面又调用了父类的select函数:在这里插入图片描述
      6)可以看到数据是从表里取出来的,那就要看什么时候插入数据了,全文搜索insert或者update,在select函数的下面找到:
在这里插入图片描述
      7)那现在就看哪里调用了这个函数,还是在这个class.php文件里,找到了调用,在这里做了同样的过滤才更新数据:
在这里插入图片描述
      8)继续找update_profile函数的调用,在update.php文件里找到:
在这里插入图片描述
      9)可以看到这里对$profile进行了赋值,值是通过post传过来的。
调用链反过来看是这样:

profile.php的file_get_contents =》 show_profile() =》 class.php里的select() =》 数据库 =》 class.php里的update() =》 update_profile() =》 update.php里调用传参。

7.从前往后看参数传递

      整个调用链反过来推清楚了。那现在我们从前往后,绕过诸多限制进行攻击。先看update.php文件里面的photo参数。
在这里插入图片描述
判断了photo的大小,然后对它进行了md5哈希???那我们就不能直接传了啊。那现在怎么办呢?

8.我们盯上了它的前一个参数——nickname参数:

这里就要利用到序列化的拼接+伪造,对nickname参数攻击,比如该序列化字符串:

a:3:{s:4:"dddd";s:6:"ddddhm";}

   
   
   
   
  • 1

我们在dddd的地方输入 dddd";s:10:“buhaobuhao”;} 就变成了:

a:3:{s:25:"dddd";s:10:"buhaobuhao";}";s:6:"ddddhm";}

   
   
   
   
  • 1

但是相应的,dddd前面的字符串长度也变了,变成25了,所以这里会报错。我们就要想办法把dddd变成25位长度,还差21位。

在这个题目里,回想一下,之前的mysql类里面有个filter()函数对参数值进行了处理替换:
在这里插入图片描述
可以看到,insert\select\update\delete都是6位长度,hacker也是6位长度,where是5位长度,而且执行的是替换操作。那么我们岂不是可以通过替换操作,把原本5位长度的where,替换成了6位的hacker?

那这样我们就变长了一位,而且preg_replace函数默认是替换所有的。那么我们差几位,就输入几个where不就好了吗?这个概念搞明白了就继续按流程来:

9.还是在update.php里面:

在这里插入图片描述
这里先对它进行了正则,这个正则的意思是匹配除了a-zA-Z0-9_之外的字符,因为 “^” 符号是在 “[]” 里面,所以是非的意思,不是开始的意思。

然后 “||” 后面判断了它的长度是否大于10。

这两个判断的绕过就要引出神奇的数组了,这里我牵了张表:

md5(Array()) = null
sha1(Array()) = null
ereg(pattern,Array()) =null
preg_match(pattern,Array()) = false
strcmp(Array(), “abc”) =null
strpos(Array(),“abc”) = null
strlen(Array()) = null

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

所以我们传入数组,就能绕过。

10.后面基本上是没啥大的限制了,比如我们输入的是:
nickname[]=where";}s:5:"photo";s:10:"config.php";}

   
   
   
   
  • 1

(为什么s:5:"photo…前面多了个 “}” 符号,我们上面的分析本来应该是没有的。

因为我们构造传入的nickname是数组。为什么是数组就要加一个“}”呢?看下面的示例:)
在这里插入图片描述
【这样就非常清晰明了了吧,这时候我们闭合的情况就是按照第一条来,不是上面分析的那个了。】

11.payload构造
      这个时候,我们的nickname[]数组实际长度是39位,除了where,多出来了34位。这个时候strlen('where') == 5 != 39,不是指定的长度会报错,所以我们要想办法把where那块地方,在序列化之后(注意时间点)再增长34位。

之前不是说过吗,我们的where变成hacker之后,从5变成了6,成功增长了一位,那么我们输入34个where,不就可以增长34位了吗?

所以最后的payload:
wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}

   
   
   
   
  • 1
12.实际利用
      1)进入register.php页面,随便输入账号密码注册:

在这里插入图片描述
      2)然后用这个账号登录,发现到了注入的页面,在nickname位置输入payload抓包,记得把nickname改成nickname[] 数组:
在这里插入图片描述
      3)然后点超链接到profile.php,看源代码找到image里面的base64字符串(因为之前分析file_get_contents的时候,它的外面还有一层base64_encode,而且它是photo参数,就是图片)
在这里插入图片描述

      4)拿去解码得到flag:
<br在这里插入图片描述




总结:以前的审计题目可没有这么多文件,这么多内容,这次整理清楚弄了点时间,不过做完以后还是挺爽的。而且这次的题目又涉及到了好几个知识点,学到很多。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值