PWN 基础
必备基础
C,python 计算机组成与原理 汇编语言 linux操作系统 ida、GDB
特别的
got/plt elf文件结构 函数调用的栈结构 堆(不同大小的堆,释放原理不同) ELF文件结构,
术语
PWN shellcode payload poc(proof of concept) eep(exploit)
1\基础环境
SOCAT
sudo apt-get install socat
socat TCP-LISTEN:4444,REUSE ADDR,FORK EXEC:/path
/home
XINETD 守护进程xinetd
sudo apt-get install xinetd
/etc/services
/etc/xinetd.d/
service pwn_test
{disable=no
port=5001
socket_type=stream
server=/home/pwn100/pwn100
wait=no
user=pwn_user
}
2\交互方式
socket zio pwntools(文档完善)
IDA Pro gdb插件(peda图形好看,gif多构架,pwndbg兼容peda命令,拥有针对pwn的插件)
安装peda
git clone
https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit
echo "DONE! debug your program with gdb and enjoy"
3\远程调试
首先在ida中分析程序,寻找要下的断点 使用raw_input()使远程程序暂停 找到进程attach 下断点 c(命令) 成功断下
如果使用pwntools的话可以使用内置的方法
gdb.attach(p,””
B *0x
B *xxx
C
“”)
4\缓解措施
ASLR地址随机化0关1代码随机2堆栈代码随机
RELRO:重定位只读,got没法劫持
PIE 位置无关可执行文件(本机随机化可以关掉,本机调试/proc/pid/maps,获得加载地址)基地址+偏移(改写peda通过偏移下断点)
NX 数据执行保护 栈没有执行权限
5、x86
寄存器(esp ebp eip)
大块的堆,用imap映射
int a=0; //.data
int b; //.bss(随机化后地址还是固定的)
const double PI =3.14159f; //.rodata
int main()
{
int c=321
char *d=malloc(16);
return 0;
}
6、GOT
Lazy binding
.text foo PLTO
.got.plt
libc system()函数的地址
got劫持,printf格式化任意字符写漏洞劫持为system()传/bin/sh
7、exploit三个阶段:
nop nop nop src+shellcode
ASLR 栈地址随机化, JSP esp
payload=nop+src+jmp esp
DEP 数据执行保护 RW权限,执行异常挂掉
解决方案:ROP
通过leave 迁移栈的位置,迁移到全局段,
GS、canary(金丝雀) stack_checkfails GS段偏移里的一个值(一个进程一个值)
解决方案:leak通过泄露读出canary的值 payload=nop+src+canary+jmp esp
crack:4个字节,forkserver,fork创建一个子进程
stack_check_fails
打印一个程序名,ssp leak ZCTF2016覆盖到基地址
printf (malloc free :hook)
PWN 流程
file
右键/copy to assembile
两个脚本,msf
ctrl+s看区段
8、格式化字符串漏洞
%d - 十进制 - 输出十进制整数
%s - 字符串 - 从内存中读取字符串
%x - 十六进制 - 输出十六进制数
%c - 字符 - 输出字符
%p - 指针 - 指针地址
%n - 到目前为止所写的字符数
%n dword
%hn word
%hhn bytes
输入如果在栈帧、
有libc通过偏移拿到system 用hn改写低地址
没有libc有printf的地址,有一个info leak的漏洞,多泄露几个函数,read,write,去对应各个版本的libc
http://libcdb.com/可以根据两个地址查询libc的版本
libc-database
输入如果不在栈帧
通过%x泄露出所有的栈数据,%**$写进栈帧
ldd 动态链接system
通过栈帧结构
HITCON-training/env_setup.sh
socat tcp-listen:12345, fork EXEC:./pwn3
PLT其实是延迟绑定技术,也就是等到调用函数的时候才进行函数地址的定位
重局偏移表(GOT, Global Offset Table),而那个额外代码段表,称为
程序链接表(PLT,Procedure Link Table)
1、盲打,栈溢出或者格式化 format string
2、ip port
3、输入做回显示,输入格式化字符串会泄漏栈
4、%p打印地址,确定x86或者x64
区别
x86:直接显示栈地址内容
x64:前五个是寄存器值,第六个是栈地址上内容
输入的位置
aaaa%x,%x对地址读写,bin got
5、dump bin file
ps aux
6\覆盖 got
printf必须一次性改成功,不然就挂掉了
ROP bypass nx保护 栈不可运行
1、Ret2libc
栈不可以执行,代码段可以执行,gadgets
2、ret2dll
3\write(fd,buf,read(fd,bud,4))
rop2(第三道题)
pico ctf 2013 rop2
方案1、call过去之后,./bin/sh直接成为了函数的参数(x64会失败)
方案2、直接ret到system函数开始,那么此时的栈结构就是已经call完的结构,那么在函数里一开始会push ebp什么的,ret是在call的时候做的事情,那么就是多一个ret在中间,这里可以随便赋值给ret,因为这里永远不会ret了,已经system了
libc ldd 泄露read write
dynelf leak函数和地址做泄露pwntools的库
用sleep调整代码保证exp打完
利用write的偏移:
利用泄露的read的终极偏移可以计算出system和/bin/sh的偏移
泄露的read的终极偏移:read_lib
base_addr=read_lib-0xdaf60
system-addr=base_addr+0x40310
简单的方法:one gadgets RCE one_gadget(可以在libc里查找已经有system exec调用的函数)
git:ROPgadget Tool
rp++ 还有一个工具:IDA 插件
ROP 正常的泄露和用one gadgets 先用本地程序调通,用信息泄露找到两个函数的间距
***如何查看libc中函数的偏移地址
1\把libc拖到IDA中去看
2\readelf -s libc.so. |grep
payload=junk+write@plt+ret_addr+p32(1)+p32(write@got)+p32(4)
构造函数
write(1,write@got,4)
new(recv(4))
payload2=junk+system+
GDB search memory
find “libc_so.6"
2\Ret2dlresolve
lazy binding的特性,寻找想要执行的函数的地址
不需要info leak
必须可以控制resolve的参数
PIERELRO
PIE存在必须leak .text段地址,
RELRO的话link_map dl_resolve会被填0 状态应该是关闭的
程序员的自我修养 书
JMPREL
DT_STRTAB
address of string table
code
乌云公开漏洞 知识库搜索
乌云镜像库
SROP
信号处理
内核和用户态的切换
sys call
全部寄存器可控,也可以改变栈的位置
需要控制EIP和栈,栈溢出空间够大,才能放下