Dohot

Tiếp tục là một task rev nhỏ của a mochi, lần này thời gian ít hơn nên mình nghĩ nó cũng không khó.

Điều quen thuộc đầu tiên của mình về task lần này là file size khá giống lần trước, khả năng cao lại là dotnet embedded.

Lần này là 1 file elf và vẫn là flag checker:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Dotnet Embedded nên lần này mình vẫn dùng dotpeek để extract toàn bộ source ra:
Tuy nhiên vì dotpeek không hỗ trợ elf nên không thể load trực tiếp vào được. Nhưng mà có 1 trick nhỏ là mình chỉ cần đổi đuôi elf thành .exe thì sẽ được. Vẫn sẽ dump được bình thường:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Okay đây là hàm main, mọi thứ trông khá là dễ dàng, chỉ cần brute từng cặp kí tự từ cuối flag trở đi là sẽ được

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Cho tới khi các bạn nhận ra không có kí tự nào phù hợp cả => chương trình rõ ràng còn vấn đề. Không thể dễ dàng lấy flag như vậy được.

Mình extract file sample1.dll ra và dùng dnspy, tiện cho việc đọc code và modified hơn:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

<Module> có một class C khá là sus, qua quá trình rev nhanh thì mình biết được nó đang cố gắng modified thứ gì đó trong lúc thực thi (runtime).

Một vấn đề nho nhỏ ở bài này là class String cũng có built-in GetHashCode, do đó trên hàm GetHashCode mà mọi người thấy có chút đặc biệt:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Bên trái là tên hàm mình copy, bên phải là mình tự gõ.Cơ bản là vì chữ 'a' trong tên hàm nó là unicode. Trong bài này thì nó hơi xàm nhưng mà thoi, coi như có thêm 1 cái thú vị để biết thêm:vvv

Quay trở lại với self-modified mình đã thử 1 số cách như sau:

  • Cố gắng dùng IDA và attach to process để trace từng hàm cho tới khi gặp được hàm check và modified
  • Dự đoán xem nó sẽ modified cái gì và cố gắn tìm ra cái đó sau khi modified
  • Mình chỉnh sample1.dll để nó log ra nhiều thứ quan trọng và tìm flag.

Okay mình đã thử hết tất cả và mất nhiều thời gian, cho tới khi mình làm cách cuối cùng.

Thứ nhất, nếu các bạn sử dụng hàm built-in GetHashCode thì các bạn sẽ biết nó dùng default seed, nên mọi thứ khá là random. Nên tác giả đã viết ra 1 hàm mới kèm 1 hằng số cố định là MERSENNE. Tới đây mình nghĩ ngay tới, thứ duy nhất mà chương trình có thể modified trong bài này để khiến cho nó dễ hơn chính là hằng số này:

Theo hướng phân tích này, mình đã làm như sau:

Flag check length == 74, đồng nghĩa kí tự cuối của flag chắc chắn lằ "}", mình chỉ cần brute kí tự kế cuối và brute 2**32 lần để tìm ra được MERSENNE chính xác, với cách này mình đã code như sau(c#):


public static int GetHashCode1(byte j, int MERSENNE1)
{
    int num1 = 352654597;
    int num2 = num1;
    byte[] str = { j, 125 };
    for (int index = 0; index < str.Length; index += 2)
    {
        num1 = (num1 << 5) + num1 ^ (int)str[index];
        if (index != str.Length - 1)
            num2 = (num2 << 5) + num2 ^ (int)str[index + 1];
        else
            break;
    }
    return num1 + num2 * MERSENNE1;
}
    
public static void Brute2(){
    for (int _const = int.MinValue; _const <= int.MaxValue; _const++){
        for (byte b = 0x20; b < 0x7f; b++){
            if (GetHаshCode1(b, _const) == 1049599002){
                Console.WriteLine("Found: " + _const + "  " + (char)b);
                //return;
            }
        }
    }
    Console.WriteLine('Done');
}

Tuy nhiên nó cho mình rất nhiều kết quả:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Tới đây thì mình có thể thử từng giá trị tìm được để recover flag, tuy nhiên mình thấy nó lặp lại như thế nên mình nghĩ rằng chỉ cần thử 1 phần, không cần thử hết =)))

Và rồi mình ko tìm được flag.

Cho tơi khi mình nghĩ ra một cách khác là:

  • Edit function trong dll và patch lại vào elf, sau đó chạy để log một vài thứ quan trọng ra

Đầu tiên là mình đã patch để cho nó in ra text, thứ mà nó sẽ bắt đầu modified:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

added line:

Console.WriteLine(text);

Và mình nhận được kết quả: "sample1.deps.json"
Okay, lúc này mình bị lú nên mình log nhiều thứ, cho tới khi nó bị lỗi stack vì log quá nhiều, lúc này mình mới chợt nhớ ra sao không print cái hằng số kia ra luôn nhỉ?

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Và rồi có hằng số, mình thử tìm flag và bum:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

