본문 바로가기

CTF

[CTF] wolvCTF

1. child-re

child-re 는 64bit elf 파일이다. ida로 디컴파일 해보자

 

프로그램을 실행하면 처음에 6 * 9의 값이 무엇인지 묻고, 값을 입력받는다.

정답인 54를 입력하면 이상한 구문이 나오고, 42를 입력하니 다른 곳을 확인하라는 구문이 출력된다.

 

Functions 탭에서 sub_1165 함수를 확인해 보자

 

 매개변수로 a1을 받고, v2에 있는 값들과 1바이트씩 xor 연산을 한다. 그리고 그 결과를 s 변수에 1바이트씩 저장하고 s 변수를 출력한다.

 a1의 값이 무엇인지 알 수 없지만, 메인함수에서 42를 입력하고 다른 곳을 보라는 힌트를 주었으니 a1의 값을 42로 넣고 위 코드를 따로 작성하여 프로그램을 돌려봤다.

 

 

리버싱 공부 후 첫 CTF 문제 해결...치고는 문제가 너무 쉬웠다. 아무래도 리버싱 첫 문제여서 난이도가 많이 쉬운 듯

 

2. Homework Help

이 파일도 64bit elf 파일이다. ida로 디컴파일 해보자

메인함수는 ask() 함수만 호출하고 종료한다. ask 함수를 들여다보자

 

 출력 문장을 보니 숙제를 도와달라는 것 같다. 2 * 1 크기의 직사각형에 지름이 0.7인 원이 몇 개 들어가는지 입력받은 후 그 값을 eval() 함수로 넘겨준다. eval() 함수도 확인해 보자

 

 accept에 "0123456789+\n" 값을 복사하고 입력받은 값 s가 정답인지 아닌지 체크하고 s가 3 혹은 1+2 형식으로 이루어져 3이 되면 flag를 체크해준다고 한다. FLAG 변수에 내가 입력하는 flag를 저장해 준다. 하지만 그 후에 플래그를 어떻게 검증하고 출력하는지 알 수 있는 함수가 없다...

 따라서 앞선 문제와 마찬가지로 Functions 탭을 다시 살펴보았다. Stack Canary 검증 오류 시 호출되는 함수인 '__stack_chk_fail' 함수가 다른 데에서는 분홍색으로 라벨이 색칠되어 있는데 여기서는 흰색탭으로, 사용자가 직접 작성한 함수처럼 나타내져 있었다. 따라서 이 함수를 보니 다음과 같았다.

 

 

 이때까지 보던 __stack_chk_fail 함수와는 코드가 다르다.

 "Well Done"이 출력되는 FLAG 값이 정답 flag일 것이다. FLAG 변수와 v4변수를 비교연산한 후, 값이 다르면 반복문을 종료한다. 아마도 이 조건이 flag 검증 여부인 듯하다. 

 v5[1]에 20을 담고 v6, v7, v8... 에 5바이트 크기의 값을 담는다. 디컴파일에서는 이렇게 표현되어 있지만, 사실 v5[0]부터 32개의 int를 담는 배열로 표현이 가능하다. 실제로 어셈블리어를 봐도 메모리주소가 이어져있는 것을 확인할 수 있다.

for 구문 내에 i = v5[v0] 이 문장이 4바이트 값을 i에 넣는 작업이다. v6부터 5바이트 값을 담는데, 이를 다르게 해석하면 v5[0] = 0, v5[1] = 20, v5[2] = 0x17, v5[3] = 0x12, v5[4] = 0x1D, ... 이런 식으로 봐도 무방하다. 

 위 코드를 짜서 출력해 보면 다음과 같은 결과를 얻을 수 있다.

이 문제도 나름 쉬운 듯하다. 

 

+번외) eval() 함수의 디컴파일에서는 맨 마지막에 ask()를 호출한다고 되어 있지만 디스어셈블리 쪽 코드를 보니 ask() 호출은 안 보이고 __stack_chk_fail 함수를 호출한다... 디컴파일 결과를 너무 맹신하지 말자

 

3. ej

이 파일도 64bit elf 파일이다. ida로 메인함수를 확인해 보자

퍼즐을 풀면 플래그가 출력되는 형식이다. 입력값을 s에 받고 s와 입력길이를 sub_159B() 함수로 넘겨준다. 

퍼즐 내용은 sub_159B() 함수에 있으니 디컴파일 결과를 확인해 보자

 

2중 for문을 보니 v4변수(이하 map)는 6 * 6 크기의 작은 체스판(2차원 배열)처럼 생각하면 될 듯하다. 요약내용은 다음과 같다.

- 'u' 입력 시, 위로 1칸 이동할 수 있으면 현재 위치에 3을 저장하고 한 칸 위로 이동한다.

- 'r' 입력 시, 오른쪽으로 1칸 이동할 수 있으면 현재 위치에 6을 저장하고 한 칸 오른쪽으로 이동한다.

- 'd' 입력 시, 아래로 1칸 이동할 수 있으면 현재 위치에 5를 저장하고 한 칸 아래로 이동한다.

- 'l' 입력 시, 왼쪽으로 1칸 이동할 수 있으면 현재 위치에 4를 저장하고 한 칸 왼쪽으로 이동한다.

- return 값으로 1을 반환해야 하므로 v7 = 0, sub_1479()와 sub_11FA() 함수의 리턴값은 1이어야 한다.

- v7이 의미하는 것은 현재 위치이므로 입력값으로 전부 이동했을 때, 처음 위치인 0으로 이동해야 한다.

 

sub_1479()와 sub_11FA() 함수 내부에서 byte_4080라는 변수를 참조하는데 이 변수는 36 bytes로, 6 * 6의 크기와 같으며 아래와 같은 모양이다.

각 함수에 대한 요약은 다음과 같다.

sub_1479()

- byte_4080[i][j]의 값이 1일 때(파란 영역), 이 위치가 가리키는 반대 방향의 값과 map[i][j]의 값이 같아야 한다. 

sub_11FA()

- byte_4080[i][j]의 값이 2일 때(빨간 영역), 이 위치가 가리키는 방향의 값과 map[i][j]의 값이 같아야 한다. 

- 빨간 영역일 때, map[i][j]가 왼쪽 혹은 오른쪽을 가리키는 값이라면, 위아래 중 1곳은 2칸 연속으로 본인을 향하는 방향값을 가져야 한다.

- 빨간 영역일 때, map[i][j]가 위쪽 혹은 아래쪽을 가리키는 값이라면, 좌우 중 1곳은 2칸 연속으로 본인을 향하는 방향값을 가져야 한다.

 

이 조건을 고려했을 때, 칸을 모두 채우는 입력은 다음 루트로 나타낼 수 있다. (반대로 진행해도 조건은 성립된다.)

 

그러나 이 루트를 u, d, l, r에 대응하게 입력하니 이상한 값이 출력되었다.

그래서 이번에는 우측 상단에 있는 꺾는 구간을 생략하고 34글자를 입력하니 제대로 된 플래그가 나왔다.

약간 어거지로 푼 듯한....

참고로 정답을 표시하면서 따라가면 문제 제목인 ej(?)를 확인할 수 있다!

 

 

'CTF' 카테고리의 다른 글

[CTF] CCE 2024 Qual Write-up  (0) 2024.08.13
[CTF] Codegate 2024 Write-up  (0) 2024.06.02
[CTF] LINE CTF 2023  (0) 2023.03.28