[C#, webhacking.kr] Challenge 4번 풀기
카테고리: C# + Unity
문제 상황
일반적인 webhacking.kr의 문제는 preg_match 회피 및 sql injection이 주를 이루지만 challege 4는 기존의 문제들과는 양상이 다르다.
아래는 challenge 4의 소스코드 중 일부이다.
<?php
sleep(1); // anti brute force
if((isset($_SESSION['chall4'])) && ($_POST['key'] == $_SESSION['chall4'])) solve(4);
$hash = rand(10000000,99999999)."salt_for_you";
$_SESSION['chall4'] = $hash;
for($i=0;$i<500;$i++) $hash = sha1($hash);
?>
해석하자면 10000000부터 99999999 사이의 랜덤한 숫자 하나를 골라 salt_for_you라는 단어를 salt로 사용하여 뒷 부분에 합친다.
이후, 해당 값을 chall4라는 이름의 세션에 담고 500번 sha1 해싱을 진행한다.
문제 해결
결론적으로, 문제를 해결하려면 출력된 hash 값을 보고 원래의 문자열을 알아 맞춰야하는 역해싱 문제이다.
해결하는 방법은 여러가지가 있겠지만 귀찮아서 10000000부터 20000000 사이의 값을 미리 생성한 후 비교하고 해당하는 값이 없으면 새로고침을 반복하는 방법으로 해결하려고 아래와 같은 소스 코드를 작성하였다.
소스 코드
using System.Collections.Concurrent;
using System.Security.Cryptography;
using System.Text;
class Program {
static void Main(string[] args) {
ConcurrentDictionary<string, string> table = new();
string a = "14fd9c9a0b261412f27628d7430a743e82dd63e8";
object sync = new();
CancellationTokenSource cts = new();
ParallelOptions parallelOptions = new() {
MaxDegreeOfParallelism = Environment.ProcessorCount,
CancellationToken = cts.Token
};
try {
Parallel.For(10000000, 20000000, parallelOptions, (i, loopState) => {
string pw = i.ToString() + "salt_for_you";
for (int j = 0; j < 500; j++) {
pw = ComputeSHA1Hash(pw);
}
table.TryAdd(i.ToString(), pw);
if (pw == a) {
lock (sync) {
Console.WriteLine("Find : " + i + "salt_for_you");
}
cts.Cancel();
loopState.Stop();
}
});
} catch (OperationCanceledException) {
Console.WriteLine("Operation canceled.");
} finally {
cts.Dispose();
}
StringBuilder sb = new();
foreach (KeyValuePair<string, string> kvp in table) {
sb.AppendLine(string.Format("{0} {1}", kvp.Key, kvp.Value));
}
SaveFile("./dictionary.txt", sb.ToString());
}
static string ComputeSHA1Hash(string input) {
byte[] inputBytes = Encoding.ASCII.GetBytes(input);
byte[] hashBytes = SHA1.HashData(inputBytes);
StringBuilder sb = new();
for (int i = 0; i < hashBytes.Length; i++) {
sb.Append(hashBytes[i].ToString("x2"));
}
return sb.ToString();
}
public static void SaveFile(string filePath, string content) {
try {
using StreamWriter sw = new(filePath);
sw.Write(content);
} catch (Exception ex) {
Console.WriteLine("Error: " + ex.Message);
}
}
}
해설
빠른 SHA1 해시 데이터 생성을 위해 Parallel.For과 동시성 제어를 위한 Concurrent Class를 사용한 것 빼면 challenge 4의 소스코드를 C#(.Net 6)으로 재작성한 것 뿐이다.
약 한시간 가량에 걸쳐서 1000만개의 역해시 데이터를 생성한 후 저장하였고, 몇 번 새로고침하여 해시 값을 비교한 결과 해당 문제를 해결할 수 있었다.
데이터 파일 : https://drive.google.com/file/d/1K8fEuBFnbBNnE3-MSjJ0iPzzGrIHiK3F/view?usp=sharing
더 읽어보기
https://learn.microsoft.com/ko-kr/dotnet/api/system.threading.tasks.parallel.for?view=net-8.0
https://syudal.github.io/post/C-생산자-소비자-문제에-사용-가능한-Concurrent-Class-사용하기/