1. 程式人生 > 其它 >Bugku 雜項 - Snowfall

Bugku 雜項 - Snowfall

Whitespace.

1 題目

http://ctf.bugku.com/challenges/detail/id/318.html

2 題目分析

step1 和 step2 兩個 txt,VSCode 開啟,可以看到裡面有很多空字元(不要用記事本開啟,分不出來空格、Tab 和回車)

關於換車和換行,Windows 下是 CRLF,UNIX-like 一般是 LF[1],所以判斷換行的標誌就是 LF(ASCII 10)。
這是一種名為 Whitespace 程式語言[2],一個名為 Whitelips 的網站可以執行這種程式碼。
也可以寫 Python 程式碼找出所有的空字元(空格、Tab 和換行),按照空格=0、Tab=1、換行=" "的規則進行連線,程式碼如下[3]

s = open(r"C:\Users\X\Desktop\step1.txt", "rb").read()

a = ""
for i in s:
    if i == 32:  # 空格
        a += "0"
    elif i == 9:  # tab
        a += "1"
    elif i == 10:  # 換行
        a += " "

print(a)
for i in a.split(" 1 "):
    i = int(i, 2)
    print(chr(i), end="")

可以看到結果是一個以 " 1 "分割的字串,將每一部分轉換成對應對應的 ASCII 碼,可以得到一個 key。
OK now you can run whitespace code. By the way, the key is H0wt0Pr1ntAWh17e5p4ceC0de.

用網站執行 step1 的話,也是同樣的結果。

再把 step2 執行一下,

可以看到執行結果是一個 7z 檔案,裡面還有一個 flag.txt 檔案。

如何儲存這個壓縮包呢?

還是根據上面這位大佬[4]的 wp,需要觀察右邊堆疊的執行過程,把每次 printc 的結果轉換成最終的 7z 檔案。

因為網站最終 output 的是字元,沒法直接複製來生成 7z 檔案,所以稍微改了下網站的 js 程式碼,使得 printc 可以直接輸出轉義前的數字:

修改前後的程式碼如下:

//   WsPrintChar: function() {
//     this.run = function(env) {
//       var ch = env.stackPop();
//       env.print(String.fromCharCode(ch));
//       env.register.IP++;
//     };
//     this.getAsm = asmWithNoParam;
//   },

  WsPrintChar: function() {
    this.run = function(env) {
      var ch = env.stackPop();
      env.print(ch);
      env.print(",");
      env.register.IP++;
    };
    this.getAsm = asmWithNoParam;
  },

最終得到結果如下:

複製出來,用 Python 轉成 7z,

x = [55,122,188,175,39,28,0,4,233,178,103,148,176,0,0,0,0,0,0,0,106,0,0,0,0,0,0,0,205,61,162,91,148,163,10,161,6,123,111,146,195,229,199,77,197,176,226,227,44,177,43,96,161,183,25,95,211,125,221,70,102,117,157,219,2,113,89,134,199,190,90,208,113,2,30,131,134,158,192,184,130,200,49,95,169,69,184,36,202,69,2,69,160,13,36,13,176,115,55,167,181,220,144,24,156,128,159,52,143,64,170,177,64,129,83,122,169,252,159,170,33,201,53,141,86,73,35,149,56,209,111,227,46,146,218,18,60,77,165,23,248,38,213,201,136,18,249,150,90,225,255,195,101,23,65,13,144,238,93,31,150,182,136,40,73,137,105,218,0,3,2,92,123,250,128,137,207,217,187,15,202,154,187,172,229,221,223,77,58,56,62,234,238,175,206,236,90,65,197,234,53,242,98,189,93,69,135,58,1,4,6,0,1,9,128,176,0,7,11,1,0,2,36,6,241,7,1,18,83,15,181,85,78,250,249,198,199,186,171,74,81,185,17,229,245,136,33,33,1,0,1,0,12,128,162,131,85,0,8,10,1,126,78,13,98,0,0,5,1,17,19,0,102,0,108,0,97,0,103,0,46,0,116,0,120,0,116,0,0,0,25,0,20,10,1,0,50,92,151,50,148,119,215,1,21,6,1,0,32,0,0,0,0,0,]

f = b''
for i in x:
    f += i.to_bytes(1, 'big')

out = open("1.7z", "wb")
out.write(f)

開啟裡面有一個加密的 flag.txt,用上面 step1 的 key 解壓,還是一個 Whitespace。

用 Whitelips 執行一下,並沒有看到輸出,因為這裡的堆疊指令是 drop,會彈出棧頂元素,但是並不列印。。。

還是改一下 Whitelips 的 js 程式碼,出棧的同時轉換成字元列印。

//   WsDropTop: function() {
//     this.run = function (env) {
//       env.register.SP--;
//       env.register.IP++;
//     }
//     this.getAsm = asmWithNoParam;
//   },

  WsDropTop: function() {
    this.run = function (env) {
      env.print(String.fromCharCode(env.stackPeek()));
      env.register.SP--;
      env.register.IP++;
    }
    this.getAsm = asmWithNoParam;
  },

重新執行,在 output 可以看到 flag:bugku{F1xAnE5olangPr0gr4mT0Cap7ureTh3F14g}


  1. https://www.zhihu.com/question/46542168 ↩︎

  2. https://zh.m.wikipedia.org/wiki/Whitespace ↩︎

  3. https://blog.csdn.net/weixin_45696568/article/details/111413521 ↩︎

  4. https://blog.csdn.net/weixin_45696568/article/details/111413521 ↩︎