johnpoint

johnpoint

(。・∀・)ノ゙嗨
github

Hackergame 2020 の解説

最終成績#

Sat Nov  7 09:59:22 AM CST 2020
現在のスコア:1500、 総ランキング:225 / 2415
binary:0 , general:850 , math:300 , web:350

ああ、私は本当に下手だ(

ほんの少ししか問題を解けなかった

チェックイン#

招待ありがとうございます、利害関係者:古いチェックイン出題者です。

今年の出題グループの要求は「私たちのコンペに参加する学生の多くは初心者であり、私たちのチェックイン問題は明確で簡単に理解できるようにして、学生が簡単にチェックインできるようにすること」です。

私は完全に理解しました、チェックイン問題はフラグを送ることです、送るなら送ります、私はそれが得意です.jpg

まず、問題の紹介を書きます:「下の青い「問題を開く/ダウンロード」ボタンをクリックする必要があります。開いたウェブページで flag{...} の形のフラグを取得し、このページに戻って、下のテキストボックスにそのフラグを完全に記入し、灰色の「送信」ボタンをクリックすることでこの問題を完了します。」

次にフラグ抽出器を作成します。選手が必要なフラグの数だけフラグを提供します。緑の背景、赤の太字、目立つ位置、標準のフォーマット、これを送るとは呼びません。それなら何が送ると言えるでしょうか。

「問題を開く/ダウンロード」ボタンをクリックして、フラグ抽出器を開き、最初のフラグを取得しましょう!

ヒント:問題を解決するのに困難がありますか?2018年のチェックイン問題の解説と2019年のチェックイン問題の解説を参考にできます。

image

F12 でスライダーを特定し、最大値を 1 に変更してからスライダーを最大にドラッグするとフラグを取得できます。

<input type="range" id="number" name="number" class="form-control" value="0" min="0" max="1" step="0.00001">

猫の質問 ++#

科大西区の大学院食堂の隣には、肥満した猫がたくさんいるコンクリートの石板があります。晴れた昼の間、その上には白と黒の猫が日向ぼっこをしています。そして、多くの昼食を終えた学生たちも、この良い機会に猫を撫でることができます。

しかし、ある日突然、コンクリートの石板の上に猫の頭と体を持つ動物が現れ、猫を撫でに来た学生たちを阻止し、彼らを試すために用意した謎を出します。すべての質問に正解しなければ猫を撫でることはできず、間違えると毛を逆立てて見せてきます。

毎日の猫を撫でる活動を正常に戻すために、熱心なLUG協会の学生たちがこれらの謎をここに置きました。すべての謎に正解できれば、フラグが報酬として得られます。

ヒント:猫を撫でるために現地に行く必要はなく、謎を解くために科大の在校生である必要もありません。問題を解決するのに困難がありますか?2018年の猫の質問問題の解説を参考にできます。

image

  1. 手動で数えた数は 12
  2. wikipedia を検索しました -> RFC1149

A
typical MTU is 256 milligrams. Some datagram padding may be needed.

  1. https://ftp.lug.ustc.edu.cn/ 活动 / 2019.09.21_SFD/slides/ 闪电演讲 / Teeworlds/ --> Teeworlds の答え 9

  2. 百度地図のストリートビューを手動で数えた答え 9

  3. https://news.ustclug.org/2019/12/hackergame-2019/ --> 答え 17098

2048#

道は遠く、FLXGは決してあきらめない!

FLXGを実現するには、卓越した知恵、強い意志、運命の伴侶が必要です。2048の世界でこれらの貴重な資質を証明し、「大成功」を達成することで、あなたはFLXGの大旗を掲げる資格を得ることができます。

image

本当に 2048 です。js ファイルを見て、game_manager.jsというものを見つけ、ロジックをざっと見たところ、次のような文がありました。

if (merged.value === 16384) self.won = true;

ブレークポイントを打ち、変数の値を手動で変更すると成功しました。

image

一瞬のフラグ#

深秋の清晨、西湖のほとり。一人の可哀想な学生が道端のベンチに丸まって、粗い指で古びた神船ノートパソコンを叩き、デスクトップ上のプログラムを開こうと何度も試みています。プログラムが実行されるたびに、黒いコンソール上にフラグが一瞬現れます。

彼の足元には、廃棄された段ボールで作られた看板があり、「私はとても可愛いです、フラグをください」と書かれています。通りの人々は急いでいて、地面に置かれたフラグを盛るための食器は空っぽのままです。

一人の詩人の学生が通りかかり、この光景を見て、看板を「フラグが来たが、私は何も見えない!」に変更しました。

そして、あなたは新入生として、思わず同情の念を抱きました。詩人が午後に戻る前に、この可哀想な人を助けて、彼の食器をフラグで満たすことができますか?

ああ、これは、私はこのフラグが簡単に得られると思います。プログラムを実行した後、瞬時にスクリーンショットを撮ればフラグを取得できます。以前はフレームごとに判断する必要があると思っていました...

ゼロから始める記帳ツール#

いつものように、あなたのnpyが突然ショッピングリストを投げてきました。「今日は何か小さなものを買ったので、合計いくらか計算してもらえますか?」

あなたは思います:また土を食べることになるのか、これはとても簡単ではありませんか?電子スプレッドシートでドラッグするだけで計算できます。

ただし、請求書を受け取った後、どうやら手を切るときにもっと安心できるように、今回の請求書の金額はすべて中国語の大文字で表示されているようです。

注意:請求書の合計金額は小数点以下2桁を保持し、flag{}の中に提出してください。たとえば、合計金額が123.45元の場合、flag{123.45}を提出する必要があります。

ファイルダウンロード

まず csv として保存し、python を使用して csv を json に変換します。これで処理しやすくなります。

統計ソースコード:

import json


def cover(i):
    for j in range(0, len(text)):
        if text[j] == i:
            return j


yuan = 0
jiao = 0
fen = 0
text = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖", "拾"]

with open('bills.json', 'r') as f:
    a = json.load(f)
    for i in a:
        y = i["mon"].split("元")
        num = int(i["num"])
        for j in y:
            if "角" in j:
                jj = j.split("角")
                jiao += cover(jj[0])*num
                if len(jj) > 1 and "分" in jj[1]:
                    fen += cover(jj[1].split("分")[0])*num
                continue
            if "分" in j:
                fen += cover(j.split("分")[0].replace("零", ""))*num
                continue
            for i in range(0, len(j)):
                if j[i] == "整":
                    continue
                if j[i] == "佰":
                    continue
                if i+1 < len(j):
                    if j[i+1] == "拾":
                        yuan += cover(j[i])*10*num
                    elif j[i+1] == "佰":
                        yuan += cover(j[i])*100*num
                else:
                    if j[i] != "拾" and j[i] != "佰":
                        yuan += cover(j[i])*num
                if i-1 < 0 and j[i] == "拾":
                    yuan += 10*num

jiao += int(fen/10)
fen = fen % 10*0.01
yuan += int(jiao/10)
jiao = jiao % 10*0.1

print(yuan+jiao+fen)
print("y", yuan)
print("j", jiao)
print("f", fen)

答え 20262.53

一教からの画像#

小Pは一教でフーリエ光学実験を行っているとき、実験室のコンピュータのシミュレーションプログラムでこの画像を見つけました:

image

数学的基礎が不十分な小Pは、何がこのように映るのかを知りませんでした。おそらく何もないかもしれませんが、これはシミュレーションに過ぎません... しかし、これらの奇妙に見える模様の中には、確かに何らかの情報が隠されていることが確かで、地下金鉱の地図かもしれません。

とても簡単です。問題は十分なヒントを与えており、フーリエ逆変換を行うだけで得られます。

image

超簡単な世界シミュレーター#

あなたはライフゲーム(Conway's Game of Life)を知っていますか?

あなたの任務は、ライフゲームの世界で蝶が羽ばたく様子を再現し、海の向こうで嵐を引き起こす効果を引き起こすことです。

左上の15x15の領域を変更し、ゲームが200世代進化した後、特別にマークされた正方形内の細胞が「消去」されれば、対応するフラグが得られます:

任意の正方形を「消去」すると、最初のフラグが得られます。同時に2つの正方形を「消去」すると、2番目のフラグが得られます。

注:あなたの入力は15行のテキストで、各行は15個の0または1で構成され、その領域の内容を表します。

蝶の効果#

私の解:

000000000000000
000000000000000
000000000000000
000000000000000
000000110000000
000001111000000
000001101100000
000000011000000
000000000000000
000000000000000
000000110000000
000001111000000
000001101100000
000000011000000
000000000000000

知乎:ライフゲーム(Game of Life)にはどのような図形がありますか?を参考にしました。

233 さんの Docker#

233さんはソフトウェア工学の授業でDockerという便利なものを学び、自分の文字列ツールプロジェクトにDockerfileを書きました。

しかし、233さんはうっかりプライベートファイル(flag.txt)をパッケージに含めてしまったことに気づき、このファイルを削除する命令を書きました。

「もう削除したので、誰にも見つからないはずだ」と233は考えました。

Docker Hub のアドレス:8b8d3c8324c7/stringtool

Dockerfile のコマンドから見ると

/bin/sh -c rm /code/flag.txt

フラグは /code に保存されています。

docker layers の内容を抽出するだけのようです。問題は私にはできない Is there a way to tag a previous layer in a docker image or revert a commit?を検索しました。

docker save imagename $(sudo docker history -q imagename | tail -n +2 | grep -v \<missing\> | tr '\n' ' ') > image-caching.tar

このコマンドを使用すると、すべてのレイヤーが抽出され、次に各レイヤーを確認するだけです。

flag{Docker_Layers!=PS_Layers_hhh}

ゼロから始める火星文生活#

毎年恒例のHackergameが近づいてきました。LさんはQさんを呼んで参加しようとしましたが、数日間Qさんの姿を見かけませんでした。しかし、コンペの前夜にQさんからメールが届きました:

Subject: 秘密!外部に漏らさないで!!!
Body: 詳細は添付ファイルを参照
From: Q
Lさんは添付ファイルを開くと、驚愕しました。全て意味不明な漢字が書かれていました。機知に富んだLさんは、Qさんが普段GBKエンコーディングを使用していることを思い出し、開き方が間違っているかもしれないと考えました。結果、GBKで開くと、日語と数字が混ざった火星文が表示されました……

Lさんは完全に混乱し、何度も試行錯誤の末、科大で最も有名な火星文の専門家(あなた)を見つけました。長年の文字エンコーディングの解読経験を活かして、Qさんが送った火星文が何を意味するのかを解読できますか?

注:正しいフラグはすべてASCII文字で構成されています!

ファイル内容:

脦脪鹿楼脝脝脕脣 拢脠拢谩拢茫拢毛拢氓拢貌拢莽拢谩拢铆拢氓 碌脛路镁脦帽脝梅拢卢脥碌碌陆脕脣脣眉脙脟碌脛 拢忙拢矛拢谩拢莽拢卢脧脰脭脷脦脪掳脩 拢忙拢矛拢谩拢莽 路垄赂酶脛茫拢潞 拢忙拢矛拢谩拢莽拢没拢脠拢麓拢枚拢鲁拢脽拢脝拢玫拢脦拢脽拢梅拢卤拢脭拢猫拢脽拢鲁拢卯拢茫拢掳拢盲拢卤拢卯拢莽拢脽拢麓拢脦拢盲拢脽拢盲拢鲁拢茫拢掳拢脛拢卤拢卯拢脟拢脽拢鹿拢帽拢脛拢虏拢脪拢赂拢猫拢贸拢媒 驴矛脠楼卤脠脠眉脝陆脤篓脤谩陆禄掳脡拢隆 虏禄脪陋脭脵掳脩脮芒路脻脨脜脧垄脳陋路垄赂酶脝盲脣没脠脣脕脣拢卢脪陋脢脟卤禄路垄脧脰戮脥脭茫赂芒脕脣拢隆

ええと。。。この問題、拢 utf8を検索していると、ちょうどコード中に含まれる中国語がすべて文字化けしている、エンコーディングの問題について教えてください!を見つけて、回答を見ました。

alcarl   2018-01-09 01:25:21 +08:00 via Android   ❤️ 3
まず、この文字列をGB2312エンコーディングのファイルとして保存し、UTF-8エンコーディングに変換して保存し、その後8859-1に変換してからGBKで開くと良いです。=͟͟͞͞(꒪ᗜ꒪ ‧̣̥̇) 文字は以下のようになります

そしてこの操作を行うと.... 出てきました...

私はHackerGameのサーバーを攻撃し、彼らのフラグを盗みました。今、私はフラグをあなたに送ります:
flag{H4v3_FuN_w1Th_3nc0d1ng_4Nd_d3c0D1nG_9qD2R8hs}
コンペティションプラットフォームに提出してください!
この情報を他の人に転送しないでください。見つかると大変です!

ゼロから始める HTTP リンク#

ご存知の通り、配列のインデックスは0から始まるべきです。

同様に、TCPポートも0から始まるべきです。この点を実践するために、サーバーの0番ポートにウェブサイトを設置しました。

あなたは0番ポートに成功裏に接続し、フラグを取得できますか?

下の問題を開くボタンをクリックしてもウェブページは開きません。なぜなら、通常のブラウザはこれを無効なアドレスと見なすからです。

アドレス: http://202.38.93.111:0/

問題からわかるように、自分で HTTP リクエストを構築すればフラグを得られるはずです。

私の解法:

ネット上で C 言語で実装された HTTP GET を見つけました(出典

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
#define IPSTR "202.38.93.111" //サーバーIPアドレス;
#define PORT 0
#define BUFSIZE 1024
 
int main(int argc, char **argv)
{
        int sockfd, ret, i, h;
        struct sockaddr_in servaddr;
        char str1[4096], str2[4096], buf[BUFSIZE], *str;
        socklen_t len;
        fd_set   t_set1;
        struct timeval  tv;
         
         //ソケットを作成
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
                printf("ネットワーク接続の作成に失敗しました。本スレッドは終了します---socket error!\n");
                exit(0);
        };
 
        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(PORT);
        if (inet_pton(AF_INET, IPSTR, &servaddr.sin_addr) <= 0 ){
                printf("ネットワーク接続の作成に失敗しました。本スレッドは終了します--inet_pton error!\n");
                exit(0);
        };
 
        if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
                printf("サーバーへの接続に失敗しました、connect error!\n");
                exit(0);
        }
        printf("リモートと接続が確立されました\n");
        memset(str2, 0, 4096);
        str=(char *)malloc(128);
        len = strlen(str2);
        sprintf(str, "%d", len);
 
        memset(str1, 0, 4096);
        strcat(str1, "GET / HTTP/1.1\n");
        strcat(str1, "Host: 202.38.93.111\n");
        strcat(str1, "\n\n");
 
        // strcat(str1, str2);
        strcat(str1, "\r\n\r\n");
        printf("%s\n",str1);
 
        ret = write(sockfd,str1,strlen(str1));
        if (ret < 0) {
                printf("送信に失敗しました!エラーコードは%d、エラー情報は'%s'\n",errno, strerror(errno));
                exit(0);
        }else{
                printf("メッセージが正常に送信され、合計%dバイトが送信されました!\n\n", ret);
        }
 
        FD_ZERO(&t_set1);
        FD_SET(sockfd, &t_set1);
 
        while(1){
                sleep(2);
                tv.tv_sec= 0;
                tv.tv_usec= 0;
                h= 0;
                // printf("--------------->1\n");
                h= select(sockfd +1, &t_set1, NULL, NULL, &tv);
                // printf("--------------->2\n");
 
                //if (h == 0) continue;
                if (h < 0) {
                        close(sockfd);
                        printf("データパケットを読み取る際にSELECTで異常が検出され、この異常によりスレッドが終了しました!\n");
                        return -1;
                };
 
                if (h > 0){
                        memset(buf, 0, 4096);
                        i= read(sockfd, buf, 4095);
                        if (i==0){
                                close(sockfd);
                                printf("データパケットを読み取る際にリモートが閉じたことが発見され、このスレッドは終了します!\n");
                                return -1;
                        }
 
                        printf("%s\n", buf);
						break;
                }
        }
        close(sockfd);
 
        return 0;
}

index.htmlファイルを取得して重要な情報を得ました。

<script>
      const term = new Terminal();
      const fitAddon = new FitAddon.FitAddon();
      term.loadAddon(fitAddon);
      term.open(document.getElementById("terminal"));
      fitAddon.fit();
      window.addEventListener('resize', function(event) {
        fitAddon.fit();
      });
      var firstmsg = true;
      const socket = new WebSocket(
         "ws://202.38.93.111:0/shell"
      );
      const attachAddon = new AttachAddon.AttachAddon(socket);
      term.loadAddon(attachAddon);
      socket.onclose = event => {
        term.write("\nConnection closed");
      };
      socket.onmessage = event => {
        if (firstmsg) {
          firstmsg = false;
          let token = new URLSearchParams(window.location.search).get("token");
          window.history.replaceState({}, null, '/');
          if (token) {
            localStorage.setItem('token', token);
          } else {
            token = localStorage.getItem('token');
          }
          if (token) socket.send(token + "\n");
        }
      };
      term.focus();
    </script>

次に、C++ の websocketを使ってサーバーに接続し、トークンを送信してフラグを取得しました。

easywsclient: connecting: host=202.38.93.111 port=0 path=/shell
Connected to: ws://202.38.93.111:0/shell
>>> 2533:MEUCIQCz8PiKvLdy1K7+TZJTwqM581W17UdJRfk3Q6hxPtr6sQIgb+Cy14NALA4ETpFQfXyfDhIxz10fyy0+t7GDEhEpS3c=

>>> Please input your token: 
>>> flag{TCP_P0RT_0_1s_re5erved_BUT_w0rks_e7e56860a1}

不意の伝送#

メッセージの解読#

ある学生がある知られざる百科事典サイトで「不意の伝送」という奇妙な暗号プロトコルを見つけました。

それで、彼はウェブサイトに記載されている「1–2不意の伝送」に従って、プロトコルの一方のロジックを実装しました。あなたはもう一方としてそれと対話することができます。

百科事典サイトのアルゴリズムに完全に従って実装されたプロトコルには問題がないでしょうか?

ソースコードをダウンロードするにはクリックしてください。

ウェブ端末の他に、nc 202.38.93.111 10031を通じて接続することもできます。

ソースコード

問題の中の 1–2 不意の伝送を検索すると、これを見つけました。

次に、Python を開いて、手順に従って一歩ずつ進めば、解読されたメッセージを得ることができます。

flag{U_R_0n_Th3_ha1f_way_0f_succe55_w0rk_h4rder!_163a930598}

超安全なプロキシサーバー#

シークレットを見つける#

2039年、前例のないパンデミックが発生しました。各地の学生が「パンツ大学」のウェブサイトにアクセスして「毎日の健康チェックイン」を行うために、小Cさんはこのようなプロキシサービスを提供しました。かつて情報セキュリティの専門家であった小Cは、このプロキシを最も安全なものに設計することに決めました。

ヒント:ブラウザはこのTLS証明書が無効であると警告するかもしれませんが、これはこの問題の解法には関係ありません。信頼してください。

お知らせ:問題のヘルプページ(https://146.56.228.227/help)の右下の「管理センター」リンクは誤っており、ホームページと同じで、http://127.0.0.1:8080/を指すべきです。

アドレス https://146.56.228.227/

まずページに入ってみましょう~

Notice: 我们已经向您 推送(PUSH) 了最新的 Secret ,但是你可能无法直接看到它。

Google で検索したところ、How to Test HTTP/2 Push using Google Chromeを見つけ、指示に従ってHTTP/2 and SPDY indicator拡張機能をインストールしました。開くと次のように表示されました。

The net-internals events viewer and related functionality has been removed. Please use chrome://net-export to save netlogs and the external netlog_viewer to view them.

ログをエクスポートし、netlog_viewer でこの HTTP/2 セッションを探すと、次のように簡単に見ることができます。

t=1410 [st=281729]  HTTP2_SESSION_SEND_RST_STREAM
                    --> description = "Duplicate pushed stream with url: https://146.56.228.227/e3b2a173-d763-409e-807c-584d13a10c92"
                    --> error_code = "7 (REFUSED_STREAM)"
                    --> stream_id = 6

上記の URL にアクセスすると、フラグを取得できます flag{d0_n0t_push_me}

参考リンク#

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。