Level1
代码逻辑
- 地图:颜色,不同元素类型(豆子和墙壁)
- 按键:省略
-
关键函数/代码
“”POST””
肯定有数据交互,所以搜“”POST””,没有就搜“POST”,可以定位到发包处。
看看发包的数据结构和内容,如果对渗透比较熟的,可以自己用“BurpSuit”构建一个假包发过去。“success”
可以定位到逻辑成功处,看看能不能强跳过来——当然,如果要和服务器交互,过不了服务器的验证,强跳是假跳。
关键函数completedLevel
function completedLevel() {
fetch("/games/pacman/api/1", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "same-origin",
body: JSON.stringify({ action: `${eaten}`, _csrf: $("#csrf").val() })
})
.then((resp) => resp.json())
.then(function (data) {
if (data.success)
window.location.href =
"/games/pacman/level/2?mode_easy=5a6d46736332553d&code=7";
else alert(data.data);
});
setState(WAITING);
level += 1;
map.reset();
user.newLevel();
startLevel();
}
解构completedLevel()函数逻辑
给“/games/pacman/api/1”发送“POST”包
- “Content-Type”类型是json
- “credentials”认证和当前一样
- “body”内容是json字符串
- “
eaten = null
”4个- “
eaten === null
”1个 - “
eaten !== null
”1个
- “
- “
eaten = 0
”1个,处于“newLevel()
”函数中,重新赋值 - “
eaten = game.getTick()
”1个,处于“eat()
”函数中 - “
**eaten += 1**
” - “
**eaten === 182**
”
调用completedLevel()
函数的逻辑如下:
if (
((isMidSquare(position.y) || isMidSquare(position.x)) &&
block === Pacman.BISCUIT) ||
block === Pacman.PILL
) {
map.setBlock(nextWhole, Pacman.EMPTY);
addScore(block === Pacman.BISCUIT ? 10 : 50);
eaten += 1;
if (eaten === 182) {
game.completedLevel();
}
if (block === Pacman.PILL) {
game.eatenPill();
}
}
所以,发送的值必然为182。修改代码如下:
eaten += 1;
改为
eaten += 182;
HTTP包
除正确调用之外,还有我之前比较擅长,现在没有工具就和废了一样的伪造虚假包,已经可以看到报文内容了,还是很简单的明文,构造完发过去即可。
详见下文~
Level2
关键代码/函数
function completedLevel() {
fetch("/games/pacman/api/2", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "same-origin",
body: JSON.stringify({
action: `hacked${hacked}`,
_csrf: $("#csrf").val(),
}),
})
.then((resp) => resp.json())
.then(function (data) {
if (data.success) window.location.href = "/games/pacman/level/3";
else alert(data.data);
});
setState(WAITING);
level += 1;
map.reset();
user.newLevel();
startLevel();
}
解构completedLevel()函数逻辑
……省略……
“body”内容是json字符串
- action:
hacked${hacked}
, -
hacked${hacked}
hacked的值为:
var hacked = url.searchParams.get("mode_easy") == "64484a315a513d3d";
检查URL的参数“mode_easy”值是否为“64484a315a513d3d”。
“==
”相等条件对比,结果只有true
或者false
,根据文字的意思,选true
。
至此,发包的逻辑捋顺了,那么接下来的问题就是如何调用发包的函数completedLevel()
。调用completedLevel()
调用处
搜索“
completedLevel()
”,定位到:if ( ((isMidSquare(position.y) || isMidSquare(position.x)) && block === Pacman.BISCUIT) || block === Pacman.PILL ) { map.setBlock(nextWhole, Pacman.EMPTY); addScore(block === Pacman.BISCUIT ? 10 : 50); eaten += 1; if (eaten === 182) { game.completedLevel(); } if (block === Pacman.PILL) { game.eatenPill(); } }
调用逻辑为“
eaten
”变量为182,可以把每次得分直接从得1分改为得182分:eaten += 1; 改为 eaten += 182;
或者无所谓得分,直接
if(1)
,恒成立:if (1) { game.completedLevel(); }
同理还有把“
eaten
”成立的对应数字改成1,改分方式不多赘述:if (eaten === 1) { game.completedLevel(); }
action&hacked
将“
hacked
”改为true
:var hacked = true
或者发包代码改为:
action: `hacked${true}`, 或者 action: `hackedtrue`,
或者发包内容改为:
action: "hackedtrue",
虚假包
关键payload
action: "hackedtrue"
返回包
Level3
代码逻辑
使发包逻辑成立
1. addScore(简单)
function addScore(nScore) { score += 6666;// 大于5000的值 if (score >= 10000 && score - nScore < 10000) { lives += 1; }
2. 修改发包逻辑(麻烦一点)
成立条件“
if (score > 5000)
”改为恒成立的“if (1)
”。
但是有个值“action:
storage${pAcman}`”的“
pAcman`”不知道是没获取到还是没运行到,定位其赋值代码:setInterval(function () { if (sessionStorage.getItem("scorePerCherry") > 0) { window.pAcman = 20; } }, 1000);
不过既然知道“pAcman = 20”,分数要大于5000,那么修改代码如下:
if (1) fetch("/games/pacman/api/3", { method: "POST", headers: { "Content-Type": "application/json", }, credentials: "same-origin", body: JSON.stringify({ action: `storage${20}`, score: 6666,
HTTP包
发包
返回包
Level4
代码逻辑
发包代码
if ( md5(userPos.y + "mario") == "5fd3e45cc1044dfe5d5357789968e086" && (md5(userPos.x + "mario") == "8f33eb149d3653873f1be1c66fa46979" || md5(userPos.x + "mario") == "16342dc95b0fce33753a273e0ab598e6") ) { fetch("/games/pacman/api/4", { method: "POST", headers: { "Content-Type": "application/json", }, credentials: "same-origin", body: JSON.stringify({ action: `maze`, score: moveByXy, // _csrf: $("#csrf").val(), }), }) .then((resp) => resp.json()) .then(function (data) { if (data.success) window.location.href = "/games/mario/level/1"; else alert(data.data); }); } }
MD5值
16342dc95b0fce33753a273e0ab598e6 = 为“0mario”,即y为0。
其他的值比较奇怪,从0-100遍历“[0-100]mario”,只有0的“16342dc95b0fce33753a273e0ab598e6 ”匹配上了,“5fd3e45cc1044dfe5d5357789968e086”和“8f33eb149d3653873f1be1c66fa46979”没匹配上:Python遍历0-100的“mario”
```javascript import hashlib
- action:
for i in range(100): str2md5 = str(i)+”mario” strUTF = str2md5.encode( ‘utf-8’ )
encodeMD5 = hashlib.md5()
encodeMD5.update(strUTF)
print( strUTF )
print( encodeMD5.hexdigest() )
i += 1
<a name="XuZx6"></a>
### moveByXy
赋值处为“`for (x of Pacman.border) for (y of x) moveByXy += y;`”<br />根据字符串“`score`”认为,但实际上应该是大于0即可:<br /><br />改为:
```javascript
if (1) {
fetch("/games/pacman/api/4", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "same-origin",
body: JSON.stringify({
action: `maze`,
score: 6,
// _csrf: $("#csrf").val(),
}),
})
.then((resp) => resp.json())
.then(function (data) {
if (data.success) window.location.href = "/games/mario/level/1";
else alert(data.data);
});
}
}