Yet another pyjail (Quals PHDays IV) [Writeup]

Вообще сам сервис является реализацией sandbox’a.
Сандбокс позволяет выполнять любой код с некоторыми ограничениями:

  • Доступный набор символов:
    alphabet = ' \n\r0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ(),.:;<=>[]_{}'
  • Ограничение globals. А именно, доступно к использованию только (True, False, type, int).
  • Фильтрация по ключевым словам из набора: (__, import, globals, locals, exec, eval, join, format, replace, translate, try, except, with, content, frame, back)

Помимо этого в области видимости доступна функция div(), возвращающая  другую функцию.
Задача сводится к тому, что необходимо передать два параметра в эти функции, так, чтобы выражение int(v1) / int(v2) == EXPECTED, где EXPECTED=13.37, являлось истинной. Проблема в том что в python < 3 результатом деления двух int переменных, является int.

Первое, что приходит в голову, это переопределить int() увы сходу мне это результатов не дало, как оказывается такой вариант решения тоже существует, но помимо этого необходимо было переопределять операцию деления.

Но мы пошли другим путем, пытаясь посмотреть что из полей у нас доступно в объекте функции div.
«Приватные» поля мы использовать не можем, благодаря фильтру на «__» остаётся только:
func_code, func_defaults, func_doc, func_globals, func_closure.
func_globals мы использовать тоже не можем. func_code.co_code is read only. Теоретически можно было создать новый инстанс CodeObject, с помощью type(), c необходимым нам кодом и подсунуть его в функцию div. Но это проверить не удалось.
Нам доступен аттрибут func_closure, в котором хранятся cell objects, ссылки на переменные, текущего уровня стека.
Просмотрев список, использовав немного магии:

def get_cell_value(cell):
    return type(lambda: 0)(
        (lambda x: lambda: x)(0).func_code, {}, None, None, (cell,)
    )()

for cell in div(1).func_closure:
print get_cell_value(cell)

Вывод:

You are lucky!
Try again!
0
0
0
0
0
0
0
0
1
function we_must_be_sure_flag_part2_is_ready at 0x7f9358cb8de8

мы можем заметить что среди этого списка есть функция we_must_be_sure_flag_part2_is_ready копирующая вторую часть ключа. Нам остаётся её только вызвать:

part2=get_cell_value(div(1).func_closure[11])
part2()

После чего ключ скопируется полностью, и сервис пройдя проверку:

try:
    assert FLAG != part1_of_flag
    print FLAG
except:
    print '********************'

покажет его нам.

Leave a Comment

Your email address will not be published.

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.