By the way, mình có một số script để làm 1 và việc cụ thể trong task này:

Muốn edit function/class thì chỉ cần edit trong dnspy, sau đó save module và chạy script này sẽ có modified.

with open('dothot','rb') as f:
    d = f.read()
with open('sample1.dll','rb') as f:
    dll = f.read()
print(hex(d.index(dll[-400:])+400))
new_dohot = d[:0xa4a660] + dll.ljust(7680,b'\x00') + d[0xa4c460:]
with open('dothot_modded','wb') as f:
    f.write(new_dohot)

Đây là full code tìm flag ở c#:

using System;
using System.Security.Cryptography;


#nullable enable
namespace HackTM
{
    public static class Program
    {
        public static int MERSENNE = 1566083941;
        //public static int MERSENNE_recovered = -2144631796; _
        public static int MERSENNE_recovered = -889275714; //7
        public static string m = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!_{}";
        public static int GetHаshCode(this string str)
        {
            int num1 = 352654597;
            int num2 = num1;
            for (int index = 0; index < str.Length; index += 2)
            {
                num1 = (num1 << 5) + num1 ^ (int)str[index];
                if (index != str.Length - 1)
                    num2 = (num2 << 5) + num2 ^ (int)str[index + 1];
                else
                    break;
            }
            return num1 + num2 * Program.MERSENNE_recovered;
        }
        public static int GetHаshCode1(byte j, int MERSENNE1)
        {
            int num1 = 352654597;
            int num2 = num1;
            byte[] str = { j, 125 };
            for (int index = 0; index < str.Length; index += 2)
            {
                num1 = (num1 << 5) + num1 ^ (int)str[index];
                if (index != str.Length - 1)
                    num2 = (num2 << 5) + num2 ^ (int)str[index + 1];
                else
                    break;
            }
            return num1 + num2 * MERSENNE1;
        }
        public static void Brute()
        {
            string str = "";
            int[] hashcodes = { -2104661303, 1378022687, 184432526, 624792136, 1970426703, 577351341, -449824532, -2106988298, -1626288950, 678475525, 370460347, 1572244394, -1400819104, -1197305264, 2075645699, -709513774, 2010057725, 1173219516, -1870221406, -190290901, 958902434, 975549771, -1503425085, -1927839566, 54511062, 1658296083, 572463218, 1782994933, 419683795, -1426808306, 1024406933, -1553229066, -753021734, -848431867, -1957265642, 658742975, 1049599002 };
            for (int i = hashcodes.Length - 1; i >= 0; i--)
            {
                bool Found = false;
                for (int j = 0; j < m.Length; j++)
                {
                    for (int k = 0; k < m.Length; k++)
                    {
                        string tmp = m[j] + "" + m[k] + "" + str;
                        //Console.WriteLine(tmp + " " + tmp.Length + " " + GetHаshCode(tmp) + " " + hashcodes[i]);
                        //return;
                        if (GetHаshCode(tmp) == hashcodes[i])
                        {
                            Found = true;
                            str = tmp;
                            Console.WriteLine(str);
                        }
                    }
                }
                if (!Found)
                {
                    Console.WriteLine("not");
                    return;
                }
            }
        }
        public static void Brute2(){
            for (int _const = int.MinValue; _const <= int.MaxValue; _const++){
                for (byte b = 0x20; b < 0x7f; b++){
                    if (GetHаshCode1(b, _const) == 1049599002){
                        Console.WriteLine("Found: " + _const + "  " + (char)b);
                        //return;
                    }
                }
            }
            Console.WriteLine("Done");
        }
        public static void Main(string[] args)
        {
            //Brute();
            Brute();

            return;

        }
        public static bool Check(string flag)
        {
            if (flag.Length != 74)
                return false;
            string[] strArray = "-2104661303,1378022687,184432526,624792136,1970426703,577351341,-449824532,-2106988298,-1626288950,678475525,370460347,1572244394,-1400819104,-1197305264,2075645699,-709513774,2010057725,1173219516,-1870221406,-190290901,958902434,975549771,-1503425085,-1927839566,54511062,1658296083,572463218,1782994933,419683795,-1426808306,1024406933,-1553229066,-753021734,-848431867,-1957265642,658742975,1049599002".Split(",", (StringSplitOptions)0);
            int num = 0;
            for (int index = 0; index < flag.Length; index += 2)
                num += string.Equals(flag.Substring(index).GetHashCode().ToString(), strArray[index / 2]) ? 1 : 0;
            return num == strArray.Length;
        }
    }
}

Ban đầu mình làm bằng C tuy nhiên lúc không ra flag mình tưởng do mình code sai nên qua C# và nó cũng vậy, sau đó mới rev và biết được nó self-modified:V

Cảm ơn a Mochi vì 1 bài rev hay và nhiều thứ thú vị.