一、前言
最近学Pwn有点遇到瓶颈了,干脆停下来整理下前面的知识。刚入门的时候最头疼的就是配置Pwn的环境,也是做了很多试错,最后敲定了wsl+docker的方案,下面给大家分享下。
二、Docker in WSL
简而言之,Windows Subsystem for Linux(WSL)是集成于Windows系统的Linux虚拟机,相比例如VMWare的其他虚拟机软件,突出的特点是启动特别快;以及你可以直接用Windows文件资源管理器(explorer.exe)访问Linux文件系统,非常令人满足。
在2023年,WSL的安装非常简单。我在这里直接引用微软文档里的原话:可以使用单个命令安装 WSL 所需的一切。 在管理员模式下打开 PowerShell 或 CMD,输入 wsl --install 命令,然后重启计算机。
wsl --install
如果你的网络通畅的话,喝杯茶上个厕所,回来就差不多该提示你重启了。重启之后再次运行wsl
(可能也不用手动运行,我记得好像重启之后WSL终端会自己弹出来),然后按照提示配置用户名密码,你的Linux环境就搞定了。
Docker是另一种虚拟化技术。简单地可以理解为它用于在Linux系统(是的,Linux系统,这也是为什么我们要装WSL)中启动更加轻量的虚拟机。关于Docker的入门知识,我强烈推荐这篇Docker从入门到实践,花上一两个小时把这篇文章过一遍,非常有帮助。
但在此之前,我们需要先安装Docker。如果你看了之前那篇微软的文档,你可能已经找到了这篇WSL 2 上的 Docker 远程容器入门。跟着文档做就好,我也说不出什么别的需要注意的了。文档里提到了安装 Visual Studio Code和安装 Windows 终端两个选做,对于我们的需求来说都是必做,别偷懒。
在正式尝试Docker之前,另一项重要工作是给Docker换源(一点也不出人意料呢)。参照这篇博客docker 设置国内镜像源,选一个国内镜像源地址,推荐用阿里云的那个。但那篇里的“修改方法”里说的改/etc/docker/daemon.json
对我们是没用的,高贵的docker-desktop用图形界面。如下图所示进到docker gui的设置界面,选择docker engine选项卡,填上registry-mirrors
配置项。
同样在设置里,确认你打开了docker的wsl集成。
一切顺利的话,你已经可以在WSL中使用Docker了。
再次提示,如果你对Docker还不太了解,花些实践阅读Docker从入门到实践。你现在可以在你的系统中实践上面的操作了。
在WSL系统中,使用
code .
命令用vscode打开当前文件夹,使用explorer.exe .
用Windows文件资源管理器打开当前文件夹。
三、DockerFile
写累了,明儿再写,这里先给一个DockerFile的参考:或者直接用skysider师傅的pwndocker。
FROM ubuntu
WORKDIR /root
COPY ./sources.list /etc/apt/sources.list
COPY ./pwn ./pwn
# 处理32位程序支持
RUN dpkg --add-architecture i386 \
&& apt-get update \
&& apt-get install -y libc6:i386 libncurses5:i386 libstdc++6:i386 zlib1g:i386
# 安装实用程序
RUN apt-get install -y openssh-server gdb tmux vim netcat
# 安装python相关组件
RUN apt-get install -y python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential \
&& python3 -m pip install --upgrade pip \
&& python3 -m pip install --upgrade pwntools \
&& python3 -m pip install --upgrade LibcSearcher
# 安装pwndbg
COPY ./pwndbg-dev ./pwndbg-dev
WORKDIR /root/pwndbg-dev
RUN chmod +x ./setup.sh \
&& ./setup.sh \
&& echo "export LANG=C.UTF-8" >> /root/.bashrc
WORKDIR /root
# Configure SSH server
RUN mkdir /var/run/sshd \
&& echo 'root:pwn' | chpasswd \
&& sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd \
&& echo "export VISIBLE=now" >> /etc/profile
COPY ./sshd_config /etc/ssh/sshd_config
ENV NOTVISIBLE "in users profile"
# 暴露SSH端口
EXPOSE 22
# 暴露ida Linux调试器端口;不过好像用不太上
EXPOSE 23946
# start sshd
CMD ["/usr/sbin/sshd","-D"]
# docker run -d --name zzpwn -p 32222:22 -p 23946:23946 zzkluck/pwnenv
使用时用vscode的ssh插件连进去就好了。
四、基础模板
首先是一个小脚本setup.sh
用于第一次把二进制文件拷贝到环境中之后的初始化,减少了一些重复性的劳作:
#!/bin/bash
echo $1
pwn=$1
export pwn
chmod +x $pwn
checksec $pwn
$pwn
使用source
调用:
source setup.sh ~/your_path/your_pwn_binary
第二个要分享的是pwntools的python模板pwn_init.py
,用于另一些重复劳作:
from pwn import * # 引入pwntools
from pwnlib.util.packing import p64, u64, p32, u32 # 帮助编辑器找到符号,消除warning
from os import getenv # 通过读取环境变量自动获取目标文件
# 由pwntools提供的简单易用命令行参数解析器
# https://docs.pwntools.com/en/stable/args.html
online = args.R
debug = args.D
libc_local = args.L
# 决定使用哪一种LibcSearcher
if libc_local:
import sys
sys.path.append('/root/LibcSearcher-master')
from LibcSearcher_local import LibcSearcher
else:
from LibcSearcher import LibcSearcher
# 设置pwntools日志级别,根据需要在info和debug之间切换
context.log_level = 'info'
# 指定tmux,使得gdb调试时可以分屏
context.terminal = ['tmux','splitw','-h']
# 从环境变量$pwn中获取目标文件位置
target_file = getenv('pwn')
# “The recommended method is to use context.binary to automagically set all of the appropriate values.”
# --- https://docs.pwntools.com/en/stable/context.html
# pwntools能够从二进制文件中自动解析context信息,主要是程序的32/64bits信息
context.binary = target_file
elf = context.binary
# 根据推断的程序位数决定libc
if elf.bits == 32:
libc_file = '/lib/i386-linux-gnu/libc.so.6'
else:
libc_file = '/lib/x86_64-linux-gnu/libc.so.6'
libc_ld = None
# 当然,也可以指定特定的libc,需要同时指定ld
# libc_file = 'libc/libc-2.23-u16-64.so'
# libc_file = "glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so"
# libc_ld = 'glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so'
libc = ELF(libc_file)
# 根据命令行参数选择启动方式,远程、调试或者直接运行
run_target = [target_file] if libc_ld is None else [libc_ld, target_file]
if online:
p = remote('node4.buuoj.cn', int(args.R))
elif debug:
p = gdb.debug(run_target, '''
b *_start
''', env={'LD_PRELOAD': libc_file})
else:
p = process(run_target, env={"LD_PRELOAD": libc_file})
p.info("Init Success!")
初始化模板完成以下几个任务:
- 根据命令行标志
L
决定选择哪个版本的LibcSearcher; - 配置pwntools日志级别;
- 配置tmux分屏;
- 从环境变量$pwn读取由setup.sh指定的二进制文件位置;
- 推断或指定所需的libc,并配置程序运行时使用指定的libc;
- 如果指定了命令行标志
R
,则远程连接到靶场运行; - 如果指定了命令行标志
D
,则挂载GDB调试运行。
对于攻击脚本exp.py
,按以下方法使用:
from pwn import *
from pwnlib.util.packing import p64, u64, p32, u32
from pwn_init import p, elf, libc, LibcSearcher
# ---------------------------------------
# ------ Assistant Function Here ------
# ---------------------------------------
def foo():
pass
# ------------------------------
# ------ Your Code Here ------
# ------------------------------
foo()
p.interactive()