Shi0shishi0

汐鹿生

picoCTF 2021 writeup

picoCTF 2021にソロで参加して27/88問に解答しました。得点はメモしてなかったので不明です。 開催期間が結構長かったのに数日しか参加出来なかったので悲しい。

メモが残っていた問題のwriteup

ARMssembly 0

問題文は以下の通り。ARMv8のアセンブリが渡されて、このプログラムの引数が"4112417903"と"1169092511"である場合に出力される値を答える問題。

Description
What integer does this program print with arguments 4112417903 and 1169092511? File: chall.S Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})

ソースファイル(chall.S)が提供される。

  .arch armv8-a
    .file   "chall.c"
    .text
    .align  2
    .global func1
    .type   func1, %function
func1:
    sub sp, sp, #16
    str w0, [sp, 12]
    str w1, [sp, 8]
    ldr w1, [sp, 12]
    ldr w0, [sp, 8]
    cmp w1, w0
    bls .L2
    ldr w0, [sp, 12]
    b   .L3
.L2:
    ldr w0, [sp, 8]
.L3:
    add sp, sp, 16
    ret
    .size   func1, .-func1
    .section    .rodata
    .align  3
.LC0:
    .string "Result: %ld\n"
    .text
    .align  2
    .global main
    .type   main, %function
main:
    stp x29, x30, [sp, -48]!
    add x29, sp, 0
    str x19, [sp, 16]
    str w0, [x29, 44]
    str x1, [x29, 32]
    ldr x0, [x29, 32]
    add x0, x0, 8
    ldr x0, [x0]
    bl  atoi
    mov w19, w0 # w19 = 4112417903
    ldr x0, [x29, 32]
    add x0, x0, 16
    ldr x0, [x0]
    bl  atoi
    mov w1, w0 # w1 = 1169092511
    mov w0, w19 # w0 = 4112417903
    bl  func1
    mov w1, w0
    adrp    x0, .LC0
    add x0, x0, :lo12:.LC0
    bl  printf
    mov w0, 0
    ldr x19, [sp, 16]
    ldp x29, x30, [sp], 48
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0"
    .section    .note.GNU-stack,"",@progbits

main関数のbl命令でfunc1関数を実行して、実行結果をprintf関数で出力すると思われる。

  stp x29, x30, [sp, -48]!
    add x29, sp, 0
    str x19, [sp, 16]
    str w0, [x29, 44]
    str x1, [x29, 32]
    ldr x0, [x29, 32]
    add x0, x0, 8
    ldr x0, [x0]
    bl  atoi # atoi関数
    mov w19, w0 # w19 = 4112417903
    ldr x0, [x29, 32]
    add x0, x0, 16
    ldr x0, [x0]
    bl  atoi # atoi関数
    mov w1, w0 # w1 = 1169092511
    mov w0, w19 # w0 = 4112417903
    bl  func1 # func1関数(引数1 : 4112417903, 引数2 : 1169092511)
    mov w1, w0
    adrp    x0, .LC0 # "Result: %ld\n"
    add x0, x0, :lo12:.LC0
    bl  printf

問題文にある引数を与えた場合、func1関数の返り値として、w0には4112417903が格納される。

func1:
    sub sp, sp, #16
    str w0, [sp, 12] # w0(4112417903) -> [sp, 12]
    str w1, [sp, 8] # w1(1169092511) -> [sp, 8]
    ldr w1, [sp, 12] # w1 <- [sp, 12](4112417903)
    ldr w0, [sp, 8] # w0 <- [sp, 8](1169092511)
    cmp w1, w0 # 4112417903, 1169092511
    bls .L2 # not jump
    ldr w0, [sp, 12] # w0 <- [sp, 12](4112417903)
    b   .L3
.L2:
    ldr w0, [sp, 8] 
.L3:
    add sp, sp, 16
    ret
    .size   func1, .-func1
    .section    .rodata
    .align  3

問題文の指定より、フラグは16進数表記、プレフィックス無しの形式になる。

