roaris / ctf-log

0 stars 0 forks source link

CakeCTF 2022 : luau #78

Open roaris opened 1 month ago

roaris commented 1 month ago

https://alpacahack.com/challenges/luau

roaris commented 1 month ago

main.lua

local libflag = require "libflag"
io.write("FLAG: ")
flag = io.read("*l")
if libflag.checkFlag(flag, "CakeCTF 2022") then
   print("Correct!")
else
   print("Wrong...")
end

libflag.luaはバイナリ形式になっている バイトコード? image

roaris commented 1 month ago

問題名のluauというのは、luaの拡張言語とのこと https://github.com/luau-lang/luau ただ、この問題にluauが関係しているのか分からない

libflag.luaはやはりバイトコードらしい

$ file libflag.lua
libflag.lua: Lua bytecode, version 5.3
roaris commented 1 month ago

lua bytecode decompilerで調べると、https://luadec.metaworm.site/ を見つけた libflag.luaを与えると、luaのソースコードが出てきた

-- filename: 
-- version: lua53
-- line: [0, 0] id: 0
return {
  checkFlag = function(r0_1, r1_1)
    -- line: [1, 32] id: 1
    local r2_1 = {
      62,
      85,
      25,
      84,
      47,
      56,
      118,
      71,
      109,
      0,
      90,
      71,
      115,
      9,
      30,
      58,
      32,
      101,
      40,
      20,
      66,
      111,
      3,
      92,
      119,
      22,
      90,
      11,
      119,
      35,
      61,
      102,
      102,
      115,
      87,
      89,
      34,
      34
    }
    if #r0_1 ~= #r2_1 then
      return false
    end
    local r3_1 = {}
    local r4_1 = {}
    for r8_1 = 1, #r0_1, 1 do
      r3_1[r8_1] = string.byte(r0_1:sub(r8_1, r8_1 + 1))
    end
    for r8_1 = 1, #r1_1, 1 do
      r4_1[r8_1] = string.byte(r1_1:sub(r8_1, r8_1 + 1))
    end
    for r8_1 = 1, #r3_1, 1 do
      for r12_1 = r8_1 + 1, #r3_1, 1 do
        r3_1[r8_1] = r3_1[r12_1]
        r3_1[r12_1] = r3_1[r8_1]
      end
    end
    for r8_1 = 1, #r3_1, 1 do
      r3_1[r8_1] = r3_1[r8_1] ~ r4_1[1 + (r8_1 - 1) % #r4_1]
      if r3_1[r8_1] ~= r2_1[r8_1] then
        return false
      end
    end
    return true
  end,
}
roaris commented 1 month ago

Pythonのコードに書き直してみた luaは1-indexedらしい

def checkFlag(r0, r1):
    r2 = [62, 85, 25, 84, 47, 56, 118, 71, 109, 0, 90, 71, 115, 9, 30, 58, 32, 101, 40, 20, 66, 111, 3, 92, 119, 22, 90, 11, 119, 35, 61, 102, 102, 115, 87, 89, 34, 34]

    if len(r0) != len(r2):
        return False

    r3 = [0] * len(r0)
    r4 = [0] * len(r1)

    for i in range(len(r0)):
        r3[i] = r0[i]

    for i in range(len(r1)):
        r4[i] = r1[i]

    for i in range(len(r3)):
        for j in range(i + 1, len(r3)):
            r3[i] = r3[j]
            r3[j] = r3[i]

    for i in range(len(r3)):
        r3[i] = r3[i] ^ r4[i % len(r4)]

        if r3[i] != r2[i]:
            return False

    return True
roaris commented 1 month ago
for i in range(len(r3)):
    for j in range(i + 1, len(r3)):
        r3[i] = r3[j]
        r3[j] = r3[i]

がどう考えてもおかしくて、r3の要素全てが、r3の最後の要素になってしまう decompile結果が間違っている?

roaris commented 1 month ago

https://github.com/xgladius/luauDec luauのdecompilerを見つけたが、ビルドに失敗した

swapだと推測すると、上手くいった

r2 = [62, 85, 25, 84, 47, 56, 118, 71, 109, 0, 90, 71, 115, 9, 30, 58, 32, 101, 40, 20, 66, 111, 3, 92, 119, 22, 90, 11, 119, 35, 61, 102, 102, 115, 87, 89, 34, 34]
r1 = [ord(c) for c in 'CakeCTF 2022']
r3 = [0] * len(r2)

for i in range(len(r3)):
    r3[i] = r2[i] ^ r1[i % len(r1)]

for i in range(len(r2) - 1, -1, -1):
    for j in range(len(r2) - 1, i, -1):
        r3[i], r3[j] = r3[j], r3[i]

flag = ''.join(chr(c) for c in r3)
print(flag) # CakeCTF{w4n1w4n1_p4n1c_uh0uh0_g0ll1r4}
roaris commented 1 month ago

https://luadec.metaworm.site/ が作られたのが2023年で、それよりも前に出題されたので、本来は解くのがもっと大変なようだ https://github.com/viruscamp/luadec によるdisassemble結果を読んで解いているwriteupが多かった

roaris commented 1 month ago
$ make linux
cd src && make linux
make[1]: Entering directory '/home/roaris/alpacahack/luau/luadec/lua-5.3/src'
make all SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline"
make[2]: Entering directory '/home/roaris/alpacahack/luau/luadec/lua-5.3/src'
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lapi.o lapi.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lcode.o lcode.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lctype.o lctype.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ldebug.o ldebug.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ldo.o ldo.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ldump.o ldump.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lfunc.o lfunc.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lgc.o lgc.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o llex.o llex.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lmem.o lmem.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lobject.o lobject.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lopcodes.o lopcodes.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lparser.o lparser.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lstate.o lstate.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lstring.o lstring.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ltable.o ltable.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ltm.o ltm.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lundump.o lundump.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lvm.o lvm.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lzio.o lzio.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lauxlib.o lauxlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lbaselib.o lbaselib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lbitlib.o lbitlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lcorolib.o lcorolib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ldblib.o ldblib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o liolib.o liolib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lmathlib.o lmathlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o loslib.o loslib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lstrlib.o lstrlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o ltablib.o ltablib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lutf8lib.o lutf8lib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o loadlib.o loadlib.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o linit.o linit.c
ar rcu liblua.a lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o lmathlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o loadlib.o linit.o 
ar: `u' modifier ignored since `D' is the default (see `U')
ranlib liblua.a
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lua.o lua.c
lua.c:80:10: fatal error: readline/readline.h: No such file or directory
   80 | #include <readline/readline.h>
      |          ^~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [<builtin>: lua.o] Error 1
