前排提示:我是搜索型選手,以前沒打過 CTF。我很菜的。

本文由我撰寫的部分放棄版權,請隨意。

白與夜

右鍵那張圖片 Open image in new tab 就能看到 flag 文字。

flag{4_B14CK_C4T}

信息安全 2077

打開 DevTools → Network 複製請求的 CURL,終端修改參數 If-Unmodified-Since 成指定的時間執行就可。

flag{Welc0me_to_competit1on_in_2077}

宇宙終極問題

第一部分:Google 搜索 42 sum of cubes

得到三個數是 -80538738812075974804357581458175153126021232973356313

第二部分:

(丟人)

第三部分:

雖然我自己也寫了個 python 腳本,使用 primefac 和 math.stackexchange 上的代碼。但是運行速度過於緩慢,達不到題目的要求。

https://www.alpertron.com.ar/ECM.HTM (再度丟人)

如果服務器給的隨機數合適,就可以表成兩數平方和。但是下列情況之一的,不可能表成兩數平方和:

  1. 隨機數本身模 4 餘 3
  2. 因數分解後模 4 餘 3 的質因子冪次爲奇數

網頁讀取器

下載源碼,由於 flask 這種框架有安全問題的可能性較低,肯定是他自己的源碼寫錯了。果不其然,其有一行去除鏈接中第一個 @ 及之前所有字符。構造鏈接 http://web1/flag?@example.com 就可。

大冒險

一開始我不會做這個題目,因爲設置了一個干擾選項“打怪升級”,在我看來只有戲劇效果。

後來,我發現“料理大市場”場景可以在控制檯用 ws.send(<integer>) 與服務器通訊,輸入不在 0 到 10 之間的數也可以。那就輸入一個巨大的負數使得 ATK 溢出爲一大正數,由於惡龍攻擊力只有 8 位數,很輕鬆就被我們秒掉了。在與國王的對話中選擇 flag 即可。

flag{what_an_amazing_dream}

Happy LUG

我一讀完題就知道怎麼做了,然而,當時我看錯了域名……

對 Unicode 域名,搜索 Punycode 或者直接打在瀏覽器地址欄回車就行。

$ drill xn--g28h.hack.USTCLUG.org txt
(部分輸出已省略)
xn--g28h.hack.USTCLUG.org.    300    IN    TXT    "flag{DN5_C4N_H4VE_em0ji_haha}"

命令 drill 是 archlinux 特色,若無請換成 dig

正則驗證器

Google 搜索 regex DoS,找到 Wikipedia 頁面。看源碼只允許 6 字符的正則表達式和 24 字符的文本,我們選擇 (x+)+$xxxxxxxxxxxxxxxxxxxxxxx! 來測試。遂得到 flag。

flag{R3g3x_can_D0S_<signature>}

別樣的 python 考試

我卡 challenge 14 沒做出來。只能 95 分。

以下是不完全解答:

  1. "Hello"
  2. 1,1,1.0,1
  3. ""
  4. [1],1
  5. [3,2,1]
  6. {1,2},{1,3}
  7. (1,),4,-5
  8. (1,2),-2,-2
  9. 3,-1
  10. '12377',''
  11. ((10,),)
  12. (),(1,2)
  13. {1},{1}
  14. 未解出
  15. '','123'
  16. b"\xe9"
  17. 1, {0:1}
  18. 1e400,1e400
  19. "\u06f0\u1c43\u1c59\u1c59"
  20. [0, 0.0, 0.0j, False, -0.0, -0.0j, -0.0-0.0j]

關於 14 題參見 Python Programming FAQ

小巧玲瓏的 ELF

用 IDA Pro 載入這個 ELF,debug 運行就能看到對應的 C 代碼,導出數據後解密即可。

#include <stdio.h>
const char key[] = {
  102, 110, 101, 107, -125, 78, 109, 116, -123, 122, 111, 87, -111, 115, -112, 79, -115, 127, 99, 54, 108, 110, -121, 105, -93, 111, 88, 115, 102, 86, -109, -97, 105, 112, 56, 118, 113, 120, 111, 99, -60, -126, -124, -66, -69, -51
};
int main ()
{
  char buf[47];
  for (int j = 0; j <= 45; j++)
    buf[j] = key[j];
  for (int i = 0; i <= 45; i++)
    {
      buf[i] += i;
      buf[i] ^= i;
      buf[i] -= 2 * i;
    }
  buf[46] = '\0';
  printf ("%s", buf);
  return 0;
}
flag{Linux_Syst3m_C4ll_is_4_f4scin4ting_t00ls}

