汐白初学PWN
工具的准备
kali-Linux
叭说了,kali这么好用为什么不用,Ubuntu16.04也行
pwntools
pwn必备python包,pip直接安装,python2的
peda
很好用的一个Linux下gdb调试器的版本吧算是
git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit
pwndbg
另一个版本的用于Linux下程序调试的gdb,但是没用过,据说很强,推荐先用peda
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh
odjdump
转载:
odjdump的使用(Linux反汇编工具)
(出处: GPS导航技术社区)
ROPgadget
构建ROP的实用工具
项目地址:
https://github.com/JonathanSalwan/ROPgadget
安装:
git clone -b master http://github.com/JonathanSalwan/ROPgadget.git
cd ROPgadget
cd ./dependencies/capstone-next
./make.sh
sudo ./make.sh install
cd ./bindings/python
make
sudo make install
IDA PRO
ida不用说了,经典软件,既有Windows的版本也有Linux的版本,不过一般推荐直接用windows下的,Linux似乎安装比较麻烦。
64位Linux下安装教程:https://www.52pojie.cn/thread-542682-1-1.html
工具的简单使用
pwntools简单使用
虽然这个百度就可以,不过还是习惯性记录一下
终端中输入python2
进入python命令状态
from pwn import * #pwnrools包的使用方法
io = remote('IP',port) #这个是做pwn题时设定远程攻击的IP地址和端口
io = process('name') #这个是题目文件下载到本地进行测试自己的脚本是否成功获取权限时用的,name为文件名
io.sendline(payload) #向目标程序发送自己构造的payload
io.recv() #接收程序的输出
io.interactive() #如果成功获取shell权限通过该命令与目标机的shell进行互动
#构建payload时
payload=p64(***) #对***使用64位系统的储存方式
payload=p32(***) #对***使用32位系统的储存方式
ROPgadget使用
ROPgadget --binary name --only '***' | grep '***' #查询需要的汇编命令所在地址
#按道理来说它是这样查命令的,不过查询有限制,一般后面***这里要这么输:'***|ret'|grep '***' ***根据需要来写
ROPgadget --binary name --string "***" #查询需要的字符所在地址
ROPgadget --binary name --only 'int' #查询'int 80'
gdb-peda的简单命令介绍
终端:gdb
打开gdb ; gdb name
用gdb调试器加载目标程序
r/run #运行程序,或是在程序中途重新加载运行程序,类似 OD 里的 ctrl+F2
ni #直接运行该行命令,OD 的单步步过
si #进入该行命令内部,进入函数内部用,OD 单步步入
file #加载目标程序
find/searchmem #搜索目标字符
c/continue #继续运行程序
telescope address #查看目标内存地址信息
info #查看各种信息:
info file #查看当前文件的信息,例如程序入口点(Entry point)
info break #查看当前断点信息
disas name #查看目标函数的反汇编内容
b/break name/address #为目标函数或地址设置断点
pattern_create number #生成一串number长度的字符,在测试溢出长度时挺方便的
pattern_offset 溢出位置的字符 #返回输入入口距离溢出点的长度
shellcode
pwn一般目的是为了获取目标机的shell
权限,同时也可以是对目标机进行其他的攻击。而其攻击方式一般是通过程序自身的漏洞劫持eip,然后按照攻击者的需要使其执行相应的系统命令。
获取shell权限一般是控制程序运行出execve("/bin/sh",0,0)
函数或者说system(“/bin/sh”)
函数,从而拿到shell
因为程序已经是被编译生成的可执行程序,所以我们要做的就是让其在运行时按照execve("/bin/sh",0,0)
或system(“/bin/sh”)
函数的需要依次序执行相应的命令使其在没有该函数的情况下实现该函数的作用。
为了实现这一目的而向目标程序发送的数据一般称为shellcode
或者说payload
Linux-i386处理器系统的简单shellcode原理
32位系统要执行execve("/bin/sh",0,0)
时,可用以下汇编代码简单说明
mov eax,0xb #execve()函数的系统调用号为0xb,将其放入eax
mov ebx,address #address为字符"/bin/sh"的地址,ebx为所要调用的execve函数的第一个参数,即"/bin/sh"
mov ecx,0 #第二个参数0
mov edx,0 #第三个参数0
int 80h #呼叫系统调用,运行该指令后会根据**eax**中的值判断系统调用的结果
int 80h #该指令并非和其他指令配套的指令,它的功能就是中断程序运行去进行系统调用,而系统调用的结果由`eax`中的值决定
Linux-i386下的系统调用号查看:http://asm.sourceforge.net/syscall.html#p3
Linux-amd64系统的简单shellcode原理
原理和32位系统基本一样,不过不一样的是64位系统毕竟与32位有很大区别,他们的传参方法和进行系统调用时的方式都不同。
64位Linux系统的参数首先被放在edi,esi,edx,ecx,r8,r9六个寄存器中,多余的参数才放入堆栈
所并且其系统调用命令为syscall
而非是int 80h
mov edi,0x3b
mov esi,address
mov edx,0
mov ecx,0
syscall #Linux-amd64系统的系统调用命令,这里和int 80h应该是不一样的,具体不清楚
如何查看系统调用号
通过本地文件看:
locate unistd_32 #查询Linux-i386系统调用号参数表的位置
//或者
locate unistd_64 #查询Linux-amd64系统调用号参数表的位置
然后直接cat
著名的shell-storm.org的ShellCode数据库
地址:shell-storm.org/shellcode/
里面有各种类型的shellcode,简单情况可以直接在里面找合适的shellcode来用,特殊情况需要自行对shellcode进行改造