Однажды, устав от насмешек всех остальных хакеров, он решил, наконец, взглянуть на BASH.
Его первой мыслью было: «Баш? Баш винду? Ох уж эти жестокие сценарные детишки!». Пройдя сотни онлайн-руководств,
он случайно (очевидно) нашел флаг. Следующим обновлением его статуса было «Дети со сценариями никогда не смогут получить флаг из этого защищенного паролем двоичного файла». Как он смеет называть вас и нас «сценарными детишками»?! Убейте его.

Вот файл . Для 32-битных пользователей — файл
Флаг SHA-256 полученного хэша MD-5.

Создатель: Рави Кишоре Р

Начнем с того, что откроем бинарник в GDB и проверим его дизассемблирование.

0x0000000000400943 <+0>: push rbp
 0x0000000000400944 <+1>: mov rbp,rsp
 0x0000000000400947 <+4>: sub rsp,0x30
 0x000000000040094b <+8>: mov DWORD PTR [rbp-0x24],edi
 0x000000000040094e <+11>: mov QWORD PTR [rbp-0x30],rsi
 0x0000000000400952 <+15>: mov rax,QWORD PTR fs:0x28
 0x000000000040095b <+24>: mov QWORD PTR [rbp-0x8],rax
 0x000000000040095f <+28>: xor eax,eax
 0x0000000000400961 <+30>: cmp DWORD PTR [rbp-0x24],0x1
 0x0000000000400965 <+34>: jle 0x400b47 <main+516>
 0x000000000040096b <+40>: mov rax,QWORD PTR [rbp-0x30]
 0x000000000040096f <+44>: add rax,0x8
 0x0000000000400973 <+48>: mov rax,QWORD PTR [rax]
 0x0000000000400976 <+51>: add rax,0x1
 0x000000000040097a <+55>: movzx eax,BYTE PTR [rax]
 0x000000000040097d <+58>: test al,al
 0x000000000040097f <+60>: je 0x400ad3 <main+400>
 0x0000000000400985 <+66>: mov rax,QWORD PTR [rbp-0x30]
 0x0000000000400989 <+70>: add rax,0x8
 0x000000000040098d <+74>: mov rax,QWORD PTR [rax]
 0x0000000000400990 <+77>: add rax,0x1
 0x0000000000400994 <+81>: movzx eax,BYTE PTR [rax]
---Type <return> to continue, or q <return> to quit---
 0x0000000000400997 <+84>: test al,al
 0x0000000000400999 <+86>: jne 0x400ad3 <main+400>
 0x000000000040099f <+92>: mov esi,0x400cd0
 0x00000000004009a4 <+97>: mov edi,0x602060
 0x00000000004009a9 <+102>: call 0x400730 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
 0x00000000004009ae <+107>: mov esi,0x400770
 0x00000000004009b3 <+112>: mov rdi,rax
 0x00000000004009b6 <+115>: call 0x400760 <_ZNSolsEPFRSoS_E@plt>
 0x00000000004009bb <+120>: mov esi,0x400cf0
 0x00000000004009c0 <+125>: mov edi,0x602060
 0x00000000004009c5 <+130>: call 0x400730 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
 0x00000000004009ca <+135>: mov esi,0x400770
 0x00000000004009cf <+140>: mov rdi,rax
 0x00000000004009d2 <+143>: call 0x400760 <_ZNSolsEPFRSoS_E@plt>
 0x00000000004009d7 <+148>: mov esi,0x400d15
 0x00000000004009dc <+153>: mov edi,0x602060
 0x00000000004009e1 <+158>: call 0x400730 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
 0x00000000004009e6 <+163>: mov esi,0x400770
 0x00000000004009eb <+168>: mov rdi,rax
 0x00000000004009ee <+171>: call 0x400760 <_ZNSolsEPFRSoS_E@plt>

Начнем с сохранения кадра стека и выделения 0x30 байт в стеке.

0x000000000040094b <+8>: mov DWORD PTR [rbp-0x24],edi
 0x000000000040094e <+11>: mov QWORD PTR [rbp-0x30],rsi

Мы сохраняем в стеке содержимое edi (которое устанавливается равным количеству вещей в argv при вызове main) и rsi (которое указывает на вектор аргументов).

0x0000000000400952 <+15>: mov rax,QWORD PTR fs:0x28

Я понятия не имею, что делает эта строка, если кто-то из вас знает, напишите об этом в комментариях.

