SQL注入

thinkphp基本没得SQL注入,除非魔改

ORM框架的错误使用

一个专门用来防御SQL注入的框架

错误写法-java/mybatis

<select id = "findUserByname" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User">
<!--拼接mysql,引起SQL注入-->
SELECT * FROM table WHERE username = '${username}'
</select> @Test
public void testFindUserByName() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用userMapper的方法
list<User> list = userMapper.findUserByName("fuckdada' and 1=1#");
sqlSession.close();
System.out.println(list);
}

分析:

SELECT * FROM table WHERE username = '${username}'
如果使用'#{value}'绑定对象,没有漏洞,#{value}会采用预编译的形式针对value进行绑定;会被替换成一个问号(?),并且有参数映射,在调用的时候,会明确?是一个变量,会返回java中找变量的输入("fuckdada' and 1=1#"),这就是预编译。
能够有效防止SQL 如果用${value},这就是一个拼接了。就能够试试注入

错误写法-python/flask/sqlalchemy模块

flask快速入门唯一一点小问题就是,最好用mysql,方便点

mysql增删改查

预编译快速入门

环境:python3+mysql(sqli-labs靶场的security数据库)

@app.route("/",methods=["GET"])
def test():
username = request.args.get("username")
res = db.session.query(table).filter("username='{}'".format(username))

分析:

db.session(table).fileter("username={}".format(username))
filter是支持预编译的,但是如果采用format进行填充数据,将会形成sql注入,
可以理解为:采用format直接填充数据之后就成了拼接 为什么说没有经过预编译呢?
因为,在执行中,先"username={}".format(username)进行了拼接,在给orm进行预编译,注入发生在编译之前

正确写法:

@app.route("/",methods=["GET"])
def test():
username = request.args.get("username")
res = db.session.query(table).filter(table.username == username))

然后花了一亿点时间写了个代码(我是真的没想到需要用单音号进行一个闭合呀)

sql_injection.py

from flask import Flask,request
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine,text
from models import Users app = Flask(__name__)
engine = create_engine("mysql+pymysql://root:123456@127.0.0.1:3306/security", max_overflow=0, pool_size=5,echo = True)
Connection = sessionmaker(bind=engine)
con = Connection() # ############# 执行ORM操作:查看 #############
@app.route("/inject",methods = ["POST"])
def inject():
# username = request.form.get("username")
username = request.form.get("username")
print("[*] input username: " + username)
# users_query = con.query(Users).filter(Users.username==username) # safe
# users_query = con.query(Users).filter(Users.username == "{}".format(username)) #safe
users_query = con.query(Users).filter(text("Users.username='{}'".format(username)))
users = users_query.all() #报错注入 if users:
for item in users:
print(item.username)
return users[0].password
return "not found" if __name__ == "__main__":
app.run()

modles.py(和上一个代码同级就行,虽然这里累赘了,就这吧累了)

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column,Integer,String,Text,ForeignKey,DateTime,UniqueConstraint,Index Base = declarative_base() class Users(Base):
__tablename__ = 'users'#database name
id = Column(Integer,primary_key=True)
username = Column(String(32),index=True,nullable=False) # name colume,Index,not null
password = Column(String(32),nullable = False) def set_data(self,username="",password=""):
self.username=username
self.password=password # def set_data(self,username="",password=""):
# self.id=id
# self.username=username
# self.password=password def init_db():
"""
根据类创建数据表中
return
"""
engine = create_engine(
"mysql+pymysql://root:123456@127.0.0.1:3306/security?charset=utf8",
max_overflow = 0, # 超过连接池大小外最多创建的连接
pool_size=5 ,# 连接池大小
pool_timeout = 30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1, # 多久之后对线程池中的线程进行一次连接的回收(重置)\
)
Base.metadata.create_all(engine) def drop_db():
"""
根据类删除数据库表
:return:
"""
engine = create_engine(
"mysql+pymysql://root:123456@127.0.0.1:3306/security?charset=utf8",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
) Base.metadata.drop_all(engine) if __name__ == '__main__':
# drop_db()
init_db()

接下来调试代码

有注入的

这里是username='-secure'#',这里是进行的拼接;不过当前的代码来看要是查不出user对象,这里是不会回结果的,而且对返回结果进行了指定。。。。