C:\Users\user>python
Python 2.7.16 (v2.7.16:413a49145e, Mar  4 2019, 01:37:19) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> hex(4112417903)
'0xf51e846fL'

Flag : picoCTF{f51e846f}

ARMssembly 1

問題文は以下の通り。ARMv8のアセンブリが渡されて、このプログラムにどのような引数が与えられた時に win が出力されるのかを答える問題。

For what argument does this program print `win` with variables 81, 0 and 3? File: chall_1.S Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})

ソースファイル(chall_1.S)が提供される。

  .arch armv8-a
    .file   "chall_1.c"
    .text
    .align  2
    .global func
    .type   func, %function
func:
    sub sp, sp, #32
    str w0, [sp, 12]
    mov w0, 81
    str w0, [sp, 16]
    str wzr, [sp, 20]
    mov w0, 3
    str w0, [sp, 24]
    ldr w0, [sp, 20]
    ldr w1, [sp, 16]
    lsl w0, w1, w0
    str w0, [sp, 28]
    ldr w1, [sp, 28]
    ldr w0, [sp, 24]
    sdiv    w0, w1, w0
    str w0, [sp, 28]
    ldr w1, [sp, 28]
    ldr w0, [sp, 12]
    sub w0, w1, w0
    str w0, [sp, 28]
    ldr w0, [sp, 28]
    add sp, sp, 32
    ret
    .size   func, .-func
    .section    .rodata
    .align  3
.LC0:
    .string "You win!"
    .align  3
.LC1:
    .string "You Lose :("
    .text
    .align  2
    .global main
    .type   main, %function
main:
    stp x29, x30, [sp, -48]!
    add x29, sp, 0
    str w0, [x29, 28]
    str x1, [x29, 16]
    ldr x0, [x29, 16]
    add x0, x0, 8
    ldr x0, [x0]
    bl  atoi
    str w0, [x29, 44]
    ldr w0, [x29, 44]
    bl  func
    cmp w0, 0
    bne .L4
    adrp    x0, .LC0
    add x0, x0, :lo12:.LC0
    bl  puts
    b   .L6
.L4:
    adrp    x0, .LC1
    add x0, x0, :lo12:.LC1
    bl  puts
.L6:
    nop
    ldp x29, x30, [sp], 48
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0"
    .section    .note.GNU-stack,"",@progbits

func関数に与えられた値の動きを確認する。問題文にある通り、81、0、3が関数内で使用されている。また、 sub w0, w1, w0 でfunc関数の引数が計算に使用されている。

func:
    sub sp, sp, #32
    str w0, [sp, 12] # w0(★funcの引数) -> [sp, 12]
    mov w0, 81 # w0 = 81
    str w0, [sp, 16] # w0(81) -> [sp, 16]
    str wzr, [sp, 20] # wzr(zero_register) -> [sp, 20]
    mov w0, 3 # w0 = 3
    str w0, [sp, 24] # w0(3) -> [sp, 24]
    ldr w0, [sp, 20] # w0 <- [sp, 20](0)
    ldr w1, [sp, 16] # w1 <- [sp, 16](81)
    lsl w0, w1, w0 # w0(81) <- 81 << 0
    str w0, [sp, 28] # w0(81) -> [sp, 28]
    ldr w1, [sp, 28] # w1 <- [sp, 28](81)
    ldr w0, [sp, 24] # w0 <- [sp, 24](3)
    sdiv    w0, w1, w0 # w0(27) <- w1(81) / w0(3)
    str w0, [sp, 28] # w0(27) -> [sp, 28]
    ldr w1, [sp, 28] # w1 <- [sp, 28](27)
    ldr w0, [sp, 12] # w0 <- ★funcの引数
    sub w0, w1, w0 # w0 <- w1(27) - w0(★funcの引数)
    str w0, [sp, 28]
    ldr w0, [sp, 28] # w0 = "w1(27) - w0(★funcの引数)"の計算結果
    add sp, sp, 32
    ret
    .size   func, .-func
    .section    .rodata
    .align  3

