-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
180703
- Loading branch information
Showing
3 changed files
with
365 additions
and
0 deletions.
There are no files selected for viewing
267 changes: 267 additions & 0 deletions
267
docs/reversing/windows/[2018_VolgaCTF] [REV] Crack Me.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,267 @@ | ||
===================================================================== | ||
[2018_VolgaCTF] [REV] Crack Me | ||
===================================================================== | ||
|
||
문제 내용 | ||
===================================================================== | ||
|
||
Just do it. | ||
|
||
|
||
문제 풀이 | ||
===================================================================== | ||
|
||
파일 다운로드 시 실행 파일 Crackme.exe와 암호화 텍스트 Crackme.txt가 주어진다. | ||
Crackme.exe 실행 시 다음과 같은 화면이 출력된다. | ||
|
||
.. code-block:: console | ||
Incorrect arguments | ||
Usage: CrackMe.exe <input_file> <output_file> <user_pass_phrase> <mode> | ||
ilspy로 디컴파일한 뒤, 출력되는 문자열을 검색하면 다음 코드 부분을 확인할 수 있다. | ||
|
||
.. code-block:: c# | ||
// CrackMe.Program | ||
private static void Main(string[] args) | ||
{ | ||
if (args.Length != 4) | ||
{ | ||
Console.WriteLine("Incorrect arguments"); | ||
Console.WriteLine("Usage: CrackMe.exe <input_file> <output_file> <user_pass_phrase> <mode>"); | ||
return; | ||
} | ||
string text = args[0]; | ||
string outputFile = args[1]; | ||
string userPassword = args[2]; | ||
string a = args[3]; | ||
if (!File.Exists(text)) | ||
{ | ||
Console.WriteLine("Input file doesn't exist"); | ||
return; | ||
} | ||
CryptoOperation cryptoOperation = new CryptoOperation(); | ||
cryptoOperation.FileName = text; | ||
cryptoOperation.UserPassword = userPassword; | ||
if (a == "encrypt") | ||
{ | ||
Program.Encrypt(cryptoOperation, outputFile); | ||
return; | ||
} | ||
if (!(a == "decrypt")) | ||
{ | ||
Console.WriteLine("Incorrect mode"); | ||
Console.WriteLine("Use encrypt or decrypt"); | ||
return; | ||
} | ||
Program.Decrypt(cryptoOperation, outputFile); | ||
} | ||
mode 인자값에 따라 암호화 복호화가 가능하며, 주어진 CrackMe.txt파일을 복호화하는게 이번 문제에 핵심으로 보인다. | ||
|
||
.. code-block:: c# | ||
// CrackMe.CryptoOperation | ||
public byte[] DecryptFile() | ||
{ | ||
byte[] result = null; | ||
using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider()) | ||
{ | ||
aesCryptoServiceProvider.Key = this.UserKey; | ||
aesCryptoServiceProvider.IV = this.IV; | ||
try | ||
{ | ||
ICryptoTransform transform = aesCryptoServiceProvider.CreateDecryptor(aesCryptoServiceProvider.Key, aesCryptoServiceProvider.IV); | ||
FileInfo fileInfo = new FileInfo(this.FileName); | ||
using (MemoryStream memoryStream = new MemoryStream(this.ProcessingBytes)) | ||
{ | ||
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Read)) | ||
{ | ||
using (BinaryReader binaryReader = new BinaryReader(cryptoStream)) | ||
{ | ||
result = binaryReader.ReadBytes((int)fileInfo.Length); | ||
} | ||
} | ||
} | ||
} | ||
catch | ||
{ | ||
Console.WriteLine("Failed to decrypt file {0}: wrong password.", this.FileName); | ||
} | ||
} | ||
return result; | ||
} | ||
aes로 암복호화를 하고 있으며, Userkey값을 키값으로 쓰고 있다. | ||
UserKey값은 3번째 인자값을 다음과 같이 변행하여 적용한다. | ||
|
||
.. code-block:: c# | ||
// CrackMe.CryptoOperation | ||
public string UserPassword | ||
{ | ||
set | ||
{ | ||
this.KeyLength = 16; | ||
byte[] userKey = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(value)); | ||
this.UserKey = this.CombineKeys(userKey); | ||
} | ||
} | ||
// CrackMe.CryptoOperation | ||
private byte[] CombineKeys(byte[] UserKey) | ||
{ | ||
AppSettings appSettings = new AppSettings(); | ||
byte[] expr_16 = Encoding.UTF8.GetBytes(appSettings.DefaultKey); | ||
long num = BitConverter.ToInt64(expr_16, 0); | ||
long num2 = BitConverter.ToInt64(expr_16, 8); | ||
long num3 = BitConverter.ToInt64(UserKey, 0); | ||
long num4 = BitConverter.ToInt64(UserKey, 8); | ||
long num5 = num ^ num3; | ||
long num6 = num2 ^ num4; | ||
long num7 = (~num & num3) | (~num3 & num); | ||
long num8 = (~num2 & num4) | (~num4 & num2); | ||
int num9 = BitConverter.ToInt32(BitConverter.GetBytes(num5), 0); | ||
int num10 = BitConverter.ToInt32(BitConverter.GetBytes(num5), 4); | ||
int num11 = BitConverter.ToInt32(BitConverter.GetBytes(num6), 0); | ||
int num12 = BitConverter.ToInt32(BitConverter.GetBytes(num6), 4); | ||
num9 >>= 2; | ||
num10 >>= 2; | ||
num9 <<= 1; | ||
num10 <<= 1; | ||
num12 = num9 << 1; | ||
num11 >>= 2; | ||
num11 = num9 << 1; | ||
num12 >>= 2; | ||
if (~(num9 & num12) == (~num9 | ~num12)) | ||
{ | ||
num11 = num10; | ||
if (~(num9 & num12) == (~num9 | ~num12)) | ||
{ | ||
num10 = num12; | ||
} | ||
else | ||
{ | ||
num12 = num10; | ||
} | ||
num9 = ~num12; | ||
} | ||
else | ||
{ | ||
num11 = num9; | ||
if (~(~num7) == num5 && ~(~num8) == num6) | ||
{ | ||
num10 = num12; | ||
} | ||
else | ||
{ | ||
num12 = num10; | ||
} | ||
num9 = ~num10; | ||
} | ||
num9 = ~num9; | ||
byte[] bytes = BitConverter.GetBytes(num9); | ||
byte[] bytes2 = BitConverter.GetBytes(num10); | ||
byte[] bytes3 = BitConverter.GetBytes(num11); | ||
byte[] bytes4 = BitConverter.GetBytes(num12); | ||
byte[] array = new byte[16]; | ||
for (int i = 0; i < 4; i++) | ||
{ | ||
array[i] = bytes[i]; | ||
array[i + 4] = bytes2[i]; | ||
array[i + 8] = bytes3[i]; | ||
array[i + 12] = bytes4[i]; | ||
} | ||
return array; | ||
} | ||
위 코드는 보기엔 복잡한 계산식이지만 트릭이 있다. | ||
계산식 중 "num ^ num3"은 "~num & num3) | (~num3 & num)"과 같으며, "num2 ^ num4"도 역시 "(~num2 & num4) | (~num4 & num2)"과 같다. | ||
그리고 if 조건문이 존재하는데 "(~(num9 & num12) == (~num9 | ~num12))"은 어떤 값이든 항상 참으로 else 문이 필요없다. | ||
그리고 if 조건문 안에 추가 if 조건문이 존재하는데 "(~(num9 & num12) == (~num9 | ~num12))"은 어떤 값이든 항상 거짓으로 else문으로 가게된다. | ||
해당 내용에 맞게 위 코드는 다음과 같이 정리할 수 있다. | ||
|
||
|
||
.. code-block:: c# | ||
// CrackMe.CryptoOperation | ||
private byte[] CombineKeys(byte[] UserKey) | ||
{ | ||
AppSettings appSettings = new AppSettings(); | ||
byte[] expr_16 = Encoding.UTF8.GetBytes(appSettings.DefaultKey); | ||
long num = BitConverter.ToInt64(expr_16, 0); | ||
long num2 = BitConverter.ToInt64(expr_16, 8); | ||
long num3 = BitConverter.ToInt64(UserKey, 0); | ||
long num4 = BitConverter.ToInt64(UserKey, 8); | ||
long num5 = num ^ num3; | ||
long num6 = num2 ^ num4; | ||
long num7 = num ^ num3; | ||
long num8 = num2 ^ num4; | ||
int num9 = BitConverter.ToInt32(BitConverter.GetBytes(num5), 0); | ||
int num10 = BitConverter.ToInt32(BitConverter.GetBytes(num5), 4); | ||
int num11 = BitConverter.ToInt32(BitConverter.GetBytes(num6), 0); | ||
int num12 = BitConverter.ToInt32(BitConverter.GetBytes(num6), 4); | ||
num9 >>= 2; | ||
num10 >>= 2; | ||
num9 <<= 1; | ||
num10 <<= 1; | ||
num12 = num9 << 1; | ||
num11 >>= 2; | ||
num11 = num9 << 1; | ||
num12 >>= 2; | ||
num11 = num10; | ||
num12 = num10; | ||
num9 = ~num12; | ||
num9 = ~num9; | ||
byte[] bytes = BitConverter.GetBytes(num9); # num9 = num12 | ||
byte[] bytes2 = BitConverter.GetBytes(num10); # num10 = (BitConverter.ToInt32(BitConverter.GetBytes(BitConverter.ToInt64(expr_16, 0) ^ BitConverter.ToInt64(UserKey, 0)), 4)>>2) << 1 | ||
byte[] bytes3 = BitConverter.GetBytes(num11); # num11 = num10 | ||
byte[] bytes4 = BitConverter.GetBytes(num12); # num12 = num10 | ||
byte[] array = new byte[16]; | ||
for (int i = 0; i < 4; i++) | ||
{ | ||
array[i] = bytes[i]; | ||
array[i + 4] = bytes2[i]; | ||
array[i + 8] = bytes3[i]; | ||
array[i + 12] = bytes4[i]; | ||
} | ||
return array; | ||
} | ||
결국 리턴값 array에 들어갈 값은 4바이트가 연속되는 값들이 들어가게 된다. | ||
|
||
.. code-block:: text | ||
ex> | ||
31323334 31323334 31323334 31323334 | ||
41424344 41424344 41424344 41424344 | ||
해당 키값을 획득하기 위해 브루트포싱 진행 | ||
- 오른쪽으로 2번 시프트 연산 왼쪽으로 1번 시프트 연산 | ||
- 오른쪽 1bit는 0 | ||
- 왼쪽 1bit는 0 | ||
|
||
.. code-block:: python | ||
from Crypto.Cipher import AES | ||
import struct | ||
f = open("CrackMe.txt","rb") | ||
data = f.read() | ||
f.close() | ||
iv = data[:16] | ||
data = data[16:] | ||
for i in range(0x10000000,0x80000000,2): | ||
key = struct.pack('>I',i) | ||
aes = AES.new(key*4, AES.MODE_CBC, iv) | ||
dec = aes.decrypt(data) | ||
if "Volga" in str(dec): | ||
print(key) | ||
print(dec) | ||
break |
68 changes: 68 additions & 0 deletions
68
docs/reversing/windows/[2018_Xiomara] [REV] Fortune Jack.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
===================================================================== | ||
[2018_Xiomara] [REV] Fortune Jack | ||
===================================================================== | ||
|
||
문제 내용 | ||
===================================================================== | ||
|
||
If your smartphone gets connected to a VPN, you feel like you won a lucky draw. | ||
|
||
Lucky_Drawer.exe | ||
|
||
문제 풀이 | ||
===================================================================== | ||
|
||
실행 시 로또같은 화면이 나오며, Generate 버튼 클릭 시 가운데 숫자가 변경되며 "Sorry You are Not So Lucky :( OH!" 메시지 출력 | ||
ilspy로 디컴파일한 뒤, 출력되는 문자열을 검색하면 다음 코드 부분을 확인할 수 있음. | ||
|
||
.. code-block:: c# | ||
// XiomaraChallenge.Form1 | ||
private void checkflag(int key) | ||
{ | ||
StringBuilder stringBuilder = new StringBuilder(); | ||
string str = "xiomara{"; | ||
string text = "þæþÖîûìèýÖðæüÖíàíÖàýÖ³\u00a0"; | ||
string str2 = "}"; | ||
string text2 = "DB2C17E69713C8604A91AA7A51CBA041"; | ||
for (int i = 0; i < text.Length; i++) | ||
{ | ||
stringBuilder.Append((char)((int)text[i] ^ key)); | ||
} | ||
string text3 = stringBuilder.ToString(); | ||
string text4 = Form1.CreateMD5(text3); | ||
bool flag = text4.Equals(text2); | ||
if (flag) | ||
{ | ||
this.label3.Text = str + text3 + str2; | ||
this.label3.Visible = true; | ||
} | ||
bool flag2 = text4 != text2; | ||
if (flag2) | ||
{ | ||
this.label3.Text = "Sorry You are Not So Lucky :( OH!"; | ||
this.label3.Visible = true; | ||
} | ||
} | ||
- 해당 문자열이 출력되지 않으려면 flag2가 false여야 함 | ||
- flag2가 false가 되기 위해서는 text4와 text2가 같아야 함. | ||
- text4와 text2가 같기 위해서는 stringBuilder값을 md5한 값이 "DB2C17E69713C8604A91AA7A51CBA041"와 같아야 함. | ||
- md5값을 확인하기 위해서는 임의값 입력을 통한 브루트포싱을 진행 | ||
|
||
.. code-block:: python | ||
#-*- coding: utf-8 -*- | ||
from hashlib import md5 | ||
arr = u"þæþÖîûìèýÖðæüÖíàíÖàýÖ³\u00a0" | ||
md5hash = "db2c17e69713c8604a91aa7a51cba041" | ||
for key in range(256): | ||
flag = '' | ||
for b in arr: | ||
flag += chr(key ^ ord(b)) | ||
if md5hash == md5(flag.decode("utf-8","ignore").encode('utf-8')).hexdigest(): | ||
print("xiomara{" + flag + "}") | ||
30 changes: 30 additions & 0 deletions
30
docs/reversing/windows/[2018_sharifctf 8] [REV] crack me.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
===================================================================== | ||
[2018_SharifCTF 8] [REV] Crack me! | ||
===================================================================== | ||
|
||
문제 내용 | ||
===================================================================== | ||
|
||
Find the password. | ||
|
||
|
||
동작 화면 | ||
===================================================================== | ||
|
||
```sh | ||
$ ./crackme | ||
Enter Password: | ||
aaaaaa | ||
Try again | ||
``` | ||
|
||
문제 풀이 | ||
===================================================================== | ||
|
||
- 패스워드 값이 참이 아닐 경우, "Try again" 메시지 출력. 해당 출력이 발생되는 함수 부분을 디버깅을 통해 확인: sub_402140에서 해당 메시지가 출력됨 | ||
- sub_402140이 받는 인자값 확인: v53 | ||
- sub_401e70에서 v53값이 저장됨 (-1|0) | ||
- -1일 경우 "Try again" | ||
- 0일 경우 "Correct:Flag is MD5 Of Password" | ||
- 0이 출력되기 위해서는 Dst값이 whynxt과 일치해야함. Dst값은 입력값이 암호화된 값 | ||
|