habrahabr

Fucky new year!

  • четверг, 1 января 2015 г. в 02:10:56
http://habrahabr.ru/post/247161/

Простите за мат в заголовке, это намёк на развлечение, начало которому дал язык «Брейнфак» — написать на каком-либо языке код, выполняющий что-то разумное, не используя букв и цифр. Мы уже видели JSFuck, PHPFuck, теперь я вам хочу представить Bashfuck:

__=${_##*/};____=<(:);___=${__#???};_____=$((${#___}<<${#___}))
__=${__::-${#___}}${____:$_____:${#___}}
__=$__$((${#__}|$_____))$((${#__}));___=$___${__:${#___}:${#___}};____=$($__<<<$_____|$__)
_____=${____:$((${#__}-${#___})):${#?}};___=$___$_____$_____;____=$($__<<<$____|$__|$__)
___=$___${____:$((${#?}+${#__})):${#?}};___=$___' '${____:$((${#___}+${#___})):${#?}}
___=$___${__:$((${#____}/${#___}-${#?})):${#?}};___=$___${____:$((${#____}#$_____-${#___})):${#?}}
___=$___\ ${____:$((${#__}+${#?})):${#?}}${__:$((${#__}>>${#?})):${#?}}${__:${#_____}:${#?}}
___=$___${____:$((${#___}-${#?}-${#?})):${#?}};___=${___,,}
____=${____:$((${#___}+${#__}-${#?})):$((${#?}+${#?}))}
____=${____::${#?}}${__:${#_____}:${#?}}${____:${#?}};${____,,}<<<${___^}

Для запуска потребуется «Баш» четвёртой версии. Ничего вредоносного скрипт не делает смело запускайте из-под «рута», просто выведет надпись «Happy new year». Исходник надо скопировать в файл и запустить.

Теперь немного о принципе работы.

«Баш», к счастью, богат на разнообразные закорюки, но имена переменных, в условиях наших ограничений, могут состоять только из разного количество символов подчёркивания, их хорошо видно в коде — в них я собираю нужные последовательности букв. Откуда же берутся сами буквы?

О, тут мне пришлось поломать голову!

Чтобы начать получать буквы в промышленных количествах, мне сначала нужно получить в какой-то переменной имя команды base64 — передавая ей на вход всякий бред, можно получить на выходе весь алфавит.

Первые три буквы я взял из имени командного интерпретатора («bash», благо путь к нему передаётся на входе в переменной «$_»), а четвёртую — из имени специального файла, который используется, если некая программа не умеет принимать данные на стандартный вход. Имя файла всегда начинается с «/dev/fd», отсюда и берётся недостающая «e».

Цифры получить проще.

Во-первых, «баш» (как и многие шеллы) позволяет измерить длину переменной через конструкцию «${#имя}» (например, получить единицу проще простого — это просто длина значения переменной кода возврата предыдущей команды, так как у меня это значение всегда ноль, её длина всегда один).

Во-вторых, конструкция $((…)) позволяет делать вычисления, комбинируя длины разных переменных с операциями, я получаю недостающие цифры. Операций много, что даёт довольно большую свободу, из экзотики мне пришлось один раз применить операцию смены системы исчисления — решётку.

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

Ближе к концу пригождаются новые операции с переменными в четвёртом «баше» — там теперь можно менять регистр буквы, без этого пришлось бы куда тяжелее.

Так в конце получается команда «cat<<<'Happy new year'», которую я и запускаю. Почему не «echo» или «printf»? Они просто длиннее — каждая лишняя буква это морока с переменными и операциями.

Happy new year!