본문으로 바로가기

Codegate 2017 prequals hunting Write Up

category 해킹/Write Up 2017. 2. 21. 19:47

0. Introduce

실제 대회에서 babymisc를 풀고 끝날때까지 잡고있었던 문제입니다. 그만큼 정(?)이붙어서 대회끝나고도 한 2일동안 분석을 한거같네요. 계속계속 라업을 확인하다가 올라온 라업을 발견하고 풀 수 있었던 문제입니다. 정말 재미있었고 이런식으로 취약점이 발견될지는 정말 몰랐습니다. 일부로 취약점을 만들어두고 거기다가 삽질을 유도한것때문에 힘들었지만 많은 시간을 투자해서 분석하고 익스한만큼 성취감이 엄청납니다..


1. Binary

사실 이것때문에 약간 애를 먹었는데 카나리랑 NX가 켜져있는걸 보고 카나리만 leak하면 rop로 익스가 가능할꺼란 희망이 생겨서 삽질을 많이했다. 결국에 rop익스는 아니였다.


바이너리는 생각보다 간단하다. 위와같이 6가지 메뉴로 구성 되어있다. (초기 HP : 500)

1. How to play : You have to kill the boss monster. You can use several skills, and you must stop the attack of boss.  Have fun! 출력

2. Use skill : 선택한 스킬로 보스를 공격. 각각의 스킬마다 계산되는 데미지가 다르며 공격후에는 보스의 공격을 막을 쉴드를 선택할 수 있음. 어떤 종류의 쉴드를 선택하냐에 따라서 막을 수 있는지 없는지가 판단되며 매번 공격할때마다 막을 수 있는 쉴드가 랜덤으로 바뀜. (쉴드 : iceshield, fireshield, windshied) 그리고 Use skill을 선택하면 새로운 스레드가 생성됨.

3. Chagne skill : 스킬을 바꿀 수 있음.( 1. attack 2. fireball 3. iceball 4. magicball 5. lightning 6. hellfire 7. icesword 8. magicsword 9. hollylight) 보스레벨이 4이상일때만 5번 이상의 스킬들을 사용 가능)

4. Remove skill : 현재 가지고있는 스킬을 없애줌

5. Recieve suggestion : 입력할 수 있는 창이 나오고 입력이 끝나면 ok, thanks.출력


그래서 보스의 피가 0 이하가 될 때마다 레벨이 올라가는데, 보스레벨이 5 이상이되면 게임종료 후 cat flag (ssh로 접속 후 문제 해결)

level 1 Boss Hp : 0x64(100)

level 2 Boss Hp : 0x3e8(1000)

level 3 Boss Hp : 0xbb8(3000)

level 4 Boss Hp : 0x7ffffffffffffffe(9223372036854775806) 


2. VulnerAbility

5번에서 간단하게 버퍼오버플로우 취약점이 발생한다. 스택카나리만 없다면 이문제를 바로 풀 수 있겠지만 스택카나리가 존재한다.

그래서 소스를 계속 분석하면서 Leak을 낼 수 있는 방법에대해서 고민했었다. 하지만 결국 이렇게 푸는건 아니였다.


그리고 핵심적으로 문제를 푸는데 필요한 취약점인 정수 오버플로우다. level 4 Boss Hp는 0x7ffffffffffffffe이다 즉 9223372036854775806이지만 여기서 2를 더해 0x8000000000000000으로 만든다면 __int64형 변수에서 정수 오버플로우가 발생해 -9223372036854775808로 변환된다. 그러면 바로 level4보스를 죽일 수 있게된다.


3. Exploit

문제를 푸는데 해야할것은 다음과 같다.

1) Go to level 4.

2) Use integer overflow to kill boss


1) Go to level 4

level 4까지 가기위해서는 보스의 공격을 무조건 막을 수 있으면 된다.

위 함수를 토대로 rand값을 이용해 무조건 defense할 수 있는 입력값을 찾는다.

여기서 v3는 복잡한듯 보이지만 사실 rand & 3과 같다.


rand의 seed는 time(0)이기때문에 위 정보를 기반으로 무조건 defense할 수 있는 입력값을 찾으면 한번도 공격받지 않고 level4까지 갈 수 있다.

여러 스킬을 사용해보았지만 iceball이 가장 빠르게 올라갈 수 있다. (스킬 함수 참조)


2) Use integer overflow to kill boss

출제자가 문제를 낼 때 소스코드의 여러 부분에서 이상한 점을 느낄 수 있게 만들어 그정보들로 정답에 접근할 수 있도록 만들어 놓은 것 같다. 첫번째로 공격하는 함수이다. 얼핏보면 4이하의 스킬공격과 5이상의 스킬공격이 같아보인다. 하지만 4이하의 스킬공격은 (singed int)*(_QWORD *)(a1 + 72)이며 5이상의 스킬공격은 (_QWORD *)(a1 + 72)이다. 차이가 거의 없어보일 수 있지만 두번째 함수를 본다면 이부분이 매우 중요하다는것을 알 수 있다.


