상세 컨텐츠

본문 제목

2013 CodeGate YUT Binary 200 | 2013 코드게이트 바이너리 200 풀이

0x10 정보보안/0x14 Reverse Engineering

by sweetchip 2013. 3. 10. 16:10

본문

반응형


바이너리 200점 문제..


생각보다 낚시가 있었던 문제이다.


파티션에 접근하고 MBR에도 직접 접근해서 그곳에서 뭔짓을 하긴 하는데 자세히 분석은 안해봤다.


역시나 시간을 많이 소비한 문제... 역시 바이너리는 어렵다.


100점에서 갑자기 난이도가 뛰어도 되나 ㅠ-ㅠ



f8af14c66a2a1c96281d278b40c9af2c.exe



바이너리 :P


그리고 간단한 시스템정보를 얻어오는것 같고 MBR에도 접근한것을 볼수 있다.


그리고 현재 드라이브의 이름은? 이라는 질문에 답하면 시스템 메세지와 그냥 메세지를 출력하는 프로그램이다.


솔직히 처음에는 뭘 원하는건지 몰랐다..;


그냥 저렇게만 나오니 디스크에 관련이 있나? 라고 생각을 했는데 풀다보니 아니라는걸 느꼇고


특히나 저 시스템 메세지와 그냥 메세지가 하는일이 궁금했다.


그리고 처음 실행할때 zlib가 필요했고 실제로 함수에도 compress 함수가 쓰였다.


당시엔 확실하진 않았지만, 저 메세지와 시스템 메세지가 큰 관련이 있을것이라고 생각하고 분석하는 방향을 바꿔서 다시 시작했다.



처음 시작할때는 이렇게 많은 점프문을 볼수 있는데 아마 디버그 모드로 컴파일 되서 그런것 같다..


아.. 이런 문제가 정말 불편하다. ㄷㄷ


함수 이름 등을 꺠끗하게 볼수 있는 방법을 아는 분은 댓글을 날려주심 감사하겠습니다.


이리저리 돌아다니다가 문제를 출력하는 부분을 찾았다.




위에서 Congretz! Auth Key is [???? ???? ????] 가 보였다.


헐 설마 Key가 ???? ???? ???? 그대로인가? 라고 생각햇지만 에이 설마.. 하고 그냥 넘겼다.


물론 나중에 확인해보니 당연히 아니었다 ㅋㅋ


아무튼 저게 그냥 나와있는건 아니라고 생각해뒀다..


그리고 밑에 Input Drive Name 이라는 글자와 함께 입력을 받고



그 입력을 받은 글자를 통해서 압축 -> 암호화를 하는 루틴이다.


그리고 마지막엔 메세지로 띄운다.


대략 정히해보면 | 문제띄우기 -> 드라이브이름 입력 -> 입력값을 압축 [zlib.compress] -> Encrypt | 이다.


그리고 아까 시스템 메세지가 궁금해서 Bintext로 현재 프로그램의 문자열을 조사했다.



시스템 메세지는 하드코딩이 되어있는 상태이고 그냥 메세지는 입력값에따라 바뀌는 값이다.



sweetchip을 입력한다면 위의 메세지와 같이 나올것이다.



다시 디버깅을 해보자.



zlib 의 compress 함수를 거치고나면 sweetchip은 위와 같이 압축되어버린다.



이제 Encrypt의 부분으로 들어가면 길다란 함수가 펼쳐진다.


처음 반복하는 부분이 있는데 아래 사진을 보자.



무언가 계속 돌면서 xor 0x03 연산을 한다.


어떤것이 연산을 하는지 보려고 Hex dump를 확인했다.



위와 같이 QwErTy ... 가 연산이 되고 있는데 [1/5 정도 된 상태]


일단은 연산이 모두 끝나면 어찌되나 보려고 했다.



위 사진은 연산이 모두완료된 상태이다.



아래로 내려오면 또 이상한 연산을 하는데 쉬프트 연산같은 이게 진짜 암호화인것 같다.


그리고 위에서 xor된것을 테이블로 활용하는것 같았다.


"QwErTyUiOpAsDfGhJkLzXcVbNm0246813579qWeRtYuIoPaSdFgHjKlZxCvBnM /" 이 테이블이다.


이게 뭔 연산인지 몰라서 다른분의 풀이를 보니 base64와 관련이 있다고 했다.


하지만 보통 base64가 아니고 테이블이 바뀌어져 있는 base64 라는것을 힌트로 얻고 분석을 계속했다.


base64 알고리즘을 인터넷으로 찾아보고 위 어셈블리 코드와 대강 비교하니 똑같은것 같고 확실히 다른건 테이블만 달랐다.


base64 에 대한 Wiki : http://en.wikipedia.org/wiki/Base64



실제로 3개의 바이트값를 입력하고, 위 파란 부분에서 4바이트값을 배출[?] 한다.


스택을 덤프로 살펴보자.



아니! 이것은 아까 처음에 봤던 글자가 확실하다.


잠시 정리를 해보면


입력값 받음 -> zlib 라이브러리로 Compress 함수사용 -> encode


로 진행이 되고있다. 인코딩은 base64 알고리즘을 적용했지만 인코딩 테이블이 다른 base64이다.


처음에 중간에 나왔던 System Message: 8pFHHoMssjtoucpX4EdPgcrdzuKXgEFV7iNur4YzDrOdfyNOA/bp7lX= <-- 이것은 시스템 메세지인데


