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
.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で解く
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)を書く
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)))
結果
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")
[------------------------------------------------------------------------------]
ビンゴ