Open roaris opened 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はバイナリ形式になっている バイトコード?
問題名のluauというのは、luaの拡張言語とのこと https://github.com/luau-lang/luau ただ、この問題にluauが関係しているのか分からない
libflag.luaはやはりバイトコードらしい
$ file libflag.lua
libflag.lua: Lua bytecode, version 5.3
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,
}
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
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結果が間違っている?
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}
https://luadec.metaworm.site/ が作られたのが2023年で、それよりも前に出題されたので、本来は解くのがもっと大変なようだ https://github.com/viruscamp/luadec によるdisassemble結果を読んで解いているwriteupが多かった
$ 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
https://alpacahack.com/challenges/luau