CTF/OtterCTF

OtterCTF WriteUp - Closure

geunyeong 2020. 4. 3. 18:13

멀웨어의 startAction 메서드를 보면 사용자의 바탕화면을 파일 암호화의 최초 폴더로 잡고 있다.

 

또한 encryptDirectory 메서드를 보면 암호화 할 파일들의 확장자 목록을 갖고 있다.

 

암호화 대상인 txt 파일을 먼저 찾아봤다. Rick 계정의 바탕화면에 Flag.txt가 보인다.

 

HxD로 열어보니 임의 비트열 뿐이다. 암호화 된 듯 하다. 48바이트 이후론 모두 NULL 바이트여서 제거했다.

 

멀웨어의 EncryptFile 메서드를 보면 앞서 생성했던 15자리의 암호키를 SHA256로 해시화한 후 AES_Encrypt 메서드의 암호키로 넘기는 걸 볼 수 있다.

 

public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
	byte[] result = null;
	byte[] salt = new byte[]
	{
		1,
		2,
		3,
		4,
		5,
		6,
		7,
		8
	};
	using (MemoryStream memoryStream = new MemoryStream())
	{
		using (RijndaelManaged rijndaelManaged = new RijndaelManaged())
		{
			rijndaelManaged.KeySize = 256;
			rijndaelManaged.BlockSize = 128;
			Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(passwordBytes, salt, 1000);
			rijndaelManaged.Key = rfc2898DeriveBytes.GetBytes(rijndaelManaged.KeySize / 8);
			rijndaelManaged.IV = rfc2898DeriveBytes.GetBytes(rijndaelManaged.BlockSize / 8);
			rijndaelManaged.Mode = CipherMode.CBC;
			using (CryptoStream cryptoStream = new CryptoStream(memoryStream, rijndaelManaged.CreateEncryptor(), CryptoStreamMode.Write))
			{
				cryptoStream.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
				cryptoStream.Close();
			}
			result = memoryStream.ToArray();
		}
	}
	return result;
}

AES_Encrypt 메서드를 보면 Rfc2898DeriveBytes라는 클래스를 사용하는데, MSDN에 따르면 난수를 생성해주는 클래스라고 한다. 혹시 시간에 따라 난수가 달라지나 걱정했는데 실험해본 결과 시간에 상관 없이 넘겨주는 값이 같으면 항상 같은 난수를 반환했다.

 

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace _001_OtterCTF_DecryptFlagTxt {
	class Program {
		static void Main(string[] args) {
			byte[] bytesToBeEncrypted = File.ReadAllBytes("Flag.txt");
			byte[] passwordBytes = Encoding.UTF8.GetBytes("aDOBofVYUNVnmp7");
			passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

			Program p = new Program();
			File.WriteAllBytes("dFlag.txt", p.AES_Encrypt(bytesToBeEncrypted, passwordBytes));
		}
		
		public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes) {
			byte[] result = null;
			byte[] salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8};

			using (MemoryStream memoryStream = new MemoryStream()) {
				using (RijndaelManaged rijndaelManaged = new RijndaelManaged()) { 
					rijndaelManaged.KeySize	= 256;
					rijndaelManaged.BlockSize = 128;
					Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(passwordBytes, salt, 1000);
					rijndaelManaged.Key = rfc2898DeriveBytes.GetBytes(rijndaelManaged.KeySize / 8);
					rijndaelManaged.IV = rfc2898DeriveBytes.GetBytes(rijndaelManaged.BlockSize / 8);
					rijndaelManaged.Mode = CipherMode.CBC;
					using (CryptoStream cryptoStream = new CryptoStream(memoryStream, rijndaelManaged.CreateDecryptor(), CryptoStreamMode.Write))
					{
						cryptoStream.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
						cryptoStream.Close();
					}
					result = memoryStream.ToArray();
				}
			}
			return result;
		}
	}
}

Rfc2898DeriveBytes 클래스를 사용하기 위해 C#으로 복호화 코드를 작성했다. 멀웨어의 AES_Encrypt 메서드 내용을 모두 복사한 후 rijndaelManaged.CreateEncryptor()만 CreateDecryptor로 수정했다. C#을 안해봐서 CreateDecryptor라는 메서드가 없을까봐 걱정했는데 다행히 있었다.

 

복호화된 파일을 열어보면 플래그가 들어있다.

 

CTF{Im_Th@_B3S7_RicK_0f_Th3m_4ll}