--- tags: writeup, rev, ctfzone2021 --- # **Write-up Invalid Machine (CTFZone 2021)** > [name=User1] > [time=Tue, Jun 29, 2021 3:00 AM] ![](https://i.imgur.com/UqqFsm1.png) > [color=#1cefda]Этот райтап спонсирован каналом [@ch4nnel1](https://t.me/ch4nnel1) Original write-up: [https://hackmd.io/@osogi/Invalid-Machine](https://hackmd.io/@osogi/Invalid-Machine) ## Разбор + история ![](https://i.imgur.com/jKqumbe.png) <p style="text-align: center;">Сам таск (https://ctf.bi.zone/challenges/9)</p> Ну как обычно запустим [бинарник](https://ctf.bi.zone/files/invalid_machine.3f0e596d7cfe4822e25ca80c96cb8c30) ![](https://i.imgur.com/9yu4b1n.png) Он скажет, что какая-то машина, скорее всего наш комп, невалидна. Откроем его в радаре, любым удобным способом выйдем на "главную" функцию `fcn_00001ce1` обзавем ее `Main` (так как main занят), там происходит примерно следующее. ```python=1 def Main: start_arr=[0x8c, 0x2a ... 0xf5, 0x0f] #[rbp - 0x90]...[rbp - 0x11] #len(start_arr)==0x80 buf_arr=[0]*0x80 #[rbp - 0x110]...[rbp - 0x91] hashid=[0]*0x20 #[rbp-0x140]-[rbp-0x121] leng=0x80 #[rbp - 0x144] if(!fcn_0000179e(hashid)): return 0 if(!fcn_00001c23(hashid)): return 0 buf_arr=start_arr.copy() #Какая-то магия с buf_arr и hashid #В результате которой buf_arr меняется start_arr=buf_arr.copy() if(!fcn_00001a15(start_arr, leng)): print("Invalid machine...") return 0 print("Good job") for c in start_arr[0x40:leng]: print(chr(c), end='') print() return 1 ``` Рассмотрим функцию `fcn_0000179e` (я ее сильно упростил, там были еще проверки на успешное завершение функций, но функции могли завершиться некорректно только из-за сбоя в системе) ```python=1 def fcn_0000179e(a): integer=0 s=read_machine_id(32) #fcn_00001326 # read_machine_id(n) - выделить в памяти n+1 байт, # прочитать в них n байт из "/etc/machine-id", # вернуть указатель на них hex_to_int(s, integer) #fcn_00001246 # hex_to_int(a, b) == b=int(a[:8], 16) hashid = sha256(integer, 4) #fcn_000011e5. Определяем, что это sha256 по константам в глубине этой функции # sha256(arg, ln) arg-то от чего считается хеш, ln-размер arg в байтах #Тут, снова криптографическая магия, но в этот раз с hashid a=hashid return 0 ``` Получается `fcn_0000179e` вернет в `Main` некий преобразованный хеш от 4 байт, представленных в `/etc/machine-id`, и запишет его в `hashid` Рассмотрим `Main` дальше, в функции `fcn_00001c23` происходит просто проверка на то, что `hashid` состоит не полностью из нулей. А вот `fcn_00001a15` будет чуть интереснее (псевдокод как и в прошлый раз приведен без 'системных' проверок) ```python=1 def fcn_00001a15(arr, leng): first=arr[0:0x40].copy() second=arr[0x40:leng].copy() buf=sha256(second, leng-0x40) hexstr=to_hexstr(buf, 32) #fcn_000018e8 #to_hexstr(arg, ln) == hex(buf) при этом sizeof(buf)==ln return (hexstr==str(first)) ``` Посмотрев на все эти функции и куски кода с криптографической магией. Мне показалось, что самым верным и быстрым способом решения будет сбрутить `integer` из `fcn_0000179e`, так как `hex_to_int` возвращает только 4 байта и прога использует `integer`, как 4 байтную переменную. Хоть 4 байта и можно сбрутить, но это будет не слишком быстро, так что нужно это максимально оптимизировать, и способ из разряда, менять `/etc/machine-id`, запускать бинарь и смотреть на его вывод, точно не будет достаточно быстрым. В результате мной было решено запатчить бинарь, патч в псевдокоде должен был выглядеть примерно так ```python=1 def Main: while True: start_arr=[0x8c, 0x2a ... 0xf5, 0x0f] #[rbp - 0x90]...[rbp - 0x11] #len(start_arr)==0x80 buf_arr=[0]*0x80 #[rbp - 0x110]...[rbp - 0x91] hashid=[0]*0x20 #[rbp-0x140]-[rbp-0x121] leng=0x80 #[rbp - 0x144] if(!fcn_0000179e(hashid)): return 0 if(!fcn_00001c23(hashid)): return 0 buf_arr=start_arr.copy() #Какая-то магия с buf_arr и hashid #В результате которой buf_arr меняется start_arr=buf_arr.copy() if(!fcn_00001a15(start_arr, leng)): continue #patched print("Good job") for c in start_arr[0x40:leng]: print(chr(c), end='') print() return 1 def fcn_0000179e(a): integer=0 glob+=1 #patched integer=glob hashid = sha256(integer, 4) #fcn_000011e5. #Тут, снова криптографическая магия, но в этот раз с hashid a=hashid return 0 glob = 0 #patched ``` Проблемы с которыми я столкнулся: 1. Где размещать глобальную переменную? Это решилось гениальным или неочень способом, я разместил ее на месте занопленного (заполненного nop'ами) кода, но это вызвало еще другую проблему. 2. Изменить права секции и сегмента на rwx, права секции я изменил через радар, а вот разрешения сегмента пришлось менять вручную через 010editor 3. Радар/ризин часто косячут с преобразованием асм инструкций, и приходится либо исжитряться либо пользоваться другими тулзами. Я воспользовался первым способом. ![](https://i.imgur.com/e7KQ8Br.png) В результате получил примерно такой [бинарь](https://github.com/osogi/writeups/blob/main/ctfzone2021/Invalid_Machine/invalid_machine_patched.elf). Пока он стоял на бруте, я успел поделать другие таски, устал, сделал еще одну версию бинарника, которая бы перебирала результат с верху, посчитал что даже с двумя активными прогами я не успею перебрать весь отрезок, растроился, отчаился, разобрал куски кода с криптографической магией, понял, что в теории зная формат флага и начальное состояние массива можно востановить `hashid` из `Main`, а потом и весь флаг, решил воспользоваться angr'ом, для совершения этого плана. Но в моей голове пошло что-то не так и в результате вместо, поиска валидного значения `hashid` для получения правильного начала флага, я заставил angr искать `integer`, который я пытался сбрутить. Вроде мой скрипт с angr'ом даже начал работать, но у меня сложилось впечатление, что он просто начал брутить, так что я остановил две свои брут-машины (и записал значение на которых они остановились) и решил дать ему шанс поработать 10 минут, но он за отведенное время ничего не выдал => был ~~казнен~~ остановлен. Я запустил свои брут-машины снова, и каково было мое удивление, когда одна из них спустя 3 минуты выдала это ![](https://i.imgur.com/VIerfw9.png) Тип, вроде флаг, ура! Но нет, сайт говорит: "Флаг - инвалид", тут я уже растроился, что стратегия с брутом не сработала, но тут мне опять помогла моя тима ![](https://i.imgur.com/1ukyBzw.png) Оказывается верным флагом был не `ctfzone{_You_are_a_hacker_but_you_are_the_good_kind_of_hacker!_}`, а `ctfzone{You_are_a_hacker_but_you_are_the_good_kind_of_hacker!}`, ну или по крайней мере мне так сообщил тимейт. ## Решение - Разреверсить fcn_00001ce1 и fcn_0000179e - Понять, что в fcn_0000179e есть четырехбайтная переменная, которую можно сбрутить - Пропатчить файл, чтобы он сам себя брутил ([пример пропатченого файла](https://github.com/osogi/writeups/blob/main/ctfzone2021/Invalid_Machine/invalid_machine_patched.elf)) - Поставить брутить - Подождать 5 часов ([версия для нетерпеливых на 3 минуты](https://github.com/osogi/writeups/blob/main/ctfzone2021/Invalid_Machine/invalid_machine_patched_flash.elf)) - Закончить брут, попытаться сдать флаг `ctfzone{_You_are_a_hacker_but_you_are_the_good_kind_of_hacker!_}` - Понять, что в нем лишние нижние подчеркивания, сдать флаг `ctfzone{You_are_a_hacker_but_you_are_the_good_kind_of_hacker!}` ## Эпилог Хоть я и решил этот таск, но кажется авторское, правильное решение далеко не такое. Так что пожалуйста, если Вы знаете как его решить по нормальному и читаете этот райтап. Напишите свой райтап, поделитесь своими знаниями с миром, в том числе и со мной. За сим я откланиваюсь, свою миссию по райтапам для ctfzone2021 уже выполнил, и теперь свободен. ![](https://pa1.narvii.com/6456/4e3f00283ac6ae4b98a540aa78aaa768093e4413_hq.gif)