И снова привет хабру еще раз! Прошлый пост был по 7 главе, где я написал о том что сегодня выйдет 8 отрывок из 8 главы, соответственно вот он. Так, как 8 глава - глава о шеллкодах, то я выбрал по моему мнению наиболее подходящий отрывок:

Глава 8. Написание шеллкодов на Rust

Поскольку у моего первого компьютера был всего 1 ГБ оперативной памяти (Asus EeePC), мои хобби были очень низкоуровневыми и нетребовательными к ресурсам.

Одно из таких хобби было создание шеллкодов. Не ради наступательного взлома или чего-то подобного, а просто ради искусства написания ассемблера x86. Можно потратить огромное количество времени на создание шеллкодов: ASCII-шеллкоды (шеллкоды, финальное шестнадцатеричное представление которых состоит только из байтов ASCII-таблицы), полиморфные шеллкоды (шеллкоды, которые могут переписывать сами себя и тем самым снижают обнаружимость и замедляют реверс-инжиниринг…). Как и в поэзии, пределы ставит только ваше воображение.

8.1 Что такое шеллкод

Цель эксплойта — выполнить код. Шеллкод — это сырой код, выполняемый на эксплуатируемой машине.

Но есть проблема: написание шеллкодов обычно выполняется напрямую на ассемблере. Это даёт вам абсолютный контроль над тем, что вы создаёте, но недостаток в том, что это требует много знаний, трудно отлаживать, абсолютно не переносимо между архитектурами и является кошмаром для переиспользования и сопровождения с течением времени и командами из нескольких разработчиков.

Вот пример шеллкода:

488d35140000006a01586a0c5a4889c70f056a3c5831ff0f05ebfe68656c6c6f20776f726c640a

Не поняли? Это нормально. Это шестнадцатеричное представление не помогает.

Но, записав его в файл:

$ echo '488d35140000006a01586a0c5a4889c70f056a3c5831ff0f05ebfe68656c6c6f20776f726c640a' \
  | xxd -r -p > shellcode.bin

и дизассемблировав:

$ objdump -D -b binary -mi386 -Mx86-64 -Mintel shellcode.bin


shellcode.bin:         file format binary



Disassembly of section .data:


00000000 <.data>:
   0:    48 8d 35 14 00 00 00       lea      rsi,[rip+0x14]           # 0x1b
   7:    6a 01                      push     0x1
   9:    58                         pop      rax
   a:    6a 0c                      push     0xc
   c:    5a                         pop      rdx
   d:    48 89 c7                   mov      rdi,rax
  10:    0f 05                      syscall              # <- write(1, "hello world\n", 12)
  12:    6a 3c                      push     0x3c
  14:    58                         pop      rax
  15:    31 ff                      xor      edi,edi
  17:    0f 05                      syscall              # <- exit
  19:    eb fe                      jmp      0x19
  1b:    68 65 6c 6c 6f             push     0x6f6c6c65 # <- hello world\n
  20:    20 77 6f                   and      BYTE PTR [rdi+0x6f],dh
  23:    72 6c                      jb       0x91
  25:    64                         fs
  26:    0a                         .byte 0xa

Это раскрывает реальный фрагмент кода, который по сути делает:

write(STOUDT, "hello world\n", 12);
exit(0);

Но, будучи сырым кодом intel x86_64, он не может быть выполнен операционной системой как есть. Его нужно обернуть в исполняемый файл.

Напоминаю главы, переводы и исходники лежат у пеня на гитхабе вот репо: https://github.com/smokeplay250-png/black-hat-ru

Если кому то код код не зашел или вы нашли ошибки скажем как в посте про 5 главу с инъекциями, то не спешите писать об этом в комментах. Напомню, что код в переводах я не трогаю необходимости пока нету.