func関数以降のコードを確認すると、返り値が0と等しくない時に.L4にジャンプして"You Lose :("を出力する。"You win!"と出力されるのはfunc関数の返り値(w0)が0の場合になる。

  bl  func
    cmp w0, 0
    bne .L4
    adrp    x0, .LC0 # "You win!"
    add x0, x0, :lo12:.LC0
    bl  puts
    b   .L6

func関数の sub w0, w1, w0 の実行結果が0になるのはfunc関数の引数が27の場合。

C:\Users\user>python
Python 2.7.16 (v2.7.16:413a49145e, Mar  4 2019, 01:37:19) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> hex(27)
'0x1b'

FLAG : picoCTF{0000001b}

ARMssembly 2

問題文は以下の通り。ARMv8のアセンブリが渡されて、このプログラムに与えられる引数が2610164910の時に出力される値を答える。

Description
What integer does this program print with argument 2610164910? File: chall_2.S Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})

アセンブリファイル(chall_2.S)の内容は以下の通り。

  .arch armv8-a
    .file   "chall_2.c"
    .text
    .align  2
    .global func1
    .type   func1, %function
func1:
    sub sp, sp, #32
    str w0, [sp, 12]
    str wzr, [sp, 24]
    str wzr, [sp, 28]
    b   .L2
.L3:
    ldr w0, [sp, 24]
    add w0, w0, 3
    str w0, [sp, 24]
    ldr w0, [sp, 28]
    add w0, w0, 1
    str w0, [sp, 28]
.L2:
    ldr w1, [sp, 28]
    ldr w0, [sp, 12]
    cmp w1, w0
    bcc .L3
    ldr w0, [sp, 24]
    add sp, sp, 32
    ret
    .size   func1, .-func1
    .section    .rodata
    .align  3
.LC0:
    .string "Result: %ld\n"
    .text
    .align  2
    .global main
    .type   main, %function
main:
    stp x29, x30, [sp, -48]!
    add x29, sp, 0
    str w0, [x29, 28]
    str x1, [x29, 16]
    ldr x0, [x29, 16]
    add x0, x0, 8
    ldr x0, [x0]
    bl  atoi
    bl  func1
    str w0, [x29, 44]
    adrp    x0, .LC0
    add x0, x0, :lo12:.LC0
    ldr w1, [x29, 44]
    bl  printf
    nop
    ldp x29, x30, [sp], 48
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0"
    .section    .note.GNU-stack,"",@progbits

L3では[sp, 24]が3ずつ、[sp, 28]が1ずつ増加する。

func1:
    sub sp, sp, #32
    str w0, [sp, 12] # w0(2610164910) -> [sp, 12]
    str wzr, [sp, 24] # wzr(0) -> [sp, 24]
    str wzr, [sp, 28] # wzr(0) -> [sp, 28]
    b   .L2 # jump to .L2
.L3:
    ldr w0, [sp, 24] # w0 <- [sp, 24](0)
    add w0, w0, 3 # w0 <- w0(0) + 3
    str w0, [sp, 24] # w0(3) -> [sp, 24]
    ldr w0, [sp, 28] # w0 <- [sp, 28](0)
    add w0, w0, 1 # w0 <- w0(0) + 1
    str w0, [sp, 28] # w0(1) -> [sp, 28]
.L2:
    ldr w1, [sp, 28] # w1 <- [sp, 28](0)
    ldr w0, [sp, 12] # w0 <- [sp, 12](2610164910)
    cmp w1, w0
    bcc .L3
    ldr w0, [sp, 24]
    add sp, sp, 32
    ret
    .size   func1, .-func1
    .section    .rodata
    .align  3

func1関数ではループカウンタ([sp, 28])が引数の値(2610164910)と一致するまでループが行われて、[sp, 24]の値が3ずつ増加する。そのため、ループを抜ける時の[sp, 24]の値がfunc1関数の返り値になる。[sp, 24]の値は 2610164910 * 3 = 7830494730 になる。

