Dest0g3招新赛 ETH方向writeup

d0g3战队给学弟学妹引荐了一下,我这就捎带看了看eth题目,顺手a了下misc,写下eth的wp吧,misc太多了懒得写((

Where the flag?

先看合约代码

contract find{
    uint96 private a=7855;
    address private owner=msg.sender;
    bool private f=false;
    bool private t=true;
    string[] private flag=[flag1,flag2];
}

直接把flag两端写在变量定义处了,也就是说直接去合约的地址是可以看见flag明文的。

QQ截图20220526221737.png

 

eazy_predict

先看合约代码

 

contract storageplace{
     mapping(uint=>string)private _flag;
     address owner;
     constructor()public{     
     owner=msg.sender;
    }
    function flag() public view returns(string memory)
    {
        require(msg.sender==owner);
    }
    function buy(uint number) public returns(bytes1){
        require(msg.sender==owner);
    }
}

contract question{
    
    mapping(address=>bool)public regeister;
    
    mapping(address=>uint)private seed;
    
    uint constant Price_Per_Char=10 ether;
    
    address owner;
    
    storageplace immutable Flag;

    constructor() public {
        owner=msg.sender;
        
        storageplace _Flag = new storageplace();
        
        Flag = _Flag;
    }
    
    modifier isowner(){
        require(msg.sender==owner,"I think you are not the rignt person");
        _;
    }
    
    function addRight(address tar)public isowner{
         regeister[tar]=true;
    }
    
    function removeRight(address tar)public isowner{
         regeister[tar]=false;
    }
    
    function regeist() public {
        require(regeister[msg.sender]==false);
        regeister[msg.sender]=true;
        seed[msg.sender]=block.number+1;
    }
    
    function buyflag(uint want) public payable returns(bytes1){
        require(msg.value==Price_Per_Char,"is not free");
        return Flag.buy(want);
    }
    
    function query(bytes32 answer) public view returns(string memory)
    {
        require(regeister[msg.sender]);
        require(block.number >seed[msg.sender],"too early");
        bytes32 result = blockhash(seed[msg.sender]);
        require(answer==result,"wrong answer");
        return Flag.flag();
    }
    
    function withdraw() public payable{
        require(msg.sender==owner);
        msg.sender.transfer(address(this).balance);
    }

}


简单过一遍,首先regist注册用户,然后进行buyflag,不过一次就要10eth,非常贵了,最后在query处进行获得最终flag,注意到这里的flag被定义了一个immutable,里面是存在一些方法的,所以在题目合约地址的hex处看见flag。

当然,如果正常解的话,我这里技艺不精了,但是我感觉还是在伪随机数这个地方,重点应该还是在query处吧,等官方wp在学习学习。

Common found

多少有点偏密码了属于是,先看合约。

pragma solidity ^0.8.9;


contract turn {

    string private flag;
    address private owner;

    constructor(string memory _flag) {
        flag = _flag;
        owner = msg.sender;
    }

    function random() private view returns (uint) {
        return uint(
            keccak256(
                abi.encodePacked(
                    block.difficulty, 
                    block.timestamp,
                    msg.sender,
                    block.coinbase))
                    );        
    }

    function calculate() public payable returns (bytes1) {
        require(msg.value >= 5 ether);
        bytes memory _flag = bytes(flag);
        bytes1 entropy = bytes1(uint8(random() % _flag.length));
        return _flag[uint8(entropy)] ^ bytes1(keccak256(abi.encode(entropy)));
    }

    function withdraw(address payable receipt) public payable {
        require (msg.sender == owner);
        receipt.transfer(address(this).balance);
    }

    receive() payable external{}
}

https://ropsten.etherscan.io/tx/0xda1f22f9146a50c51973b89ef927eb74540f873e117bfbbb58e65c281b38982f

重点是他每次异或是随机地址异或,也就是说位置随机,但是注意到他的flag明文是可以直接在合约地址中取出的,也就是说只要先把后面keccak256的全部值计算出来,与他给的flag异或即可。

写一下脚本,不太能直接用solidity直接写脚本异或,就先把需要异或的内容算出来,最后用python写个脚本就行了。

pragma solidity ^0.8.9;


contract turn {

    string private flag = "6dd433b6ba64c5ddb75e9972efba88d26f598a08890aacf6eeff36097e322790bb5e548a3f741aecbead8e641a2e4a";
    address private owner;


    function random() private view returns (uint) {
        return uint(
            keccak256(
                abi.encodePacked(
                    block.difficulty, 
                    block.timestamp,
                    msg.sender,
                    block.coinbase))
                    );        
    }

    function calculate() public view returns ( bytes1[94] memory) {
        bytes1[94] memory val;
        uint256 entropy1;
        for(uint8 i = 0; i < 94; i++){
            entropy1 = uint256(i);
            val[i] = bytes1(keccak256(abi.encode(entropy1)));
        }
        return val;
    }

    receive() payable external{}
}

剩余内容:

b = [0x29,0xb1,0x40,0xc2,0x8a,0x03,0xf6,0xa6,0xf3,0x6e,0xc6,0x01,0xdf,0xd7,0xbb,0x8d,0x1b,0x31,0xbb,0x66,0xce,0x55,0xd8,0xc6,0xb1,0x94,0x05,0x3a,0x0e,0x6d,0x50,0xa0,0xc9,0x3a,0x61,0xd5,0x7c,0x40,0x74,0x98,0xe1,0xcb,0xbe,0x11,0x74,0x4a,0x37,0xa8,0x6f,0xc5,0x11,0x82,0x46,0xcf,0x4a,0x42,0x38,0xdc,0xa2,0xbb,0xc6,0xec,0x8d,0xc0,0x35,0x7c,0x38,0x96,0x9b,0xa8,0x12,0xc4,0x15,0x37,0xfc,0x17,0x42,0x1b,0x9b,0xa2,0x55,0x99,0xa9,0x4c,0xf0,0x71,0xea,0xe8,0x65,0xd7,0xe8,0xfc,0xec,0x26]
flag = [0x6d,0xd4,0x33,0xb6,0xba,0x64,0xc5,0xdd,0xb7,0x5e,0x99,0x72,0xef,0xba,0x88,0xd2,0x6f,0x59,0x8a,0x08,0x89,0x0a,0xac,0xf6,0xee,0xff,0x36,0x09,0x7e,0x32,0x27,0x90,0xbb,0x5e,0x54,0x8a,0x3f,0x74,0x1a,0xec,0xbe,0xad,0x8e,0x64,0x1a,0x2e,0x4a]

for i in range(len(flag)):
    print(chr(flag[i] ^ b[i]), end='')

有个坑点,他输入的flag内容直接是hex值,,不需要二次hex,这里倒是卡了好久。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 共1条
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情
    • 头像0XFF0