Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Tags
more
Archives
Today
Total
관리 메뉴

D1N0's hacking blog

02_angr_find_condition 본문

Reversing/angr_ctf

02_angr_find_condition

D1N0 2021. 2. 26. 20:46

지난번 글을 보지 않았다면 먼저 보고 오자

 

01_angr_avoid

지난 글을 보지 않았다면 먼저 보고 오자 00_angr_find 들어가기 전에 이 글은 angr에 대해 배운 내용을 정리하는 글이다 C와 파이썬, 간단한 리버싱 지식을 기본 전제로 하고 있다 모든 문제는 github.c

d1n0.tistory.com

시작

이번에는 예고한 대로 find와 avoid 인자에 주소를 직접 넣는 대신 특정 조건을 넣는 방법을 알아보겠다

이에 대해 설명하기 전에 예제를 먼저 분석해보겠다

undefined4 main(undefined4 param_1,undefined4 param_2)

{
  char cVar1;
  int iVar2;
  int in_GS_OFFSET;
  int local_48;
  int local_44;
  char local_3c [20];
  undefined4 local_28;
  undefined4 local_24;
  int local_14;
  undefined *local_c;
  
  local_c = (undefined *)&param_1;
  local_14 = *(int *)(in_GS_OFFSET + 0x14);
  local_48 = 0;
  while (local_48 < 0x14) {
    *(undefined *)((int)&local_28 + local_48) = 0;
    local_48 = local_48 + 1;
  }
  local_28 = 0x52525856;
  local_24 = 0x5255454a;
  printf("Enter the password: ");
  __isoc99_scanf(&DAT_0804d333,local_3c);
  local_44 = 0;
  while (local_44 < 8) {
    cVar1 = complex_function((int)local_3c[local_44],local_44 + 8);
    local_3c[local_44] = cVar1;
    local_44 = local_44 + 1;
  }
  iVar2 = strcmp(local_3c,(char *)&local_28);
  if (iVar2 == 0) {
    puts("Good Job.");
  }
  else {
    puts("Try again.");
  }
  if (local_14 == *(int *)(in_GS_OFFSET + 0x14)) {
    return 0;
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}

기드라로 까 보면 이렇게 생겼다

우리의 목표는 Good Job을 띄우는 입력값을 찾는 것이다

전처럼 puts("Good Job.");와 puts("Try again.");의 주소를 직접 구해도 되겠지만 이번에는 표준 출력의 결과를 활용해 구할 것이다

scaffold02.py를 보면 다음과 같다

import angr
import sys

def main(argv):
  path_to_binary = argv[1]
  project = angr.Project(path_to_binary)
  initial_state = project.factory.entry_state()
  simulation = project.factory.simgr(initial_state)

  def is_successful(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return ???

  def should_abort(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return ???

  simulation.explore(find=is_successful, avoid=should_abort)

  if simulation.found:
    solution_state = simulation.found[0]
    print solution_state.posix.dumps(sys.stdin.fileno())
  else:
    raise Exception('Could not find the solution')

if __name__ == '__main__':
  main(sys.argv)
import angr
import sys

def main(argv):
  path_to_binary = argv[1]
  project = angr.Project(path_to_binary)
  initial_state = project.factory.entry_state()
  simulation = project.factory.simgr(initial_state)

이 부분은 전과 같으니 넘어가고 다음 부분을 보겠다

def is_successful(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return ???

is_successful이라는 함수를 선언하고 있다

이 함수가 바로 주소를 직접 넣는 것을 대체하는 방법이다

앞에서 잠깐 언급했듯이 조건을 넘기기 위해 사용하는 것인데, 때문에 이 함수의 반환 값은 bool 타입이어야 한다

함수는 state 인자를 넘겨받아 무언가 연산을 해서 반환 값이 True인 것이 find와 avoid 인자에 영향을 준다

 

is_successful 함수는 시뮬레이션 상황에서 표준 출력의 결과를 stdout_output에 넣고 있다

이따가 보겠지만 이 is_successful 함수는 find인자에 들어갈 함수이므로 표준 출력에 Good Job. 이 있는 상황을 찾아야 한다

우리는 프로그램이 Good Job을 출력하기를 바란다

이 말은 표준 출력에 Good Job이 들어있어야 한다는 것이다

그러므로 이 함수는 stdout_output변수에 Good Job이 들어있으면 True를 반환하면 된다

그래서 ??? 부분에는 b'Good Job.' in stdout_output을 넣으면 된다

b'Good Job.' 앞에 b가 붙은 이유는 posix.dumps()의 반환 타입이 bytes이기 때문이다

def should_abort(state):
  stdout_output = state.posix.dumps(sys.stdout.fileno())
  return ???

should_abort도 다를 거 없다

???에 b'Try again.' in stdout_output을 넣으면 된다

  if simulation.found:
    solution_state = simulation.found[0]
    print solution_state.posix.dumps(sys.stdin.fileno())
  else:
    raise Exception('Could not find the solution')

if __name__ == '__main__':
  main(sys.argv)

마지막 부분은 전 예제들과 다르지 않다

이제 print 부분은 알아서 고칠 것이라 생각한다

 

전체 코드는 아래와 같다

import angr
import sys

def main(argv):
  path_to_binary = argv[1]
  project = angr.Project(path_to_binary)
  initial_state = project.factory.entry_state()
  simulation = project.factory.simgr(initial_state)

  def is_successful(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return b'Good Job.' in stdout_output

  def should_abort(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return b'Try again.' in stdout_output

  simulation.explore(find=is_successful, avoid=should_abort)

  if simulation.found:
    solution_state = simulation.found[0]
    print(solution_state.posix.dumps(sys.stdin.fileno()))
  else:
    raise Exception('Could not find the solution')

if __name__ == '__main__':
  main(sys.argv)

실행해보면 HETOBRCU이 나온다

Good Job도 잘 나오는 것을 확인할 수 있다

 

지금까지 함수를 활용해 find와 avoid인자에 함수를 사용해 조건을 넘기는 방법을 알아보았다

다음번에는 표준 입출력을 벗어나 레지스터를 다루는 방법을 알아보겠다

'Reversing > angr_ctf' 카테고리의 다른 글

04_angr_symbolic_stack  (0) 2021.04.10
03_angr_symbolic_registers  (0) 2021.03.26
01_angr_avoid  (0) 2021.02.26
00_angr_find  (0) 2021.02.24
Comments