C:\Users\user>python
Python 2.7.16 (v2.7.16:413a49145e, Mar  4 2019, 01:37:19) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> w0 = 2610164910 * 3
>>> hex(w0)
'0x1d2bbde0aL'
>>> flag = 0x1d2bbde0a & 0xffffffff
>>> hex(flag)
'0xd2bbde0aL'

FLAG : picoCTF{d2bbde0a}

ARMssembly 3

問題文は以下の通り。ARMv8のアセンブリが渡されて、このプログラムに与えられる引数が469937816の時に出力される値を答える。

Description
What integer does this program print with argument 469937816? File: chall_3.S Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})

与えられたファイル(chall_3.S)を確認する。

L2では[x29, 28]が0では無い場合、ループを実行する。[x29, 28]の値と0x01のAND演算の結果を取得して、演算結果が0の時はL3(1バイトの右シフト演算を行う)にジャンプする。演算結果が0以外の時はfunc2関数(カウンタとして使用している[x29, 44]に3を加算する)を実行する。

まとめると、[x29, 28]が0になるまでAND演算と右シフト演算を繰り返し、その中でAND演算の結果が0以外になったタイミングではカウンタに3を加算する。このカウンタの値がfunc1関数の返り値になるので、これを求める。

  .arch armv8-a
    .file   "chall_3.c"
    .text
    .align  2
    .global func1
    .type   func1, %function
func1:
    stp x29, x30, [sp, -48]!
    add x29, sp, 0
    str w0, [x29, 28] # w0(469937816) -> [x29, 28]
    str wzr, [x29, 44] # wzr(0) -> [x29, 44]
    b   .L2
.L4:
    ldr w0, [x29, 28] # w0 <- [x29, 28](469937816)
    and w0, w0, 1 # w0 <- 469937816 and 1
    cmp w0, 0
    beq .L3
    ldr w0, [x29, 44]
    bl  func2
    str w0, [x29, 44]
.L3:
    ldr w0, [x29, 28] # w0 <- [x29, 28](469937816)
    lsr w0, w0, 1 # w0(234968908) <- 469937816 >> 1
    str w0, [x29, 28] # w0(234968908) -> [x29, 28]
.L2:
    ldr w0, [x29, 28] # w0 <- [x29, 28](469937816)
    cmp w0, 0
    bne .L4
    ldr w0, [x29, 44]
    ldp x29, x30, [sp], 48
    ret
    .size   func1, .-func1
    .align  2
    .global func2
    .type   func2, %function
func2:
    sub sp, sp, #16
    str w0, [sp, 12]
    ldr w0, [sp, 12]
    add w0, w0, 3 # w0 <- w0 + 3
    add sp, sp, 16
    ret
    .size   func2, .-func2
    .section    .rodata
    .align  3
.LC0:
    .string "Result: %ld\n"
    .text
    .align  2
    .global main
    .type   main, %function
main:
    stp x29, x30, [sp, -48]!
    add x29, sp, 0
    str w0, [x29, 28]
    str x1, [x29, 16]
    ldr x0, [x29, 16]
    add x0, x0, 8
    ldr x0, [x0]
    bl  atoi
    bl  func1 # func1(469937816)
    str w0, [x29, 44]
    adrp    x0, .LC0
    add x0, x0, :lo12:.LC0
    ldr w1, [x29, 44]
    bl  printf
    nop
    ldp x29, x30, [sp], 48
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0"
    .section    .note.GNU-stack,"",@progbits

計算すると最終的にカウンタの値は36になる。

C:\Users\user>python
Python 2.7.16 (v2.7.16:413a49145e, Mar  4 2019, 01:37:19) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> hex(36)
'0x24'

FLAG : picoCTF{00000024}

ARMssembly 4

問題文は以下の通り。ARMv8のアセンブリが渡されて、このプログラムに与えられる引数が3434881889の時に出力される値を答える。

