我正在学习Shellcooder手册的"格式化字符串"部分。正如书中所建议的那样,我使用这样的代码来进行测试:
[formatstring.c]
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if(argc>1) {
if(argc>2) {
printf("Push a key to continue...n");
getc(stdin);
}
printf("Sortie format string => ");
printf( argv[1] );
printf("n");
}
printf("n");
}
所以,我知道诀窍是在堆栈上用偏移量定位参数(传递给formatstring的链,稍后由printf使用)。
./formatstring "aaaa%$offset$x"
(将kernel.randomize_va_space设置为0,以便偏移保持不变)。为了找到这个偏移量,他们使用了一个小批量脚本
for((i=0; i<1000; i++)); do echo -n "$i " && ./formatstring "AAAAAAAA%$i$x"; done | grep 4141
我把这个弄出来了(这里偏移量=137)
137 Sortie format string => AAAAAAAA41414141
138 Sortie format string => AAAAAAAA25414141
首先,我的"AAAAAAAA"在堆栈上没有"对齐"(我在这里只能数7个41,但我向formatstring发送了8个"A"),并且它们在堆栈上的放置方式似乎在一段时间内发生了变化=>如果我在2小时后启动我的bash脚本(for),"A"的"对齐"可能会发生变化。
更令人不安的是,当我向发送到的参数添加字节时,偏移量似乎发生了变化/formatstring。如果我运行
for((i=0; i<1000; i++)); do echo -n "$i " && ./formatstring "AAAAAAAA%32x%$i$x"; done | grep 4141
我得到
136 Sortie format string => AAAAAAAA b7ff103041414141
137 Sortie format string => AAAAAAAA b7ff103025414141
或者运行
for((i=0; i<1000; i++)); do echo -n "$i " && ./formatstring "AAAAAAAA%320x%$i$x"; done | grep 4141
我得到
139 Sortie format string => AAAAAAAA b7ff103041410067
140 Sortie format string => AAAAAAAA b7ff103041414141
141 Sortie format string => AAAAAAAA b7ff103033254141
正如你所看到的,偏移量的变化遵循了一个我无法理解的逻辑。根据这本书,这一切都不应该发生。你知道它是从哪里来的吗?它是一种堆栈保护机制吗?我可以在gcc-formatstring.c时删除它吗?
好吧,我想明白了。这本书没有解释的是(或者我误解了,因为你可以看到英语不是我的母语lang),如果你想让它在堆栈上保持相同的偏移量,你只能在你的论点中添加16个字符(字节)的集合。
因此,如果您将"%320x"添加到参数中,您还必须用(16-5=11)"A"(或任何其他字符)完成,因为strlen("%320x")=5。