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. Referenced file contains errors (http://mybatis.org/dtd/mybatis-3-config.dtd). For more information, right click on the message in the Problems View and select "Show Details..."

    mybatis配置文件报错Referenced file contains errors mybatis的配置文件报错 The errors below were detected when vali ...

  2. SpringCloud Alibaba(六) - Seata 分布式事务锁

    1.Seata 简介 1.1 Seata是什么 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 AT.TCC.SAGA 和 XA 事 ...

  3. 【SQL真题】SQL3:每类视频近一个月的转发量/率

    题目: https://www.nowcoder.com/practice/a78cf92c11e0421abf93762d25c3bfad?tpId=268&tqId=2285068& ...

  4. 简单的Dos命令学习

    Dos命令学习 打开CMD的方式 从菜单栏打开,windows系统里 win+R 输入cmd 在任意文件夹下,按住shift+右键,点击打开PowerShell 在资源管理器的地址栏前面加上cmd+空 ...

  5. 详记apache-poi的使用,将word,excel,ppt转换为html

    原文:https://blog.51cto.com/yunyaniu/5210961 java:Java的jar包之POI的简介.安装.使用方法(基于POI的转换-Word.Excel.Ppt等转ht ...

  6. python中文词云生成

    一.词云 "词云"就是对网络文本中出现频率较高的"关键词"予以视觉上的突出,形成"关键词云层"或"关键词渲染",从而过滤 ...

  7. 同步异步、mutiprocessing创建进程process模块及进程对象的多种方法、消息队列Queue

    目录 同步异步 阻塞与非阻塞 综合使用 创建进程的多种方式之multiprocess.process模块 进程间数据隔离 进程的join方法 IPC机制 生产者 消费者模型 进程对象的多种方法 守护进 ...

  8. LeetCode HOT 100:最大子数组和

    题目:53. 最大子数组和 题目描述: 给你一个整数数组,在该数组的所有子数组中,找到一个子数组中所有元素相加和最大,返回这个最大的和.子数组就是一个数组中,由一个或几个下标连续的元素,组成的小数组, ...

  9. 基于.NetCore开发博客项目 StarBlog - (25) 图片接口与文件上传

    前言 上传文件的接口设计有两种风格,一种是整个项目只设置一个接口用来上传,然后其他需要用到文件的地方,都只存一个引用ID:另一种是每个需要文件的地方单独管理各自的文件.这俩各有优劣吧,本项目中选择的是 ...

  10. GC耗时高,原因竟是服务流量小?

    原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 最近,我们系统配置了GC耗时的监控,但配置上之后,系统会偶尔出现GC耗时大于1s的报警,排查花了一些力气,故在这里 ...