Description
What integer does this program print with argument 3434881889? File: chall_4.S Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})

chall_4.Sを読むと、func1の引数が3434881889の場合、func1を実行 -> 引数に100を加算 -> func2を実行 -> 引数に13を加算 -> func5を実行 -> func8を実行 -> 引数に2を加算 -> 演算結果を返り値とする -> func1の返り値を出力 という流れで動作することが分かる。

  .arch armv8-a
    .file   "chall_4.c"
    .text
    .align  2
    .global func1
    .type   func1, %function
func1:
    stp x29, x30, [sp, -32]!
    add x29, sp, 0
    str w0, [x29, 28]
    ldr w0, [x29, 28] # w0 <- [x29, 28](3434881889)
    cmp w0, 100
    bls .L2 # not jump
    ldr w0, [x29, 28]
    add w0, w0, 100 # w0(3434881989) <- w0(3434881889) + 100
    bl  func2 # func2(3434881989)
    b   .L3
.L2:
    ldr w0, [x29, 28]
    bl  func3
.L3:
    ldp x29, x30, [sp], 32
    ret
    .size   func1, .-func1
    .align  2
    .global func2
    .type   func2, %function
func2:
    stp x29, x30, [sp, -32]!
    add x29, sp, 0
    str w0, [x29, 28]
    ldr w0, [x29, 28] # w0 <- [x29, 28](3434881989)
    cmp w0, 499
    bhi .L5 # jump to L5
    ldr w0, [x29, 28]
    sub w0, w0, #86
    bl  func4
    b   .L6
.L5:
    ldr w0, [x29, 28] # w0 <- [x29, 28](3434881989)
    add w0, w0, 13 # w0(3434882002) <- w0(3434881989) + 13
    bl  func5 # func5(3434882002)
.L6:
    ldp x29, x30, [sp], 32
    ret
    .size   func2, .-func2
    .align  2
    .global func3
    .type   func3, %function
func3:
    stp x29, x30, [sp, -32]!
    add x29, sp, 0
    str w0, [x29, 28]
    ldr w0, [x29, 28]
    bl  func7
    ldp x29, x30, [sp], 32
    ret
    .size   func3, .-func3
    .align  2
    .global func4
    .type   func4, %function
func4:
    stp x29, x30, [sp, -48]!
    add x29, sp, 0
    str w0, [x29, 28]
    mov w0, 17
    str w0, [x29, 44]
    ldr w0, [x29, 44]
    bl  func1
    str w0, [x29, 44]
    ldr w0, [x29, 28]
    ldp x29, x30, [sp], 48
    ret
    .size   func4, .-func4
    .align  2
    .global func5
    .type   func5, %function
func5:
    stp x29, x30, [sp, -32]!
    add x29, sp, 0
    str w0, [x29, 28]
    ldr w0, [x29, 28] # w0 <- [x29, 28](3434882002)
    bl  func8 # func8(3434882002)
    str w0, [x29, 28]
    ldr w0, [x29, 28]
    ldp x29, x30, [sp], 32
    ret
    .size   func5, .-func5
    .align  2
    .global func6
    .type   func6, %function
func6:
    sub sp, sp, #32
    str w0, [sp, 12]
    mov w0, 314
    str w0, [sp, 24]
    mov w0, 1932
    str w0, [sp, 28]
    str wzr, [sp, 20]
    str wzr, [sp, 20]
    b   .L14
.L15:
    ldr w1, [sp, 28]
    mov w0, 800
    mul w0, w1, w0
    ldr w1, [sp, 24]
    udiv    w2, w0, w1
    ldr w1, [sp, 24]
    mul w1, w2, w1
    sub w0, w0, w1
    str w0, [sp, 12]
    ldr w0, [sp, 20]
    add w0, w0, 1
    str w0, [sp, 20]
.L14:
    ldr w0, [sp, 20]
    cmp w0, 899
    bls .L15
    ldr w0, [sp, 12]
    add sp, sp, 32
    ret
    .size   func6, .-func6
    .align  2
    .global func7
    .type   func7, %function
