본문 바로가기

Reverse Engineering/Wargame

Dreamhack : simple-operation

문제 링크

https://dreamhack.io/wargame/challenges/836

 

simple-operation

Description 우리의 친구 아모가 미션을 주었습니다. "내가 원하는 결과가 나오도록 값을 입력해 줘!" 주어진 바이너리를 분석하고 알맞은 값을 입력하면 플래그가 출력됩니다. 플래그는 flag 파일에

dreamhack.io

 

풀이

 

그림 1

 

해당 문제는 nc로 해당 호스트에 접근 시, Random number 가 출력이 되고, Input? 이 printf 된 이후에 사용자 입력 값을 받는다. 그 후에 Result 값과 Try again이라는 문자열이 반환된다. 

 

그림 2

 

위 그림 2에서 Try again 문자열을 확인할 수 있고, 위 분기문을 확인했을 때, strcmp 비교를 한 후 왼쪽과 오른쪽 분기로 나눠짐을 알 수 있다. 

 

그림 3

 

그림 2에서 디컴파일(F5)을 수행하면, 그림 3과 같이 디컴파일된 코드를 확인할 수 있다. 이 문제에서는 문자열 포맷 형식이 문제를 푸는데 주요한 부분이기 때문에, 해당 부분을 빨간 박스로 강조해두었다.

먼저, 리스트 s1의 원소는 a0b4c1d7임을 strcmp를 통해 알 수 있고, for문을 통해 리스트 s가 7d1c4b0a의 원소를 갖게 됨을 알 수 있다. 

다음으로 snprintf 함수 부분을 살펴보면, v6 ^ v7의 결과가  s에 저장이 됨을 알 수 있고, 이때 문자 포맷은 % 08x이다.

 

더보기

snprintf 란?

 

sprintf 함수의 취약성을 보완하고자 나온 함수로 지정한 크기만큼만 데이터를 버퍼에 저장하고 초과되는 데이터는 무시하는 함수이며, 아래와 같은 형식을 가지게 된다. 

 

#include <stdio.h>
int snprintf(char *buffer, size_t n, const char *format-string,
             argument-list);

 

 

그 후 scanf를 통해 사용자로부터 정수형 입력을 받아 v7에 저장하게 된다. 그리고 v6는 Random number 문자열과 함께 %#x 포맷으로 출력된다. 

 

더보기

문자 포맷

 

% x는 정수를 16진수로 출력하며, %#x는 여기에 0x 접두사를 추가해 16진수 표기임을 명확히 한다.

%08 포맷은 8자리로 출력하며, 부족한 자릿수는 0으로 채워 출력하도록 지정된 형식이다. 

 

지금까지의 과정을 정리해 보면, 아래와 같은 연산 관계를 도출할 수 있다. 

 

0x7d1c4b0a(배열  s) = v6(Random 16진수 값) XOR v7(사용자 정수 입력 값)

 

XOR 연산의 특성상 이를 다음과 같이 변형할 수 있다.

 

0x7d1c4b0a(배열  s) xor v6(Random 16진수 값) = v7(사용자 정수 입력 값)

 

코드로 나타내면 아래와 같다. 

 

a = 0xdee53285 # random 값
b = 0x7d1c4b0a # s

v7 = a ^ b

print("V7 = 0x{:08x}".format(v7))  # 16진수 출력
print("V7 = {}".format(v7))        # 10진수 출력