fork download
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <stdint.h>
  5.  
  6. // Прагмы нужны для того, чтобы оптимизатор не выкинул половину нашего кода.
  7. #pragma GCC push_options
  8. #pragma GCC optimize "-O0"
  9. static int is_admin = 0;
  10. #pragma GCC pop_options
  11.  
  12. static void vulnerable(size_t index, size_t length)
  13. {
  14. // Пишем безопасный код: запрещаем атакующему обращаться к данным за
  15. // пределами массива.
  16. if (index >= length) {
  17. printf("oops, the index is out of bounds\n");
  18. return;
  19. }
  20.  
  21. // Выделяем память, обращаемся к ней. В общем-то ничего плохого не
  22. // делаем.
  23. uint8_t *ptr = malloc(length);
  24. printf("got some memory from malloc(): %p\n", (void *) ptr);
  25. ptr[index] = 1;
  26. free(ptr);
  27. }
  28.  
  29. static void destroy_the_world(void)
  30. {
  31. if (!is_admin) {
  32. printf("access denied\n");
  33. return;
  34. }
  35.  
  36. printf("nuclear apocalypse in 3... 2... 1...\n");
  37. }
  38.  
  39. int main(void)
  40. {
  41. // Представим, что размер и индекс контролируются атакующим.
  42. size_t index_from_user = (size_t) &is_admin;
  43. size_t length_from_user = SIZE_MAX;
  44.  
  45. printf("BEFORE: is_admin = %u\n", is_admin);
  46. vulnerable(index_from_user, length_from_user);
  47. printf("AFTER: is_admin = %u\n", is_admin);
  48.  
  49. destroy_the_world();
  50. }
Success #stdin #stdout 0s 4256KB
stdin
Standard input is empty
stdout
BEFORE: is_admin = 0
got some memory from malloc(): (nil)
AFTER:  is_admin = 1
nuclear apocalypse in 3... 2... 1...