CrackMe 15.exe (in Simples) 문제풀이 동명대학교정보보호동아리 THINK www.mainthink.net 강동현 Blog: johnghb.tistory.com e-mail: cari2052@gmail.com 1
목차 : 1. 문제설명및기본분석 --------------------------- P. 03 2 상세분석 --------------------------- P. 05 2
문제설명및기본분석 Crackme 15 from Simples 사용툴 : PEiD v0.95, HashCalc.exe, IDA Pro, Visual Studio 2005 Q : 정답인증은 Password의 MD5 해쉬값 ( 대문자 ) 답 : 718070D944DE096F3A6696B077E4E2CE -------------------------------------------------------------------------------------------------------------- 먼저프로그램실행모습입니다. 그림 1 그림 1과같이 Please enter the password 라는문자열이외는아무런정보가없습니다. 또한아래줄부터사용자입력을대기하는것을보면 password입력후정상적인값과비교하도록되어있음을예측할수있습니다. 3
임의의값을넣고진행해보면아래그림 2 와같은결과를확인할수있습니다. 그림 2 잘못된입력값을넣으면 Bad Luck! Try again! 이라는문자열이나오는것을보면정상적인입력값을넣으면그와반대되는문자열이있음을예측할수있습니다. 또한컴파일정보를알아보기위해 PEiD 툴로확인해보았습니다. 그림 3 확인결과.NET 으로컴파일했음을알수있습니다. 4
상세분석 먼저 IDA Pro 를통해파일의내부를확인해봅니다. 그림 4 위그림 4는문제파일의 Main 부분의소스입니다. 그림의빨간박스를통해확인가능하며그아래내용들은각각암호화되어있는문자열인것인지를의심해보아야합니다. 또한메인함수가 RijndaeSimpleTest 클래스내부에있음을기억해둡니다. 5
좀더아래코드를확인해봅니다. 그림 5 위그림 5에서는이전암호화된문자열을복호화하여두개의문자열을비교하는것을볼수있습니다. ( 그림 5 에서의빨간줄의내용들은길이가길어서캡쳐그림에서누락된것임.) 그림의 Please enter the password 라는문자열과 Bad Luck! Try again! 문자열은이전사전조사한내용과일치하며나머지 Well Done! You cracked it! 은정상적인 password를입력시나타나는문자열임을알수있습니다. 또한그림의빨간박스 ( 첫번째 ) 위의라인은 Equality함수로비교구문임을쉽게확인할수있습니다. 그결과를통해어느위치의문자열을출력할것인지를구분되어집니다. 6
그림 5 의빨간라인의함수는 Encrypt, Decrypt 함수로함수형식은아래와같습니다. String Encrypt( String plaintext, String passphrase, String saltvalue, String hashalgorithm, int passworditerations, String initvector, int keysize ) String Decrypt( String ciphertext, String passphrase, String saltvalue, String hashalgorithm, int passworditerations, String initvector, int keysize ) 7
.NET 분석툴인 reflextor 을이용하여문제파일을불러옵니다. 그림 6 8
이전에분석해두었던 Main, Decrypt, Encrypt 함수들을볼수있습니다. 또한더블클릭을하게되면그함수의세부소스를볼수있습니다. 그림 7 그림 8 9
그림 9 그림 10 10
분석한소스들의바탕으로암호화되어있는값을복호화시켜그값을출력하도록합니다. using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Security.Cryptography; namespace Simples_Crackme15 { class Program { static void Main(string[] args) { string plaintext = ""; string ciphertext = "BnCxGiN4aJDE+qUe2yIm8Q=="; string passphrase = "^F79ejk56$\x00a3"; string saltvalue = "DHj47&*)$h"; string hashalgorithm = "MD5"; int passworditerations = 0x400; string initvector = "&!\x00a3$%^&*()cvhge!"; int keysize = 0x100; plaintext = RijndaelSimple.Decrypt(cipherText, passphrase, saltvalue, hashalgorithm, passworditerations, initvector, keysize); Console.WriteLine(String.Format("Encripted : {0}", plaintext)); } } public class RijndaelSimple { // Methods public static string Decrypt(string ciphertext, string passphrase, string saltvalue, string hashalgorithm, int passworditerations, string initvector, int keysize) { byte[] bytes = Encoding.ASCII.GetBytes(initVector); byte[] rgbsalt = Encoding.ASCII.GetBytes(saltValue); byte[] buffer = Convert.FromBase64String(cipherText); byte[] rgbkey = new PasswordDeriveBytes(passPhrase, rgbsalt, hashalgorithm, passworditerations).getbytes(keysize / 8); RijndaelManaged managed = new RijndaelManaged(); managed.mode = CipherMode.CBC; ICryptoTransform transform = managed.createdecryptor(rgbkey, bytes); MemoryStream stream = new MemoryStream(buffer); CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Read); byte[] buffer5 = new byte[buffer.length]; int count = stream2.read(buffer5, 0, buffer5.length); stream.close(); stream2.close(); return Encoding.UTF8.GetString(buffer5, 0, count); } 11
public static string Encrypt(string plaintext, string passphrase, string saltvalue, string hashalgorithm, int passworditerations, string initvector, int keysize) { byte[] bytes = Encoding.ASCII.GetBytes(initVector); byte[] rgbsalt = Encoding.ASCII.GetBytes(saltValue); byte[] buffer = Encoding.UTF8.GetBytes(plainText); byte[] rgbkey = new PasswordDeriveBytes(passPhrase, rgbsalt, hashalgorithm, passworditerations).getbytes(keysize / 8); RijndaelManaged managed = new RijndaelManaged(); managed.mode = CipherMode.CBC; ICryptoTransform transform = managed.createencryptor(rgbkey, bytes); MemoryStream stream = new MemoryStream(); CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Write); stream2.write(buffer, 0, buffer.length); stream2.flushfinalblock(); byte[] inarray = stream.toarray(); stream.close(); stream2.close(); return Convert.ToBase64String(inArray); } } } 위의소스로컴파일하여실행해보면아래그림과같은결과를얻을수있습니다. 그림 11 12
Password 값은 Leteminman 임을확인하고이문자열을 HashCalc 툴을이용하여 MD5값을얻습니다. 그림 12 문제의인증값인 718070D944DE096F3A6696B077E4E2CE 를얻을수있습니다. 13