문제 링크
https://dreamhack.io/wargame/challenges/836
simple-operation
Description 우리의 친구 아모가 미션을 주었습니다. "내가 원하는 결과가 나오도록 값을 입력해 줘!" 주어진 바이너리를 분석하고 알맞은 값을 입력하면 플래그가 출력됩니다. 플래그는 flag 파일에
dreamhack.io
풀이

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

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

그림 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진수 출력