func7:
    sub sp, sp, #16
    str w0, [sp, 12]
    ldr w0, [sp, 12]
    cmp w0, 100
    bls .L18
    ldr w0, [sp, 12]
    b   .L19
.L18:
    mov w0, 7
.L19:
    add sp, sp, 16
    ret
    .size   func7, .-func7
    .align  2
    .global func8
    .type   func8, %function
func8:
    sub sp, sp, #16
    str w0, [sp, 12]
    ldr w0, [sp, 12]
    add w0, w0, 2 # w0(3434882004) <- w0(3434882002) + 2
    add sp, sp, 16
    ret
    .size   func8, .-func8
    .section    .rodata
    .align  3
.LC0:
    .string "Result: %ld\n"
    .text
    .align  2
    .global main
    .type   main, %function
main:
    stp x29, x30, [sp, -48]!
    add x29, sp, 0
    str w0, [x29, 28]
    str x1, [x29, 16]
    ldr x0, [x29, 16]
    add x0, x0, 8
    ldr x0, [x0]
    bl  atoi
    str w0, [x29, 44]
    ldr w0, [x29, 44]
    bl  func1 # func1(3434881889)
    mov w1, w0
    adrp    x0, .LC0
    add x0, x0, :lo12:.LC0
    bl  printf
    nop
    ldp x29, x30, [sp], 48
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0"
    .section    .note.GNU-stack,"",@progbits

引数の値(3434881889)に115を加算した値がフラグになる。

C:\Users\user>python
Python 2.7.16 (v2.7.16:413a49145e, Mar  4 2019, 01:37:19) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> flag = 3434881889 + 115
>>> hex(flag)
'0xccbc23d4L'

Flag : picoCTF{ccbc23d4}

Let's get dynamic

問題文は以下の通り。アセンブリファイル(chall.S)が渡される

Description
Can you tell what this file is reading? chall.S

与えられたファイルは以下の通り。読むのが面倒臭そうに思える。

  .file   "chall.c"
    .text
    .section    .rodata
    .align 8
.LC1:
    .string "Correct! You entered the flag."
.LC2:
    .string "No, that's not right."
    .align 8
.LC0:
    .string "\002qs\312\307*\207\375\313-\370\371+\361\025I\020<"
    .string "TL\r\357\247C\250\002M\367\314\231\223\327\210\226\230\030\370\306*\205LX3\312\353Q\237\347"
    .text
    .globl  main
    .type   main, @function
main:
.LFB5:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    pushq   %rbx
    subq    $296, %rsp
    .cfi_offset 3, -24
    movl    %edi, -292(%rbp)
    movq    %rsi, -304(%rbp)
    movq    %fs:40, %rax
    movq    %rax, -24(%rbp)
    xorl    %eax, %eax
    movq    .LC0(%rip), %rax
    movq    8+.LC0(%rip), %rdx
    movq    %rax, -144(%rbp)
    movq    %rdx, -136(%rbp)
    movq    16+.LC0(%rip), %rax
    movq    24+.LC0(%rip), %rdx
    movq    %rax, -128(%rbp)
    movq    %rdx, -120(%rbp)
    movq    32+.LC0(%rip), %rax
    movq    40+.LC0(%rip), %rdx
    movq    %rax, -112(%rbp)
    movq    %rdx, -104(%rbp)
    movzwl  48+.LC0(%rip), %eax
    movw    %ax, -96(%rbp)
    movabsq $-7866547665503188383, %rax
    movabsq $750938240303713972, %rdx
    movq    %rax, -80(%rbp)
    movq    %rdx, -72(%rbp)
    movabsq $-245100717349187545, %rax
    movabsq $-1321891645065211527, %rdx
    movq    %rax, -64(%rbp)
    movq    %rdx, -56(%rbp)
    movabsq $4728704058583732155, %rax
    movabsq $-7828694793552836984, %rdx
    movq    %rax, -48(%rbp)
    movq    %rdx, -40(%rbp)
    movw    $185, -32(%rbp)
    movq    stdin(%rip), %rdx
    leaq    -208(%rbp), %rax
    movl    $49, %esi
    movq    %rax, %rdi
    call    fgets@PLT
    movl    $0, -276(%rbp)
    jmp .L2
