簡體   English   中英

理解格式字符串利用的困難

[英]Difficulties Understanding Format String Exploitation

我正在讀一本書,Hacking: The Art of Exploitation 2nd Edition,我正在閱讀格式字符串漏洞的章節。 我多次閱讀該章節,但即使使用谷歌搜索,我也無法清楚地理解它。

所以,書中有這個易受攻擊的代碼:

 char text[1024];
...
 strcpy(text, argv[1]);
 printf("The right way to print user-controlled input:\n");
 printf("%s", text);
 printf("\nThe wrong way to print user-controlled input:\n");
 printf(text);

然后編譯后,

reader@hacking:~/booksrc $ ./fmt_vuln $(perl -e 'print "%08x."x40')
The right way to print user-controlled input:
%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.
%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.
%08x.%08x.
The wrong way to print user-controlled input:
bffff320.b7fe75fc.00000000.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252
e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.2
52e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e78
38.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.

字節 0x25、0x30、0x38、0x78 和 0x2e 似乎重復了很多。

reader@hacking:~/booksrc $ printf "\x25\x30\x38\x78\x2e\n"
%08x.

首先,為什么這個價值會重演?

如您所見,它們是格式字符串本身的 memory。 因為格式 function 將始終位於最高堆棧幀上,只要格式字符串已存儲在堆棧上的任何位置,它將位於當前幀指針下方(位於更高的 memory 地址)。

但在我看來,這與他之前寫的內容以及堆棧幀的組織方式相矛盾

當調用此 printf() function 時(與任何函數一樣),arguments 以相反的順序被推入堆棧。

那么,格式字符串不應該位於較低的 memory 地址,因為它是第一個參數嗎? 格式字符串存儲在哪里?

reader@hacking:~/booksrc $ ./fmt_vuln AAAA%08x.%08x.%08x.%08x
The right way to print user-controlled input:
AAAA%08x.%08x.%08x.%08x
The wrong way to print user-controlled input:
AAAAbffff3d0.b7fe75fc.00000000.41414141

再次,為什么在41414141中重復AAAA From what I understand, the printf function prints AAAA first, then when it sees the first %08x , it gets a value from a memory address in the preceding stack frame, then does the same with the second %08x , thus the value of the second is located in a memory address higher than the first one, and finally returns to the value of AAAA located in a lower memory address, in the stack frame of printf function.

我用$(perl -e 'print "%08x."x40')作為參數調試了第一個示例。 我運行:Linux 5.3.0-40-generic,18.04.1-Ubuntu,x86_64

(gdb) run $(perl -e 'print "%08x." x 40')
Starting program: /home/kuro/fmt_vuln $(perl -e 'print "%08x." x 40')
The right way to print user-controlled input:
%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.
The wrong way to print user-controlled input:
07a51260.4b3eb8c0.4b10e154.00000000.4b16c3a0.9d357fc8.9d357b10.78383025.30252e78.2e783830.3830252e.252e7838.78383025.30252e78.2e783830.3830252e.252e7838.78383025.30252e78.2e783830.3830252e.252e7838.78383025.30252e78.2e783830.3830252e.252e7838.78383025.30252e78.2e783830.3830252e.252e7838.4b618d00.4b5fd000.00000000.9d357c80.00000000.00000000.00000000.4b3ef6f0.