이것도 base64 처럼 생겼다.


그렇다면 위처럼 생성된 알고리즘을 바탕으로 복호화 시키면 될것이다.


일단은 시도 해보기로 하고 zlib 닷넷전용 라이브러리를 구해서 sweetchip을 그대로 compress 해본 결과..



글자가 깨진 상태긴 해지만 디버깅 할때 compress 된 값과 같은걸로 보아서 제대로 구한것 같다.


준비물을 모두 구햇으니 이제 코딩만 하면된다


Plain Text -> Compress -> Encoding 순으로 값이 나왔으니 반대로 Decoding -> Decompress -> Plain Text 로 코딩하면 될것이다.


C#으로 코딩한다.



대충 코딩하고 8pdIsqMfsXRGgEF3 을 입력하니 위와 같은 값이 나왔다.


그렇다면..



쭈욱 코딩하고 시스템 메세지를 넣고



컴파일을 하고~


버튼을 눌렀다.



답이 나왔다! 만세 ㅠㅠ


Congratz! Auth Key is [BuRn 2013 VuLn]


Flag is BuRn 2013 VuLn


ZLIB.NET : http://www.componentace.com/zlib_.NET.htm


/*

* Programmed by sweetchip

* Date : 2013.03.10

* 2013 Codegate Binary

* Zlib & base64[custom]

*/

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.IO;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;

using zlib;

using System.IO.Compression;


namespace Codegate_2013_bin200

{

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

}


private void button1_Click(object sender, EventArgs e)

{

string Encoded = "8pFHHoMssjtoucpX4EdPgcrdzuKXgEFV7iNur4YzDrOdfyNOA/bp7lX="; // system Message

Base64Decoder(Encoded.ToCharArray()); // Decode base64

byte[] temp = GetDecoded();

byte[] result = new byte[2048];

DecompressData(temp, out temp);

MessageBox.Show(UTF8Encoding.UTF8.GetString(temp));

}


// Deflate compressed data.

public static void DecompressData(byte[] inData, out byte[] outData)

{

using (MemoryStream outMemoryStream = new MemoryStream())

using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream))

using (Stream inMemoryStream = new MemoryStream(inData))

{

CopyStream(inMemoryStream, outZStream);

// outZStream.finish(); // 오류나서 주석처리 했습니다. 원래는 주석처리 되어있지 않습니다.

outData = outMemoryStream.ToArray();

}

}


public static void CopyStream(System.IO.Stream input, System.IO.Stream output)

{

byte[] buffer = new byte[2000];

int len;

while ((len = input.Read(buffer, 0, 2000)) > 0)

{

output.Write(buffer, 0, len);

}

output.Flush();

}



// Decode base64

public char[] source;

public int length, length2, length3;

public int blockCount;

public int paddingCount;

public void Base64Decoder(char[] input)

{

int temp = 0;

source = input;

length = input.Length;


//find how many padding are there

for (int x = 0; x < 2; x )

{

if (input[length - x - 1] == '=')

temp ;

}

paddingCount = temp;

//calculate the blockCount;

//assuming all whitespace and carriage returns/newline were removed.

blockCount = length / 4;

length2 = blockCount * 3;

}


public byte[] GetDecoded()

{

byte[] buffer = new byte[length];//first conversion result

byte[] buffer2 = new byte[length2];//decoded array with padding


for (int x = 0; x < length; x )

{

buffer[x] = char2sixbit(source[x]);

}


byte b, b1, b2, b3;

byte temp1, temp2, temp3, temp4;


for (int x = 0; x < blockCount; x )

{

temp1 = buffer[x * 4];

temp2 = buffer[x * 4 1];

temp3 = buffer[x * 4 2];

temp4 = buffer[x * 4 3];


b = (byte)(temp1 << 2);

b1 = (byte)((temp2 & 48) >> 4);

b1 = b;


b = (byte)((temp2 & 15) << 4);

b2 = (byte)((temp3 & 60) >> 2);

b2 = b;


b = (byte)((temp3 & 3) << 6);

b3 = temp4;

b3 = b;


buffer2[x * 3] = b1;

buffer2[x * 3 1] = b2;

buffer2[x * 3 2] = b3;

}

//remove paddings

length3 = length2 - paddingCount;

byte[] result = new byte[length3];


for (int x = 0; x < length3; x )

{

result[x] = buffer2[x];

}


return result;

}


private byte char2sixbit(char c)

{

string b_table = "QwErTyUiOpAsDfGhJkLzXcVbNm0246813579qWeRtYuIoPaSdFgHjKlZxCvBnM /";

char[] lookupTable = b_table.ToCharArray();

if (c == '=')

return 0;

else

{

for (int x = 0; x < 64; x )

{

if (lookupTable[x] == c)

return (byte)x;

}

//should not reach here

return 0;

}


}


}

}



base64와 decompress 라이브러리, 함수는 검색을 통해 구했습니다.


구글신 만세~



2013/03/08 - [0x10 정보보안/0x14 Reverse Engineering] - 2013 CODEGATE YUT BINARY 300 Write-up | 2013 코드게이트 바이너리 300 풀이


2013/03/09 - [0x10 정보보안/0x14 Reverse Engineering] - CODEGATE 2013 YUT BINARY 100 | 코드게이트 2013 바이너리 100


반응형

관련글 더보기