# Week10 r3:0 異世界網站挑戰心得
###### tags: `BE101` `PHP` `進度筆記第十周` `Lidemy心得`
***
一共十關,看你能闖到第幾關:r3:0 異世界網站挑戰(特別感謝第三期 @minw 製作遊戲)。
***
## lv0
https://r30challenge.herokuapp.com/lv0.php
想辦法利用 token 來獲取網址位置,系統提示如下:
\[系統\] 例如: /lv1.php?token=xxx,xxx 不包含大括號
\[系統\] 得到技能 hint: 利用 help 可以縮小 token 所在的範圍
\[系統\] 例如: /lv1.php?hint=help
\[系統\] 前往 lv1 : 請透過 query string 傳入 token
透過這些資訊用 `/lv1.php?token=r30:start` 就可以去往 lv1 的位址~
---
## lv1
為了去到 lv2 系統給了幾個資訊:
\[求救訊息\] 100101001001100001110
\[系統\] 前往 lv2: 透過 token 將怪物的名字轉成十八進位傳給 m3nt0r
經過宣告求救訊息 `parseInt()` 、 `toString` 可以得知怪物名字是 `bad18`
~~先用 http://www.kwuntung.net/hkunit/base/base.php 偷看了答案~~
### 複習了一下 [`parseInt()`](https://medium.com/unalai/%E8%AA%8D%E8%AD%98-parseint-parsefloat-%E8%88%87-number-%E8%BD%89%E6%8F%9B%E6%88%90%E6%95%B8%E5%AD%97%E7%9A%84%E4%B8%89%E7%A8%AE%E6%96%B9%E6%B3%95-276640aedb4e) 的用法
```
let num = '100101001001100001110';
// 先做字串轉換, 將 num 當做2進位值, 並轉成 10 進位。
let result = parseInt(num, '2');
console.log(result);
let res18 = result.toString(18);
console.log(res18);
```
// 依照 ECMA 規範, 基數如果是 10 以外的值, 如填入 18 則轉成 18 進位。
代入 token 得到: `lv2.php?token=bad18`
---
## lv2
進入 lv2 後看到:

有個 `<div class="hidden"> {divsurprise} </div>` 固定躲在最上層。
~~如果是 Firefox 瀏覽器有可能會直接顯示~~
但其實可以開啟 Devtool 來看~
因此帶入 token : `lv3.php?token=divsurprise` 。
---
## lv3
進入 lv3 後看到:

水面一片黑, 這就是小提示了, 再度開啟除錯工具, 點 `body` 的部分可以看到在 `body` 最底下藏了一個 ` <--!{commentfaker}--> ` 於是代入。
Token:`lv4.php?token=commentfaker`
---
## lv4

仔細觀察後, 會發現 CSS 有動過, 是 CSS 偽元素 ``:: after`` 隱藏了字串。
`html` 的部分:
```
<span class="special">{csspersona!}</span>
```
行內樣式表的部分:
```
.special::after {
content: '{tRaNspar3nT}';
margin-left: -160px;
background-color: #000;
}
```
以 ``csspersona!`` 代入, 馬上就 fail XD
但其實已經到了 lv5 !
---
## lv5
原因是出在網頁的跳轉, 仔細一看, 輸入 token 的瞬間, 網址列瞬間從 lv5 跳到 lv6 XDDD
轉址的瞬間按下 ESC 會看到 windowhack 。
p.s. 別忘了 ESC 可以停止載入網頁!
---
## lv6
基於停止載入網頁後, 使用 token: `lv6.php?token=windowhack`
會進入到新的挑戰, 這關的挑戰更ㄎ一ㄤ, 更有趣了XD
前往 lv7:解出檔案裡面顏文字的秘密,或找到 window 裡面隱藏的 token 資訊。
短短的提示僅有這樣?!
開啟除錯看之後, 我到底看了些甚麼????

於是去 console 輸入提到的關鍵字 "window" 試試看。
會跳出, ``__IamToken: "emojicute"``:

試著代入看看: `lv7.php?token=emojicute`
---
## lv7
進來之後, 這個勇者真的沒問題嗎XD 開始要賄賂惡魔是哪招XDDD"
這時候的提示是, [系統] 請找到放在包包深處的餅乾 token 。
打開除錯會發現, 由於 Cookie「TokenIsMe」的「SameSite」屬性設定為「None」或無效值,卻缺少「secure」屬性,此 Cookie 未來將被拒絕。
因此前往儲存空間, 找到餅乾 Cookie 並且看到了值 `%7Bcookieyumyum%7D` !

`%7B %7D` 相當於 `{}` 因此去掉後代入 token: `lv8.php?token=cookieyumyum` 。
---
## lv8
惡魔會吃個資啊...看到一個無頭騎士說他的 KDA 很高, 嗯???
提示告訴你 [系統] 前往 lv9:請在 response 找出無頭騎士的頭的密碼,讓他解開封印。
這個一定是工程師笑話XD Response Header 我猜, 除錯下去找後果然發現 `Tokenisme {headshot}`:

