得分:10/10
C程序homework08.c的主函数如下:
1
2
3
4
5
6
7
8
9
10
11
12
| int main(int argc, char * argv[]) {
init_buf(Lbuffer, LEN);
switch(argc)
{
case 1: f00(); break;
case 2: f01(); break;
case 3: f02(); break;
default: f00(); break;
}
puts("Done.\nThe program exited normally.");
return 0;
}
|
- 在32位的ubuntu16.04系统中用
gcc -fno-stack-protector
编译该程序,得到的可执行程序见附件,通过gdb调试,对f00()、f01()和f02()进行分析:
(1) 函数f00()、f01()和f02()是否导致段错误。
- 如果没有命令行参数(argc 等于 1,因为程序名本身也算一个参数),则执行函数 f00()。
- 如果有一个命令行参数(argc 等于 2),则执行函数 f01()。
- 如果有两个命令行参数(argc 等于 3),则执行函数 f02()。
- 如果有三个或更多的命令行参数,还是执行函数 f00()。
![[Pasted image 20231122231415.png]]
函数foo()
, 和 foo01()
都会导致段错误。
如果函数f00()、f01()和f02()导致段错误,计算出被攻击的缓冲区首地址与函数的返回地址所在的栈地址的距离(即偏移OFFSET),给出溢出后函数的返回地址(用16进制数表示)。
f00()
![[Pasted image 20231121150016.png]]
打断点
函数入口处的堆栈指针esp指向的栈(地址为0xffffd1dc)保存了
函数f00()返回到调用函数(main)的地址(0x080485a8),即“函数的返回地址”
记录堆栈指针esp的值,在此以A标记:A=$esp = 0xffffd1dc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| (gdb) x/x $esp
0xffffd1dc: 0x080485a8
(gdb) c
Continuing.
Breakpoint 2, 0x080484e9 in f00 ()
1: x/i $eip
=> 0x80484e9 <f00+24>: call 0x8048320 <strcpy@plt>
(gdb) x/x $esp
0xffffd140: 0xffffd155
(gdb)
0xffffd144: 0x0804a060
(gdb) x/x 0x0804a060
0x804a060 <Lbuffer>: 0x44434241
|
令B = 0xffffd155,则offset=A-B=0xffffd1dc - 0xffffd155 =0x87=135。
1
2
3
4
5
6
7
8
9
10
| (gdb) c
Continuing.
Breakpoint 3, 0x080484f3 in f00 ()
1: x/i $eip
=> 0x80484f3 <f00+34>: ret
(gdb) x/x $esp
0xffffd1dc: 0x49484746
(gdb) x/s $esp
0xffffd1dc: "FGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW"...
|
执行ret之前的堆栈的内容可以推断执行ret后将跳到地址0x49484746去执行
f01
执行程序
1
| azureuser@MyServer:~/hw$ gdb homework08
|
main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| (gdb) disas main
Dump of assembler code for function main:
0x0804856c <+0>: lea 0x4(%esp),%ecx
0x08048570 <+4>: and $0xfffffff0,%esp
0x08048573 <+7>: pushl -0x4(%ecx)
0x08048576 <+10>: push %ebp
0x08048577 <+11>: mov %esp,%ebp
0x08048579 <+13>: push %ebx
0x0804857a <+14>: push %ecx
0x0804857b <+15>: mov %ecx,%ebx
0x0804857d <+17>: sub $0x8,%esp
0x08048580 <+20>: push $0x400
0x08048585 <+25>: push $0x804a060
0x0804858a <+30>: call 0x804846b <init_buf>
0x0804858f <+35>: add $0x10,%esp
0x08048592 <+38>: mov (%ebx),%eax
0x08048594 <+40>: cmp $0x2,%eax
0x08048597 <+43>: je 0x80485aa <main+62>
0x08048599 <+45>: cmp $0x3,%eax
0x0804859c <+48>: je 0x80485b1 <main+69>
0x0804859e <+50>: cmp $0x1,%eax
0x080485a1 <+53>: jne 0x80485b8 <main+76>
0x080485a3 <+55>: call 0x80484d1 <f00>
0x080485a8 <+60>: jmp 0x80485be <main+82>
0x080485aa <+62>: call 0x80484f4 <f01>
0x080485af <+67>: jmp 0x80485be <main+82>
0x080485b1 <+69>: call 0x8048530 <f02>
0x080485b6 <+74>: jmp 0x80485be <main+82>
0x080485b8 <+76>: call 0x80484d1 <f00>
0x080485bd <+81>: nop
0x080485be <+82>: sub $0xc,%esp
0x080485c1 <+85>: push $0x8048660
0x080485c6 <+90>: call 0x8048330 <puts@plt>
0x080485cb <+95>: add $0x10,%esp
0x080485ce <+98>: mov $0x0,%eax
0x080485d3 <+103>: lea -0x8(%ebp),%esp
0x080485d6 <+106>: pop %ecx
0x080485d7 <+107>: pop %ebx
0x080485d8 <+108>: pop %ebp
0x080485d9 <+109>: lea -0x4(%ecx),%esp
0x080485dc <+112>: ret
End of assembler dump.
|
f01()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| (gdb) disas f01
Dump of assembler code for function f01:
0x080484f4 <+0>: push %ebp
0x080484f5 <+1>: mov %esp,%ebp
0x080484f7 <+3>: sub $0x508,%esp
0x080484fd <+9>: sub $0x8,%esp
0x08048500 <+12>: push $0x400
0x08048505 <+17>: lea -0x4fe(%ebp),%eax
0x0804850b <+23>: push %eax
0x0804850c <+24>: call 0x804846b <init_buf>
0x08048511 <+29>: add $0x10,%esp
0x08048514 <+32>: sub $0x8,%esp
0x08048517 <+35>: lea -0x4fe(%ebp),%eax
0x0804851d <+41>: push %eax
0x0804851e <+42>: lea -0xfe(%ebp),%eax
0x08048524 <+48>: push %eax
0x08048525 <+49>: call 0x8048320 <strcpy@plt>
0x0804852a <+54>: add $0x10,%esp
0x0804852d <+57>: nop
0x0804852e <+58>: leave
0x0804852f <+59>: ret
End of assembler dump.
|
设置断点
1
2
3
4
5
6
| (gdb) b*(f01+0)
Breakpoint 1 at 0x80484f4
(gdb) b*(f01+49)
Breakpoint 2 at 0x8048525
(gdb) b*(f01+59)
Breakpoint 3 at 0x804852f
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| (gdb) display/i $eip
1: x/i $eip
<error: No registers.>
(gdb) x/i $eip
No registers.
(gdb) run 1
Starting program: /home/azureuser/hw/homework08 1
Breakpoint 1, 0x080484f4 in f01 ()
1: x/i $eip
=> 0x80484f4 <f01>: push %ebp
(gdb) x/x $esp
0xffffd1cc: 0x080485af
|
记录堆栈指针esp的值,在此以A标记:A=$esp = 0xffffd1cc
继续执行到下一个断点
1
2
3
4
5
6
7
8
9
10
11
12
| (gdb) c
Continuing.
Breakpoint 2, 0x08048525 in f01 ()
1: x/i $eip
=> 0x8048525 <f01+49>: call 0x8048320 <strcpy@plt>
(gdb) x $esp
0xffffccb0: 0xffffd0ca
(gdb)
0xffffccb4: 0xffffccca
(gdb) x/x 0xffffccca
0xffffccca: 0x44434241
|
B=0xffffd0ca。
offset=A-B= 0xffffd1cc - 0xffffd0ca =0x102=258。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| (gdb) c
Continuing.
Breakpoint 3, 0x0804852f in f01 ()
1: x/i $eip
=> 0x804852f <f01+59>: ret
(gdb) x/x $esp
0xffffd1cc: 0x42415a59
(gdb) x/s $esp
0xffffd1cc: "YZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOP"...
(gdb) si
0x42415a59 in ?? ()
1: x/i $eip
=> 0x42415a59: <error: Cannot access memory at address 0x42415a59>
(gdb) x/s $esp
0xffffd1d0: "CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRST"...
|
返回地址变 为 0x42415a59
其他(本次实验的一些其它尝试)
- 由于这个可执行文件是ubuntu16.04编译的,本身我的虚拟机系统是ubuntu18.04,一开始执行文件老是报错:
1
2
| ~$ ./homework08
-bash: ./homework08: No such file or directory
|
查询之后发现不是文件不存在,是缺少需要的依赖,因为Ubuntu18.04默认去掉了32bit的library。
解决方法
1
| sudo apt-get install lib32z1
|
之后就可以执行了。
- 本身自己的电脑是mac m2芯片,一开始没尝试使用虚拟机而是docker在容器内去pull ubuntu的镜像来尝试实验:
% docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -it --platform linux/386 -v "/Users/agq/Downloads/srcToStudent:/srcToStudent" --name=hw6 i386/ubuntu /bin/bash
发现能运行文件,并且可以显示段错误:
但由于qemu天生不支持ptrace系统调用,而gdb正是依赖这个系统调用,所以无法进行调试(QEMU’s user-mode emulation does not support the ptrace system call)所以第二题就做不了,遂作罢。