書式文字列攻撃に関するメモ
値の調整
'%%%dc' % ((value - 1) % 256 + 1)
としないといけない。
まず%c
について。
%d
や%x
を使うと、偶然それに対応する引数の値が大きかった場合、出力させたい文字数より多い文字数が出力されるため。
$-1$ / $+1$の調整について。これは$0$を作らないため。
$\mathrm{value} = 0$のとき(python等の常に非負を返すmodであれば)$(\mathrm{value} - 1) \bmod = 255$となり全体で$256$となる。
%0c
のようになってしまうと、これは別の意味(空白でなくて0
埋め)のflagと解釈されてしまう。そうでなくても最低$1$文字出力される。
例
$ cat a.c
#include <stdio.h>
int main(void) {
int c, d;
printf("%0c%n", 65, &c);
printf("%6d%n", 1000000007, &d);
printf("\nc = %d\nd = %d\n", c, d);
printf("%012d\n", 123);
return 0;
}
$ gcc a.c
$ ./a.out
A1000000007
c = 1
d = 10
000000000123
golf
書き込みの際はshort writeを使うと便利であるが、%hhn
は長くなるので注意。
以下は$4$byte書き込みたい時の比較。
12345678123456791234567a1234567b%123c%12$hhn%123c%13$hhn%123c%14$hhn%123c%15$hhn
123456781234567a%12345c%12$hn%12345c%13$hn
12345678%123456789c%12$n
payloadの生成のためのコードも(関数化しない場合は)同様に長くなる。
順序
%hn
と%hhn
を併用するとき、%hn
を先に使い%hhn
は後にするとよい。
%hn
は$\bmod 65536$だが%hhn
は$256$なので、逆にするとひとつ前の書き込み結果のみからの調整ができない。