0
0

More than 3 years have passed since last update.

picoCTF Practice Let's get dynamic をGhidraで解いたが。。。

Last updated at Posted at 2021-04-25

picoCTF Practice Let's get dynamic
本当は,今研修で勉強している gdb を使って解きたかったが,1日勉強したぐらいでは,gdb で stack strings を拝ませてもらうことはできなかった。 なので Ghidra で解いた。
いつか gdb で解く。
gdb を gdb-peda にしたら解けた。

Let's get dynamic

Description:
Can you tell what this file is reading? chall.S
Hints:
1. Running this in a debugger would be helpful

chall.S
    .file   "chall.c"
    .text
    .section    .rodata
    .align 8
.LC0:
    .string "Correct! You entered the flag."
.LC1:
    .string "No, that's not right."
    .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
    movabsq $4137700413143496212, %rax
    movabsq $3668774195188830448, %rdx
    movq    %rax, -144(%rbp)
    movq    %rdx, -136(%rbp)
    movabsq $-3415231997387159298, %rax
    movabsq $3180240096696696075, %rdx
    movq    %rax, -128(%rbp)
    movq    %rdx, -120(%rbp)
    movabsq $-5717177924950513641, %rax
    movabsq $-3967246834314051972, %rdx
    movq    %rax, -112(%rbp)
    movq    %rdx, -104(%rbp)
    movw    $97, -96(%rbp)
    movabsq $6214777055764401527, %rax
    movabsq $8184225536171504527, %rdx
    movq    %rax, -80(%rbp)
    movq    %rdx, -72(%rbp)
    movabsq $-8364134581669616439, %rax
    movabsq $5916610601309242417, %rdx
    movq    %rax, -64(%rbp)
    movq    %rdx, -56(%rbp)
    movabsq $-2598080388612165765, %rax
    movabsq $-4252370736625094538, %rdx
    movq    %rax, -48(%rbp)
    movq    %rdx, -40(%rbp)
    movw    $63, -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    .LC0(%rip), %rdi
    call    puts@PLT
    movl    $0, %eax
    jmp .L6
.L4:
    leaq    .LC1(%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

Solution:
とりあえずコンパイルしてみる。

$ gcc chall.S

gdbで解く

金曜に勉強し始めた gdb やってみる

$ gdb ./a.out
(gdb) br memcmp
Breakpoint 1 at 0x690
(gdb) r
Starting program: /mnt/c/Users/xxx/downloads/a.out
aaa
Correct! You entered the flag.
[Inferior 1 (process 384) exited normally]

とまらねー。
いろいろ試したがダメだ。
gdb で解けないのは悔しいが,Ghidraで解く

Ghidraで解く

main
bool main(void)

{
  int iVar1;
  size_t sVar2;
  long in_FS_OFFSET;
  int local_11c;
  byte local_118 [64];
  char local_d8 [64];
  undefined8 local_98;
  undefined8 local_90;
  undefined8 local_88;
  undefined8 local_80;
  undefined8 local_78;
  undefined8 local_70;
  undefined2 local_68;
  undefined8 local_58;
  undefined8 local_50;
  undefined8 local_48;
  undefined8 local_40;
  undefined8 local_38;
  undefined8 local_30;
  undefined2 local_28;
  long local_20;

  local_20 = *(long *)(in_FS_OFFSET + 0x28);
  local_98 = 0x396c109a7067b614;
  local_90 = 0x32ea1ab1495990f0;
  local_88 = 0xd09aa897d230c8fe;
  local_80 = 0x2c227b84b00f7d0b;
  local_78 = 0xb0a880f7d99ea817;
  local_70 = 0xc8f18206086afe7c;
  local_68 = 0x61;
  local_58 = 0x563f52ce0f15cd77;
  local_50 = 0x719435c3652ef38f;
  local_48 = 0x8bec9fe9be05a4c9;
  local_40 = 0x521c05fe8d590431;
  local_38 = 0xdbf1c3a6dadcef7b;
  local_30 = 0xc4fc8b585631f076;
  local_28 = 0x3f;
  fgets(local_d8,0x31,stdin);
  local_11c = 0;
  while( true ) {
    sVar2 = strlen((char *)&local_98);
    if (sVar2 <= (ulong)(long)local_11c) break;
    local_118[local_11c] =
         (byte)local_11c ^
         *(byte *)((long)&local_98 + (long)local_11c) ^ *(byte *)((long)&local_58 + (long)local_11c)
         ^ 0x13;
    local_11c = local_11c + 1;
  }
  iVar1 = memcmp(local_d8,local_118,0x31);
  if (iVar1 == 0) {
    puts("No, that\'s not right.");
  }
  else {
    puts("Correct! You entered the flag.");
  }
  if (local_20 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return iVar1 == 0;
}

local_98 の 変数名を key に
local_58 の 変数名を enc に
local_11c の 変数名を i に
local_118 の 変数名を flag に
local_98 の 型を byte[49] に
local_58 の 型を byte[49] に
変更すると

  i = 0;
  while( true ) {
    sVar2 = strlen((char *)key);
    if (sVar2 <= (ulong)(long)i) break;
    flag[i] = (byte)i ^ key[i] ^ enc[i] ^ 0x13;
    i = i + 1;
  }
  iVar1 = memcmp(local_d8,flag,0x31);
  if (iVar1 == 0) {
    puts("No, that\'s not right.");
  }
  else {
    puts("Correct! You entered the flag.");
  }

フラグの復号は i ^ key[i] ^ enc[i] ^ 0x13 ですね。
ソルバー(Ghidra Script)を書く

solver.py
def qword_parse(value):
    #return([(value & 0xff00000000000000) / 0x100000000000000,(value & 0x00ff000000000000) / 0x1000000000000,(value & 0x0000ff0000000000) / 0x10000000000,(value & 0x000000ff00000000) / 0x100000000,(value & 0x00000000ff000000) / 0x1000000,(value & 0x0000000000ff0000) / 0x10000,(value & 0x000000000000ff00) / 0x100,(value & 0x00000000000000ff) / 0x1])
    return([(value & 0x00000000000000ff) / 0x1,(value & 0x000000000000ff00) / 0x100,(value & 0x0000000000ff0000) / 0x10000,(value & 0x00000000ff000000) / 0x1000000,(value & 0x000000ff00000000) / 0x100000000,(value & 0x0000ff0000000000) / 0x10000000000,(value & 0x00ff000000000000) / 0x1000000000000,(value & 0xff00000000000000) / 0x100000000000000])

key=[]
inst = getInstructionAt(toAddr(0x001007f2))
key.extend(qword_parse(inst.getOpObjects(1)[0].getValue()))
inst = inst.getNext()
key.extend(qword_parse(inst.getOpObjects(1)[0].getValue()))
inst = getInstructionAt(toAddr(0x00100814))
key.extend(qword_parse(inst.getOpObjects(1)[0].getValue()))
inst = inst.getNext()
key.extend(qword_parse(inst.getOpObjects(1)[0].getValue()))
inst = getInstructionAt(toAddr(0x00100830))
key.extend(qword_parse(inst.getOpObjects(1)[0].getValue()))
inst = inst.getNext()
key.extend(qword_parse(inst.getOpObjects(1)[0].getValue()))
inst = getInstructionAt(toAddr(0x0010084c))
key.append(inst.getOpObjects(1)[0].getValue())
print(key)
print("key="+''.join(map(chr,key)))

enc=[]
inst = getInstructionAt(toAddr(0x00100852))
enc.extend(qword_parse(inst.getOpObjects(1)[0].getValue()))
inst = inst.getNext()
enc.extend(qword_parse(inst.getOpObjects(1)[0].getValue()))
inst = getInstructionAt(toAddr(0x0010086e))
enc.extend(qword_parse(inst.getOpObjects(1)[0].getValue()))
inst = inst.getNext()
enc.extend(qword_parse(inst.getOpObjects(1)[0].getValue()))
inst = getInstructionAt(toAddr(0x0010088a))
enc.extend(qword_parse(inst.getOpObjects(1)[0].getValue()))
inst = inst.getNext()
enc.extend(qword_parse(inst.getOpObjects(1)[0].getValue()))
inst = getInstructionAt(toAddr(0x001008a6))
enc.append(inst.getOpObjects(1)[0].getValue())
print(enc)
print("enc="+''.join(map(chr,enc)))

ans=[]
i = 0
while i < 49:
    ans.append( i ^ enc[i] ^ key[i] ^ 0x13 )
    i = i + 1
print(ans)
print("ans="+''.join(map(chr,ans)))

結果

image.png

gdb-peda で解く

まずインストールでお世話になったサイト

gdb実行

$ gdb -q ./a.out
Reading symbols from ./a.out...(no debugging symbols found)...done.

main にブレークポイントしかけて実行

gdb-peda$ b main
Breakpoint 1 at 0x7ce
gdb-peda$ r
Breakpoint 1, 0x00000000080007ce in main ()

main関数を確認

gdb-peda$ pdisass main
Dump of assembler code for function main:
   0x00000000080007ca <+0>:     push   rbp
   0x00000000080007cb <+1>:     mov    rbp,rsp
=> 0x00000000080007ce <+4>:     push   rbx
   0x00000000080007cf <+5>:     sub    rsp,0x128
   0x00000000080007d6 <+12>:    mov    DWORD PTR [rbp-0x124],edi
   0x00000000080007dc <+18>:    mov    QWORD PTR [rbp-0x130],rsi
   0x00000000080007e3 <+25>:    mov    rax,QWORD PTR fs:0x28
   0x00000000080007ec <+34>:    mov    QWORD PTR [rbp-0x18],rax
   0x00000000080007f0 <+38>:    xor    eax,eax
   0x00000000080007f2 <+40>:    movabs rax,0x396c109a7067b614
   0x00000000080007fc <+50>:    movabs rdx,0x32ea1ab1495990f0
   0x0000000008000806 <+60>:    mov    QWORD PTR [rbp-0x90],rax
   0x000000000800080d <+67>:    mov    QWORD PTR [rbp-0x88],rdx
   0x0000000008000814 <+74>:    movabs rax,0xd09aa897d230c8fe
   0x000000000800081e <+84>:    movabs rdx,0x2c227b84b00f7d0b
   0x0000000008000828 <+94>:    mov    QWORD PTR [rbp-0x80],rax
   0x000000000800082c <+98>:    mov    QWORD PTR [rbp-0x78],rdx
   0x0000000008000830 <+102>:   movabs rax,0xb0a880f7d99ea817
   0x000000000800083a <+112>:   movabs rdx,0xc8f18206086afe7c
   0x0000000008000844 <+122>:   mov    QWORD PTR [rbp-0x70],rax
   0x0000000008000848 <+126>:   mov    QWORD PTR [rbp-0x68],rdx
   0x000000000800084c <+130>:   mov    WORD PTR [rbp-0x60],0x61
   0x0000000008000852 <+136>:   movabs rax,0x563f52ce0f15cd77
   0x000000000800085c <+146>:   movabs rdx,0x719435c3652ef38f
   0x0000000008000866 <+156>:   mov    QWORD PTR [rbp-0x50],rax
   0x000000000800086a <+160>:   mov    QWORD PTR [rbp-0x48],rdx
   0x000000000800086e <+164>:   movabs rax,0x8bec9fe9be05a4c9
   0x0000000008000878 <+174>:   movabs rdx,0x521c05fe8d590431
   0x0000000008000882 <+184>:   mov    QWORD PTR [rbp-0x40],rax
   0x0000000008000886 <+188>:   mov    QWORD PTR [rbp-0x38],rdx
   0x000000000800088a <+192>:   movabs rax,0xdbf1c3a6dadcef7b
   0x0000000008000894 <+202>:   movabs rdx,0xc4fc8b585631f076
   0x000000000800089e <+212>:   mov    QWORD PTR [rbp-0x30],rax
   0x00000000080008a2 <+216>:   mov    QWORD PTR [rbp-0x28],rdx
   0x00000000080008a6 <+220>:   mov    WORD PTR [rbp-0x20],0x3f
   0x00000000080008ac <+226>:   mov    rdx,QWORD PTR [rip+0x20075d]        # 0x8201010 <stdin@@GLIBC_2.2.5>
   0x00000000080008b3 <+233>:   lea    rax,[rbp-0xd0]
   0x00000000080008ba <+240>:   mov    esi,0x31
   0x00000000080008bf <+245>:   mov    rdi,rax
   0x00000000080008c2 <+248>:   call   0x80006a0 <fgets@plt>
   0x00000000080008c7 <+253>:   mov    DWORD PTR [rbp-0x114],0x0
   0x00000000080008d1 <+263>:   jmp    0x8000915 <main+331>
   0x00000000080008d3 <+265>:   mov    eax,DWORD PTR [rbp-0x114]
   0x00000000080008d9 <+271>:   cdqe
   0x00000000080008db <+273>:   movzx  edx,BYTE PTR [rbp+rax*1-0x90]
   0x00000000080008e3 <+281>:   mov    eax,DWORD PTR [rbp-0x114]
   0x00000000080008e9 <+287>:   cdqe
   0x00000000080008eb <+289>:   movzx  eax,BYTE PTR [rbp+rax*1-0x50]
   0x00000000080008f0 <+294>:   xor    edx,eax
   0x00000000080008f2 <+296>:   mov    eax,DWORD PTR [rbp-0x114]
   0x00000000080008f8 <+302>:   xor    eax,edx
   0x00000000080008fa <+304>:   xor    eax,0x13
   0x00000000080008fd <+307>:   mov    edx,eax
   0x00000000080008ff <+309>:   mov    eax,DWORD PTR [rbp-0x114]
   0x0000000008000905 <+315>:   cdqe
   0x0000000008000907 <+317>:   mov    BYTE PTR [rbp+rax*1-0x110],dl
   0x000000000800090e <+324>:   add    DWORD PTR [rbp-0x114],0x1
   0x0000000008000915 <+331>:   mov    eax,DWORD PTR [rbp-0x114]
   0x000000000800091b <+337>:   movsxd rbx,eax
   0x000000000800091e <+340>:   lea    rax,[rbp-0x90]
   0x0000000008000925 <+347>:   mov    rdi,rax
   0x0000000008000928 <+350>:   call   0x8000670 <strlen@plt>
   0x000000000800092d <+355>:   cmp    rbx,rax
   0x0000000008000930 <+358>:   jb     0x80008d3 <main+265>
   0x0000000008000932 <+360>:   lea    rcx,[rbp-0x110]
   0x0000000008000939 <+367>:   lea    rax,[rbp-0xd0]
   0x0000000008000940 <+374>:   mov    edx,0x31
   0x0000000008000945 <+379>:   mov    rsi,rcx
   0x0000000008000948 <+382>:   mov    rdi,rax
   0x000000000800094b <+385>:   call   0x8000690 <memcmp@plt>
   0x0000000008000950 <+390>:   test   eax,eax
   0x0000000008000952 <+392>:   je     0x8000967 <main+413>
   0x0000000008000954 <+394>:   lea    rdi,[rip+0xcd]        # 0x8000a28
   0x000000000800095b <+401>:   call   0x8000660 <puts@plt>
   0x0000000008000960 <+406>:   mov    eax,0x0
   0x0000000008000965 <+411>:   jmp    0x8000978 <main+430>
   0x0000000008000967 <+413>:   lea    rdi,[rip+0xd9]        # 0x8000a47
   0x000000000800096e <+420>:   call   0x8000660 <puts@plt>
   0x0000000008000973 <+425>:   mov    eax,0x1
   0x0000000008000978 <+430>:   mov    rcx,QWORD PTR [rbp-0x18]
   0x000000000800097c <+434>:   xor    rcx,QWORD PTR fs:0x28
   0x0000000008000985 <+443>:   je     0x800098c <main+450>
   0x0000000008000987 <+445>:   call   0x8000680 <__stack_chk_fail@plt>
   0x000000000800098c <+450>:   add    rsp,0x128
   0x0000000008000993 <+457>:   pop    rbx
   0x0000000008000994 <+458>:   pop    rbp
   0x0000000008000995 <+459>:   ret
End of assembler dump.

0x8000932にブレークポイントを設定すれば,復号が終わってる

gdb-peda$ b *0x8000932
Breakpoint 2 at 0x8000932
gdb-peda$ c
Continuing.

入力待ちになるので適当な文字を入力

aaa
[----------------------------------registers-----------------------------------]
RAX: 0x31 ('1')
RBX: 0x31 ('1')
RCX: 0x0
RDX: 0xc0fe000000000000
RSI: 0x7ffffffee1a0 --> 0x7f000a616161
RDI: 0x7ffffffee1e0 --> 0x396c109a7067b614
RBP: 0x7ffffffee270 --> 0x80009a0 --> 0x41d7894956415741
RSP: 0x7ffffffee140 --> 0x7ffffffee358 --> 0x7ffffffee57f ("/mnt/c/Users/xxx/Downloads/a.out")
RIP: 0x8000932 --> 0x48fffffef08d8d48
R8 : 0x0
R9 : 0x7fffff16e6a0 (<__memcpy_ssse3+8208>:     mov    dx,WORD PTR [rsi-0x3])
R10: 0x8402010 --> 0x0
R11: 0x7fffff1bce60 --> 0xfffb1480fffb12b8
R12: 0x80006c0 --> 0x89485ed18949ed31
R13: 0x7ffffffee350 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8000928 <main+350>:        call   0x8000670 <strlen@plt>
   0x800092d <main+355>:        cmp    rbx,rax
   0x8000930 <main+358>:        jb     0x80008d3 <main+265>
=> 0x8000932 <main+360>:        lea    rcx,[rbp-0x110]
   0x8000939 <main+367>:        lea    rax,[rbp-0xd0]
   0x8000940 <main+374>:        mov    edx,0x31
   0x8000945 <main+379>:        mov    rsi,rcx
   0x8000948 <main+382>:        mov    rdi,rax
[------------------------------------stack-------------------------------------]
0000| 0x7ffffffee140 --> 0x7ffffffee358 --> 0x7ffffffee57f ("/mnt/c/Users/xxx/Downloads/a.out")
0008| 0x7ffffffee148 --> 0x1ff62b710
0016| 0x7ffffffee150 --> 0x0
0024| 0x7ffffffee158 --> 0x31ff40b39f
0032| 0x7ffffffee160 ("picoCTF{dyn4m1c_4n4ly1s_1s_5up3r_us3ful_14bfa700}7\033\377\377\177")
0040| 0x7ffffffee168 ("dyn4m1c_4n4ly1s_1s_5up3r_us3ful_14bfa700}7\033\377\377\177")
0048| 0x7ffffffee170 ("4n4ly1s_1s_5up3r_us3ful_14bfa700}7\033\377\377\177")
0056| 0x7ffffffee178 ("1s_5up3r_us3ful_14bfa700}7\033\377\377\177")
[------------------------------------------------------------------------------]

ビンゴ

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0