环境搭建
虚拟机安装
- 镜像下载网站
- 为了避免环境问题建议 22.04 ,20.04,18.04,16.04 等常见版本 ubuntu 虚拟机环境各准备一份。注意定期更新快照以防意外。
- 虚拟机建议硬盘 256 G 以上,内存也尽量大一些。硬盘大小只是上界,256 G 不是真就占了 256 G,而后期如果硬盘空间不足会很麻烦。
基础工具
vim
sudo apt install vim
gedit
不习惯 vim 的可以使用 gedit 文本编辑器。
sudo apt install gedit
git
sudo apt install git
gcc
sudo apt install gcc
python
ipython 提供了很好的 python 交互命令行,建议安装。
sudo apt install python2 ipython2
sudo apt install python3 ipython3
另外有的版本 ubuntu 的不好安装 pip2 可以使用 get-pip.py
脚本安装。
curl https://bootstrap.pypa.io/get-pip.py --output get-pip.py
sudo python2 get-pip.py
docker
sudo apt install docker.io
sudo apt install docker-compose
pwn 相关工具
gdb
sudo apt-get install gdb gdb-multiarch
pwntools
注意我这里的 pwntools 是 python2 版本的。
pip install pwntools
这样安装的 pwntools 的 plt 功可能无法正常使用,需要手动安装 Unicorn 库。
pip install unicorn==1.0.3
gdb 插件
主要有 pwndbg,peda,gef ,这里我常用的是 pwndbg 。对于一些版本过于古老导致环境装不上的可以尝试一下 peda 。
先将三个项目的代码都拉取下来。
git clone https://github.com/longld/peda.git
git clone https://github.com/pwndbg/pwndbg.git
git clone https://github.com/hugsy/gef.git
pwndbg 需要运行初始化脚本。
cd pwndbg & sudo ./setup.sh
另外还有一个 pwngdb 插件在调试多线程堆(heapinfoall
命令)的时候很有用,建议安装。
git clone https://github.com/scwuaptx/Pwngdb.git
gdb 在启动的时候会读取当前用户的主目录的 .gdbinit
文件进行 gdb 插件的初始化,这里提供一个配置方案。
source /home/sky123/tools/pwndbg/gdbinit.py
#source /home/sky123/tools/peda/peda.py
#source /home/sky123/tools/gef/gef.py#source /home/sky123/tools/muslheap/muslheap.pysource /home/sky123/tools/Pwngdb/pwngdb.py
source /home/sky123/tools/Pwngdb/angelheap/gdbinit.pydefine hook-run
python
import angelheap
angelheap.init_angelheap()
end
end
注意,以普通用权限和管理员权限启动 gdb 时读取的 .gdbinit
文件的路径是不同的,普通权限读取的是 /home/<username>/.gdbinit
而管理员权限读取的是 /root/.gdbinit
。
gadget 搜索工具
ROPgdbget
安装:
git clone https://github.com/JonathanSalwan/ROPgadget.git
cd ROPgadget
sudo python3 setup.py install
使用:
ROPgadget --binary ntdll.dll > rop
ropper
- 安装:
- 在 pypi 的 ropper 官网上下载 ropper
- 运行安装脚本完成 ropper 安装
python setup.py install
- 使用:
ropper --file ./pwn --nocolor > rop
one_gadget
用于搜索 libc 中能够实现 execve("/bin/sh", (char *[2]) {"/bin/sh", NULL}, NULL);
的效果的跳转地址,由于是采用特征匹配的方法,因此只能是在 libc 中查找。
- 安装:
sudo apt install -y ruby ruby-dev sudo gem install one_gadget
- 使用:可以查找到 gadget 地址以及条件限制。
➜ ~ one_gadget /lib/x86_64-linux-gnu/libc.so.6 0x50a37 posix_spawn(rsp+0x1c, "/bin/sh", 0, rbp, rsp+0x60, environ) constraints:rsp & 0xf == 0rcx == NULLrbp == NULL || (u16)[rbp] == NULL0xebcf1 execve("/bin/sh", r10, [rbp-0x70]) constraints:address rbp-0x78 is writable[r10] == NULL || r10 == NULL[[rbp-0x70]] == NULL || [rbp-0x70] == NULL0xebcf5 execve("/bin/sh", r10, rdx) constraints:address rbp-0x78 is writable[r10] == NULL || r10 == NULL[rdx] == NULL || rdx == NULL0xebcf8 execve("/bin/sh", rsi, rdx) constraints:address rbp-0x78 is writable[rsi] == NULL || rsi == NULL[rdx] == NULL || rdx == NULL
如果 one_gadget
在一个版本的 Ubuntu 中搜索某一版本的glibc 的 gadget 出现如下报错可以尝试换另一个版本的 Ubuntu ,具体原因未知。
seccomp-tools
用于查看和生成程序沙箱规则。
- 安装:
sudo gem install seccomp-tools
- 使用:
seccomp-tools dump ./pwn
LibcSearcher
通过泄露的 libc 中函数的地址来确定 libc 版本。
git clone https://github.com/lieanu/LibcSearcher.git
cd LibcSearcher
sudo python3 setup.py install
patchelf
安装:
sudo apt install patchelf
qemu
sudo apt install qemu-user qemu-system
工具使用
vim
功能
命令行模式下的文本编辑器。
- 根据文件扩展名自动判别编程语言。支持代码缩进、代码高亮等功能。
- 使用方式:
vim filename
- 如果已有该文件,则打开它。
- 如果没有该文件,则打开个一个新的文件,并命名为
filename
。
模式
- 一般命令模式
默认模式,按不同字符即可进行不同操作。可以复制、粘贴、删除文本等。 - 编辑模式
- 在一般命令模式里按下
i
,会进入编辑模式。 - 按下
Esc
会退出编辑模式,返回到一般命令模式。
- 在一般命令模式里按下
- 命令行模式
- 在一般命令模式里按下
:/?
三个字母中的任意一个,会进入命令行模式。命令行在最下面。 - 可以查找、替换、保存、退出、配置编辑器等。
- 在一般命令模式里按下
操作
i
:进入编辑模式。Esc
:进入一般命令模式。h
或←
:光标向左移动一个字符。j
或↓
:光标向下移动一个字符。k
或↑
:光标向上移动一个字符。- l 或
→
:光标向右移动一个字符。 n<Space>
:n
表示数字,按下数字后再按空格,光标会向右移动这一行的n
个字符。0
或功能键[Home]
:光标移动到本行开头。$
或功能键[End]
:光标移动到本行末尾。G
:光标移动到最后一行。:n
或nG
:n
为数字,光标移动到第n
行。gg
:光标移动到第一行,相当于1G
。n<Enter>
:n
为数字,光标向下移动n
行。/word
:向光标之下寻找第一个值为word
的字符串。?word
:向光标之上寻找第一个值为word
的字符串。n
:重复前一个查找操作。N
:反向重复前一个查找操作。:n1,n2s/word1/word2/g
:n1
与n2
为数字,在第n1
行与n2
行之间寻找word1
这个字符串,并将该字符串替换为word2
。:1,$s/word1/word2/g
:将全文的word1
替换为word2
。:1,$s/word1/word2/gc
:将全文的word1
替换为word2
,且在替换前要求用户确认。v
:选中文本。d
:删除选中的文本。dd
: 删除当前行。y
:复制选中的文本。yy
: 复制当前行。p
: 将复制的数据在光标的下一行/下一个位置粘贴。u
:撤销。Ctrl + r
:取消撤销。>
:将选中的文本整体向右缩进一次。<
:将选中的文本整体向左缩进一次。:w
:保存。:w!
:强制保存。:q
:退出。:q!
:强制退出。:wq
:保存并退出。:set paste
:设置成粘贴模式,取消代码自动缩进。:set nopaste
:取消粘贴模式,开启代码自动缩进。:set nu
:显示行号。:set nonu
:隐藏行号。gg=G
:将全文代码格式化。:noh
:关闭查找关键词高亮。Ctrl + q
:当 vim 卡死时,可以取消当前正在执行的命令。
异常处理
每次用 vim 编辑文件时,会自动创建一个 .filename.swp
的临时文件。如果打开某个文件时,该文件的 swp
文件已存在,则会报错。此时解决办法有两种:
- 找到正在打开该文件的程序,并退出。
- 直接删掉该
swp
文件即可。
docker
将当前用户添加到 docker 用户组
为了避免每次使用 docke r命令都需要加上 sudo 权限,可以将当前用户加入安装中自动创建的 docker 用户组(可以参考官方文档):
sudo usermod -aG docker $USER
执行完此操作后,需要退出服务器,再重新登录回来,才可以省去 sudo 权限。
镜像(images)
docker pull ubuntu:20.04
:拉取一个镜像docker images
:列出本地所有镜像docker image rm ubuntu:20.04
或docker rmi ubuntu:20.04
:删除镜像ubuntu:20.04
docker [container] commit CONTAINER IMAGE_NAME:TAG
:创建某个container
的镜像docker save -o ubuntu_20_04.tar ubuntu:20.04
:将镜像ubuntu:20.04
导出到本地文件ubuntu_20_04.tar
中docker load -i ubuntu_20_04.tar
:将镜像ubuntu:20.04
从本地文件ubuntu_20_04.tar
中加载出来
容器(container)
docker [container] create -it ubuntu:20.04
:利用镜像ubuntu:20.04
创建一个容器。docker ps -a
:查看本地的所有容器docker [container] start CONTAINER
:启动容器docker [container] stop CONTAINER
:停止容器docker [container] restart CONTAINER
:重启容器docker [contaienr] run -itd ubuntu:20.04
:创建并启动一个容器docker [container] attach CONTAINER
:进入容器- 先按
Ctrl-p
,再按Ctrl-q
可以挂起容器
- 先按
docker [container] exec CONTAINER COMMAND
:在容器中执行命令docker [container] rm CONTAINER
:删除容器docker container prune
:删除所有已停止的容器docker export -o xxx.tar CONTAINER
:将容器CONTAINER
导出到本地文件xxx.tar
中docker import xxx.tar image_name:tag
:将本地文件xxx.tar
导入成镜像,并将镜像命名为image_name:tag
docker export/import
与docker save/load
的区别:export/import
会丢弃历史记录和元数据信息,仅保存容器当时的快照状态save/load
会保存完整记录,体积更大
docker top CONTAINER
:查看某个容器内的所有进程docker stats
:查看所有容器的统计信息,包括CPU、内存、存储、网络等信息docker cp xxx CONTAINER:xxx
或docker cp CONTAINER:xxx xxx
:在本地和容器间复制文件docker rename CONTAINER1 CONTAINER2
:重命名容器docker update CONTAINER --memory 500MB
:修改容器限制
ssh
ssh 登录
基本用法
远程登录服务器:
ssh user@hostname
user
: 用户名hostname
: IP 地址或域名
第一次登录时会提示:
The authenticity of host '123.57.47.211 (123.57.47.211)' can't be established.
ECDSA key fingerprint is SHA256:iy237yysfCe013/l+kpDGfEG9xxHxm0dnxnAbJTPpG8.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
输入 yes
,然后回车即可。这样会将该服务器的信息记录在 ~/.ssh/known_hosts
文件中。然后输入密码即可登录到远程服务器中。
ssh 默认登录端口号为 22 。如果想登录某一特定端口可以用 -p
参数指定。
ssh user@hostname -p 22
配置文件
创建文件 ~/.ssh/config
,然后在文件中输入:
Host myserver1HostName IP地址或域名User 用户名Host myserver2HostName IP地址或域名User 用户名
之后再使用服务器时,可以直接使用别名 myserver1
、myserver2
。
密钥登录
创建密钥:
ssh-keygen
然后一直回车即可。
执行结束后,~/.ssh/
目录下会多两个文件:
id_rsa
:私钥id_rsa.pub
:公钥
之后想免密码登录哪个服务器,就将公钥传给哪个服务器即可。
例如,想免密登录 myserver
服务器。则将公钥中的内容,复制到 myserver
中的 ~/.ssh/authorized_keys
文件里即可。
也可以使用如下命令添加公钥:
ssh-copy-id myserver
执行命令
命令格式:ssh user@hostname command
。
scp传文件
命令格式:
- 将
source
路径下的文件复制到destination
中:scp source destination
。 - 一次复制多个文件:
scp source1 source2 destination
。 - 复制文件夹:
scp -r ~/tmp myserver:/home/
。 - 指定服务器的端口号:
scp -P 22 source1 source2 destination
。
注意:scp
的-r
、-P
等参数尽量加在source
和destination
之前。
git
git 基本概念
- 工作区:仓库的目录。工作区是独立于各个分支的。
- 暂存区:数据暂时存放的区域,类似于工作区写入版本库前的缓存区。暂存区是独立于各个分支的。
- 版本库:存放所有已经提交到本地仓库的代码版本
- 版本结构:树结构,树中每个节点代表一个代码版本。
git 常用命令
git config --global user.name xxx
:设置全局用户名,信息记录在~/.gitconfig
文件中。git config --global user.email xxx@xxx.com
:设置全局邮箱地址,信息记录在~/.gitconfig
文件中。git init
:将当前目录配置成 git 仓库,信息记录在隐藏的.git
文件夹中。git add XX
:将XX
文件添加到暂存区。git add .
:将所有待加入暂存区的文件加入暂存区。git rm --cached XX
:将文件从仓库索引目录中删掉。git commit -m "给自己看的备注信息"
:将暂存区的内容提交到当前分支。git status
:查看仓库状态。git diff XX
:查看XX
文件相对于暂存区修改了哪些内容。git log
:查看当前分支的所有版本。git reflog
:查看HEAD
指针的移动历史(包括被回滚的版本)。git reset --hard HEAD^
或git reset --hard HEAD~
:将代码库回滚到上一个版本。git reset --hard HEAD^^
:往上回滚两次,以此类推。git reset --hard HEAD~100
:往上回滚 100 个版本。git reset --hard 版本号
:回滚到某一特定版本。git checkout -- XX
或git restore XX
:将XX
文件尚未加入暂存区的修改全部撤销。git remote add origin git@git.acwing.com:xxx/XXX.git
:将本地仓库关联到远程仓库。git push -u
(第一次需要-u以后不需要):将当前分支推送到远程仓库。git push origin branch_name
:将本地的某个分支推送到远程仓库。git clone git@git.acwing.com:xxx/XXX.git
:将远程仓库XXX
下载到当前目录下。git checkout -b branch_name
:创建并切换到branch_name
这个分支。git branch
:查看所有分支和当前所处分支。git checkout branch_name
:切换到branch_name
这个分支。git merge branch_name
:将分支branch_name
合并到当前分支上。git branch -d branch_name
:删除本地仓库的branch_name
分支。git branch branch_name
:创建新分支。git push --set-upstream origin branch_name
:设置本地的branch_name
分支对应远程仓库的branch_name
分支。git push -d origin branch_name
:删除远程仓库的branch_name
分支。git pull
:将远程仓库的当前分支与本地仓库的当前分支合并。git pull origin branch_name
:将远程仓库的branch_name
分支与本地仓库的当前分支合并。git branch --set-upstream-to=origin/branch_name1 branch_name2
:将远程的branch_name1
分支与本地的branch_name2
分支对应。git checkout -t origin/branch_name
:将远程的branch_name
分支拉取到本地。git stash
:将工作区和暂存区中尚未提交的修改存入栈中。git stash apply
:将栈顶存储的修改恢复到当前分支,但不删除栈顶元素。git stash drop
:删除栈顶存储的修改。git stash pop
:将栈顶存储的修改恢复到当前分支,同时删除栈顶元素。git stash list
:查看栈抱歉,似乎在我的回答中遗漏了一部分内容。以下是完整的。git config --global user.name xxx
:设置全局用户名,信息记录在~/.gitconfig
文件中。git config --global user.email xxx@xxx.com
:设置全局邮箱地址,信息记录在~/.gitconfig
文件中。git init
:将当前目录配置成 git 仓库,信息记录在隐藏的.git
文件夹中。git add XX
:将XX
文件添加到暂存区。git add .
:将所有待加入暂存区的文件加入暂存区。git rm --cached XX
:将文件从仓库索引目录中删掉。git commit -m "给自己看的备注信息"
:将暂存区的内容提交到当前分支。git status
:查看仓库状态。git diff XX
:查看XX
文件相对于暂存区修改了哪些内容。git log
:查看当前分支的所有版本。git reflog
:查看HEAD指针的移动历史(包括被回滚的版本)。git reset --hard HEAD^
或git reset --hard HEAD~
:将代码库回滚到上一个版本。git reset --hard HEAD^^
:往上回滚两次,以此类推。git reset --hard HEAD~100
:往上回滚 100 个版本。git reset --hard 版本号
:回滚到某一特定版本。git checkout -- XX
或git restore XX
:将XX
文件尚未加入暂存区的修改全部撤销。git remote add origin git@git.acwing.com:xxx/XXX.git
:将本地仓库关联到远程仓库。git push -u
(第一次需要-u
以后不需要):将当前分支推送到远程仓库。git push origin branch_name
:将本地的某个分支推送到远程仓库。git clone git@git.acwing.com:xxx/XXX.git
:将远程仓库XXX
下载到当前目录下。git checkout -b branch_name
:创建并切换到branch_name
这个分支。git branch
:查看所有分支和当前所处分支。git checkout branch_name
:切换到branch_name
这个分支。git merge branch_name
:将分支branch_name
合并到当前分支上。git branch -d branch_name
:删除本地仓库的branch_name
分支。git branch branch_name
:创建新分支。git push --set-upstream origin branch_name
:设置本地的branch_name
分支对应远程仓库的branch_name分支。git push -d origin branch_name
:删除远程仓库的branch_name
分支。git pull
:将远程仓库的当前分支与本地仓库的当前分支合并。git pull origin branch_name
:将远程仓库的branch_name
分支与本地仓库的当前分支合并。git branch --set-upstream-to=origin/branch_name1 branch_name2
:将远程的branch_name1
分支与本地的branch_name2
分支对应。git checkout -t origin/branch_name
:将远程的branch_name
分支拉取到本地。git stash
:将工作区和暂存区中尚未提交的修改存入栈中。git stash apply
:将栈顶存储的修改恢复到当前分支,但不删除栈顶元素。git stash drop
:删除栈顶存储的修改。git stash pop
:将栈顶存储的修改恢复到当前分支,同时删除栈顶元素。git stash list
:查看栈中所有元素。