.L3:
    movl    -276(%rbp), %eax
    cltq
    movzbl  -144(%rbp,%rax), %edx
    movl    -276(%rbp), %eax
    cltq
    movzbl  -80(%rbp,%rax), %eax
    xorl    %eax, %edx
    movl    -276(%rbp), %eax
    xorl    %edx, %eax
    xorl    $19, %eax
    movl    %eax, %edx
    movl    -276(%rbp), %eax
    cltq
    movb    %dl, -272(%rbp,%rax)
    addl    $1, -276(%rbp)
.L2:
    movl    -276(%rbp), %eax
    movslq  %eax, %rbx
    leaq    -144(%rbp), %rax
    movq    %rax, %rdi
    call    strlen@PLT
    cmpq    %rax, %rbx
    jb  .L3
    leaq    -272(%rbp), %rcx
    leaq    -208(%rbp), %rax
    movl    $49, %edx
    movq    %rcx, %rsi
    movq    %rax, %rdi
    call    memcmp@PLT
    testl   %eax, %eax
    je  .L4
    leaq    .LC1(%rip), %rdi
    call    puts@PLT
    movl    $0, %eax
    jmp .L6
.L4:
    leaq    .LC2(%rip), %rdi
    call    puts@PLT
    movl    $1, %eax
.L6:
    movq    -24(%rbp), %rcx
    xorq    %fs:40, %rcx
    je  .L7
    call    __stack_chk_fail@PLT
.L7:
    addq    $296, %rsp
    popq    %rbx
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE5:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
    .section    .note.GNU-stack,"",@progbits

動的解析を行うことを推奨しているような問題名なので、与えられたファイルをgccコンパイルする。

gcc chall.S -o chall

challを実行してFlagでは無い文字列を入力しても"Correct! You entered the flag."という文字列が出力される。

root@DESKTOP-G3LRDHC:/mnt/d/CTF/picoCTF2021/Let's get dynamic# ./chall
aaa
Correct! You entered the flag.

ltraceコマンドの結果より、memcmpで何らかの比較処理を行っているようなのでこの辺りを確認する。

root@DESKTOP-G3LRDHC:/mnt/d/CTF/picoCTF2021/Let's get dynamic# ltrace -i ./chall
[0x7f8e550008ba] fgets(aaa
"aaa\n", 49, 0x7f8e54beba00)                                                                                                = 0x7ffff4cea420
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000920] strlen("\002qs\312\307*\207\375\313-\370\371+\361\025I\020<")                                                                     = 18
[0x7f8e55000943] memcmp(0x7ffff4cea420, 0x7ffff4cea3e0, 49, 0x7ffff4cea3e0)                                                                        = 0xfffffff1
[0x7f8e55000953] puts("Correct! You entered the flag."Correct! You entered the flag.
)                                                                                            = 31
[0xffffffffffffffff] +++ exited (status 0) +++

challのコードを確認したところ、2種類のハードコードされた値とループカウンタと0x13をXORしていることが分かった。

import sys

