$ file 05_angr_symbolic_memory
05_angr_symbolic_memory: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=7fce021dfa8d22282d85297e98dd62a266eb5975, not stripped
.text:080485BF ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:080485BF public main
.text:080485BF main proc near ; DATA XREF: _start+26↑o
.text:080485BF
.text:080485BF var_C = dword ptr -0Ch
.text:080485BF var_4 = dword ptr -4
.text:080485BF argc = dword ptr 8
.text:080485BF argv = dword ptr 0Ch
.text:080485BF envp = dword ptr 10h
.text:080485BF
.text:080485BF ; __unwind {
.text:080485BF lea ecx, [esp+4]
.text:080485C3 and esp, 0FFFFFFF0h
.text:080485C6 push dword ptr [ecx-4]
.text:080485C9 push ebp
.text:080485CA mov ebp, esp
.text:080485CC push ecx
.text:080485CD sub esp, 14h
.text:080485D0 sub esp, 4
.text:080485D3 push 21h ; n
.text:080485D5 push 0 ; c
.text:080485D7 push offset user_input ; s
.text:080485DC call _memset
.text:080485E1 add esp, 10h
.text:080485E4 sub esp, 0Ch
.text:080485E7 push offset aEnterThePasswo ; "Enter the password: "
.text:080485EC call _printf
.text:080485F1 add esp, 10h
.text:080485F4 sub esp, 0Ch
.text:080485F7 push offset unk_AB232D8
.text:080485FC push offset unk_AB232D0
.text:08048601 push offset unk_AB232C8
.text:08048606 push offset user_input
.text:0804860B push offset a8s8s8s8s ; "%8s %8s %8s %8s"
.text:08048610 call ___isoc99_scanf
.text:08048615 add esp, 20h
.text:08048618 mov [ebp+var_C], 0
.text:0804861F jmp short loc_804864E
.text:08048621 ; ---------------------------------------------------------------------------
.text:08048621
.text:08048621 loc_8048621: ; CODE XREF: main+93↓j
.text:08048621 mov eax, [ebp+var_C]
.text:08048624 add eax, 0AB232C0h
.text:08048629 movzx eax, byte ptr [eax]
.text:0804862C movsx eax, al
.text:0804862F sub esp, 8
.text:08048632 push [ebp+var_C]
.text:08048635 push eax
.text:08048636 call complex_function
.text:0804863B add esp, 10h
.text:0804863E mov edx, eax
.text:08048640 mov eax, [ebp+var_C]
.text:08048643 add eax, 0AB232C0h
.text:08048648 mov [eax], dl
.text:0804864A add [ebp+var_C], 1
.text:0804864E
.text:0804864E loc_804864E: ; CODE XREF: main+60↑j
.text:0804864E cmp [ebp+var_C], 1Fh
.text:08048652 jle short loc_8048621
.text:08048654 sub esp, 4
.text:08048657 push 20h ; n
.text:08048659 push offset s2 ; "OSIWHBXIFOQVSBZBISILSCLBIAXSEWUT"
.text:0804865E push offset user_input ; s1
.text:08048663 call _strncmp
.text:08048668 add esp, 10h
.text:0804866B test eax, eax
.text:0804866D jz short loc_8048681
.text:0804866F sub esp, 0Ch
.text:08048672 push offset s ; "Try again."
.text:08048677 call _puts
.text:0804867C add esp, 10h
.text:0804867F jmp short loc_8048691
.text:08048681 ; ---------------------------------------------------------------------------
.text:08048681
.text:08048681 loc_8048681: ; CODE XREF: main+AE↑j
.text:08048681 sub esp, 0Ch
.text:08048684 push offset aGoodJob ; "Good Job."
.text:08048689 call _puts
.text:0804868E add esp, 10h
.text:08048691
.text:08048691 loc_8048691: ; CODE XREF: main+C0↑j
.text:08048691 mov eax, 0
.text:08048696 mov ecx, [ebp+var_4]
.text:08048699 leave
.text:0804869A lea esp, [ecx-4]
.text:0804869D retn
.text:0804869D ; } // starts at 80485BF
.text:0804869D main endp
int __cdecl main(int argc, const char **argv, const char **envp)
{
signed int i; // [esp+Ch] [ebp-Ch]
memset(user_input, 0, 0x21u);
printf("Enter the password: ");
__isoc99_scanf("%8s %8s %8s %8s", user_input, &unk_AB232C8, &unk_AB232D0, &unk_AB232D8);
for ( i = 0; i <= 31; ++i )
*(_BYTE *)(i + 179450560) = complex_function(*(char *)(i + 179450560), i);
if ( !strncmp(user_input, "OSIWHBXIFOQVSBZBISILSCLBIAXSEWUT", 0x20u) )
puts("Good Job.");
else
puts("Try again.");
return 0;
}
scanf로 4개의 스트링을 입력받는다.
이후 strncmp로 0x20byte만큼 "OSIWHBXIFOQVSBZBISILSCLBIAXSEWUT”와 비교 후 동일하면 “Good Job.”을, 아니면 “Try again.”을 출력한다.
.text:080485FC push offset unk_AB232D0
.text:08048601 push offset unk_AB232C8
.text:08048606 push offset user_input
.text:0804860B push offset a8s8s8s8s ; "%8s %8s %8s %8s"
.text:08048610 call ___isoc99_scanf
.text:08048615 add esp, 20h
.text:08048618 mov [ebp+var_C], 0
이 문제에서도 scanf로 여러 입력을 받는데 angr는 이를 지원하지 않으므로 scanf 호출 다음으로 시작 주소를 준다.
state = p.factory.blank_state(
addr=0x08048618,
add_options={angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS}
)
scanf로 4개의 스트링 입력을 받으므로, 입력값을 설정해줄 symbolic bitvector를 만들어준다.
# set bitvectors
input0 = state.solver.BVS('input0', 8*8)
input1 = state.solver.BVS('input1', 8*8)
input2 = state.solver.BVS('input2', 8*8)
input3 = state.solver.BVS('input3', 8*8)
scanf("%8s %8s %8s %8s", user_input, &unk_AB232C8, &unk_AB232D0, &unk_AB232D8);
.bss:0AB232C0 user_input db 8 dup(?) ; DATA XREF: main+18↑o
.bss:0AB232C0 ; main+47↑o ...
.bss:0AB232C8 unk_AB232C8 db ? ; ; DATA XREF: main+42↑o
.bss:0AB232C9 db ? ;
.bss:0AB232CA db ? ;
.bss:0AB232CB db ? ;
.bss:0AB232CC db ? ;
.bss:0AB232CD db ? ;
.bss:0AB232CE db ? ;
.bss:0AB232CF db ? ;
.bss:0AB232D0 unk_AB232D0 db ? ; ; DATA XREF: main+3D↑o
.bss:0AB232D1 db ? ;
.bss:0AB232D2 db ? ;
.bss:0AB232D3 db ? ;
.bss:0AB232D4 db ? ;
.bss:0AB232D5 db ? ;
.bss:0AB232D6 db ? ;
.bss:0AB232D7 db ? ;
.bss:0AB232D8 unk_AB232D8 db ? ;
이번 문제에서는 입력값이 전역변수 user_input에 차례대로 저장된다.
첫 번째 입력값 주소는 0AB232C0, 두 번째부터 각각 0AB232C8, 0AB232D0, 0AB232D8이다. 각각 8byte 크기인걸 확인할 수 있다.
# set global variables with bitvectors
state.memory.store(0x0AB232C0, input0)
state.memory.store(0x0AB232C8, input1)
state.memory.store(0x0AB232D0, input2)
state.memory.store(0x0AB232D8, input3)
이후부터는 simulation manages의 explore를 사용해서 find, avoid로 solution을 찾아준다.
#!/usr/bin/python
import angr,sys
# create angr Project
p = angr.Project('./05_angr_symbolic_memory')
# set start state
state = p.factory.blank_state(
addr=0x08048618,
add_options={angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS}
)
# set bitvectors
input0 = state.solver.BVS('input0', 8*8)
input1 = state.solver.BVS('input1', 8*8)
input2 = state.solver.BVS('input2', 8*8)
input3 = state.solver.BVS('input3', 8*8)
# set global variables with bitvectors
state.memory.store(0x0AB232C0, input0)
state.memory.store(0x0AB232C8, input1)
state.memory.store(0x0AB232D0, input2)
state.memory.store(0x0AB232D8, input3)
# create simulation managers
simgr = p.factory.simgr(state)
# search possible path to find solution
simgr.explore(find=lambda s: 'Good'.encode() in s.posix.dumps(sys.stdout.fileno()), avoid=lambda s: 'Try'.encode() in s.posix.dumps(sys.stdout.fileno()))
if simgr.found:
solution_state = simgr.found[0]
print('solution state:', end=' ')
solution0 = solution_state.solver.eval(input0, cast_to=bytes).decode()
solution1 = solution_state.solver.eval(input1, cast_to=bytes).decode()
solution2 = solution_state.solver.eval(input2, cast_to=bytes).decode()
solution3 = solution_state.solver.eval(input3, cast_to=bytes).decode()
print("%s %s %s %s" % (solution0, solution1, solution2, solution3))
else:
raise Exception('could not find the solution')
[angr_ctf] 07_angr_symbolic_file (0) | 2022.05.14 |
---|---|
[angr_ctf] 06_angr_symbolic_dynamic_memory (0) | 2022.05.14 |
[angr_ctf] 04_angr_symbolic_stack (0) | 2022.05.14 |
[angr_ctf] 03_angr_symbolic_registers (0) | 2022.05.14 |
[angr_ctf] 02_angr_find_condition (0) | 2022.05.14 |