$ file 08_angr_constraints
08_angr_constraints: 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]=d53f4be8c8a8535398c061131666b583f07c6b19, not stripped
int __cdecl main(int argc, const char **argv, const char **envp)
{
signed int i; // [esp+Ch] [ebp-Ch]
password = 'WISO';
dword_804A034 = 'IXBH';
dword_804A038 = 'VQOF';
dword_804A03C = 'BZBS';
memset(&buffer, 0, 0x11u);
printf("Enter the password: ");
__isoc99_scanf("%16s", &buffer);
for ( i = 0; i <= 15; ++i )
*(_BYTE *)(i + 0x804A040) = complex_function(*(char *)(i + 0x804A040), 15 - i);
if ( check_equals_OSIWHBXIFOQVSBZB((int)&buffer, 0x10u) )
puts("Good Job.");
else
puts("Try again.");
return 0;
}
int __cdecl complex_function(signed int a1, int a2)
{
if ( a1 <= '@' || a1 > 'Z' )
{
puts("Try again.");
exit(1);
}
return (a1 - 65 + 53 * a2) % 26 + 65;
}
_BOOL4 __cdecl check_equals_OSIWHBXIFOQVSBZB(int input_addr, unsigned int size)
{
int v3; // [esp+8h] [ebp-8h]
unsigned int i; // [esp+Ch] [ebp-4h]
v3 = 0;
for ( i = 0; size > i; ++i )
{
if ( *(_BYTE *)(i + input_addr) == *(_BYTE *)(i + 0x804A030) )
++v3;
}
return v3 == size;
}
따라서 complex_function() 결과로 암호화된 입력값 buffer와 “OSIWHBXIFOQVSBZB”가 같아야 한다.
컴퓨터는 모든 분기를 보는데 오래 걸리기 때문에, complex_function 함수 호출 전 프로그램 멈춰서 check~ 함수에서 비교하는 password인 “OSIWHBXIFOQVSBZB”와 암호화된 buffer(입력)가 동일하도록 해서 입력값(solution)을 찾는다.
state = p.factory.blank_state(
addr=0x804863c,
add_options={angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS}
)
# symbolic bitvector
buffer = state.solver.BVS('buffer', 8*16)
# set buffer value
password_addr = 0x804A040
state.memory.store(password_addr, buffer)
이제 Good Job을 찾으려면 65,536개의 분기를 봐야 하기 때문에 해당 경로를 찾는건 할 수 없다. 대신 check_equals_OSIWHBXIFOQVSBZB() 호출 시 넣어주는 buffer 값과 “OSIWHBXIFOQVSBZB”이 같기만 하면 되므로, 해당 함수 호출 전 buffer 값이
.text:08048683 push 10h
.text:08048685 push offset buffer
.text:0804868A call check_equals_OSIWHBXIFOQVSBZB
check_equals_OSIWHBXIFOQVSBZB() 함수 호출 전 buffer 16바이트를 넣는 주소(0x08048683)를 찾는다.
# create simulation managers
simgr = p.factory.simgr(state)
# find state before check_equals()
simgr.explore(find=0x08048683)
# get buffer value
constrained_addr = 0x804A040
constrained_size = 16
constrained_bitvector = solution_state.memory.load(constrained_addr, constrained_size)
# constrain system to find an input that make constrained_bitvector equal desired value
constrained_desired_value = "OSIWHBXIFOQVSBZB".encode()
# test whether constrained_bitvector == desired value
solution_state.add_constraints(constrained_bitvector == constrained_desired_value)
solution = solution_state.solver.eval(buffer, cast_to=bytes).decode()
check_equals 호출 전 0x804a040 주소(buffer)에서의 16바이트 값과 “OSIWHBXIFOQVSBZB”가 같은지 add_constraint로 비교해서 같게 하는 solution을 구한다.
#!/usr/bin/python
import angr,sys
p = angr.Project('./08_angr_constraints')
state = p.factory.blank_state(
addr=0x804863c,
add_options={angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS}
)
# symbolic bitvector
buffer = state.solver.BVS('buffer', 8*16)
# set buffer value
password_addr = 0x804A040
state.memory.store(password_addr, buffer)
# create simulation managers
simgr = p.factory.simgr(state)
# find state before check_equals()
simgr.explore(find=0x08048683)
if simgr.found:
solution_state = simgr.found[0]
print('solution state:', end=' ')
print(solution_state)
# get buffer value
constrained_addr = 0x804A040
constrained_size = 16
constrained_bitvector = solution_state.memory.load(constrained_addr, constrained_size)
# constrain system to find an input that make constrained_bitvector equal desired value
constrained_desired_value = "OSIWHBXIFOQVSBZB".encode()
# test whether constrained_bitvector == desired value
solution_state.add_constraints(constrained_bitvector == constrained_desired_value)
solution = solution_state.solver.eval(buffer, cast_to=bytes).decode()
print('solution:', end=' ')
print(solution)
else:
raise Exception('could not find the solution.')
[EKOPARTY CTF 2016] Fuckzing reverse (ft. angr) (0) | 2022.07.16 |
---|---|
[angr_ctf] 07_angr_symbolic_file (0) | 2022.05.14 |
[angr_ctf] 06_angr_symbolic_dynamic_memory (0) | 2022.05.14 |
[angr_ctf] 05_angr_symbolic_memory (0) | 2022.05.14 |
[angr_ctf] 04_angr_symbolic_stack (0) | 2022.05.14 |