key1 = [0x02, 0x71, 0x73, 0xCA, 0xC7, 0x2A, 0x87, 0xFD, 0xCB, 0x2D, 0xF8, 0xF9, 0x2B, 0xF1, 0x15, 0x49, 0x10, 0x3C, 0x00, 0x54, 0x4C, 0x0D, 0xEF, 0xA7, 0x43, 0xA8, 0x02, 0x4D, 0xF7, 0xCC, 0x99, 0x93, 0xD7, 0x88, 0x96, 0x98, 0x18, 0xF8, 0xC6, 0x2A, 0x85, 0x4C, 0x58, 0x33, 0xCA, 0xEB, 0x51, 0x9F, 0xE7]
key2 = [0x61, 0x0A, 0x01, 0xB5, 0x93, 0x68, 0xD4, 0x92, 0xB4, 0x4E, 0x8F, 0xD5, 0x59, 0xDE, 0x6B, 0x0A, 0x27, 0x50, 0x35, 0x38, 0x32, 0x3A, 0x99, 0xFC, 0x79, 0xD1, 0x54, 0x70, 0x8D, 0xB2, 0xA7, 0xED, 0xBB, 0xCF, 0xD4, 0x9B, 0x49, 0xBB, 0x9F, 0x41, 0x88, 0x46, 0x55, 0x3F, 0x90, 0xE3, 0x5A, 0x93, 0xB9]

for i in range(len(key1)):
    temp = key1[i] ^ key2[i] ^ i ^ 0x13
    sys.stdout.write((chr(temp)))

Pythonスクリプトで同じ処理を行うことでフラグが得られた。

# root@DESKTOP-G3LRDHC:/mnt/c/Users/hamasho/Desktop# python solver.py 
picoCTF{dyn4m1c_4n4ly1s_1s_5up3r_us3ful_6044e660}

Flag : picoCTF{dyn4m1c_4n4ly1s_1s_5up3r_us3ful_6044e660}

gogo

与えられたファイルはGolangバイナリっぽい。objdumpやGhidraで解析することが推奨されている。

Description
Hmmm this is a weird file... enter_password. There is a instance of the service running at mercury.picoctf.net:4052.

Hints
use go tool objdump or ghidra

ざっと眺めると以下のような関数が見つかる。

main_checkPassword : 1回目の入力値の処理っぽい
main_ambush : 2回目の入力値の処理っぽい

main_checkPassword関数では入力値とハードコードされた値(861836f13e3d627dfa375bdb8389214e)をXORした結果がmain_statictmp_4と等しいかを確認している。ハードコードされた値とmain_statictmp_4をXORして期待される入力値を確認する。入力するべき値は"reverseengineericanbarelyforward"であることが分かる。

import sys

key1 = [0x4A, 0x53, 0x47, 0x5D, 0x41, 0x45, 0x03, 0x54, 0x5D, 0x02, 0x5A, 0x0A, 0x53, 0x57, 0x45, 0x0D, 0x05, 0x00, 0x5D, 0x55, 0x54, 0x10, 0x01, 0x0E, 0x41, 0x55, 0x57, 0x4B, 0x45, 0x50, 0x46, 0x01]
key2 = [0x38, 0x36, 0x31, 0x38, 0x33, 0x36, 0x66, 0x31, 0x33, 0x65, 0x33, 0x64, 0x36, 0x32, 0x37, 0x64, 0x66, 0x61, 0x33, 0x37, 0x35, 0x62, 0x64, 0x62, 0x38, 0x33, 0x38, 0x39, 0x32, 0x31, 0x34, 0x65]

for i in range(len(key1)):
    temp = key1[i] ^ key2[i]
    sys.stdout.write((chr(temp)))

enter_passwordを実行して、パスワードとしてreverseengineericanbarelyforwardを入力するとunhashed keyを聞かれる。main_ambushでも先程と同じ値(861836f13e3d627dfa375bdb8389214e)がハードコードされていて、これと入力した文字列のMD5ハッシュ値が比較されていることが分かる。

ハードコードされている値"861836f13e3d627dfa375bdb8389214e"をGoogleで検索すると"goldfish"のMD5ハッシュ値であることが分かる。

root@DESKTOP-G3LRDHC:~# nc mercury.picoctf.net 4052
Enter Password: reverseengineericanbarelyforward
=========================================
This challenge is interrupted by psociety
What is the unhashed key?
goldfish
Flag is:  picoCTF{p1kap1ka_p1c09a4dd7f3}

Flag : picoCTF{p1kap1ka_p1c09a4dd7f3}