2011-10-22 34 views
0

當你調用像printf這樣的函數時,格式字符串和參數被壓入堆棧。如果省略參數,但在格式字符串中用「%x」或「%s」或「%n」指定它們,則無法訪問(讀取或寫入)格式字符串。在我測試過的一個系統上,格式字符串是第四個參數。另一個則超過了200。爲什麼堆棧上格式化字符串的位置在不同的linux系統上如此不同?

例如,我得到了下面的程序,很容易受到formatString的開發,其中包含以下語句:

printf(userSuppliedString); 

不,我想讀一個特定ADRESS。例如。 0xbffffdd7。 我把它通過以下方式:

./fmt_vuln $(printf "\xd7\xfd\xff\xbf")%08x.%08x.%08x.%s 

在此示例格式字符串是第四參數(「%S」)。所以%s將取格式字符串的開頭。因爲這是我們指定的地址,所以這個地址的內容將被打印出來。

現在在這臺機器上的格式字符串是第四個paraemter。但在其他Linux系統上,它的東西卻完全不同。 這是爲什麼呢?

+3

你能提供一些示例代碼來說明你的問題嗎? – ObscureRobot

+3

你說的是字符串*內容*的位置嗎?所有在堆棧中傳遞的是一個*指針*(即分配給它的地址)。對於可變參數函數,通常將參數從右向左推入,以便它位於堆棧的頂部(因此'printf'總能找到第一個參數)。 –

回答

6

當您調用像printf這樣的函數時,格式字符串和 參數被壓入堆棧。如果您省略參數,但 在格式字符串中用「%x」或「%s」或「%n」指定它們,則不能訪問(讀取或寫入)格式字符串。在我測試的一個系統上, 格式字符串是第四個參數。另一方面,它超過了第二百零二號的 。

不,你可能誤解了。

當您使用一個參數(格式字符串)調用printf時,指向格式字符串的指針將被壓入堆棧。這是一個char *這個指針可以指向內存中的任何位置 - printf只是在它的位置被告知並將該內存位置作爲格式字符串讀取。

在通常的一個參數情況下,您將字符串文字傳遞給printf ("hello world!");編譯器將文本hello world放在內存中某處,並生成一個指向它的指針以傳遞給printf。然後它執行任何調用約定表示它應該爲函數調用執行的操作 - 例如,在x86上將指針壓入堆棧。然後Printf從堆棧讀取它的第一個參數,很高興!

在通常的n參數情況下,字符串文字和指針發生同樣的事情。對於函數調用,編譯器會傳遞每個值。再次使用x86(因爲推送比描述比較複雜的參數傳遞方式的ARM更容易描述)。這些值從右向左推送到堆棧。所以如果你有一個printf ("%d, %s, %d", x, name, y);的調用,y被推入堆棧,然後命名,x,最後是格式字符串。

現在,在printf中我們讀取第一個參數(從堆棧中獲取它)。這是一個char *,指向"%d, %s, %d"。我們可以閱讀這個,然後 - 知道編譯器如何傳遞參數,我們可以讀出推入堆棧的三件事情 - 我們也很高興!

格式化字符串漏洞的工作原理是錯誤信念printf has和編譯器的信念。

我們可以通過調用傳遞給printf的錯誤數量參數引起的未定義行爲來顯示它。在調用printf ("%s");編譯器不推送對應於printf期望使用的char *來完成%s指令的參數。但是 - 因爲printf不知道編譯器沒有這樣做,所以它無論如何都會在棧上查找參數。它從堆棧中拉出一個未定義的值並嘗試讀取它指向的字符串。

在你的情況下,你允許任意格式的字符串傳遞給printf。這些參數在預期的參數數量和傳遞的參數數量之間肯定不匹配,所以printf讀取堆棧 - 這是堆滿了垃圾。

如果你很幸運 - 你可以操縱這個垃圾指向你控制的東西 - 並且可以用它來讀取你沒有想到的信息。如果您可以欺騙%n參數指向您控制的某個位置,則可以使用打印的字符數寫入該內存位置。

所以 - 考慮到這個描述,我找不到解決你的問題的方法,這是有道理的。也許你可以更清楚,我可以更新我的答案?

1
./fmt_vuln $(printf "\xd7\xfd\xff\xbf")%08x.%08x.%08x.%s 

在此示例格式字符串是第四參數( 「%S」)。

不,不是真的。問題在於你沒有訪問printf的第四個參數,而是在訪問其調用函數中的局部變量或參數(或進一步向上)。因此,它完全取決於調用函數的代碼。爲了演示它有什麼作用在386:

Breakpoint 1, __printf (format=0xbffff543 "%p") at printf.c:29 
29  printf.c: Adresář nebo soubor neexistuje. 
     in printf.c 
(gdb) x/120a $ebp 

Description: $esp   return addr    fmtstring  parameters 

0xbffff2d8:  0xbffff2f8  0x80483fd <main+25>  0xbffff543  0xb7ff1310 
0xbffff2e8:  0x804842b <__libc_csu_init+11> 0xb7fb7ff4  0x8048420 <__libc_csu_init>  0x0 
0xbffff2f8:  0xbffff378  0xb7e78e46 <__libc_start_main+230>  0x2  0xbffff3a4 
0xbffff308:  0xbffff3b0  0xb7fe1860  0xb7ff7411  0xffffffff 
0xbffff318:  0xb7ffeff4  0x8048254  0x1  0xbffff360 
0xbffff328:  0xb7ff0996  0xb7fffac0  0xb7fe1b58  0xb7fb7ff4 
0xbffff338:  0x0  0x0  0xbffff378  0xa32ae5c4 
0xbffff348:  0x93d0f3d4  0x0  0x0  0x0 
0xbffff358:  0x2  0x8048330 <_start>  0x0  0xb7ff65b0 
0xbffff368:  0xb7e78d6b <__libc_start_main+11>  0xb7ffeff4  0x2  0x8048330 <_start> 
0xbffff378:  0x0  0x8048351 <_start+33> 0x80483e4 <main>  0x2 
0xbffff388:  0xbffff3a4  0x8048420 <__libc_csu_init>  0x8048410 <__libc_csu_fini>  0xb7ff1310 
0xbffff398:  0xbffff39c  0xb7fff908  0x2  0xbffff539 
0xbffff3a8:  0xbffff543  0x0  0xbffff546  0xbffff55a 
0xbffff3b8:  0xbffff56a  0xbffff581  0xbffff58c  0xbffff5dc 
0xbffff3c8:  0xbffff5f3  0xbffff654  0xbffff66f  0xbffff689 

正如你所看到的,格式字符串只會進一步存在於內存中,在由libc中運行,其中argv點初始化的區域。你必須更好地研究你攻擊的代碼。

相關問題