두번째 함수는 스킬에 따라 데미지를 계산하는 함수이다. 하지만 자세히보면 맨위에 fireball(s2)의 return값은 sleep(0x1)이고 iceword의 return값도마찬가지로 sleep(0x1)이다. 여기서 두번째 의혹을 가지고 iceword 함수를 본다면 아래와 같이 iceword의 결과값이 항상 0xffffffff임을 알 수 있다. 이 0xffffffff는 (_QWORD)로 표현된다면 4294967295를 나타낸다. 하지만 이값이 (singed int)로 표현된다면 integer overflow가 발생해 -1이 된다. 즉 이 공격을 4이하의 스킬공격으로 간주할 수 있게만 한다면 보스에 HP에 1을 더할 수 있게된다.


iceword의 스킬공격을 4이하의 스킬공격으로 간주하게 하는방법은 다음과 같이 스킬을 사용할 때 스레드를 생성한다는 것을 가지고 할 수 있다. 일단 스레드는, 스레드가 생성되면 생성된 스레드와는 개별적으로 메인스레드에서 작업할 수 있다. 그래서 fire ball을 실행해 4이하의 스킬공격 구문으로 들어가기 바로전에 스레드가 멈춰있는것[sleep(1)]을 이용해 순간적으로 icesword 스킬을 사용하면 데미지는 0xffffffff인 채로 4이하의 스킬공격 구문에 들어갈 수 있다. 그렇게된다면 (singed int)*(_QWORD *)(a1 + 72)을 거쳐 -1이 데미지로 전달되고 보스의 HP에 1을 더해줄 수 있다. 이렇게 (singed int)*(_QWORD *)를 거쳐야만 -1이 되므로 두번째에 (_QWORD *)값이 음수이면 경고문을 출력하는 부분을 우회할 수 있다.


즉 정리하자면 출제자는

1. level 4 Boss Hp : 0x7ffffffffffffffe에서 integer overflow가 발생할 수 있다는것을 인지.

2. Boss Hp에 데미지만큼 뺄 때, 같은 코드임에도 4이하와 5이상을 나눠놓은 것을 확인후 (singed int)*(_QWORD *)를 확인.

3. 스킬중에서 두가지에만 sleep(1)이 있는것을 보고 이상하게 여겨 각각의 코드를 확인.

4. icesword가 실제로 0xffffffff만을 결과값으로 출력한다는것을 확인한 뒤에 스레드를 이용한 integer overflow 설계.

다음과 같이 생각하고 풀것을 의도한것 같다. 문제 여러곳에 이런 힌트들이 존재한다는것이 문제를 풀면서 정말 신기했고 재미있었다. 하지만 여러 부분들에서 0으로 만드는 비트연산이라던가 일부로 꼬아논것들이 있어서 함정에 걸리지 않아야 한다.


4. Exploit

( a.out 코드는 깃허브에서 확인 가능 / 깔끔하게 익스하고싶었으나 코드를 건드릴 엄두가 안나서 풀때 사용한 익스를 올립니다. )

(https://github.com/LYoungJoo/CTF-Write-Up/tree/master/2017_CodeGate_Prequals%20Write%20Up/hunting)


Exploit Tip

1) seed값이 정해져있을 때 rand값을 예측하기 위해서는 rand의 개수와 위치를 잘 파악해야한다.

2) c의 rand를 python에서 사용할 경우에는 c코드의 컴파일된 결과값을 이용하는게 좋다. (.rstrip().split('\n')  이용)

3) 시드 값이 time함수일때 실제 ssh 서버연결시 드는 시간과 바이너리를 실행하는데 시간이 걸릴 수 있으므로 rand값이 이상하다면 time() - 1을 시드값으로 주어 확인하는것도 하나의 방법이 될 수 있다.

4) 프로그램에 값을 넣을 때, sleep함수를 적절히 사용하여 제시간에 값이 들어가도록 해야한다.

5) integer overflow를 확인할 때는 https://msdn.microsoft.com/ko-kr/library/s3f49ktz.aspx 이 사이트를 이용한다.


FLAG ( local Exploit )


'해킹 > Write Up' 카테고리의 다른 글

XiomaraCTF 2017 mint Write Up  (0) 2017.02.27
XiomaraCTF 2017 pwn50 Write Up  (0) 2017.02.27
9447CTF 2015 serach engine Write Up  (2) 2017.02.19
Codegate 2017 prequals BabyMISC Write Up  (0) 2017.02.16
Codegate 2017 prequals Babypwn Write Up  (0) 2017.02.16