代入 token: `lv9.php?token=headshot`
---
## lv9
一進來, 話不多說, 看到了:
[系統] 前往 lv10: 請解開留在 html 裡面的 php 程式碼,輸入正確的 token
這時候開啟除錯來看~

稍微翻了一下資料可以發現 php 語法的 `strlen()` 是計算字串長度的函數, 但它不會判斷字串的編碼( `mb_strlen()`則會 ), 而 `ord()` 則可將字串轉成 ASCII 碼。
也因此這段程式碼的規則是:
```
<?php
function isTokenValid($token) {
if (strlen($token) !== 8) return false;
for($i = 1; $i <= 7; $i+=2) {
if ((ord($token[$i]) * ord($token[$i - 1])) % $i !== 0) {
return false;
}
}
return true;
}
?>
當我有個函式名為 `($token)`
假如這個 Token 的字母數 不相等於 8 的時候返回
也因此 Token 字母數應不超過 8 位
迴圈內的 ``$i = 1`` 會一直加總直到 ``<=7``
假如 2 * (2-1) % 1 不會等於 0 則返回
以此類推找 8 個值餘數為 0 應該可以過關。
```
將 `aaccddii` 代入 Token~
參考資料:
https://www.wibibi.com/info.php?tid=91
https://www.wibibi.com/info.php?tid=92
https://expect7.pixnet.net/blog/post/44229026
https://www.wibibi.com/info.php?tid=PHP_ord_%E5%87%BD%E6%95%B8
---
## lv10
看了一下提示 "[系統] 前往 lv11: 請從 POST 中找到密碼進入城堡" 。
這次大概要看一下 CORS 的甚麼東西, 嗯 果然主控台告訴你:
```
已封鎖跨來源請求: 同源政策不允許讀取 https://glacial-everglades-11859.herokuapp.com/api.php 的遠端資源。(原因: 缺少 CORS 'Access-Control-Allow-Origin' 檔頭)。
```
大概要 request CORS, 在裝有 NPM 的情況下試著寫寫看:
```
const request = require('request')
request(
'https://glacial-everglades-11859.herokuapp.com/api.php',
function (error, response, body){
console.log(body)
}
)
```
並用 `node.js` 去執行, 不過搜了幾次, 也試著用 `request.post` 還是代不到 token 出來, 上網搜了一下 CORS 的議題後, 也發現頁面是 404 的狀態:

~~試著從網路上代 Token: sosdan 進入下一關~~
---
## lv11
一進來點開, 先開 Dev tool (O), 發現:

然後畫面中有個前往另一個網站: http://r30challenge.herokuapp.com/news.php 的位址。
點進去後還以為跑到八卦版(?), 每個文章左上角似乎都有文章 ID , 有個文章被刪除了, 試著代入那個被刪除的文章 ID 到 Token看看。
```
const request = require('request')
request(
'http://r30challenge.herokuapp.com/news_api.php?id=888888',
function (error, response, body){
console.log(body)
}
)
```
總之就是到偽八卦的留言板那邊使用代入 `id` 的方式, 進去被刪除的文章頁面。
出現: 能看到這則留言的你,想必就是天選之人吧! {fakeituntilyoumakeit} 拯救這個世界吧!
---
## lv12
這次的提示是 [系統] 前往 lv13: 找找看關於 cookie 的秘密打倒小餅乾, 利用除錯去看看 Cookie 發生甚麼事情。

嗯, Cookie 一切正常, 看看 response header 有沒有甚麼狀況:

答案好像藏在這裡? 代 `you_are_cookie_master` 進去看看!
然後就進到下一關了?! 伺服器會透過 set-cookie 傳遞 response header 給瀏覽器, 瀏覽器收到後把會把 cookie 存起來, 如果之後登入相同網站會傳同樣的 cookie 給伺服器。
網路上找一下 set-cookie 的相關捏他:
https://segmentfault.com/a/1190000019586281
https://shubo.io/cookies/
---
## lv13
這次的提示是: [系統] 前往 lv14: 請拿四碼數字測試看看送信人的拖延症,直到找出正確的密碼出來。
提示數字會造成 delay 的話, 只好代代看到 token 內。
代入 8901, 5678, 1357, 0157 都會比較慢, 只好慢慢找是哪幾個數字會造成回應延遲:

發現這幾個數字會比較慢後, 代到 5371, 就成功了~
---
## lv.14
一進去就發現左上角有個 timer, 試著用除錯看看網頁發生甚麼事情:
```
secret logic
function isTokenValid($token) {
$h = date('H');
$m = date('i');
$a = $h * $m + 42;
$count = 0;
for($i = 0; $i < 8; $i++) {
$count += ord($token[$i]) - 65;
}
if ($count <= 100) {
return false;
}
return $a % $count === 0;
}
```
看了一下這段 code, 猜測:
token 的條件可能小於八個字
count 從 0 開始
這幾個字的 ASCII 減去 65 後必須大於 100
返回到 `$a` 的條件是 小時乘以分鐘 +42 後必須能整除 `count `