Shell 駭客

  1. 由於沒有任何限制,Google 搜索 x64 execve shellcode 即可。我是用 pwntools payload 的,用 websocket 說不定也行。
  2. $ msfvenom -a x86 --platform linux -p linux/x86/exec CMD=/bin/sh -e x86/alpha_upper -f python 即可生成。
  3. 我測試了 ecx86/shellcode_encoder,指定 rax,發現並不行。查找網上資源打算手寫一個 x64 printable shellcode,失敗。所以本小題未解出。

後來瞭解到有個工具叫 alpha3

三教奇妙夜

打開視頻觀看前一分鐘就能找到兩幀 flag 黑屏圖(即“flag{”)。

$ ffmpeg -i output.mp4 -vf blackdetect=d=0.04:pic_th=0.95:pix_th=0.01 -f rawvideo -y /dev/null

等輸出,再找到秒數對應的幀看就可。

(輸出已經簡略)
[blackdetect @ 0x5621517b67c0] black_start:59.96 black_end:60.04 black_duration:0.08
[blackdetect @ 0x5621517b67c0] black_start:183 black_end:183.08 black_duration:0.08speed= 331x    
[blackdetect @ 0x5621517b67c0] black_start:10183 black_end:10183.1 black_duration:0.08peed= 332x    
[blackdetect @ 0x5621517b67c0] black_start:30059.1 black_end:30059.2 black_duration:0.08eed= 309x    
[blackdetect @ 0x5621517b67c0] black_start:42404.1 black_end:42404.2 black_duration:0.08peed= 308x    
[blackdetect @ 0x5621517b67c0] black_start:43104.2 black_end:43104.2 black_duration:0.08peed= 308x

output.00_00_59_23.Still003.png

output.00_03_02_23.Still001.png

output.02_49_42_24.Still002.png

output.08_20_59_00.Still003.png

output.11_46_44_01.Still004.png

output.11_58_24_03.Still004.png

flag{ViDe0_prOcE55_with_program_1s_eaSy}

小插曲:未解出時我曾試圖用 Google Video Intelligence 提取文本,結果爲空。

小 U 的加密

根據題目提示是位運算。用 GHex 打開發現文件各處都有很多的字符 9(0x39),將全部字節 xor 0x39 就得到原文件,然而我一開始並不認識 MThd MTrk 這個魔數,但可以推測該文件格式編碼效率很低,不是正常的音頻編碼。於是發現其是 MIDI 文件。在 Windows 系統下載一個 MIDI 編輯器打開後即看到 flag 圖形。

flag{justxorandmidi}

獻給最好的你

本題疑似玩梗 2019 年各大高校 9.27 事件(原名“獻給最好的 TA”)。

解壓 APK 包(這個包在我太過低級的 Huawei 手機上並不能安裝),得到 classes.dex 文件。下載 dex2jar 最新的 nightly build,發現仍然無法轉換爲 jar 文件。無奈直接把魔數 dex\n038 改成 dex\n037,就可以用 dex2jar 了。用 jd-gui 打開得到的 jar 文件,定位到 com/hackergame.eternalEastlyWind/LoginResult.class,讀一下 login 和 logout 兩個函數的源碼,解密即可。

#!/usr/bin/python3
from base64 import b64encode, b64decode
mysterious_string = "AgfJA2vYz2fTztiWmtL3AxrOzNvUiq=="
flxg_bytes = bytes([
    14, 13, 2, 12, 30, 30, 2, 0, 31, 11,
    109, 81, 83, 8, 3, 54, 21, 6, 2, 39,
    33, 104, 44, 62, 17, 14, 19, 23, 21, 18,
    8, 24
])
def xchange_case(s):
    ret = ''
    for ch in s:
        if ch.islower():
            ret += ch.upper()
        elif ch.isupper():
            ret += ch.lower()
        else:
            ret += ch
    return ret
def rewritten_logout(param_string_bytes, param_array_of_bytes):
    # param_string rawpassword
    # param_array_of_bytes flxg - is related to the flag
    i = len(param_array_of_bytes) - 1
    lps = len(param_string_bytes)
    
    sb = ''
    j = 0
    while True:
        ch = chr( param_array_of_bytes[j] ^ param_string_bytes[j % lps])
        print("pass2", ch)
        sb += ch
        if j != i:
            j += 1
            continue
        break
    print("pass2", sb)
    return sb
def rewritten_login(param_string_bytes):
    # param_string: password
    #array_of_byte = param_string.encode('utf-8')
    array_of_bytes = param_string_bytes
    original_str = b64encode(array_of_bytes[2:])
    new_str = xchange_case(original_str)
    print("pass1", new_str)

    if new_str != mysterious_str:
        print("wrong password")
        return False # Failure
    return True # Success
def decrypt():
    rs = xchange_case(mysterious_string)
    bf2 = b64decode(rs)
    rewritten_logout(bf2, flxg_bytes)
if __name__ == '__main__': decrypt()
flag{learn_ab1t_andROID_reverse}

天書殘篇

下載那個文件發現只有三種字符:普通空格,製表符 \t 和換行 \n。找到在線 whitespace 編譯器,載入 whitespace 源碼,點擊右邊 Run 就會出現人能看懂的彙編代碼,拖下來。雖然代碼中有許多 label,但可以看出有一串 label 是在逐位判斷輸入是否符合編碼的 flag,提取數據寫程序解密即可。

#include <stdio.h>
const char source[] = {127, 53, 105, 54, 119, 105, 112, 54, 110, 97, 111, 54, 116, 105, 50, 116, 114, 97, 118, 110, 119, 101, 107, 104, 104, 107, 102, 97, 99, 97, 117, 107, 97, 53, 101, 54, 114, 117, 53, 118, 107, 106, 89, 125, 105, 99, 110, 104};
char buf[49];
int main()
{
    buf[48] = '\0';
    for (int j = 47; j >= 0; --j)
    {
        buf[47-j] = source[j] - 2;
    }
    printf("%s", buf);
    return 0;
}
flag{Whit3sp4c3_is_a_difficult_pr0gr4m_l4ngu4g3}

我想要個家

VirtualBox 虛擬機隨便載入一張 Linux Live CD(並非必要)。由於我太菜不會去掉根目錄的 /proc/sys,只能 chroot

/mnt 作爲 chroot jail,創建子目錄 lib,複製 bash 和 sleep 到 /mnt,用 ldd 查看兩個文件的依賴並把相關庫複製到 /mnt/lib 目錄中。按要求在 /mnt 創建目錄、文件和符號鏈接,開一個終端無限循環每 0.1 秒寫入當前時間。

while true
do
    sleep 0.1
    date +%H:%M:%S > /mnt/Living_Room/Clock
done

在 jail 外準備完成後,複製題目的二進制文件到 /mnt,用 chroot /mnt /bash,運行二進制文件。等提示輸入 /sleep 10,等待 10 秒即可得到 flag,英文是 I am happy now。

被泄漏的薑戈

本題疑似致敬 openbilibili。

上 GitHub 搜索 openlug,找到此名的用戶和其倉庫 django-common,clone 之。有價值的只有 db.sqlite3 中的 admin 用戶密碼和 openlug/settings.py 中的 SECRET_KEY。閱覽 django 官方文檔和源代碼即可用 python 解題。

由於 Kali Linux Live 虛擬機被我不慎關閉,python 控制檯記錄也就永久丟失了。我使用的是官方題解中“複雜的解法”。

flag{Never_leak_your_sEcReT_KEY}

沒有 BUG 的教務系統

只做了第一問,由於第二問需要 pwn 積累,我是做不出來的。

for (i = 0; i <= 7; ++i)
  temp_password[i] = ((temp_password[i] | temp_password[i + 1]) & ~(temp_password[i] & temp_password[i + 1]) | i) & ~((temp_password[i] | temp_password[i + 1]) & ~(temp_password[i] & temp_password[i + 1]) & i);
if(memcmp(temp_password, "\x44\x00\x02\x41\x43\x47\x10\x63\x00", 9)) {
  cout << "Bad guy! Wrong password!" << endl;
  exit(0);
}

temp_password[i] 爲 A,temp_password[i+1] 爲 B,i 爲 C,輸入 WolframAlpha 中得到真值表和 Venn 圖,非常漂亮。寫一段程序即可逆推出密碼。

photo_2019-10-22_15-39-19.jpg

#include <iostream>
using namespace std;
// "\x44\x00\x02\x41\x43\x47\x10\x63\x00"
const char *rsrc = "\x00\x63\x10\x47\x43\x41\x02\x00\x44";
char buf[9] = {0,0,0,0,0,0,0,0,0};
char bitwise_decipher(const char b, const char c, const char v) {
    int sum = (b << 2) | (c << 1) | v;
    switch (sum) {
    case 7:
    case 4:
    case 2:
    case 1:
        return 1;
    case 6:
    case 5:
    case 3:
    case 0:    return 0;
    }
    return 0;
}
void decipher(char &a, char b, char c, char v) {
    a = 0;
    for (int i = 0; i < 8; i++) {
        a |= (bitwise_decipher(
            (b >> i) & 1,
            (c >> i) & 1,
            (v >> i) & 1
        ) << i);
    }
}
int main() {
    for (int j = 1; j < 9; j++) {
        decipher(buf[j], buf[j-1], (char)(8-j), rsrc[j]);
    }
    for (int j = 0; j < 9; j++) std::cout << buf[8-j];
    return 0;
}

得到密碼 p455w0rd

其他題目均未解出

尾聲

3500,終局 #38,校內榜一(前輩們都沒怎麼打,讓我們萌新玩玩?)

首尾呼應:我好菜啊.jpg 電子競技菜是原罪.jpg