首页
关于
友链
Search
1
设备部署-NIDS入侵检测系统-Snort&Suricata
5 阅读
2
从方法重写到SQL注入-信呼OA审计
5 阅读
3
CVE-2025-11001
4 阅读
4
设备部署-HIDS入侵检测系统-Elkeid&Wazuh
4 阅读
5
Web入侵分析入口思路
3 阅读
蓝队
应急响应
设备部署
二进制
基础
代码审计
基础理论
实践分析
登录
Search
标签搜索
学习笔记
蓝队
应急响应
代码审计
设备部署
内存马查杀
IDS
漏洞复现
JumpServer
HFish
雷池WAF
HIDS
Snort
Suricata
NIDS
Yara规则识别样本
ELK日志分析系统
Rookit查杀
容器应急
docker
N0va7
累计撰写
31
篇文章
累计收到
1
条评论
首页
栏目
蓝队
应急响应
设备部署
二进制
基础
代码审计
基础理论
实践分析
页面
关于
友链
搜索到
7
篇与
的结果
2025-09-10
SQL注入的本质-是什么数据库
SQL注入的基础代码以下知识仅为个人学习过程中的记录<?php $db = init_db(); $username = $_GET['username']; //input: 111' and 1=1# $db->query("select * from table where username = '$username'"); ?>string connectionstring = "xxx"; SqlConnection con = new SqlConnection(connectionstring); con.Open(); string idCard = Request.QueryString["idCard"]; string sql = "select * from table where idCard = '" + idCard + "'"; SqlDataAdapter adapter = new SqlDataAdapter(sql, con); DataSet dataSet = new System.Data.DataSet(); adapter.Fill(dataSet); con.Close()conn = DBHerpel.getConnection(); if (conn == null) return; String username = request.getParameter("username"); String Sql = "select * from table where username = '" + username + "'"; stt = conn.createStatement(); set = stt.executeQuery(Sql);@app.route("/", methods=["GET"]) def test(): username = request.args.get('username') sql = "select * from table where username = '" + username + "'" conn = connect(host='localhost',port=3306,user='root',password='',database='test',charset='utf8') cs1 = conn.cursor() count = cs1.execute(sql)哪怕不是全部了解上面的语言,也可以看出来,这些代码都是没有使用ORM框架,直接调用原生数据库操作函数的实例。(ORM框架其实本身也是调用原生数据库操作函数,但是它做了一些封装和映射,只要按照规范写法,现代ORM基本都加了一些过滤在里面)通过上面的代码,可以很明显看出来,这些sql语句都是拼接构成的,所以说他们都存在SQL注入,在数据库层面中的数据流(SQL语句)侵入到了控制流。通常这种漏洞点大概率会在不同层面组件的交汇点,像上面就是代码层和数据库层的交汇点出现了SQL注入。调用ORM的错误写法PHP对于PHP来说没有什么特别出名的ORM框架,基本都是各个Web开发框架自带的ORM。对于这种情况,可以直接审计对应Web开发框架,因为这些开发框架/CMS的ORM可能写的并不规范,没有专门针对这方面进行维护,所以说相对而言存在漏洞点的可能更高。Java/MybatisMybatis需要有一个xml配置文件来绑定映射关系<select id="findUserByName" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User"> <!-- 拼接 MySQL,引起 SQL 注⼊ --> SELECT * FROM table WHERE username = '${value}' </select>@Test public void testFindUserByName() throws Exception{ SqlSession sqlSession=sqlSessionFactory.openSession(); //创建UserMapper代理对象 UserMapper userMapper=sqlSession.getMapper(UserMapper.class); //调⽤userMapper的⽅法 List<User> list=userMapper.findUserByName("fuck' and 1=1#"); sqlSession.close(); System.out.println(list); }Mybatis存在两种变量绑定方式,分别是#{}和${}#是绑定变量的形式,底层会将#{}替换为?,有参数映射会在DefaultParameterHandler中进⾏设置占位符的操作,这就是预编译$也是绑定变量的形式,{value}是直接被替换成对应的值,没有参数映射,不会进行设置占位符的操作,本质上就是拼接在代码审计中可以直接搜$符号,针对小型的CMS来说简单而有效Python/SqlalchemySqlalchemy是Flask最经常配套使用的ORM框架,在许多的Django项目中也经常使用,是目前Python语言中最火的ORM框架@app.route("/", methods=["GET"]) def test(): username = request.args.get('username') res = db.session.query(table).filter("username={}".format(username))这个存在漏洞的原因是跟上面的Mybatis差不多,就是先"username={}".format(username)拼接字符串,然后再使用ORM框架进行查询,这个地方就是不同层面的交汇处,因为不规范的写法导致SQL注入正规写法如下:@app.route("/", methods=["GET"]) def test(): username = request.args.get('username') res = db.session.query(table).filter(table.username == username)SQL注入到底是在干什么重要核心看完了上面的原生数据库操作函数的调用导致的SQL注入以及ORM框架的错误写法导致的SQL注入,我们知道SQL注入到底是在干什么吗?不需要特别关心SQL注入的类型有哪些,像什么联合查询注入、二次注入、布尔盲注等其实,仔细总结上面的内容,可以得出一个结论:SQL注入就是去执行一段SQL语句,而这个SQL语句长什么样子,关键跟数据库类型有关不同的编程语言他们最终的目的都是将SQL语句送入数据库层进行执行,我们只要能发现注入点即可,至于用什么开发语言都是一样的对于注入类型注入类型相对于开发语言来说比较重要一些,不需要特别关注,但是我们得知道一些关键点能否堆叠注入像上面提到的,一条SQL语句最终会被解析成一段控制序列action(动作): select object(对象): table subject(⽬标客体): * condition(条件): key: username value: $username // ⽤户输⼊如果能够使用堆叠注入的话,那么我们就会跳出action的动作,进而执行其他动作,这样造成的危害程度肯定会更高但是堆叠注入的出现越来越少,一般情况下:Mssql数据库的堆叠注入最多;Oracle数据库的数量少一些;Mysql不多爆数据的速度报错~=联合查询>带外查询>布尔盲注>时间盲注对于输入点当我们发现一个注入点,我们也要关注这个注入点在SQL语句中的输入位置,根据不同的输入点,我们需要采用不同的payload,同时也要考虑是否需要进行绕过,后面的内容会联动这点select $username$,password from $table$ where $username2$ = '$xxx$' order by $username3$ desc limit $0$,1有撸点的SQL注入类型宽字节注入概念我们知道字节是计算机存储世界中最⼩的衡量单位,1Byte = 8bits。所以⼀个字节最⼤能够表示2^8=256个字符。所以:对ascii编码⽽⾔,⼀个字符⽤⼀个字节就可以表示,所以ascii编码最多可以表示256个字符。对GBK编码⽽⾔,⼀个汉字字符需要⽤两个字节表示。所以gbk编码理论上最多可以表示256*256个字符。利用方式<?php $db = init_db(); $db->query("SET NAMES 'gbk'); //设置gbk字符集 // addslashes会自动对单引号转义 $username = addslashes($_GET['username']); //input: fuck' and 1=1# $db->query("select * from table where username = '$username'"); ?>select * from table where username = 'fuck\' and 1=1#'SQL语句如上所示,在代码层会被直接插入一个\符号,从而对单引号进行转义,这样我们就没法入侵到控制流了但是当我们输入是这样的时候,就会出现不一样的效果了fuck%df\' and 1=1#数据在存储时采用字节方式存储,但是解读时采用字符标准去解读。而字符标准跟采用什么字符集有关系。所以在连接数据库执行SQL语句时(这时候就是对数据的解读),会按照字符集编码的规则去解读。而当遇到\xDF\x5C时,就会解读成運转码网站:https://www.23bei.com/tool/54.html#\x5c就是\的十六进制表示这里补充一下,并非只有\xdf才可以和\x5c组成字符,其他字符也OK,不必纠结这个,具体哪些字符组合可以自行查阅GBK编码情景利用所以在代码审计中审阅宽字节注入的方式就是查看数据库连接文件(一般是conn.php这种)。检查其字符集是否为utf-8,如果不是utf-8,那么就有可能产生注入参考文章https://xz.aliyun.com/news/1477?time__1311=eqIx9DBDnGDQitD%2F82xBKcAOzddx2AbD&u_atoken=2997a913f8636a69d9eae6cbcac41657&u_asig=1a0c380917410698476814249e0038预编译模式下的注入宽字节注入<?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(); ?>看似进行预编译好像安全了,但是在这种情况下是无法解决宽字节注入的问题的因为,在数据的流转中是这样的$stmt = $conn->prepare("select * from table where username = :username"); ==>sql = "select * from table where username = '${addslashes($input)}'"在此处我们有发现了addslashes这个函数,那不是跟传统的宽字节注入绕过方法一样吗?所以在这种情况下,预编译是不起作用的一些无法预编译的点既然讲到预编译不起作用,那么这部分聊聊那些没法通过ORM/预编译去保护的输入点,这种情况是通用的,无视任何语言like&in关键字我们知道sql语句的模糊查找⾥⾯⽤的关键字like。⽽like关键字默认是不会预编译的(如果使⽤Mybatis则是预编译报错)。数据库⽅给出的原因好像是like预编译会造成慢查询和DOS。所以对于like关键字,只能通过手动添加预编译来解决。一些开发只会照着以往的样子进行编写,不会知道like关键字的预编译会失效,所以这时候就给了我们可趁之机<?php $username = $_GET['username']; $db = "mysql:host=127.0.0.1;dbname=test;"; $dbname = "root"; $passwd = "root"; $conn = new PDO($dbs, $dbname, $passwd); $conn->query('SET NAMES GBK'); $stmt = $conn->prepare("select * from table where username like '%:username%'"); //不⽣效 $stmt = $conn->prepare("select * from table where username like concat('%',:username,'%'"); //⽣效 $stmt->bindParam(":username",$username); $stmt->execute(); ?>一些Java开发发现Mybatis编译报错,他就会改用$符号,或者直接就不写预编译。如果开发手写预编译的话,也可能没有那么完善,存在绕过的机会。同样的,in关键字也是默认不能进行预编译的,需要在预编译语法中去for循环,有些开发为了方便,写的代码少一些,就可能在这边偷工减料不能加引号的关键字结合我们上面看到宽字节绕过预编译,我们可以看到预编译+绑定变量的效果大概有两个步骤$str = addslashes($input) //内容转义 $sql = "select * from table where column = '$str'" //强制使用单引号包裹结合我们上面提到的产生注入的输入点select $username$,password from $table$ where $username2$ = '$xxx$' order by $username3$ $desc$ limit $0$,1观察上面SQL语句中的输入点,有哪些地方是必然不能加单引号的呢?如果这个地方不能加单引号,那么就无法进行预编译于是整合如下:$username$,$table$,$username2$,$username3$,$desc$,$0$也就是说列名、表名、limit子句、order by[desc/asc]都不能添加单引号,所以他们都不能进行预编译。在这种情况下,开发可能会遗漏这些点的检测,导致存在注入。参考文章https://forum.butian.net/share/1559http://cn-sec.com/archives/286656.htmlhttps://codeantenna.com/a/WzaLCig9qw权限认知-数据平面一些权限的例子在cms/web层⾯:web后台管理员权限>web前台会员权限>游客权限在数据库层⾯:root⽤户/sa⽤户/postgres⽤户>普通杂七杂⼋⽤户在操作系统层⾯:root > 所有其他⽤户对于权限的重要认知认清数据平面未授权RCE我们以游客的权限,拿到⼀个rce漏洞(也就是未授权rce),那么我们的权限是什么?是web后台管理员权限吗?并不是,而是操作系统权限,此时我们的数据平面在操作系统层面在操作系统层⾯,我们的**bash进程是httpd进程派⽣的,所以与httpd进程是同层级的,所以此时我可以读写web⽬录的任意⽂件(前提是web⽬录本身对httpd可读写)**SQL注入如果我们以游客权限,拿到⼀个sql注⼊点,那么我们的权限是什么?是web后台管理员权限吗?并不是,而是数据库权限,此时我们的数据平面在数据库层面在数据库层⾯,我们⽬前就是mysql进程维护的⼀个通信线程,我们就是数据库的root或者普通库权限(取决于web数据库配置⽂件中定义的⽤户)。SQL注入到命令执行如果我们以游客权限,拿到⼀个sql注⼊点,并且这个注⼊点可以执⾏命令,那么我们的权限是什么?是数据库的root吗?并不是,而是操作系统权限,此时我们的数据平面在操作系统层面在操作系统层⾯,我们⽬前就是mysql进程派⽣的⼀个bash进程,所以与mysql进程是同层级的,所以此时我可以读写mysql数据库⽂件⽬录的⽂件。也⼤概率有权限读web⽬录的⽂件
2025年09月10日
3 阅读
0 评论
0 点赞
2025-09-10
紧紧抓住输入
安全的本质以下知识仅为个人学习过程中的记录安全的本质是信任问题。--道哥⼀切的安全⽅案设计的基础,都是建⽴在信任关系上的。我们必须相信⼀些东⻄,必须要有⼀ 些最基本的假设,安全⽅案才能得以建⽴。反之,如果我们否定⼀切,安全⽅案就会变成⽆源之⽔、⽆本之⽊,⽆法设计,也⽆法完成。 --道哥eg信任普通用户的输入会导致前台漏洞信任管理员的输入会导致后台漏洞信任升级包、离线升级等会导致供应链攻击那么不信任任何用户的输入呢?难道这不是无源之水吗?其实这个是将信任关系转移到了对于输入的检测逻辑上,在这种情况下,一旦输入检测逻辑出现问题,信任关系就会被打破,从而出现漏洞。所有的安全模型都可以简化为:输入 -> 检测输入逻辑 -> 输出像是WAF、IDS、IPS、EDR等都是对输入进行安全检测,进而输出是否安全的结果结论通过上述的简单阐述,可以看到一切都是跟输入息息相关的,对于我们而言,我们可以掌控和能掌控的只有输入,所以挖掘漏洞的最好的入手点就是从输入去入手在代码审计的过程中,要紧紧抓住我们可控的输入,逐步跟踪传播链条判断是否有撸点程序希望用户输入什么控制流与数据流<html> <body>Hello my name is : <?php echo $_GET["name"]; ?> </body> </html><html> <script> console.log("Hello my name is :" + "<?php echo $_GET['name']; ?>") </script> </html>第一部分的代码是控制代码走向的控制流代码第二部分的代码是展示数据的数据流代码,不具备控制代码走向的能力开发者一定希望用户输入的是数据流的代码,当用户能够控制代码走向,那么将导致程序出现不可预料的结果,这是他们不愿意看到的。同时这种不可预料的结果,往往伴随着漏洞点的出现,所以当我们可以通过数据流侵入控制流时,漏洞就产生了。SQL注入<?php $db = init_db(); $username = $_GET['username']; //input: fuck' and 1=1# $db->query("select * from table where username = '$username'"); ?>输入的流转:输入->PHP的字符串->SQL语句->数据库查询在整个数据流流转的过程中,其实我们可以发现任何语言都可以形成这种查询结构,不管是PHP、Java、Python等任何编程语言,所以这时候我们可以明白这种结构跟用什么编程语言是没有关系的,编程语言仅仅是我们用来表达这个结构的,我们真正要考虑的是数据库的层面。在数据库层面:控制流是SQL语句action: select object: table subject: * condition: key: username value: $username # 输入要确保程序始终执行原意,那么开发者就需要在编写程序时对输入进行限制,确保用户输入只能影响value的位置,如果没有确保这个条件,那么漏洞就会出现action: select object: table subject: * condition: key1: username value1: $username # 输入jack key2: 1 # and 1=1 value2: 1我们在代码层的输入,在数据库层面的数据流侵入到了控制流,从而造成了SQL注入。原本数据库的数据流就是只输入jack的值,结果为select * from table where username = 'jack',但是却变成select * from table where username = 'jack' and 1=1#,从数据流侵入控制流,让输出出现了不可预料的结果。SSTI服务端模板注⼊(Server-Side Template Injection)也可以⽤相同的⽅式来理解。Twig是php的⼀套模板渲染的组件,但是不规范的渲染参数输⼊⽅式,可能导致模板注⼊。<?php require_once dirname(__FILE__).'\twig\lib\Twig\Autoloader.php'; Twig_Autoloader::register(true); $twig = new Twig_Environment(new Twig_Loader_String()); $output = $twig->render("Hello {{name}}", array("name" => $_GET["name"])); // 将⽤户输⼊作为模版变量的值 echo $output; ?>输入的流转:输入->$_GET["name"]->Twig渲染字符串->Twig发现变量{{name}}->找到变量name的绑定->解析字符串->渲染展示<?php require_once dirname(__FILE__).'/../lib/Twig/Autoloader.php'; Twig_Autoloader::register(true); $twig=newTwig_Environment(newTwig_Loader_String()); $output=$twig->render("Hello {$_GET['name']}");// 将⽤户输⼊作为模版内容的⼀部分 echo $output; ?>输入的流转:输入->$_GET["name"]->拼接name为新的PHP字符串->字符串内容被Twig渲染展示上面两种写法觉得哪种存在毛病,或者说可能存在漏洞?第一种写法是先经过Twig框架渲染再将变量渲染进去,第二种写法是先将变量拼接为一个新字符串,然后再将整个字符串通过Twig渲染。第一种方法遵循了框架的写法,通常遵循框架写法的方式基本没有漏洞。模版引擎一般都默认对渲染的变量值进行编码和转义,所以并不会造成跨站脚本攻击而第二种方法它是先拼接后渲染,并没有作为模板渲染的变量进行渲染,所以说没有做安全过滤,故而第二种写法存在漏洞,可以进行XSS攻击。同样的,此处模板渲染的过程中并非只有PHP的代码能够实现SSTI漏洞,所有的编程语言都可能存在这个漏洞,PHP只是我们表述这个漏洞的一种方式。在此处,我们在代码层的输入,造成了Twig模板层中数据流侵入到控制流,从而导致SSTI。命令执行RCE<?php $domain = $_GET["domain"]; //input:baidu.com";whoami;echo "fuck echo system('ping "'.$domain.'"'); ?>程序的原意execute: process: exe: ping --> /bin/ping arg: $domain在此处,开发者应该保证用户输入仅能影响arg的值,如果没有做到这点,那么就会造成漏洞的出现。execute: process1: exe: ping --> /bin/ping arg: $domain process2: exe: whoami --> /bin/whoami arg: - process3: exe: echo arg: "fuck"同样任何编程语言都存在这种写法,也存在这种漏洞,PHP仅为我们表述的一种方式。我们在代码层的输入导致了bash层的数据流侵入控制流,进而造成了RCE。总结漏洞并非一种语言独有,任何编程语言都是一种表述方式,我们的关注点要放在数据流和控制流上,一旦数据流可以侵入到控制流,那么信任关系就被打破,漏洞就会出现。业务流程问题除了上述的数据流侵入到控制流,还有一些业务流程、逻辑上的问题。很多逻辑漏洞、越权漏洞,往往来⾃于此。这也是现代MVC结构会出现的比较多的问题。现代mvc结构⼀般不会出现sql注⼊、xss、webshell上传,这是由于他们的框架已经自己集成了对于这些攻击的过滤,只要按照框架来写,自然就很少会出现这些漏洞。当然,不按框架写还是会出现这些漏洞的。过度信任用户输入<?php $user_id = int($_GET['user_id']); $db = init_db(); $data = $db->query("select * from user where user_id = $user_id"); echo parse_user_profile($data); ?>此处因为将输入的user_id数据进行int转换,虽然不存在SQL注入问题,但是过度信任用户的输入,导致用户输入任何数据都可以进行查询(越权),进而造成了逻辑漏洞。不信任用户输入-信任检测逻辑那我们换一种方式,不信任用户的所有输入,转而信任开发者编写的检测逻辑。<?php session_start(); $password = "test"; $_SESSION['is_login'] = 0; if ($_GET['password'] == $password){ $_SESSION['is_login'] = 1; $_SESSION['user_id'] = $_GET["user_id"]; // 假定管理员user_id=0 header("location: /user.php?is_login=1"); exit(); }else{ echo "密码错误"; exit(); } ?>// http://192.168.215.129/login.php?password=test&user_id=123 <?php header("content-type: text/html; charset=utf-8"); if ($_SESSION['is_login'] == $_GET['is_login']){ //NULL == NULL echo "你登录了"; if ($_SESSION['user_id'] == 0){ NULL == 0 echo "你是管理员"; }else{ echo "你不是管理员,付钱"; } }else{ echo "没登陆,滚"; } ?>业务流程检测逻辑不规范导致漏洞,是⼤家进⾏代码审计最经常遇到的。整个流程⾥⾯,开发者完全没有信任⽤户的输⼊。对密码进⾏了校验,校验通过才存session,并且⽤户id也是存储于session中的,没法通过cookie伪造绕过鉴权。PHP是一个弱类型的脚本语言,在php下,NULL == false == 0 == ""⽽$_SESSION的取值来⾃于cookie中PHPSESSION的输⼊,如果我们不输⼊cookie,这⾥就完全绕过这个校验。为什么呢?因为没有输入Cookie,那么$_SESSION的值为NULL,同时is_login的值也不输入,它也为NULL,进一步发现$_SESSION中的user_id也为NULL,所以就饶过了所有的校验。业务流程检测逻辑不规范导致漏洞,是代码审计过程中最常遇到的。代码审计的最终心法内容只有两点:代码审计过程中能否让数据流侵入到控制流代码审计过程中,业务逻辑可能存在问题的点有哪些?(如何快速通过污点分析找出有问题的的业务?)
2025年09月10日
3 阅读
0 评论
0 点赞
1
2