flag11
flag11是一个抽奖,抽奖的算法在题目中已经给出,所以可以使用python写一个计算脚本。通过获取blockHash,计算出特定的中奖号码和抽奖人数
import requests
import json
while True:
block_number = input("请输入 blockNumber: ")
if block_number == "q":
break
user_count_threshold = int(input("请输入 threshold: "))
url_block = 'https://api.upowerchain.com/apis/v1alpha1/block/get'
headers = {'Content-type': 'application/json'}
data_block = f'{{"number":"{block_number}"}}'
response = requests.post(url_block, headers=headers, data=data_block, verify=False)
try:
block_hash = response.json()['data']['blockHash']
print(f"获取的 blockNumber: {block_number}")
print(f"获取的 blockHash: {block_hash}")
found = 0
block_hash_int = int(block_hash, 16)
user_count = 10000
found = 0
while found < 3:
user_index = block_hash_int % user_count
if user_index > user_count_threshold:
print(f"找到第{found+1}个解:当 userCount = {user_count} 时,userIndex = {user_index} > {user_count_threshold}")
found += 1
user_count += 1
except KeyError:
print("未能正确获取 blockHash,检查 blockNumber 是否有效")
except requests.exceptions.RequestException as e:
print(f"请求错误: {e}")
然后再将网页修改一下,添加一个批量提交的按钮,输入中奖号码和总人数,程序会将自动提交,非中奖号码时在uid前补0。提交时就需要一些运气了,毕竟都在提交,会干扰。所以尽量卡在0时提交完毕,或者少提交几个。
<div class="join">
<p>免费抽奖!绝对公平公正!</p>
<p>抽奖奖品:一个 flag</p>
<p class="timer"></p>
<p>
UID: <input type="text" name="uid">
<button type="submit">参加抽奖</button>
</p>
<!-- 新增自动填充区域 -->
<hr>
<h2>自动填充抽奖入口(批量提交)</h2>
<p>
目标总参与数 (包含9980个机器人):<br>
<input type="number" id="usercount" placeholder="输入总参与数"><br><br>
命中序号 (当参与序号等于此数时使用固定 uid):<br>
<input type="number" id="winningIndex" placeholder="输入命中序号"><br><br>
<button id="autoSubmitButton">开始自动提交</button>
</p>
</div>
let joinCount = 1;
let lastJoinIndex = 0;
let timestamp;
let lastTimestampUpdate = Math.floor(Date.now() / 1000);
let lastVerifyCode = '';
function randomUID() {
return "0".repeat(joinCount) + "212618";
}
function getTimestamp() {
const currentTimestamp = Math.floor(Date.now() / 1000);
if (currentTimestamp - lastTimestampUpdate >= 60) {
lastTimestampUpdate = currentTimestamp;
timestamp = currentTimestamp;
lastVerifyCode = getVerifyCode(`${timestamp}|`);
}
return timestamp;
}
function submitJoin(targetUserCount, targetWinningIndex) {
const expectedJoinIndex = lastJoinIndex + 1;
let uidToSubmit = (expectedJoinIndex === targetWinningIndex) ? "212618" : randomUID();
const reqTimestamp = getTimestamp();
const req = {
timestamp: reqTimestamp,
uid: uidToSubmit,
verify_code: lastVerifyCode
};
fetch('/api/lottery/join', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(req),
})
.then(res => res.json())
.then(res => {
if (res.code === 0) {
lastJoinIndex = res.data.user_index;
console.log(`参与成功:序号 #${lastJoinIndex}, UID: ${uidToSubmit}`);
if(uidToSubmit=="212618")
alert("已提交uid,等待后续提交");
joinCount++;
if (lastJoinIndex < targetUserCount) {
setTimeout(() => submitJoin(targetUserCount, targetWinningIndex), 100);
} else {
alert("所有提交完成,已达到目标总参与数:" + targetUserCount);
}
} else {
alert("提交失败:" + res.msg);
}
})
.catch(err => console.error(err));
}
document.getElementById('autoSubmitButton').addEventListener('click', function(){
const targetUserCount = parseInt(document.getElementById('usercount').value);
const targetWinningIndex = parseInt(document.getElementById('winningIndex').value);
if (isNaN(targetUserCount) || isNaN(targetWinningIndex)) {
alert("请输入有效的数字!");
return;
}
lastJoinIndex = 0;
timestamp = Math.floor(Date.now() / 1000);
lastTimestampUpdate = timestamp;
lastVerifyCode = getVerifyCode(`${timestamp}|`);
submitJoin(targetUserCount, targetWinningIndex);
});
flag10
flag10的内容在抽奖页的源代码中有提示,具体的函数时在wasm中导出,calc_flag10_uid_timestamp_resultbufptr_resultbuflen_return_resultlen
函数名写的十分清晰,所以直接写一个调用就可以了
WebAssembly.instantiateStreaming(fetch('get_verify_code.wasm'))
.then(({ instance }) => {
const exports = instance.exports;
const memory = new Uint8Array(exports.memory.buffer);
const calcFlag10 = exports.calc_flag10_uid_timestamp_resultbufptr_resultbuflen_return_resultlen;
const bufferPtr = 16;
const bufferSize = 64;
const resultBuffer = new Uint8Array(memory.buffer, bufferPtr, bufferSize);
const uid = 212618;
const timestamp = 1738934615;
const resultLen = calcFlag10(uid, timestamp, bufferPtr, bufferSize);
const flag10 = new TextDecoder().decode(resultBuffer.subarray(0, resultLen));
console.log("flag10:", flag10);
});
flag9
题目说需要用到ai和web,既然10-11是web了,那么这题一定是ai,猜想是从ai口中套出flag9。
不过在对话之前,需要将验证码计算函数替换掉,抽奖页面会告诉你这个 getVerifyCode 的 wasm 实现比 blueimp-md5 js 实现快 20 倍。
可以直接在控制台输入抽奖页面那段调用wasm的代码来重载,然后就可以开始对话啦。
WebAssembly.instantiateStreaming(fetch('get_verify_code.wasm')).then(({instance}) => {
window.getVerifyCode = (prefix) => {
console.log('prefix:', prefix);
const startTime = Date.now();
const memory = new Uint8Array(instance.exports.memory.buffer);
const prefixBufPtr = 16;
const prefixBufLen = ((new TextEncoder()).encodeInto(prefix, memory.subarray(prefixBufPtr))).written;
const resultBufPtr = 0;
const resultBufLen = 16;
const resultLen = instance.exports.get_verify_code(prefixBufPtr, prefixBufLen, resultBufPtr, resultBufLen);
const code = (new TextDecoder()).decode(memory.subarray(resultBufPtr, resultBufPtr + resultLen));
console.log(`solved: ${prefix + code} ${(Date.now() - startTime) / 1000}s`);
return code;
};
});
我也是试了好多,最后使用这两句获得了flag