---
# System prepended metadata

title: AIS3 pre-exam 2021
tags: [CTF]

---

# AIS3 pre-exam 2021

## Info

* 參賽ID： Zero871015
* 比賽日期：2021/05/22 ~ 2021/05/24

## ReSident evil villAge [Crypto]

* 本題有給程式碼，是一題關於RSA的題目。
    * 題目中給予`n`和`e`，只要成功簽章`Ethan Winters`這段文字就可以得到Flag。
    * 然後題目中可以幫你簽章任意內容，但不能是題目要求的`Ethan Winters`。
* 翻了一下我之前的[RSA筆記](https://hackmd.io/@Zero871015/RSA)就知道這題是考`Chosen Ciphertext Attack`。
    * 詳細的攻擊理論可以參閱[這篇](https://crypto.stackexchange.com/questions/2323/how-does-a-chosen-plaintext-attack-on-rsa-work)。

### 以下實作

* 先連到server並存下資訊。

```python=
# connect server and get n ane e
r = remote('quiz.ais3.org', 42069)
r.recvline()
n = int(r.recvline().split(b'=')[1].strip())
e = int(r.recvline().split(b'=')[1].strip())
print('n =', n)
print('e =', e)
```

* 將題目要求的名字乘上`2^e`後送出(記得要mod`n` 不然會太大)，以迴避掉輸入不能是`Ethan Winters`的限制。
```python=
# name * 2^e to pass the restriction
name = b'Ethan Winters'
name = bytes_to_long(name)
name_b = (name * pow(2, e)) % n
r.sendline('1')
r.recv()
r.sendline(format(name_b, 'x'))
```

* 因為`2^e^d`在mod`n`的情況下會變回`2`，因此回傳的訊息除二就是答案了。
```python=
# the original result is half
sig2 = int(r.recvline().split(b': ')[2].strip())
print(sig2)
r.sendline('2')
r.sendline(str(sig2 // 2))

r.interactive()
```

## Cat Slayer ᶠᵃᵏᵉ | Nekogoroshi [Welcome]

* Welcome的題目，主要只是要熟悉工具和環境。
* 把題目hint給的code執行後，畫面上會出現一個密碼盒。
* 可以輸入`0~9`的數字，如果正確就可以輸入下一位，否則會顯示`LOCKED`，要重新連線才能繼續。
* 因為大概只需要輸入十個數字左右，最差只要嘗試`100`次左右就可以開了，所以可以直接暴力破解。
    * 可以手動也可以寫程式自動化，因為不難寫這裡就不附code了。
* 開了密碼盒之後server會丟回flag並斷開連線，如果不是用程式自動抓回傳可能會來不及看到flag畫面就消失，可以使用`python3 | tee output.txt`這種方式記錄下所以內容，事後就可以在`output.txt`看到flag了。

## Microcheese [Misc]

* 這題有給程式碼，執行一下會發現是一個遊戲程式。
![](https://i.imgur.com/RsOtuIo.png)
* 基本上就是拿石頭遊戲，和AI輪流拿，每次可以選擇一列，拿一顆以上的石頭；拿到最後一顆就贏了。
* 大家對於這種遊戲應該不陌生，都知道有必勝法了，當然用一般的方法是不可能贏的了AI的。
* 原本的解法應該是要利用遊戲中的存檔機制，去破解存檔後給的密文，自己做出一個可贏的存檔。
![](https://i.imgur.com/CPrCJJu.png)
* 不過這題code寫爛了，稍微看一下就可以發現在`play()`裡面，忘記去處理玩家選擇`0`, `1`, `2`以外的選項。
    * 所以我們選擇`3`的話，就會執行上次拿石頭的動作，而如果我們上一次拿的行數已經不存在，就不會拿石頭了。
```python=
if choice == '0':
    pile = int(input('which pile do you choose? '))
    count = int(input('how many stones do you remove? '))
    if not game.make_move(pile, count):
        print_error('that is not a valid move!')
        continue

elif choice == '1':
    game_str = game.save()
    digest = hash.hexdigest(game_str.encode())
    print('you game has been saved! here is your saved game:')
    print(game_str + ':' + digest)
    return

elif choice == '2':
    break

# no move -> player wins!
if game.ended():
    win = True
    break
else:
    print_move('you', count, pile)
    game.show()
```
* 利用這點，我們就可以讓對手一直拿石頭，直到我們可以拿最後一顆的時候再出手，就可以得到flag了。

## 🐰 Peekora 🥒 [Reverse]

![](https://i.imgur.com/wjLhGth.png)
* 因為這題太油了所以決定要做這題。
* 題目給了一個pkl檔和一段提示的command，先執行看看。
![](https://i.imgur.com/dvVygoT.png)
* 執行後要求我們輸入flag，隨便亂打則是什麼都沒發生，推測這是一支驗證flag的程式。
* google了一下pkl這個副檔名之後，會發現這是python的pickle序列化檔案。
* 使用`cat`可以直接看到opcode，或是使用python的pickletools可以得到好看一點的解譯內容。
```python=
import pickletools
data = open("flag_checker.pkl", "rb")
data = data.read()
pickletools.dis(data)
```
```
    0: c    GLOBAL     '__builtin__ input'
   19: (    MARK
   20: S        STRING     'FLAG: '
   30: t        TUPLE      (MARK at 19)
   31: R    REDUCE
   32: p    PUT        0
   35: 0    POP
   36: c    GLOBAL     '__builtin__ getattr'
   57: p    PUT        1
   60: 0    POP
   61: g    GET        1
   64: (    MARK
   65: (        MARK
   66: c            GLOBAL     '__builtin__ exit'
   84: c            GLOBAL     '__builtin__ str'
  101: l            LIST       (MARK at 65)
  102: S        STRING     '__getitem__'
  117: t        TUPLE      (MARK at 64)
  118: R    REDUCE
  119: p    PUT        2
  122: 0    POP
  123: g    GET        2
  126: (    MARK
  127: g        GET        1
  130: (        MARK
  131: g            GET        0
  134: S            STRING     'startswith'
  148: t            TUPLE      (MARK at 130)
  149: R        REDUCE
  150: (        MARK
  151: S            STRING     'AIS3{'
  160: t            TUPLE      (MARK at 150)
  161: R        REDUCE
  162: t        TUPLE      (MARK at 126)
  163: R    REDUCE
  164: (    MARK
  165: t        TUPLE      (MARK at 164)
  166: R    REDUCE
  167: g    GET        2
  170: (    MARK
  171: g        GET        1
  174: (        MARK
  175: g            GET        0
  178: S            STRING     'endswith'
  190: t            TUPLE      (MARK at 174)
  191: R        REDUCE
  192: (        MARK
  193: S            STRING     '}'
  198: t            TUPLE      (MARK at 192)
  199: R        REDUCE
  200: t        TUPLE      (MARK at 170)
  201: R    REDUCE
  202: (    MARK
  203: t        TUPLE      (MARK at 202)
  204: R    REDUCE
  205: g    GET        2
  208: (    MARK
  209: g        GET        1
  212: (        MARK
  213: g            GET        1
  216: (            MARK
  217: g                GET        0
  220: S                STRING     '__getitem__'
  235: t                TUPLE      (MARK at 216)
  236: R            REDUCE
  237: (            MARK
  238: I                INT        6
  241: t                TUPLE      (MARK at 237)
  242: R            REDUCE
  243: S            STRING     '__eq__'
  253: t            TUPLE      (MARK at 212)
  254: R        REDUCE
  255: (        MARK
  256: V            UNICODE    'A'
  259: t            TUPLE      (MARK at 255)
  260: R        REDUCE
  261: t        TUPLE      (MARK at 208)
  262: R    REDUCE
  263: (    MARK
  264: t        TUPLE      (MARK at 263)
  265: R    REDUCE
  266: g    GET        2
  269: (    MARK
  270: g        GET        1
  273: (        MARK
  274: g            GET        1
  277: (            MARK
  278: g                GET        0
  281: S                STRING     '__getitem__'
  296: t                TUPLE      (MARK at 277)
  297: R            REDUCE
  298: (            MARK
  299: I                INT        9
  302: t                TUPLE      (MARK at 298)
  303: R            REDUCE
  304: S            STRING     '__eq__'
  314: t            TUPLE      (MARK at 273)
  315: R        REDUCE
  316: (        MARK
  317: V            UNICODE    'j'
  320: t            TUPLE      (MARK at 316)
  321: R        REDUCE
  322: t        TUPLE      (MARK at 269)
  323: R    REDUCE
  324: (    MARK
  325: t        TUPLE      (MARK at 324)
  326: R    REDUCE
  327: g    GET        1
  330: (    MARK
  331: g        GET        0
  334: S        STRING     '__getitem__'
  349: t        TUPLE      (MARK at 330)
  350: R    REDUCE
  351: (    MARK
  352: I        INT        9
  355: t        TUPLE      (MARK at 351)
  356: R    REDUCE
  357: p    PUT        3
  360: 0    POP
  361: g    GET        2
  364: (    MARK
  365: g        GET        1
  368: (        MARK
  369: g            GET        1
  372: (            MARK
  373: g                GET        0
  376: S                STRING     '__getitem__'
  391: t                TUPLE      (MARK at 372)
  392: R            REDUCE
  393: (            MARK
  394: I                INT        11
  398: t                TUPLE      (MARK at 393)
  399: R            REDUCE
  400: S            STRING     '__eq__'
  410: t            TUPLE      (MARK at 368)
  411: R        REDUCE
  412: (        MARK
  413: V            UNICODE    'p'
  416: t            TUPLE      (MARK at 412)
  417: R        REDUCE
  418: t        TUPLE      (MARK at 364)
  419: R    REDUCE
  420: (    MARK
  421: t        TUPLE      (MARK at 420)
  422: R    REDUCE
  423: g    GET        2
  426: (    MARK
  427: g        GET        1
  430: (        MARK
  431: g            GET        1
  434: (            MARK
  435: g                GET        0
  438: S                STRING     '__getitem__'
  453: t                TUPLE      (MARK at 434)
  454: R            REDUCE
  455: (            MARK
  456: I                INT        14
  460: t                TUPLE      (MARK at 455)
  461: R            REDUCE
  462: S            STRING     '__eq__'
  472: t            TUPLE      (MARK at 430)
  473: R        REDUCE
  474: (        MARK
  475: g            GET        3
  478: t            TUPLE      (MARK at 474)
  479: R        REDUCE
  480: t        TUPLE      (MARK at 426)
  481: R    REDUCE
  482: (    MARK
  483: t        TUPLE      (MARK at 482)
  484: R    REDUCE
  485: g    GET        1
  488: (    MARK
  489: g        GET        0
  492: S        STRING     '__getitem__'
  507: t        TUPLE      (MARK at 488)
  508: R    REDUCE
  509: (    MARK
  510: I        INT        1
  513: t        TUPLE      (MARK at 509)
  514: R    REDUCE
  515: p    PUT        4
  518: 0    POP
  519: g    GET        2
  522: (    MARK
  523: g        GET        1
  526: (        MARK
  527: g            GET        1
  530: (            MARK
  531: g                GET        0
  534: S                STRING     '__getitem__'
  549: t                TUPLE      (MARK at 530)
  550: R            REDUCE
  551: (            MARK
  552: I                INT        5
  555: t                TUPLE      (MARK at 551)
  556: R            REDUCE
  557: S            STRING     '__eq__'
  567: t            TUPLE      (MARK at 526)
  568: R        REDUCE
  569: (        MARK
  570: V            UNICODE    'd'
  573: t            TUPLE      (MARK at 569)
  574: R        REDUCE
  575: t        TUPLE      (MARK at 522)
  576: R    REDUCE
  577: (    MARK
  578: t        TUPLE      (MARK at 577)
  579: R    REDUCE
  580: g    GET        2
  583: (    MARK
  584: g        GET        1
  587: (        MARK
  588: g            GET        1
  591: (            MARK
  592: g                GET        0
  595: S                STRING     '__getitem__'
  610: t                TUPLE      (MARK at 591)
  611: R            REDUCE
  612: (            MARK
  613: I                INT        10
  617: t                TUPLE      (MARK at 612)
  618: R            REDUCE
  619: S            STRING     '__eq__'
  629: t            TUPLE      (MARK at 587)
  630: R        REDUCE
  631: (        MARK
  632: V            UNICODE    'z'
  635: t            TUPLE      (MARK at 631)
  636: R        REDUCE
  637: t        TUPLE      (MARK at 583)
  638: R    REDUCE
  639: (    MARK
  640: t        TUPLE      (MARK at 639)
  641: R    REDUCE
  642: g    GET        2
  645: (    MARK
  646: g        GET        1
  649: (        MARK
  650: g            GET        1
  653: (            MARK
  654: g                GET        0
  657: S                STRING     '__getitem__'
  672: t                TUPLE      (MARK at 653)
  673: R            REDUCE
  674: (            MARK
  675: I                INT        12
  679: t                TUPLE      (MARK at 674)
  680: R            REDUCE
  681: S            STRING     '__eq__'
  691: t            TUPLE      (MARK at 649)
  692: R        REDUCE
  693: (        MARK
  694: V            UNICODE    'h'
  697: t            TUPLE      (MARK at 693)
  698: R        REDUCE
  699: t        TUPLE      (MARK at 645)
  700: R    REDUCE
  701: (    MARK
  702: t        TUPLE      (MARK at 701)
  703: R    REDUCE
  704: g    GET        2
  707: (    MARK
  708: g        GET        1
  711: (        MARK
  712: g            GET        4
  715: S            STRING     '__eq__'
  725: t            TUPLE      (MARK at 711)
  726: R        REDUCE
  727: (        MARK
  728: g            GET        1
  731: (            MARK
  732: g                GET        0
  735: S                STRING     '__getitem__'
  750: t                TUPLE      (MARK at 731)
  751: R            REDUCE
  752: (            MARK
  753: I                INT        13
  757: t                TUPLE      (MARK at 752)
  758: R            REDUCE
  759: t            TUPLE      (MARK at 727)
  760: R        REDUCE
  761: t        TUPLE      (MARK at 707)
  762: R    REDUCE
  763: (    MARK
  764: t        TUPLE      (MARK at 763)
  765: R    REDUCE
  766: g    GET        2
  769: (    MARK
  770: g        GET        1
  773: (        MARK
  774: g            GET        1
  777: (            MARK
  778: g                GET        0
  781: S                STRING     '__getitem__'
  796: t                TUPLE      (MARK at 777)
  797: R            REDUCE
  798: (            MARK
  799: I                INT        8
  802: t                TUPLE      (MARK at 798)
  803: R            REDUCE
  804: S            STRING     '__eq__'
  814: t            TUPLE      (MARK at 773)
  815: R        REDUCE
  816: (        MARK
  817: V            UNICODE    'w'
  820: t            TUPLE      (MARK at 816)
  821: R        REDUCE
  822: t        TUPLE      (MARK at 769)
  823: R    REDUCE
  824: (    MARK
  825: t        TUPLE      (MARK at 824)
  826: R    REDUCE
  827: g    GET        2
  830: (    MARK
  831: g        GET        1
  834: (        MARK
  835: g            GET        1
  838: (            MARK
  839: g                GET        0
  842: S                STRING     '__getitem__'
  857: t                TUPLE      (MARK at 838)
  858: R            REDUCE
  859: (            MARK
  860: I                INT        7
  863: t                TUPLE      (MARK at 859)
  864: R            REDUCE
  865: S            STRING     '__eq__'
  875: t            TUPLE      (MARK at 834)
  876: R        REDUCE
  877: (        MARK
  878: V            UNICODE    'm'
  881: t            TUPLE      (MARK at 877)
  882: R        REDUCE
  883: t        TUPLE      (MARK at 830)
  884: R    REDUCE
  885: (    MARK
  886: t        TUPLE      (MARK at 885)
  887: R    REDUCE
  888: c    GLOBAL     '__builtin__ print'
  907: (    MARK
  908: S        STRING     'Correct!'
  920: t        TUPLE      (MARK at 907)
  921: R    REDUCE
  922: .    STOP
highest protocol among opcodes = 0
```
* 接著就是慢慢讀了，只要知道基本的運作概念其實不難，因為裡面用到的功能很少。
    * 基本上就是用stack和memo記錄所有東西。
* 大致上翻譯一下：
    * 126~201: 必須是`AIS3{`開頭、`}`結尾
    * 238~256: `input[6] == 'A'`
    * 299~317: `input[9] == 'j'`
    * 352~357 + 456~475: `input[9] == input[14]`
    * 394~413: `input[11] == 'p'`
    * 510~515 + 712~753: `input[1] == input[13]`
    * 552~570: `input[5] == 'd'`
    * 613~632: `input[10] == 'z'`
    * 675~694: `input[12] == 'h'`
    * 799~817: `input[8] == 'w'`
    * 860~878: `input[7] == 'm'`
* 統整起來得到`AIS3{dAmwjzphIj}`。

## ⲩⲉⲧ ⲁⲛⲟⲧⲏⲉꞅ 𝓵ⲟ𝓰ⲓⲛ ⲣⲁ𝓰ⲉ [Web]

* 總之有個登入頁面和原始碼頁面。
```!
from flask import Flask, request, make_response, redirect, session, render_template, send_file
import os
import json

app = Flask(__name__)
app.secret_key = os.urandom(32)

FLAG = os.environ.get('FLAG', 'AIS3{TEST_FLAG}')
users_db = {
    'guest': 'guest',
    'admin': os.environ.get('PASSWORD', 'S3CR3T_P455W0RD')
}


@app.route("/")
def index():
    def valid_user(user):
        return users_db.get(user['username']) == user['password']

    if 'user_data' not in session:
        return render_template("login.html", message="Login Please :D")

    user = json.loads(session['user_data'])
    if valid_user(user):
        if user['showflag'] == True and user['username'] != 'guest':
            return FLAG
        else:
            return render_template("welcome.html", username=user['username'])

    return render_template("login.html", message="Verify Failed :(")


@app.route("/login", methods=['POST'])
def login():
    data = '{"showflag": false, "username": "%s", "password": "%s"}' % (
        request.form["username"], request.form['password']
    )
    session['user_data'] = data
    return redirect("/")


@app.route("/logout")
def logout():
    session.clear()
    return redirect("/")


@app.route("/sauce")
def sauce():
    return send_file(__file__, mimetype="text/plain")


if __name__ == '__main__':
    app.run(threaded=True, debug=True)
```
* 原始碼頁面可以知道：
    1. 有兩組帳密{guest: guest, admin: 不明}
    2. 在登入時，會把輸入的username和password做驗證，然後把帳密和`showflag = false`壓成session存起來。
    3. 如果存在session、`username!='guest'`、`showflag == true`就會給你flag。
* 可以發現`login()`的地方可以做注入攻擊，只要把`password`裡面加上雙引號就會壞掉。
    * 做個簡單的payload測試一下能不能複寫。
    * username輸入`123`
    * password輸入`guest","password":"guest","username":"guest`
    * 會發現可以成功登入guest的頁面，代表注入成功。
    * ![](https://i.imgur.com/G2Qzi7M.png)
* 這樣就可以解決`showflag`的部分，只需要延長上面的payload就可以了：`guest","password":"guest","showflag":true,"username":"guest`
* 接下來要解決`username!='guest'`的部分，我們仔細看看驗證的部分：
    * `users_db.get(user['username']) == user['password']`
* 如果`username`根本沒get到東西，`password`會怎麼樣呢...應該會變成空的。
    * 因此我們只要username隨便打，password送`null`進去就好了！
* 最後payload：
    * `guest","password":null,"showflag":true,"username":"peko`
    * ![](https://i.imgur.com/2YrHAHx.png)

## COLORS [Reverse]

![](https://i.imgur.com/v22to92.png)
* 進來這個頁面可以說幾乎啥都沒有，因此我們點開F12開始挖東西。
* 挖一挖，挖到一份很可疑的js檔案，因為這題是逆向所以被搞得有點亂。
```javascript=!
const _0x3eb4 = ['repeat', '1YqKovX', 'NDBCMjBnMzBpNTFKNjA2MDFcMzB3NDAxMzBBNDFqNDBcNDExMzBnNzB1MzBpMTBrMzBsNDA3NjB4NTBpNTBYMTBLMTBJNDBoNTBYMDBLNDFpNTFsNzA2NzBmNDBvMTA2NTA1NzBLMTFuNTE4NzA3NDFCNTAtMTE4NDB3MzFhMTByNDF6NzBLMzA9MjA9MTA9', 'substr', 'output', 'getElementsByTagName', '65022JgPEZp', 'keydown', 'length', 'innerHTML', '677PRUQAU', 'ArrowLeft', 'QWxTM3tCYXNFNjRfaTUrYjByTkluZ35cUXdvLy14SDhXekNqN3ZGRDJleVZrdHFPTDFHaEtZdWZtWmRKcFg5fQ==', '133781JKLWBV', 'ArrowUp', '90407czXCgh', 'PGRpdiBzdHlsZT0id2lkdGg6IDM1MHB4OyBwb3NpdGlvbjogYWJzb2x1dGU7IGJvdHRvbTogMHB4OyBsZWZ0OiAwcHg7Ij48ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7IGFuaW1hdGlvbjogcmFpbmJvdyAycyBsaW5lYXIgMHMgaW5maW5pdGUgbm9ybWFsOyBwb3NpdGlvbjogYWJzb2x1dGU7IHRvcDogLTEwcHg7IGxlZnQ6IDUwJTsgZm9udC1zaXplOiAyMHB4OyB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoLTUwJSk7IHdpZHRoOiAzNTBweDsiPkhlcmUgaXMgeW91cjxicj4iZW5jb2RlZCIgZmxhZyw8YnI+aW5wdXQgdG8gZW5jb2RlIHNvbWV0aGluZyBlbHNlITwvZGl2PiA8c3ZnIGlkPSLwn5CIIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGlkPSJib2R5Ij48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJmaWxsIiBkdXI9IjUwMG1zIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIga2V5VGltZXM9IjA7MC4xOzAuMjswLjM7MC40OzAuNTswLjY7MC43OzAuODswLjk7MSIgdmFsdWVzPSIgI2ZmOGQ4YjsgI2ZlZDY4OTsgIzg4ZmY4OTsgIzg3ZmZmZjsgIzhiYjVmZTsgI2Q3OGNmZjsgI2ZmOGNmZjsgI2ZmNjhmNzsgI2ZlNmNiNzsgI2ZmNjk2ODsgI2ZmOGQ4YiAiPjwvYW5pbWF0ZT48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJkIiBkdXI9IjUwMG1zIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIga2V5VGltZXM9IjA7MC4xOzAuMjswLjM7MC40OzAuNTswLjY7MC43OzAuODswLjk7MSIgdmFsdWVzPSIgTTY3LjEsMTA5LjVjLTkuNiwwLTIzLjYtOC44LTIzLjYtMjRjMC0xMi4xLDE3LjgtNDEsMzcuNS00MWMxNS42LDAsMjMuMywxMC42LDI1LjEsMjAuNSBjMS45LDEwLjcsMy45LDguMiwzLjksMTkuNWMwLDguMi0zLjgsMTctMy44LDIyLjNjMCwzLjksMS40LDcuNCwyLjksMTAuNWMxLjcsMy41LDIuNCw2LjYsMi40LDkuMkg5LjVjMC0xMy43LDEwLjgtMTQsMjEuMS0yMyBjNS42LTQuOSwxMS0xMi40LDE0LjUtMjY7IE01Ni4xLDEwNy41Yy05LjYsMC0yNC42LTEzLjgtMjQuNi0yOWMwLTE2LjIsMTMtNDIsMzMuNS00MmMxNy44LDAsMjIuMywxMS42LDI2LjEsMjIuNSBjMy42LDEwLjMsOS45LDkuMiw5LjksMjAuNWMwLDguMi0xLjgsNy0xLjgsMTIuM2MwLDQuNSwzLjQsOC4yLDYuNCwxNC4xYzIuNSw0LjgsNC44LDExLjIsNC44LDIwLjZoLTk5YzAtMTIuMSw3LjItMTcuNiwxNC43LTI0LjMgYzMuMi0yLjksNi41LTUuOSw5LjItOS44OyBNNDUuMSwxMDkuNWMtNS41LTAuMi0yNy42LTguNC0yNy42LTI3YzAtMTcuOSwxNC44LTQyLDMyLjUtNDJjMTUuNCwwLDI0LDEwLjQsMjYuMSwyMS41IGMxLjMsNi43LDkuOSw5LjgsOS45LDIxLjVjMCw4LjItMC44LDYtMC44LDExLjNjMCw3LjcsMTIuOCw5LDIwLjgsMTVjNy43LDUuOCwxNS41LDE2LjcsMTUuNSwxNi43aC0xMTBjMC00LjgsMS43LTExLjMsNS0xNiBjMy4yLTQuNSw0LjUtOC4zLDUtMTU7IE0zNiwxMjBjLTUuNS0wLjItMjguNS0xMS45LTI4LjUtMzAuNWMwLTE2LjIsMTIuNS00MiwzMy00MmMxNy44LDAsMjEuOCw5LjYsMjUuNiwyMC41IEM2OS43LDc4LjMsNzYsNzguMiw3Niw4OS41YzAsOC4yLTAuOCw0LTAuOCw5LjNjMCw1LjksMTYuNSw3LjgsMjguNCwxNS45YzgsNS41LDE3LjksMTEuOCwxNy45LDExLjhoLTExMGMwLTIuMS0xLjItNS4yLTEuOS0xNC41IGMtMC4zLTMuNi0wLjUtOC4xLTAuNS0xMy45OyBNMzcsMTE5LjVjLTE1LDAuMS0zMy41LTEyLjctMzMuNS0zMEMzLjUsNzMuMywxNiw0NywzNi41LDQ3YzE3LjgsMCwyMi44LDExLDI2LDIyIEM2NS42LDc5LjQsNzMsNzkuMiw3Myw5MC41YzAsNC0xLjgsNi42LTEuOCw4LjNjMCw1LjksMTQuMiw2LjQsMjYuNCwxNS45YzcuNyw2LDEzLjksMTEuOCwxMy45LDExLjhINy41Yy0xLjItMy40LTEuOC03LjMtMS45LTExLjIgYy0wLjItNS4xLDAuMy0xMC4xLDAuOS0xMy43OyBNNDAuNSwxMjEuNWMtMTIuNiwwLTMwLTEzLjQtMzAtMjlDMTAuNSw3Ni4zLDIzLDUzLDQzLjUsNTNjMTQuNSwwLDIyLjgsOS42LDI1LDIyIGMxLjIsNi45LDEwLDkuMiwxMCwyMC41YzAsNCwwLDUuNiwwLDcuM2MwLDQuOSw2LjEsNy41LDExLjIsMTEuOWM1LjgsNSw3LjIsMTEuOCw3LjIsMTEuOEg4LjVjMC0xLjUtMC42LTYuMSwwLjQtMTEuOCBjMC42LTMuNSwxLjktNy41LDQuMy0xMS42OyBNNDguNSwxMjEuNWMtMTIuNiwwLTI1LTYuMy0yNS0xOGMwLTE2LjIsMTMuNy00NywzNi00N2MxNS42LDAsMjQuOCw5LjEsMjcsMjEuNSBjMS4yLDYuOSw3LDkuMiw3LDE4LjVjMCw5LjUtNCwxMS00LDIyYzAsNC4xLDAuNSw1LDEsNmMwLjUsMS4yLDEsMiwxLDJoLTgxYzAtNS4zLDMuMS04LjMsNi4zLTExLjVjMi42LTIuNiw1LjQtNS4zLDYuNy05LjU7IE02OC41LDEyMS41Yy0xMi42LDAtMzMtNS44LTMzLTIzYzAtOS4yLDExLjgtMzYsMzctMzZjMTUuNiwwLDI1LjgsOC4xLDI4LDIwLjUgYzEuMiw2LjksNCw2LjIsNCwxNS41YzAsOS41LTUsMTUuMS01LDIxYzAsMS45LDEsMi4zLDEsNWMwLDEuMiwwLDIsMCwyaC05MWMwLjUtNy42LDcuMS0xMS4xLDEzLjctMTUuN2M0LjktMy40LDkuOS03LjUsMTIuMy0xNC4zOyBNNzMuNSwxMTcuNWMtMTIuNiwwLTMwLTYuMi0zMC0yNWMwLTE0LjIsMjAuOS0zNywzOC0zN2MxNy42LDAsMjUuOCwxMS4xLDI4LDIzLjUgYzEuMiw2LjksMyw3LjIsMywxNi41YzAsMTIuMS02LDE2LjEtNiwyMmMwLDQuMiwyLDUuMywyLDhjMCwxLjIsMCwxLDAsMUg3LjVjMi4xLTkuNCwxMC40LTEzLjMsMTkuMi0xOS40IGM3LjEtNSwxNC40LTExLjUsMTguOC0yMy42OyBNODAuNSwxMTUuNWMtMTIuNiwwLTMyLTkuMi0zMi0yOGMwLTE0LjIsMjIuOS0zNSw0MC0zNWMxNy42LDAsMjUuOCwxMi4xLDI4LDI0LjUgYzEuMiw2LjksMyw2LjIsMywxNS41YzAsMTIuMS02LDE5LjEtNiwyNWMwLDQuMiwyLDUuMywyLDhjMCwxLjIsMCwxLDAsMWgtMTAyYzIuMy04LjcsMTEuNi0xMS43LDIwLjgtMjAuMSBjNS4zLTQuOCwxMC41LTExLjQsMTQuMi0yMS45OyBNNjcuMSwxMDkuNWMtOS42LDAtMjMuNi04LjgtMjMuNi0yNGMwLTEyLjEsMTcuOC00MSwzNy41LTQxYzE1LjYsMCwyMy4zLDEwLjYsMjUuMSwyMC41IGMxLjksMTAuNywzLjksOC4yLDMuOSwxOS41YzAsOC4yLTMuOCwxNy0zLjgsMjIuM2MwLDMuOSwxLjQsNy40LDIuOSwxMC41YzEuNywzLjUsMi40LDYuNiwyLjQsOS4ySDkuNWMwLTEzLjcsMTAuOC0xNCwyMS4xLTIzIGM1LjYtNC45LDExLTEyLjQsMTQuNS0yNiAiPjwvYW5pbWF0ZT48L3BhdGg+PHBhdGggaWQ9ImJlYWsiIGZpbGw9IiM3YjhjNjgiPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9ImQiIGR1cj0iNTAwbXMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBrZXlUaW1lcz0iMDswLjE7MC4yOzAuMzswLjQ7MC41OzAuNjswLjc7MC44OzAuOTsxIiB2YWx1ZXM9IiBNNzguMjksNzBjMC05LjkyLDIuNS0xNCw4LTE0czgsMi4xNyw4LDEwLjY3YzAsMTUuOTItNywyNi4zMy03LDI2LjMzUzc4LjI5LDg1LjUsNzguMjksNzBaOyBNNjIuMjksNjRjMC05LjkyLDIuNS0xNCw4LTE0czgsMi4xNyw4LDEwLjY3YzAsMTUuOTItNywyNi4zMy03LDI2LjMzUzYyLjI5LDc5LjUsNjIuMjksNjRaOyBNNDguMjksNjdjMC05LjkyLDIuNS0xNCw4LTE0czgsMi4xNyw4LDEwLjY3YzAsMTUuOTItNywyNi4zMy03LDI2LjMzUzQ4LjI5LDgyLjUsNDguMjksNjdaOyBNMzYuMjksNzNjMC05LjkyLDIuNS0xNCw4LTE0czgsMi4xNyw4LDEwLjY3YzAsMTUuOTItNywyNi4zMy03LDI2LjMzUzM2LjI5LDg4LjUsMzYuMjksNzNaOyBNMzUuMjksNzVjMC05LjkyLDIuNS0xNCw4LTE0czgsMi4xNyw4LDEwLjY3YzAsMTUuOTItNywyNi4zMy03LDI2LjMzUzM1LjI5LDkwLjUsMzUuMjksNzVaOyBNNDEuMjksODFjMC05LjkyLDIuNS0xNCw4LTE0czgsMi4xNyw4LDEwLjY3YzAsMTUuOTItNywyNi4zMy03LDI2LjMzUzQxLjI5LDk2LjUsNDEuMjksODFaOyBNNTkuMjksODRjMC05LjkyLDIuNS0xNCw4LTE0czgsMi4xNyw4LDEwLjY3YzAsMTUuOTItNywyNi4zMy03LDI2LjMzUzU5LjI5LDk5LjUsNTkuMjksODRaOyBNNzIuMjksODljMC05LjkyLDIuNS0xNCw4LTE0czgsMi4xNyw4LDEwLjY3YzAsMTUuOTItNywyNi4zMy03LDI2LjMzUzcyLjI5LDEwNC41LDcyLjI5LDg5WjsgTTgwLjI5LDgyYzAtOS45MiwyLjUtMTQsOC0xNHM4LDIuMTcsOCwxMC42N2MwLDE1LjkyLTcsMjYuMzMtNywyNi4zM1M4MC4yOSw5Ny41LDgwLjI5LDgyWjsgTTg3LjI5LDc4YzAtOS45MiwyLjUtMTQsOC0xNHM4LDIuMTcsOCwxMC42N2MwLDE1LjkyLTcsMjYuMzMtNywyNi4zM1M4Ny4yOSw5My41LDg3LjI5LDc4WjsgTTc4LjI5LDcwYzAtOS45MiwyLjUtMTQsOC0xNHM4LDIuMTcsOCwxMC42N2MwLDE1LjkyLTcsMjYuMzMtNywyNi4zM1M3OC4yOSw4NS41LDc4LjI5LDcwWiAiPjwvYW5pbWF0ZT48L3BhdGg+PGVsbGlwc2UgaWQ9ImV5ZS1yaWdodCIgcng9IjMiIHJ5PSI0Ij48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJjeCIgZHVyPSI1MDBtcyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIGtleVRpbWVzPSIwOzAuMTswLjI7MC4zOzAuNDswLjU7MC42OzAuNzswLjg7MC45OzEiIHZhbHVlcz0iMTAwOzg0OzcwOzU4OzU3OzYzOzgxOzk0OzEwMjsxMDk7MTAwIj48L2FuaW1hdGU+PGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iY3kiIGR1cj0iNTAwbXMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBrZXlUaW1lcz0iMDswLjE7MC4yOzAuMzswLjQ7MC41OzAuNjswLjc7MC44OzAuOTsxIiB2YWx1ZXM9IjYyOzU2OzU5OzY1OzY3OzczOzc2OzgxOzc0OzcwOzYyIj48L2FuaW1hdGU+PC9lbGxpcHNlPjxlbGxpcHNlIGlkPSJleWUtbGVmdCIgcng9IjMiIHJ5PSI0Ij48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJjeCIgZHVyPSI1MDBtcyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIGtleVRpbWVzPSIwOzAuMTswLjI7MC4zOzAuNDswLjU7MC42OzAuNzswLjg7MC45OzEiIHZhbHVlcz0iNjcuNTs1MS41OzM3LjU7MjUuNTsyNC41OzMwLjU7NDguNTs2MS41OzY5LjU7NzYuNTs2Ny41Ij48L2FuaW1hdGU+PGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iY3kiIGR1cj0iNTAwbXMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBrZXlUaW1lcz0iMDswLjE7MC4yOzAuMzswLjQ7MC41OzAuNjswLjc7MC44OzAuOTsxIiB2YWx1ZXM9IjYyOzU2OzU5OzY1OzY3OzczOzc2OzgxOzc0OzcwOzYyIj48L2FuaW1hdGU+PC9lbGxpcHNlPjwvc3ZnPjwvZGl2Pg==', '131837PcDnWL', '19pQimXL', '623605MIswVM', 'charCodeAt', 'join', '4WsUYDr', '686oWrfyq', 'body', 'map', 'getElementById', 'textContent', 'match', 'key', '302349wKdZHP', '4OYJFlQ', 'input', 'padStart', 'Backspace'];
function _0x4ebd(_0x532d69, _0x212ed3) {
    _0x532d69 = _0x532d69 - 0x1c6;
    let _0x3eb4a7 = _0x3eb4[_0x532d69];
    return _0x3eb4a7;
}
(function(_0x496f79, _0x226742) {
    const _0x463eac = _0x4ebd;
    while (!![]) {
        try {
            const _0x12c745 = -parseInt(_0x463eac(0x1e6)) + parseInt(_0x463eac(0x1ce)) * -parseInt(_0x463eac(0x1de)) + -parseInt(_0x463eac(0x1db)) + -parseInt(_0x463eac(0x1e7)) * parseInt(_0x463eac(0x1d7)) + -parseInt(_0x463eac(0x1d5)) * parseInt(_0x463eac(0x1c9)) + parseInt(_0x463eac(0x1df)) * -parseInt(_0x463eac(0x1d2)) + parseInt(_0x463eac(0x1d9)) * parseInt(_0x463eac(0x1da));
            if (_0x12c745 === _0x226742)
                break;
            else
                _0x496f79['push'](_0x496f79['shift']());
        } catch (_0xe36f7) {
            _0x496f79['push'](_0x496f79['shift']());
        }
    }
}(_0x3eb4, 0x57a76),
(()=>{
    const _0x1cd51f = _0x4ebd
      , _0x54579e = _0x1cd51f(0x1d8)
      , _0x78ed5a = _0x1cd51f(0x1ca)
      , _0x24fcac = _0x1cd51f(0x1d4)
      , _0x2a3765 = 0x8
      , _0x317b6e = 0xa;
    let _0x1e21d9, _0x179193 = 0x0;
    function _0xce93(_0x1b497a) {
        const _0x9fe181 = _0x1cd51f;
        if (!_0x1b497a[_0x9fe181(0x1d0)])
            return '';
        let _0x4d62de = ''
          , _0x23f867 = ''
          , _0x5395cb = 0x0;
        for (let _0x6e40b4 = 0x0; _0x6e40b4 < _0x1b497a[_0x9fe181(0x1d0)]; _0x6e40b4++)
            _0x4d62de += _0x1b497a[_0x9fe181(0x1dc)](_0x6e40b4)['toString'](0x2)[_0x9fe181(0x1c6)](0x8, '0');
        _0x5395cb = _0x4d62de[_0x9fe181(0x1d0)] % _0x317b6e / 0x2 - 0x1;
        if (_0x5395cb != -0x1)
            _0x4d62de += '0'[_0x9fe181(0x1c8)](_0x317b6e - _0x4d62de[_0x9fe181(0x1d0)] % _0x317b6e);
        _0x4d62de = _0x4d62de[_0x9fe181(0x1e4)](/(.{1,10})/g);
        for (let _0x13c6bb of _0x4d62de) {
            let _0x192141 = parseInt(_0x13c6bb, 0x2);
            _0x23f867 += _0x9f530c(_0x192141 >> 0x6 & 0x7, _0x192141 >> 0x9, atob(_0x24fcac)[_0x192141 & 0x3f]);
        }
        for (; _0x5395cb > 0x0; _0x5395cb--) {
            _0x23f867 += _0x9f530c(_0x5395cb % _0x2a3765, 0x0, '=');
        }
        return _0x23f867;
    }
    let _0x9f530c = (_0xcc032b,_0x2a8089,_0x244c3a)=>'<span><div\x20class=\x22c' + _0xcc032b + '\x20r' + _0x2a8089 + '\x22>' + _0x244c3a + '</div></span>'
      , _0x1fdafa = _0x29e3ab=>document[_0x1cd51f(0x1e2)](_0x1cd51f(0x1cc))['innerHTML'] = _0xce93(_0x29e3ab);
    document['addEventListener'](_0x1cd51f(0x1cf), _0x23e75c=>{
        const _0x12b963 = _0x1cd51f;
        if (_0x23e75c[_0x12b963(0x1e5)] === _0x12b963(0x1c7) && _0x179193 == 0xa)
            _0x1e21d9[_0x12b963(0x1e3)] = _0x1e21d9['textContent'][_0x12b963(0x1cb)](0x0, _0x1e21d9['textContent'][_0x12b963(0x1d0)] - 0x1);
        else {
            if (_0x23e75c['key'] === _0x12b963(0x1d6) && !(_0x179193 >> 0x1))
                return _0x179193 += 0x1;
            else {
                if (_0x23e75c[_0x12b963(0x1e5)] === 'ArrowDown' && !(_0x179193 >> 0x2))
                    return _0x179193 += 0x1;
                else {
                    if (_0x23e75c[_0x12b963(0x1e5)] === _0x12b963(0x1d3) && (_0x179193 == 0x4 || _0x179193 == 0x6))
                        return _0x179193 += 0x1;
                    else {
                        if (_0x23e75c[_0x12b963(0x1e5)] === 'ArrowRight' && (_0x179193 == 0x5 || _0x179193 == 0x7))
                            return _0x179193 += 0x1;
                        else {
                            if (_0x23e75c[_0x12b963(0x1e5)] === 'b' && _0x179193 == 0x8)
                                return _0x179193 += 0x1;
                            else {
                                if (_0x23e75c['key'] === 'a' && _0x179193 == 0x9)
                                    return document[_0x12b963(0x1cd)](_0x12b963(0x1e0))[0x0]['innerHTML'] += atob(_0x54579e),
                                    _0x1e21d9 = document[_0x12b963(0x1e2)](_0x12b963(0x1e8)),
                                    _0x1e21d9[_0x12b963(0x1d1)] = '',
                                    document[_0x12b963(0x1e2)]('output')[_0x12b963(0x1d1)] = atob(_0x78ed5a)[_0x12b963(0x1e4)](/(.{1,3})/g)[_0x12b963(0x1e1)](_0x5efa9e=>_0x9f530c(_0x5efa9e[0x0], _0x5efa9e[0x1], _0x5efa9e[0x2]))[_0x12b963(0x1dd)](''),
                                    _0x179193 += 0x1;
                                else {
                                    if (_0x23e75c[_0x12b963(0x1e5)][_0x12b963(0x1d0)] == 0x1 && _0x179193 == 0xa)
                                        _0x1e21d9[_0x12b963(0x1e3)] += String['fromCharCode'](_0x23e75c[_0x12b963(0x1e5)][_0x12b963(0x1dc)]());
                                    else
                                        return;
                                }
                            }
                        }
                    }
                }
            }
        }
        _0x1fdafa(_0x1e21d9[_0x12b963(0x1e3)]);
    }
    );
}
)());

```

* 這邊我稍微通靈了一下，看到檔案裏面有`ArrowDown`、`ArrowRight`、`b`和`a`，又叫我們輸入SecretCode，就想到要打`上上下下左右左右ba`，頁面就變成一個加密器。
    * ![](https://i.imgur.com/xJVpBeW.png)
* 畫面上一開始的文字是Flag加密成為的結果，然後我們可以輸入隨意文字，他會吐出密文。
    * ![](https://i.imgur.com/erlAUL7.png)
* 知道用途是加密之後就可以開始做逆向了，先找出哪一段是加密，然後看懂加密邏輯。
    * 可以發現密文後面有很多`=`，估計是padding用的，因此推測加密應該是以下這段：
```javascript=!
function _0xce93(_0x1b497a) {
        const _0x9fe181 = _0x1cd51f;
        if (!_0x1b497a[_0x9fe181(0x1d0)])
            return '';
        let _0x4d62de = ''
          , _0x23f867 = ''
          , _0x5395cb = 0x0;
        for (let _0x6e40b4 = 0x0; _0x6e40b4 < _0x1b497a[_0x9fe181(0x1d0)]; _0x6e40b4++)
            _0x4d62de += _0x1b497a[_0x9fe181(0x1dc)](_0x6e40b4)['toString'](0x2)[_0x9fe181(0x1c6)](0x8, '0');
        _0x5395cb = _0x4d62de[_0x9fe181(0x1d0)] % _0x317b6e / 0x2 - 0x1;
        if (_0x5395cb != -0x1)
            _0x4d62de += '0'[_0x9fe181(0x1c8)](_0x317b6e - _0x4d62de[_0x9fe181(0x1d0)] % _0x317b6e);
        _0x4d62de = _0x4d62de[_0x9fe181(0x1e4)](/(.{1,10})/g);
        for (let _0x13c6bb of _0x4d62de) {
            let _0x192141 = parseInt(_0x13c6bb, 0x2);
            _0x23f867 += _0x9f530c(_0x192141 >> 0x6 & 0x7, _0x192141 >> 0x9, atob(_0x24fcac)[_0x192141 & 0x3f]);
        }
        for (; _0x5395cb > 0x0; _0x5395cb--) {
            _0x23f867 += _0x9f530c(_0x5395cb % _0x2a3765, 0x0, '=');
        }
        return _0x23f867;
    }
```
* 經過我翻譯過後大概變成這樣：
```javascript=!
const _0x1cd51f = _0x4ebd
      , _0x54579e = _0x1cd51f(0x1d8)
      , _0x78ed5a = _0x1cd51f(0x1ca)
      , _0x24fcac = _0x1cd51f(0x1d4)
      , 8 = 0x8
      , 10 = 0xa;
    let _0x1e21d9, _0x179193 = 0x0;
    function _0xce93(input) {
        const _0x9fe181 = _0x1cd51f;
        if (!input[len])
            return '';
        let bits = ''
          , html = ''
          , cb = 0x0;
        for (let i = 0x0; i < input[len]; i++)
            bits += input[charCodeAt](i)['toString'](0x2)[padStart](0x8, '0');
        cb = bits[len] % 10 / 0x2 - 0x1;
        if (cb != -0x1)
            bits += '0'[repeat](10 - bits[len] % 10);
        bits = bits[match](/(.{1,10})/g); //每10個切一段
        for (let bit of bits) {
            let num = parseInt(bit, 0x2);
            html += htmlFunction(num >> 0x6 & 0x7, num >> 0x9, "AlS3{BasE64_i5+b0rNIng~\Qwo/-xH8WzCj7vFD2eyVktqOL1GhKYufmZdJpX9}"[num & 0x3f]);
        }
        for (; cb > 0x0; cb--) {
            html += htmlFunction(cb % _0x2a3765, 0, '=');
        }
        return html;
    }
```
* 看code的一些方法：
    * chrome可以按F12下中斷點，然後隨便輸入一個字讓它執行加密就會暫停。
    * 可以逐步執行之外，某些看不懂的字串代換直接反白會直接幫你翻譯。
    * ![](https://i.imgur.com/881VKeS.png)
* 加密流程大概是：
    1. 每個字元用`charCodeAt`轉成二進位數字，不滿八位元的就在前面補`0`。
    2. 全部二進位數字串起來，改為每十個切一組，不滿十個的在後面補`0`。
    3. 每組數字前四個bit變成顏色的資訊，後六個bit根據密碼表作代換。
* 基本上沒有任何地方是不可逆的加密，所以就寫一個解密器，把加密流程反過來就好了：
```python=!
code = "BgiJ6\\w1Aj\\1guikl7xiXKIhXKil6fo65Kn87B-8warzK"
table = "AlS3{BasE64_i5+b0rNIng~\\Qwo/-xH8WzCj7vFD2eyVktqOL1GhKYufmZdJpX9}"
bits = ""
# get color information
temp = '<div id="output"><span><div class="c4 r0">B</div></span><span><div class="c2 r0">g</div></span><span><div class="c3 r0">i</div></span><span><div class="c5 r1">J</div></span><span><div class="c6 r0">6</div></span><span><div class="c0 r1">\</div></span><span><div class="c3 r0">w</div></span><span><div class="c4 r0">1</div></span><span><div class="c3 r0">A</div></span><span><div class="c4 r1">j</div></span><span><div class="c4 r0">\</div></span><span><div class="c4 r1">1</div></span><span><div class="c3 r0">g</div></span><span><div class="c7 r0">u</div></span><span><div class="c3 r0">i</div></span><span><div class="c1 r0">k</div></span><span><div class="c3 r0">l</div></span><span><div class="c4 r0">7</div></span><span><div class="c6 r0">x</div></span><span><div class="c5 r0">i</div></span><span><div class="c5 r0">X</div></span><span><div class="c1 r0">K</div></span><span><div class="c1 r0">I</div></span><span><div class="c4 r0">h</div></span><span><div class="c5 r0">X</div></span><span><div class="c0 r0">K</div></span><span><div class="c4 r1">i</div></span><span><div class="c5 r1">l</div></span><span><div class="c7 r0">6</div></span><span><div class="c7 r0">f</div></span><span><div class="c4 r0">o</div></span><span><div class="c1 r0">6</div></span><span><div class="c5 r0">5</div></span><span><div class="c7 r0">K</div></span><span><div class="c1 r1">n</div></span><span><div class="c5 r1">8</div></span><span><div class="c7 r0">7</div></span><span><div class="c4 r1">B</div></span><span><div class="c5 r0">-</div></span><span><div class="c1 r1">8</div></span><span><div class="c4 r0">w</div></span><span><div class="c3 r1">a</div></span><span><div class="c1 r0">r</div></span><span><div class="c4 r1">z</div></span><span><div class="c7 r0">K</div></span><span><div class="c3 r0">=</div></span><span><div class="c2 r0">=</div></span><span><div class="c1 r0">=</div></span></div>'
temp = temp.split("class")[1:]
xxx = [int(t[3]) for t in temp]
x = [int(t[6]) for t in temp]

# reverse to original code
for i, c in enumerate(code):
    num = table.find(c)
    bits += f"{x[i]:01b}{xxx[i]:03b}{num:06b}"

# 10 bits to 8 bits
chunks, chunk_size = len(bits), 8
byte = [ bits[i:i+chunk_size] for i in range(0, chunks, chunk_size) ]

# output flag
for b in byte:
    print(chr(int(b, 2)), end="")
```

```
AIS3{base1024_15_c0l0RFuL_GAM3_CL3Ar_thIS_IS_y0Ur_FlaG!}
```
* 成功得到flag。

###### tags: `CTF`