既然说了能注入,那就肯定能够注入,于是考虑使用布尔注入:注入如下

预编译的

SQL注入&预编译-奇安信攻防社区(写得真的好)

能够防止SQL注入;

这里在python中试了试,貌似不能够用%df;500了

SQL注入是在注入什么?

注入类型差异

核心思维:

SQL注入,就是执行一段SQL语句,关键在于SQL数据库类型

编程语言:

不同编程语言最终的目的都是为了将payload送入数据库层进行执行,能够看到注入点即可,语言不重要

产生注入的输入点

输入点决定了用什么样的Vector,以及是否需要绕过

SQL注入结构

一般来说,一个普通的SQL注入结构如下

action:select
object:table
subject(target):*
condition:
key:usersname
value:$username// user input

如果能够执行执行堆叠注入(是否能够加分号;),那么能够跳出action:select,执行更多的操作如,action:delete action:update

爆破数据的速度

报错 = 联合注入>外带数据>布尔盲注>时间盲注

为什么把报错放在第一位?

实际环境中,联合注入不一定能够构造出来,报错注入范围更加广阔,某些情况下,报错比联合快

输入点很多

不同的输入点有不同注入方式,代表着能不能绕过框架什么的,例如在预编译中,order之后能绕鱼变意思

可能进行SQL注入

宽字节注⼊

们知道字节是计算机存储世界中最⼩的衡量单位,1Byte = 8bits。所以⼀个字节最⼤能够表
示2^8=256个字符。
所以:
对ascii编码⽽⾔,⼀个字符⽤⼀个字节就可以表示,所以ascii编码最多可以表示256个字
符。
对GBK编码⽽⾔,⼀个汉字字符需要⽤两个字节表示。所以gbk编码理论上最多可以表示
256*256个字符。

案例:看SQLlabs的宽字节就行

