CTF/리버싱

[SharkyCTF] Z3ROBOTWAVES - 리버싱 / IDA

SecurityMan 2022. 8. 16. 11:00

 

리버싱 문제

 

그렇게 어렵진 않았는데 매우 귀찮은 문제였다.

 

반응형

 

문제 설명을 읽어보면 개발자가 어떤 로봇을 만들었는데 

 

그 로봇이 잠겨서(Locked) 비밀번호를 요구한다고 한다.

 

 

문제에서 주어지는 파일은 z3_robot 파일이다.

 

 

리눅스 환경에서 file 명령어를 통해

 

어떤 파일인지 살펴보면

 

ELF 파일이라고 한다.

 

ELF는 리눅스에서 실행가능한 실행파일이다.

 

 

터미널에서 ./z3_robot 이라고 입력하면 실행이 가능하다.

 

실행시켜봤더니 아까 들었던것 처럼 비밀번호를 요구하고 있다.

 

 

시험삼아 hello 라고 입력해봤는데

 

그랬더니 로봇이 기분나쁘게 웃으면서 프로그램이 종료되었다.

 

 

IDA 라는 디스어셈블러를 이용해 문제파일을 살펴보았다.

 

main 함수의 수도코드를 보면,

 

fgets 함수를 이용해 s 라는변수에 사용자 입력값을 25자 받아서 저장하고,

 

check_flag 함수에 s 값을 넘겨서 그 결과가 참일경우,

 

shkCTF 로 시작하는 플래그를 알려주는것이 보인다.

 

 

check_flag 함수를 살펴보면 내용이 아주 가관이다.

 

사용자에게 입력받은 값을 한글자씩 a1 배열에 저장하는데,

 

조건이 하나만 있는게 아니라 &&를 이용해 엄청나게 많은 조건을 부여해놨다.

 

이 모든 조건을 다 만족시켜야 플래그를 얻을 수 있다.

 

_BOOL8 __fastcall check_flag(char *a1)
{
  return (a1[20] ^ 0x2B) == a1[7]
      && a1[21] - a1[3] == -20
      && !(a1[2] >> 6)
      && a1[13] == 116
      && 4 * a1[11] == 380
      && a1[7] >> (a1[17] % 8) == 5
      && (a1[6] ^ 0x53) == a1[14]
      && a1[8] == 122
      && a1[5] << (a1[9] % 8) == 392
      && a1[16] - a1[7] == 20
      && a1[7] << (a1[23] % 8) == 190
      && a1[2] - a1[7] == -43
      && a1[21] == 95
      && (a1[2] ^ 0x47) == a1[3]
      && *a1 == 99
      && a1[13] == 116
      && (a1[20] & 0x45) == 68
      && (a1[8] & 0x15) == 16
      && a1[12] == 95
      && a1[4] >> 4 == 7
      && a1[13] == 116
      && *a1 >> (*a1 % 8) == 12
      && a1[10] == 95
      && (a1[8] & 0xAC) == 40
      && a1[16] == 115
      && (a1[22] & 0x1D) == 24
      && a1[9] == 51
      && a1[5] == 49
      && 4 * a1[19] == 456
      && a1[20] >> 6 == 1
      && a1[7] >> 1 == 47
      && a1[1] == 108
      && a1[3] >> 4 == 7
      && (a1[19] & 0x49) == 64
      && a1[4] == 115
      && (a1[2] & a1[11]) == 20
      && *a1 == 99
      && a1[4] + a1[5] == 164
      && a1[15] << 6 == 6080
      && (a1[10] ^ 0x2B) == a1[17]
      && (a1[12] ^ 0x2C) == a1[4]
      && a1[19] - a1[21] == 19
      && a1[12] == 95
      && a1[15] >> 1 == 47
      && a1[19] == 114
      && a1[17] + a1[18] == 168
      && a1[22] == 58
      && (a1[23] & a1[21]) == 9
      && a1[6] << (a1[19] % 8) == 396
      && a1[3] + a1[7] == 210
      && (a1[22] & 0xED) == 40
      && (a1[12] & 0xAC) == 12
      && (a1[18] ^ 0x6B) == a1[15]
      && (a1[16] & 0x7A) == 114
      && (*a1 & 0x39) == 33
      && (a1[6] ^ 0x3C) == a1[21]
      && a1[20] == 116
      && a1[19] == 114
      && a1[12] == 95
      && a1[2] == 52
      && a1[23] == 41
      && a1[10] == 95
      && (a1[22] & a1[9]) == 50
      && a1[3] + a1[2] == 167
      && a1[17] - a1[14] == 68
      && a1[21] == 95
      && (a1[19] ^ 0x2D) == a1[10]
      && 4 * a1[12] == 380
      && (a1[6] & 0x40) != 0
      && (a1[12] & a1[22]) == 26
      && a1[7] << (a1[19] % 8) == 380
      && (a1[20] ^ 0x4E) == a1[22]
      && a1[6] == 99
      && a1[12] == a1[7]
      && a1[19] - a1[13] == -2
      && a1[14] >> 4 == 3
      && (a1[12] & 0x38) == 24
      && a1[8] << (a1[10] % 8) == 15616
      && a1[20] == 116
      && a1[6] >> (a1[22] % 8) == 24
      && a1[22] - a1[5] == 9
      && a1[7] << (a1[22] % 8) == 380
      && a1[22] == 58
      && a1[16] == 115
      && (a1[23] ^ 0x1D) == a1[18]
      && a1[23] + a1[14] == 89
      && (a1[5] & a1[2]) == 48
      && (a1[15] & 0x9F) == 31
      && a1[4] == 115
      && (a1[23] ^ 0x4A) == *a1
      && (a1[6] ^ 0x3C) == a1[11];
}

 

캡쳐는 좀 짤렸는데 위에 있는것이 모든 조건이다.

 

사실 조건이 많아서 그렇지 그렇게 어려운 조건들은 아닌데

 

많아도 너무 많아 귀찮다.

 

쉽게 해결할 수 있는 내용부터 찾아나가면 된다.

 

 

이렇게 단순 == 으로 비교하는 부분이 쉬운 부분이다.

 

 

위의 ASCII 코드표에서 숫자에 해당하는 글자를 찾아서 넣어주면 된다.

 

 

예를들어 맨 처음에 있는 a1[20] == 116 의 경우 a1[20] == t 와 같다.

 

a1 배열의 21번째 값은 t가 되는것이다.(배열은 0부터 시작하므로)

 

마찬가지로 20번째, 13번째, 3번째, 24번째, 11번째 값은 각각 r, _, 4, ), _ 가 된다.

 

 

위처럼 연산이 필요한 조건의 경우 역으로 연산해주면 된다.

 

지금 a1[20] 의 값이 116 인것을 알고 있으니

 

116과 0x4E 를 XOR(^) 한 값이 a1[22] 의 값이 되는것이다.

 

 

116을 16진수로 바꾸면 74가 된다.

 

74와 4E를 XOR 하면 3A가 나오는데, 이를 10진수로 바꾸면 58이 된다.

 

 

58은 ASCII 코드표에서 : (콜론) 이다.

 

a1배열의 23번째 값은 : 이 되는것이다.

 

이런식으로 각 배열의 모든 값을 하나씩 찾아나가면 된다.

 

 

이렇게 각 자릿수별로 빈칸을 만들어넣고

 

하나씩 채워넣으면 안빼먹고 다 바꿀 수 있다.

 

 

알아낸 문자열을 로봇에게 전달해주면

 

이번엔 로봇이 플래그를 알려준다.

반응형