Skip to content

Commit

Permalink
feature: 增加题目「华师币」
Browse files Browse the repository at this point in the history
  • Loading branch information
mypayne committed Dec 9, 2019
1 parent 657a66a commit 2c1bc26
Show file tree
Hide file tree
Showing 6 changed files with 684 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Crypto-影流之主账号丢失/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## 概括

- 出题人:罗裴然
- 出题人:Payne
- 类型:Crypto
- 关键字:SM3、爆破
- Flag:`HSCTF{C00l_Sm3_Cr@cker}`
Expand Down
122 changes: 122 additions & 0 deletions MISC-华师币/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# 欢迎您使用华师币

## 概括

- 出题人:Payne
- 类型:MISC
- 关键字:以太坊、智能合约、Solidity
- Flag:`HSCTF{H@pPy_ETher-Neeetw0rk!}`

## 题目内容

欢迎您使用华师币!国内首创校园实名区块链电子代币~

## 项目结构

- coin.sol: Solidity智能合约源代码
- website/: 网页客户端
- website/abi.js: 智能合约的ABI
- website/app.js: 客户端源代码
- website/index.html: 网页源代码

> 请使用 Remix 编译智能合约, 配置规则:
> - Compiler: 0.4.26
> - EVM Version: byzantium
>
> 或者使用[这个配置好的链接](https://remix.ethereum.org/#optimize=true&evmVersion=byzantium&version=soljson-v0.4.26+commit.4563c3fc.js)
## Writeup

这道题有多种解法,下面分别阐述:

### 分析智能合约法

我们可以阅读客户端的源代码,发现网页客户端使用 `ethers.js`,我们很容易找到 [Ethers.js 的官方文档](https://docs.ethers.io/ethers.js/html/index.html)

然后,我们很容易就发现智能合约的地址,可以写代码提取智能合约的源代码:

```js
provider.getCode(CONTRACT_ADDR).then(v => console.log(v));
```

使用 [https://ethervm.io/decompile](https://ethervm.io/decompile) 分析一波源代码。

找到两个异常的 `PUSH` 指令:

```
02F2 7F PUSH32 0x436165736172214b564657497b4b407353625f48576b68752d51686868777a30
031A 7F PUSH32 0x756e217d00000000000000000000000000000000000000000000000000000000
```

解码:

```javascript
function hex2a(hexx) {
var hex = hexx.toString();//force conversion
var str = '';
for (var i = 0; (i < hex.length && hex.substr(i, 2) !== '00'); i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}
hex2a('436165736172214B564657497B4B407353625F48576B68752D51686868777A30756E217D');
```

输出:

```
"Caesar!KVFWI{K@sSb_HWkhu-Qhhhwz0un!}"
```

根据提示,使用凯撒解密,偏移为3即可解出。

### 自我部署智能合约法

和前面一个方法一样,你可以获取智能合约的源代码,而且也很容易拿到智能合约的ABI。

那么我们只需要做的就是在本地搭建以太坊私网,并部署该智能合约。

使用部署该智能合约的钱包账号,运行 `test()` 函数,获得 `900000` 华师币。

再用 `bugFlag()` 函数购买 Flag,输出:

```
"Caesar!KVFWI{K@sSb_HWkhu-Qhhhwz0un!}"
```

根据提示,使用凯撒解密,偏移为3即可解出。

### 刷邀请-转账法

根据游戏规则,注册新账号可以获得 `500` 华师币。
每邀请一个用户,双方都可以获得 `3000` 华师币。

因此,每个账号价值 `3500` 华师币。
只需要刷 `254` 个账号就可以刷到足够购买 Flag 的华师币。

再购买 Flag,根据提示,使用凯撒解密,偏移为3即可解出。

### 抽奖法【运气】

根据游戏规则,注册新账号可以获得 `500` 华师币。
每邀请一个用户,双方都可以获得 `3000` 华师币。
每一次抽奖需要 `1000` 华师币。

欧洲人可以靠中奖买 Flag。

> 数学期望是负数,因此完全看人品。
### 偷看交易结果【运气】

监控区块链各个区块的交易,直到遇到了「刷邀请-转账法」大佬提交的 `flag` 函数交易,窃取其中的交易响应。

阅读ABI可以轻易发现,里面有一个Flag事件,非常诡异。看上去像是通知Flag的事件。

> 因为我们知道以太坊是靠日志LOG响应结果的。
那么如何监听一个Flag事件,看代码:

```js
contract.on(contract.filters.Flag(null, null), (fromAddress, toAddress, value, event) => {
$('txt-flag').innerText = value.args.flag;
});
```
141 changes: 141 additions & 0 deletions MISC-华师币/coin.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
pragma solidity >=0.4.22;

// SCNU Coin
contract ScnuCoin {

// Account structure
struct Account {
uint studentId;
uint balance;
}

mapping(address => Account) public accounts;
address private owner;

constructor() public {
owner = msg.sender;
}

// Register
function register(uint studentId_) public {
require(
studentId_ != 0,
"Invalid student ID"
);

require(
accounts[msg.sender].studentId == 0,
"You are registered!"
);

accounts[msg.sender].studentId = studentId_;
accounts[msg.sender].balance = 500;
}

function registerWithInvitor(uint studentId_, address invitor_) public {
require(
studentId_ != 0,
"Invalid student ID"
);

require(
accounts[msg.sender].studentId == 0,
"You are registered!"
);

require(
accounts[invitor_].studentId != 0,
"Invitor does not exist!"
);


accounts[invitor_].balance += 3000;
uint balance_ = 3000;

accounts[msg.sender].studentId = studentId_;
accounts[msg.sender].balance = balance_ + 500;
}

// Transfer
function transfer(address to_, uint value) public {
require(
accounts[to_].studentId != 0,
"The target account does not exist!"
);
require(
accounts[msg.sender].balance >= value,
"You have not enough money!"
);

accounts[msg.sender].balance -= value;
accounts[to_].balance += value;
}

// Donate
function donate(uint value) public {
require(
accounts[msg.sender].balance >= value,
"You have not enough money!"
);

accounts[msg.sender].balance -= value;
}


function random() private view returns (uint) {
return uint(keccak256(block.timestamp, block.difficulty))%251;
}

// Lucky gacha
function gacha() public returns(uint) {
require(
accounts[msg.sender].balance >= 1000,
"You have not enough money to buy gacha!"
);

accounts[msg.sender].balance -= 1000;

uint res = random() % 100;
uint win = 0;
if (res == 0) {
win = 8888;
} else if (res <= 5) {
win = 2333;
} else if (res <= 15) {
win = 1688;
} else if (res <= 30) {
win = 1000;
}

accounts[msg.sender].balance += win;

return win;
}

// Test
function test() public {
require(
owner == msg.sender,
"You are not the owner!"
);

accounts[msg.sender].balance += 900000;
}

event Flag (address indexed buyer, string flag);

// Buy flag
function buyFlag() public {
require(
accounts[msg.sender].balance > 888888,
"You must pay 888888 HSC"
);

accounts[msg.sender].balance -= 888888;

// flag: HSCTF{H@pPy_ETher-Neeetw0rk!}
// https://www.qqxiuzi.cn/bianma/kaisamima.php
// param: 3
emit Flag(msg.sender, "Caesar!KVFWI{K@sSb_HWkhu-Qhhhwz0un!}");
}
}
Loading

0 comments on commit 2c1bc26

Please sign in to comment.