<?php
$db = init_db();
$db->query("set SET NAMES 'gbk'); //设置gbk字符集
$username = addslashes($_GET['username']); //input: fuckdada' and 1=1#
$db->query("select * from table where username = '$username'");
?>

编码规范

要用%df吃到后面的字符,需要看编码规范

例如:要吃掉第二字节,需要用第一字节范围中的给出的才能吃掉

Hsql

Hibernate是⼀种ORM框架,⽤来映射与tables相关的类定义(代码),并包含⼀些⾼级特 性,包括缓存以及继承,通常在Java与.NET中使⽤(可参考NHibernate),但在Java⽣态系 统中更受欢迎。近来似乎逐渐有被Mybatis取代的趋势。

与Mybatis不同的是,Hibernate虽然也⽤了xml作为映射模型。但是他构成了⼀套⾃⼰的解析 引擎和语法,也就是HQL

https://www.cnblogs.com/chenssy/archive/2012/07/17/2594919.html
https://blog.51cto.com/jiaojusuimu/1881287

用户的输⼊作为HQL的⼀部分,先经过Hibernate解析引擎,渲染成sql语句,然后再进⼊到 数据库层进⾏查询。

所以不仅需要满足HQL的规范,同样需要满足渲染之后SQL的语法规范;

目前一般不考虑sql能够完全执⾏成功,⽽是利⽤sql报错注⼊+框架开启报错(因为java很多框架中都开启了报错),将有⽤的数据直接在错误回显中爆出来;

https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/hqlinjection-exploitation-in-mysql/
https://blog.sonarsource.com/exploiting-hibernate-injections/
https://www.sec-in.com/article/144
https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20In
jection/HQL%20Injection.md
https://conference.hitb.org/hitbsecconf2016ams/materials/D2T2%20-
%20Mikhail%20Egorov%20and%20Sergey%20Soldatov%20-
%20New%20Methods%20for%20Exploiting%20ORM%20Injections%20in%20Java%20App
lications.pdf

预编译之下的注入(复现失败)

php预编译——宽字节绕过

<?php
$username = $_GET['username'];
$db = "mysql:host=127.0.0.1;dbname=test;charset=gbk";
$dbname = "root";
$passwd = "root";
$conn = new PDO($dbs, $dbname, $passwd);
$conn->query('SET NAMES GBK');
$stmt = $conn->prepare("select * from table where username =
:username");
$stmt->bindParam(":username",$username);
$stmt->execute();
?

开始日志:(默认没开启,网上找一个一堆开慢查询的....)(51才是nb的)

但就查看的日志而言,貌似%df吃不了。。。(要是师傅们测试能过,能给俺教学一手吗?)

无法预编译的点

like后

这⾥再展开讲讲那些没办法⽤orm(没办法预编译)去保护的输⼊点,并且这种是通例,也就 是⽆视语⾔的。

在sql语句的模糊查找⾥⾯⽤的关键字like,⽽like关键字默认是不会预编译的(如果使⽤ Mybatis则是预编译报错)。数据库⽅给出的原因好像是like预编译会造成慢查询和DOS。

yu6.php
<?php
$username = $_POST['username']; // 接收username
# 建立数据库连接
$dbs = "mysql:host=127.0.0.1;dbname=security";
$dbname = "root";
$passwd = "123456";
// 创建连接,选择数据库,检测连接
try{
$conn = new PDO($dbs, $dbname, $passwd);
echo "Sucussful<br/>";
}
catch (PDOException $e){
die ("Error!: " . $e->getMessage() . "<br/>");
}
# 预编译语句
$conn -> setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
// $stmt = $conn->prepare("select * from users where username like '%:username%'"); #无预编译
$stmt = $conn->prepare("select * from users where username like concat('%',:username,'%')"); #生效
$stmt->bindParam(":username",$username);
$stmt->execute();
$row = $stmt->fetch();
print_r($stmt);
print_r($row);
// print("asdf");
$conn=null; # 关闭链接
?>

结果:

这里指的无法预编译,就直接连'%username%'都没变。

(麻了,我突然发现,为什么我昨天测试python的时候不直接开日志呢。。。。找了半天在命令行输出语句。。。。)

当然,改一下语句,用concat拼接能够执行预编译

不能加引号的地方无法预编译

在执行结果日志中看到,执行预编译的地方都会被加双引号

预编译步骤:
1. 执行 addslashes($data),为特殊字符转义
2. 强制加上单引号进行拼接,select * from users where username = '${data}'

由于会强制加上双引号,但是在执行原生SQL的时候,有的地方加不得,例如表名、列名、limit⼦句、order by[desc/asc];

例如给表名加上单引号,会被当做字符串进行输出

例如给列名加上单引号,会报错

所以当程序在特殊位置不能加预编译,就可以考虑一手注入

虽然可以人为加过滤,但是好歹绕了预编译;

[代码审计基础 02]-SQL注入和预编译和预编译绕过的更多相关文章

  1. php代码审计--sql注入

    sql注入是web安全中最常见,也是平常中危害最大的漏洞. 最近在学习代码审计,拿自己审核的一段代码做个笔记. 1.sql语句拼接可能引起sql注入 很多偷懒的程序员对于没有过滤的参数,直接将其拼接到 ...

  2. 代码审计中的SQL注入

    0x00 背景 SQL注入是一种常见Web漏洞,所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令.本文以代码审计的形式研 ...

  3. php代码审计3审计sql注入漏洞

    SQL注入攻击(sql injection)被广泛用于非法获取网站控制权,在设计程序时,忽略或过度任性用户的输入,从而使数据库受到攻击,可能导致数据被窃取,更改,删除以及导致服务器被嵌入后门程序等 s ...

  4. Java代码审计连载之—SQL注入

    前言近日闲来无事,快两年都没怎么写代码了,打算写几行代码,做代码审计一年了,每天看代码都好几万行,突然发现自己都不会写代码了,真是很DT.想当初入门代码审计的时候真是非常难,网上几乎找不到什么java ...

  5. 2020/1/27代码审计学习之SQL注入漏洞

    PHP代码审计SQL注入漏洞 0x00 首先明确什么是SQL注入,SQL语句必须掌握. 常见的注入总的来说可以分为两大类:数字型和字符型. 这两类中包含了诸如报错注入,宽字节注入,盲注,二次注入,co ...

  6. 2019-9-10:渗透测试,基础学习,sql注入笔记

    sql注入1,万能密码,自己写的网站,找到登录窗口,必须和数据库交互,往里插入构造的恶意代码,最后可以直接登录进去,不需要账号和密码,输入的恶意代码成为万能密码,后端拼接的sql语句,SELECT * ...

  7. 在SQL注入中利用MySQL隐形的类型转换绕过WAF检测

    web应用一般采用基于表单的身份验证方式(页面雏形如下图所示),处理逻辑就是将表单中提交的用户名和密码传递到后台数据库去查询,并根据查询结果判断是否通过身份验证.对于LAMP架构的web应用而言,处理 ...

  8. 面试题--如何防止sql注入,使用PreparedStatement的预编译,传入的内容就不会和原来的语句发生任何匹配的关系,达到防止注入的方法

    PreparedStatement的用法 jdbc(java database connectivity,java数据库连接)的api中的主要的四个类之一的java.sql.statement要求开发 ...

  9. WEB安全基础之sql注入基础

    1.基础sql语句 注释 单行注释# %23--+ --加空格多行注释/**/ SELECT(VERSION()) SELECT(USER()) SELECT(database()) 查数据库 SEL ...

  10. 【代码审计】VAuditDemo SQL注入漏洞

    这里我们定位 sqlwaf函数 在sys/lib.php中,过滤了很多关键字,但是42 43 44行可以替换为空 比如我们可以 uni||on来绕过过滤

随机推荐

  1. oracle 内置函数(三)日期函数

    日期函数概要: 系统时间 日期操作 一.系统时间 sysdate:还是西方的格式,我们一般需要to_char(date,'yyyy-mm-dd hh24:mi:ss') next_day:当前日期的下 ...

  2. 【PostgreSQL】PG通过SQL语句读取二进制bytea类型并进行二进制和十六进制转换

    1.将二进制编码为十六进制 select encode("AUUID_0",'hex'),"AUUID_0" from wxf_test."ABANK ...

  3. 【HBase】简介、结构、数据模型、快速入门部署、shell操作、架构原理、读写数据流程、数据刷写、压缩、分割、Phoenix、表的映射、与hive集成、优化

    一.简介 1.定义 分布式.可扩展.支持海量数据存储的NoSQL数据库 2.数据模型 2.1逻辑结构 2.2物理存储结构 2.3数据模型介绍 Name Space:相当于数据库,包含很多张表 Regi ...

  4. 如何使用Java获取货币符号?

    1. 前言 最近做了一个支付相关的需求,要求在收银台页面显示商品的价格时带上货币符号¥,类似下图中的格式: 最初我是用的下面这样的代码: System.out.println(Currency.get ...

  5. 为文本框控件添加滚动条-CEdit

    在VS2015环境下操作 创建文本框控件 设置控件属性 效果

  6. “喜提”一个P2级故障—CMSGC太频繁,你知道这是什么鬼?

    大家好,我是陶朱公Boy. 背景 今天跟大家分享一个前几天在线上碰到的一个GC故障- "CMSGC太频繁". 不知道大家看到这条告警内容后,是什么感触?我当时是一脸懵逼的,一万个为 ...

  7. 分享项目中在用的asp.net下载业务的服务端基类(支持客户端显示下载百分比进度,支持并发数控制,支持限速)

    /// <summary> /// 功能简介:asp.net的下载业务的服务端基类(支持客户端显示下载百分比进度,支持并发数控制,支持限速) /// 创建时间:2015-11-20 /// ...

  8. 数据分析中的SQL如何解决业务问题

    本文来自知乎问答. 提问:数据分析人员需要掌握sql到什么程度? 请问做一名数据分析人员,在sql方面需要掌握到什么程度呢?会增删改查就可以了吗?还是说关于开发的内容也要会?不同阶段会有不同的要求吗? ...

  9. css、js 缓存清除

    此种方式完美达到了清除缓存的效果 css引入标签可在一个引号内完成,js引入标签由于解析原因需要将两个标签拆开再组 使用:按照此格式,放在原 <link /> 或 <script&g ...

  10. ArcGIS工具 - 按线分割面

    功能说明 在ArcGIS数据处理过程中,有时需要沿线把面要素分割开,可以使用高级编辑中的分割面(Cut Polygon)工具.那么,如果要用线图层分割面图层该怎么办呢?为源GIS为您开发了一个自定义模 ...