0x000000000040095b <+24>: mov QWORD PTR [rbp-0x8],rax
 0x000000000040095f <+28>: xor eax,eax

Мы помещаем rax в стек и обнуляем eax. Не знаю, почему.

0x0000000000400961 <+30>: cmp DWORD PTR [rbp-0x24],0x1
0x0000000000400965 <+34>: jle 0x400b47 <main+516>

if (argc ‹ 0x1) { перейти к 0x400b47; }

0x400b47 содержит код, который печатает «Пожалуйста, введите пароль».

0x000000000040096b <+40>: mov rax,QWORD PTR [rbp-0x30]
 0x000000000040096f <+44>: add rax,0x8
 0x0000000000400973 <+48>: mov rax,QWORD PTR [rax]
 0x0000000000400976 <+51>: add rax,0x1

Идем дальше. Мы знаем, что argv — это двойной указатель. Здесь мы сохраняем *argv в rbp-0x30 и добавляем к нему 0x8. Итак, мы обращаемся к *(argv + 8) или argv[1].

Мы сохраняем указатель на this в rax и добавляем к нему 1.

rax теперь указывает на argv[1][1].

0x000000000040097a <+55>: movzx eax,BYTE PTR [rax]

Теперь он копирует значение *argv[1][1] в eax (1-байтовая копия с нулевым расширением). Eax занимает 4 байта, что означает, что он скопирует байт с *rax в eax и установит первые 3 байта eax в 0.

0x000000000040097d <+58>: test al,al
 0x000000000040097f <+60>: je 0x400ad3 <main+400>

если (al == 0) { jmp to 0x400ad3; }

Это верно только тогда, когда младшие 8 битов == 0, что означает, что для того, чтобы это было правдой, значение в *argv[1][1] должно быть больше 256 или 0. Следовательно, argv[1][1] должно быть 0 чтобы получить доступ к этому блоку,

Затем мы снова делаем то же самое упражнение (60–86) и прыгаем, если не равны. Следовательно, мы в любом случае перейдем к 0x400ad3. Теперь давайте проверим дизассемблирование 0x400ad3:

0x400ad3 <main+400>: mov BYTE PTR [rbp-0x20],0x4d
 0x400ad7 <main+404>: mov BYTE PTR [rbp-0x1f],0x61
 0x400adb <main+408>: mov BYTE PTR [rbp-0x1e],0x73
 0x400adf <main+412>: mov BYTE PTR [rbp-0x1d],0x74
 0x400ae3 <main+416>: mov BYTE PTR [rbp-0x1c],0x65
 0x400ae7 <main+420>: mov BYTE PTR [rbp-0x1b],0x72
 0x400aeb <main+424>: mov BYTE PTR [rbp-0x1a],0x6e
 0x400aef <main+428>: mov BYTE PTR [rbp-0x19],0x61
 0x400af3 <main+432>: mov BYTE PTR [rbp-0x18],0x6d
 0x400af7 <main+436>: mov BYTE PTR [rbp-0x17],0x65
 0x400afb <main+440>: mov BYTE PTR [rbp-0x16],0x72

Похоже, мы помещаем кучу байтов в стек.

0x400aff <main+444>: mov rax,QWORD PTR [rbp-0x30]
 0x400b03 <main+448>: add rax,0x8
 0x400aff <main+444>: mov rax,QWORD PTR [rbp-0x30]
 0x400b03 <main+448>: add rax,0x8
 0x400b07 <main+452>: mov rax,QWORD PTR [rax]
 0x400b0a <main+455>: lea rdx,[rbp-0x20]

Это тот же самый код, который мы видели ранее, он копирует указатель на argv[1] в rax. Затем мы загружаем адрес rbp-0x20 в rdx.

0x400b0e <main+459>: mov rsi,rdx
 0x400b11 <main+462>: mov rdi,rax
 0x400b14 <main+465>: call 0x4008eb <_Z7strcmprPcS_>

strcmp(строка в стеке, argv[1]);

Давайте теперь расшифруем, что на самом деле представляет собой строка в стеке:

(RBP-0x20 до 0x16)

72 65 6d 61 6e 72 65 74 73 61 4d

‹отредактировано›

перевернуть его (0x16–0x20)

‹отредактировано›

Ввод этого в качестве входных данных для двоичного файла дает нам наш флаг!