Breakpoint 1, main (argc=2, argv=0x7ffd9d357fc8) at fmt_vuln.c:19
19      printf("[*] test_val @ 0x%08x = %d 0x%08x\n", &test_val, test_val, test_val);
(gdb) x/-100xw $rsp
0x7ffd9d357940: 0x00000400  0x00000000  0x4b07c1aa  0x00007fb8
0x7ffd9d357950: 0x00000016  0x00000000  0x00000003  0x00000000
0x7ffd9d357960: 0x00000001  0x00000000  0x00002190  0x000003e8
0x7ffd9d357970: 0x00000005  0x00000000  0x00008800  0x00000000
0x7ffd9d357980: 0x00000000  0x00000000  0x00000400  0x00000000
0x7ffd9d357990: 0x00000000  0x00000000  0x5e970730  0x00000000
0x7ffd9d3579a0: 0x65336234  0x30663666  0x90890300  0x79e57be9
0x7ffd9d3579b0: 0x1cd79dbf  0x00000000  0x00000000  0x00000000
0x7ffd9d3579c0: 0x05cec660  0x000055ef  0x9d357fc0  0x00007ffd
0x7ffd9d3579d0: 0x00000000  0x00000000  0x00000000  0x00000000
0x7ffd9d3579e0: 0x9d357ee0  0x00007ffd  0x4b062f26  0x00007fb8
0x7ffd9d3579f0: 0x00000030  0x00000030  0x9d357be8  0x00007ffd
0x7ffd9d357a00: 0x9d357a10  0x00007ffd  0x90890300  0x79e57be9
0x7ffd9d357a10: 0x4b3ea760  0x00007fb8  0x07a51260  0x000055ef
0x7ffd9d357a20: 0x4b3eb8c0  0x00007fb8  0x4b0891bd  0x00007fb8
0x7ffd9d357a30: 0x00000000  0x00000000  0x4b3ea760  0x00007fb8
0x7ffd9d357a40: 0x00000d68  0x00000000  0x00000169  0x00000000
0x7ffd9d357a50: 0x07a51260  0x000055ef  0x4b08af51  0x00007fb8
0x7ffd9d357a60: 0x4b3e62a0  0x00007fb8  0x4b3ea760  0x00007fb8
0x7ffd9d357a70: 0x0000000a  0x00000000  0x05cec660  0x000055ef
0x7ffd9d357a80: 0x9d357fc0  0x00007ffd  0x00000000  0x00000000
0x7ffd9d357a90: 0x00000000  0x00000000  0x4b08b403  0x00007fb8
0x7ffd9d357aa0: 0x4b3ea760  0x00007fb8  0x9d357ee0  0x00007ffd
0x7ffd9d357ab0: 0x05cec660  0x000055ef  0x4b0808f5  0x00007fb8
0x7ffd9d357ac0: 0x00000000  0x00000000  0x05cec824  0x000055ef
(gdb) x/100xw $rsp
0x7ffd9d357ad0: 0x9d357fc8  0x00007ffd  0x9d357b10  0x00000002
0x7ffd9d357ae0: 0x78383025  0x3830252e  0x30252e78  0x252e7838
0x7ffd9d357af0: 0x2e783830  0x78383025  0x3830252e  0x30252e78
0x7ffd9d357b00: 0x252e7838  0x2e783830  0x78383025  0x3830252e
0x7ffd9d357b10: 0x30252e78  0x252e7838  0x2e783830  0x78383025
0x7ffd9d357b20: 0x3830252e  0x30252e78  0x252e7838  0x2e783830
0x7ffd9d357b30: 0x78383025  0x3830252e  0x30252e78  0x252e7838
0x7ffd9d357b40: 0x2e783830  0x78383025  0x3830252e  0x30252e78
0x7ffd9d357b50: 0x252e7838  0x2e783830  0x78383025  0x3830252e
0x7ffd9d357b60: 0x30252e78  0x252e7838  0x2e783830  0x78383025
0x7ffd9d357b70: 0x3830252e  0x30252e78  0x252e7838  0x2e783830
0x7ffd9d357b80: 0x78383025  0x3830252e  0x30252e78  0x252e7838
0x7ffd9d357b90: 0x2e783830  0x78383025  0x3830252e  0x30252e78
0x7ffd9d357ba0: 0x252e7838  0x2e783830  0x4b618d00  0x00007fb8
0x7ffd9d357bb0: 0x4b5fd000  0x00007fb8  0x00000000  0x00000000
0x7ffd9d357bc0: 0x9d357c80  0x00007ffd  0x00000000  0x00000000
0x7ffd9d357bd0: 0x00000000  0x00000000  0x00000000  0x00000000
0x7ffd9d357be0: 0x4b3ef6f0  0x00007fb8  0x4b6184c8  0x00007fb8
0x7ffd9d357bf0: 0x9d357c80  0x00007ffd  0x4b3ef000  0x00007fb8
0x7ffd9d357c00: 0x4b3ef914  0x00007fb8  0x4b3ef3c0  0x00007fb8
0x7ffd9d357c10: 0x4b617048  0x00007fb8  0x00000000  0x00000000
0x7ffd9d357c20: 0x00000000  0x00000000  0x4b6179f0  0x00007fb8
0x7ffd9d357c30: 0x4b0030e8  0x00007fb8  0x00000000  0x00000000
0x7ffd9d357c40: 0x4b3efa00  0x00007fb8  0x00000480  0x00000000
0x7ffd9d357c50: 0x00000027  0x00000000  0x00000000  0x00000000

出現在“%08x”之前的值。 以錯誤的方式 output,出現在低於“%08x”的地址中。 價值觀。 為什么? 格式字符串應該位於堆棧的頂部。

出現在“%08x”之后的值。 錯誤方式 output 的值,出現在比“%08x”更高的地址中。 價值觀。 所以在前面的堆棧中。

為什么會這樣? output 不應該從格式字符串值開始還是之后?

此外,在書中,它不會在“%08x”之后打印值。 價值觀。 但有些是在我的情況下打印的。 output 中的某些值甚至不在堆棧中,例如4b16c3a0

我必須反對你正在做的事情。 您專注於 C 中的安全漏洞,但對語言本身沒有深入了解。 這是一種沮喪的練習。 作為證據,我提出你提出的關於練習的每個問題都是通過理解printf (3) 而不是堆棧漏洞來回答的。

您的 perl 行的 output ( argv[1]的內容)以%08x.%08x.%08x.%08x.%08x開頭。 那是一個格式字符串。 每個%08x都在尋找另一個printf參數,一個 integer 以十六進制表示形式打印。 通常,你可能會做類似的事情,

int a = 'B';
printf( "%02x\n", a );

銀河系漫游指南》中的計算機快 42 倍。

您所做的是傳遞一個arguments 的長格式字符串。 printf (3)不知道通過了多少個arguments; 它必須從格式字符串中推斷出它們。 您的格式字符串告訴 printf 打印一長串整數。 由於沒有提供任何內容,它會在“堆棧上”(無論它們應該在哪里)查找它們。 您打印廢話是因為那些 memory 位置的內容是不可預測的。 或者,無論如何,不是由你定義的。

在“好”的情況下,格式字符串是"%s" ,聲明一個您提供的字符串類型的參數。 效果更好,是的。

現在大多數編譯器都特別注意 printf。 如果格式字符串不是編譯時常量,它們會產生警告,並且它們可以驗證每個參數的類型是否與其對應的格式說明符正確。 因此,只需使用編譯器的功能並注意其診斷,就可以使您書中的整個章節變得毫無意義。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM