1.1 登陆位置注入测试

后台登陆系统注入在前些年是非常常见的,我们通常会使用' or '1'='1之类的注入语句来构建一个查询结果永为真的SQL,俗称:万能密码
示例 - 用户登陆注入代码:

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <%@ page import="java.sql.Connection" %>
  3. <%@ page import="java.sql.DriverManager" %>
  4. <%@ page import="java.sql.ResultSet" %>
  5. <%@ page import="java.util.HashMap" %>
  6. <%@ page import="java.util.Map" %>
  7. <%
  8. // MYSQL sys_user示例表,测试时请先创建对应的数据库和表
  9. //
  10. // CREATE TABLE `sys_user` (
  11. // `id` int(9) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  12. // `username` varchar(16) NOT NULL COMMENT '用户名',
  13. // `password` varchar(32) NOT NULL COMMENT '用户密码',
  14. // `user_avatar` varchar(255) DEFAULT NULL COMMENT '用户头像',
  15. // `register_time` datetime DEFAULT NULL COMMENT '注册时间',
  16. // PRIMARY KEY (`id`),
  17. // UNIQUE KEY `idx_sys_user_username` (`username`) USING BTREE
  18. // ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='系统用户表'
  19. //
  20. // INSERT INTO `sys_user` VALUES ('1', 'admin', '123456', '/res/images/avatar/default.png', '2020-05-05 17:21:27'), ('2', 'test', '123456', '/res/images/avatar/default.png', '2020-05-06 18:27:10'), ('3', 'root', '123456', '/res/images/avatar/default.png', '2020-05-06 18:28:27'), ('4', 'user', '123456', '/res/images/avatar/default.png', '2020-05-06 18:31:34'), ('5', 'rasp', '123456', '/res/images/avatar/default.png', '2020-05-06 18:32:08');
  21. %>
  22. <%
  23. String sessionKey = "USER_INFO";
  24. Object sessionUser = session.getAttribute(sessionKey);
  25. // 退出登陆
  26. if (sessionUser != null && "exit".equals(request.getParameter("action"))) {
  27. session.removeAttribute(sessionKey);
  28. out.println("<script>alert('再见!');location.reload();</script>");
  29. return;
  30. }
  31. Map<String, String> userInfo = null;
  32. // 检查用户是否已经登陆成功
  33. if (sessionUser instanceof Map) {
  34. userInfo = (Map<String, String>) sessionUser;
  35. out.println("<p>欢迎回来:" + userInfo.get("username") + ",ID:" + userInfo.get("id") + " \r<a href='?action=exit'>退出登陆</a></p>");
  36. return;
  37. }
  38. String username = request.getParameter("username");
  39. String password = request.getParameter("password");
  40. // 处理用户登陆逻辑
  41. if (username != null && password != null) {
  42. userInfo = new HashMap<String, String>();
  43. ResultSet rs = null;
  44. Connection connection = null;
  45. try {
  46. Class.forName("com.mysql.jdbc.Driver");
  47. connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/javaweb-bbs", "root", "root");
  48. String sql = "select id,username,password from sys_user where username = '" + username + "' and password = '" + password + "'";
  49. System.out.println(sql);
  50. rs = connection.prepareStatement(sql).executeQuery();
  51. while (rs.next()) {
  52. userInfo.put("id", rs.getString("id"));
  53. userInfo.put("username", rs.getString("username"));
  54. userInfo.put("password", rs.getString("password"));
  55. }
  56. // 检查是否登陆成功
  57. if (userInfo.size() > 0) {
  58. // 设置用户登陆信息
  59. session.setAttribute(sessionKey, userInfo);
  60. // 跳转到登陆成功页面
  61. response.sendRedirect(request.getServletPath());
  62. } else {
  63. out.println("<script>alert('登陆失败,账号或密码错误!');history.back(-1)</script>");
  64. }
  65. } catch (Exception e) {
  66. out.println("<script>alert('登陆失败,服务器异常!');history.back(-1)</script>");
  67. } finally {
  68. // 关闭数据库连接
  69. if (rs != null)
  70. rs.close();
  71. if (connection != null)
  72. connection.close();
  73. }
  74. return;
  75. }
  76. %>
  77. <html>
  78. <head>
  79. <title>Login Test</title>
  80. </head>
  81. <body>
  82. <div style="margin: 30px;">
  83. <form action="#" method="POST">
  84. Username:<input type="text" name="username" value="admin"/><br/>
  85. Password:<input type="text" name="password" value="'=0#"/><br/>
  86. <input type="submit" value="登陆"/>
  87. </form>
  88. </div>
  89. </body>
  90. </html>

sys_user表结构如下:

id username password user_avatar register_time
1 admin 123456 /res/images/avatar/default.png 2020-05-05 17:21:27
2 test 123456 /res/images/avatar/default.png 2020-05-06 18:27:10

访问示例中的后台登陆地址:http://localhost:8000/modules/jdbc/login.jsp,如下图:
2. 1. 用户后台系统登陆注入 - 图1
攻击者通过在密码参数处输入:'=0#即可使用SQL注入的方式改变查询逻辑,绕过密码认证并登陆系统,因此用于检测用户账号密码是否存在的SQL语句变成了:select id,username,password from sys_user where username = 'admin' and password = ''=0#'
其中的password的值预期是传入用户密码,但是实际上被攻击者传入了可改变查询逻辑的SQL语句,将运算结果改变为true,从而攻击者可以使用错误的用户及密码登陆系统,如下图:
2. 1. 用户后台系统登陆注入 - 图2
毫无疑问因为攻击者输入的信息足够的短小简洁,但是对于用户网站系统来说却有极强的杀伤性,绝大多数的WAF或者RASP产品都无法精准辨别'=0#的威胁性,无法正确做到精准防御。
万能密码登陆注入原理图解:
2. 1. 用户后台系统登陆注入 - 图3