make[2]: Leaving directory '/home/roaris/alpacahack/luau/luadec/lua-5.3/src'
make[1]: *** [Makefile:110: linux] Error 2
make[1]: Leaving directory '/home/roaris/alpacahack/luau/luadec/lua-5.3/src'
make: *** [Makefile:55: linux] Error 2

include pathの問題かと思ったが、sudo apt-get install libreadline-dev で解決https://stackoverflow.com/questions/23085076/readline-readline-h-file-not-found

無事、disassemble出来たが、読むのはきつい

$ ./luadec -dis ../../libflag.lua 
cannot find blockend > 5 , pc = 4, f->sizecode = 5
cannot find blockend > 110 , pc = 109, f->sizecode = 110
; Disassembled using luadec 2.2 rev: 895d923 for Lua 5.3 from https://github.com/viruscamp/luadec
; Command line: -dis ../../libflag.lua 

; Function:        0
; Defined at line: 0
; #Upvalues:       1
; #Parameters:     0
; Is_vararg:       2
; Max Stack Size:  2

    0 [-]: CLOSURE   R0 0         ; R0 := closure(Function #0_0)
    1 [-]: NEWTABLE  R1 0 1       ; R1 := {} (size = 0,1)
    2 [-]: SETTABLE  R1 K0 R0     ; R1["checkFlag"] := R0
    3 [-]: RETURN    R1 2         ; return R1
    4 [-]: RETURN    R0 1         ; return 

; Function:        0_0
; Defined at line: 1
; #Upvalues:       1
; #Parameters:     2
; Is_vararg:       0
; Max Stack Size:  41

    0 [-]: NEWTABLE  R2 26 0      ; R2 := {} (size = 26,0)
    1 [-]: LOADK     R3 K0        ; R3 := 62
    2 [-]: LOADK     R4 K1        ; R4 := 85
    3 [-]: LOADK     R5 K2        ; R5 := 25
    4 [-]: LOADK     R6 K3        ; R6 := 84
    5 [-]: LOADK     R7 K4        ; R7 := 47
    6 [-]: LOADK     R8 K5        ; R8 := 56
    7 [-]: LOADK     R9 K6        ; R9 := 118
    8 [-]: LOADK     R10 K7       ; R10 := 71
    9 [-]: LOADK     R11 K8       ; R11 := 109
   10 [-]: LOADK     R12 K9       ; R12 := 0
   11 [-]: LOADK     R13 K10      ; R13 := 90
   12 [-]: LOADK     R14 K7       ; R14 := 71
   13 [-]: LOADK     R15 K11      ; R15 := 115
   14 [-]: LOADK     R16 K12      ; R16 := 9
   15 [-]: LOADK     R17 K13      ; R17 := 30
   16 [-]: LOADK     R18 K14      ; R18 := 58
   17 [-]: LOADK     R19 K15      ; R19 := 32
   18 [-]: LOADK     R20 K16      ; R20 := 101
   19 [-]: LOADK     R21 K17      ; R21 := 40
   20 [-]: LOADK     R22 K18      ; R22 := 20
   21 [-]: LOADK     R23 K19      ; R23 := 66
   22 [-]: LOADK     R24 K20      ; R24 := 111
   23 [-]: LOADK     R25 K21      ; R25 := 3
   24 [-]: LOADK     R26 K22      ; R26 := 92
   25 [-]: LOADK     R27 K23      ; R27 := 119
   26 [-]: LOADK     R28 K24      ; R28 := 22
   27 [-]: LOADK     R29 K10      ; R29 := 90
   28 [-]: LOADK     R30 K25      ; R30 := 11
   29 [-]: LOADK     R31 K23      ; R31 := 119
   30 [-]: LOADK     R32 K26      ; R32 := 35
   31 [-]: LOADK     R33 K27      ; R33 := 61
   32 [-]: LOADK     R34 K28      ; R34 := 102
   33 [-]: LOADK     R35 K28      ; R35 := 102
   34 [-]: LOADK     R36 K11      ; R36 := 115
   35 [-]: LOADK     R37 K29      ; R37 := 87
   36 [-]: LOADK     R38 K30      ; R38 := 89
   37 [-]: LOADK     R39 K31      ; R39 := 34
   38 [-]: LOADK     R40 K31      ; R40 := 34
   39 [-]: SETLIST   R2 38 1      ; R2[0] to R2[37] := R3 to R40 ; R(a)[(c-1)*FPF+i] := R(a+i), 1 <= i <= b, a=2, b=38, c=1, FPF=50
   40 [-]: LEN       R3 R0        ; R3 := #R0
   41 [-]: LEN       R4 R2        ; R4 := #R2
   42 [-]: EQ        1 R3 R4      ; if R3 ~= R4 then goto 44 else goto 46
   43 [-]: JMP       R0 2         ; PC += 2 (goto 46)
   44 [-]: LOADBOOL  R3 0 0       ; R3 := false
   45 [-]: RETURN    R3 2         ; return R3
   46 [-]: NEWTABLE  R3 0 0       ; R3 := {} (size = 0,0)
   47 [-]: NEWTABLE  R4 0 0       ; R4 := {} (size = 0,0)
   48 [-]: LOADK     R5 K32       ; R5 := 1
   49 [-]: LEN       R6 R0        ; R6 := #R0
   50 [-]: LOADK     R7 K32       ; R7 := 1
   51 [-]: FORPREP   R5 8         ; R5 -= R7; pc += 8 (goto 60)
   52 [-]: GETTABUP  R9 U0 K33    ; R9 := U0["string"]
   53 [-]: GETTABLE  R9 R9 K34    ; R9 := R9["byte"]
   54 [-]: SELF      R10 R0 K35   ; R11 := R0; R10 := R0["sub"]
   55 [-]: MOVE      R12 R8       ; R12 := R8
   56 [-]: ADD       R13 R8 K32   ; R13 := R8 + 1
   57 [-]: CALL      R10 4 0      ; R10 to top := R10(R11 to R13)
   58 [-]: CALL      R9 0 2       ; R9 := R9(R10 to top)
   59 [-]: SETTABLE  R3 R8 R9     ; R3[R8] := R9
   60 [-]: FORLOOP   R5 -9        ; R5 += R7; if R5 <= R6 then R8 := R5; PC += -9 , goto 52 end
   61 [-]: LOADK     R5 K32       ; R5 := 1
   62 [-]: LEN       R6 R1        ; R6 := #R1
   63 [-]: LOADK     R7 K32       ; R7 := 1
   64 [-]: FORPREP   R5 8         ; R5 -= R7; pc += 8 (goto 73)
   65 [-]: GETTABUP  R9 U0 K33    ; R9 := U0["string"]
   66 [-]: GETTABLE  R9 R9 K34    ; R9 := R9["byte"]
   67 [-]: SELF      R10 R1 K35   ; R11 := R1; R10 := R1["sub"]
   68 [-]: MOVE      R12 R8       ; R12 := R8
   69 [-]: ADD       R13 R8 K32   ; R13 := R8 + 1
   70 [-]: CALL      R10 4 0      ; R10 to top := R10(R11 to R13)
   71 [-]: CALL      R9 0 2       ; R9 := R9(R10 to top)
   72 [-]: SETTABLE  R4 R8 R9     ; R4[R8] := R9
   73 [-]: FORLOOP   R5 -9        ; R5 += R7; if R5 <= R6 then R8 := R5; PC += -9 , goto 65 end
   74 [-]: LOADK     R5 K32       ; R5 := 1
   75 [-]: LEN       R6 R3        ; R6 := #R3
   76 [-]: LOADK     R7 K32       ; R7 := 1
   77 [-]: FORPREP   R5 9         ; R5 -= R7; pc += 9 (goto 87)
   78 [-]: ADD       R9 R8 K32    ; R9 := R8 + 1
   79 [-]: LEN       R10 R3       ; R10 := #R3
   80 [-]: LOADK     R11 K32      ; R11 := 1
   81 [-]: FORPREP   R9 4         ; R9 -= R11; pc += 4 (goto 86)
   82 [-]: GETTABLE  R13 R3 R8    ; R13 := R3[R8]
   83 [-]: GETTABLE  R14 R3 R12   ; R14 := R3[R12]
   84 [-]: SETTABLE  R3 R8 R14    ; R3[R8] := R14
   85 [-]: SETTABLE  R3 R12 R13   ; R3[R12] := R13
   86 [-]: FORLOOP   R9 -5        ; R9 += R11; if R9 <= R10 then R12 := R9; PC += -5 , goto 82 end
   87 [-]: FORLOOP   R5 -10       ; R5 += R7; if R5 <= R6 then R8 := R5; PC += -10 , goto 78 end
   88 [-]: LOADK     R5 K32       ; R5 := 1
   89 [-]: LEN       R6 R3        ; R6 := #R3
   90 [-]: LOADK     R7 K32       ; R7 := 1
   91 [-]: FORPREP   R5 14        ; R5 -= R7; pc += 14 (goto 106)
   92 [-]: GETTABLE  R9 R3 R8     ; R9 := R3[R8]
   93 [-]: SUB       R10 R8 K32   ; R10 := R8 - 1
   94 [-]: LEN       R11 R4       ; R11 := #R4
   95 [-]: MOD       R10 R10 R11  ; R10 := R10 % R11
   96 [-]: ADD       R10 K32 R10  ; R10 := 1 + R10
   97 [-]: GETTABLE  R10 R4 R10   ; R10 := R4[R10]
   98 [-]: BXOR      R9 R9 R10    ; R9 := R9 ~ R10
   99 [-]: SETTABLE  R3 R8 R9     ; R3[R8] := R9
  100 [-]: GETTABLE  R9 R3 R8     ; R9 := R3[R8]
  101 [-]: GETTABLE  R10 R2 R8    ; R10 := R2[R8]
  102 [-]: EQ        1 R9 R10     ; if R9 ~= R10 then goto 104 else goto 106
  103 [-]: JMP       R0 2         ; PC += 2 (goto 106)
  104 [-]: LOADBOOL  R9 0 0       ; R9 := false
  105 [-]: RETURN    R9 2         ; return R9
  106 [-]: FORLOOP   R5 -15       ; R5 += R7; if R5 <= R6 then R8 := R5; PC += -15 , goto 92 end
  107 [-]: LOADBOOL  R5 1 0       ; R5 := true
  108 [-]: RETURN    R5 2         ; return R5
  109 [-]: RETURN    R0 1         ; return